diff options
author | Thomas White <taw@bitwiz.me.uk> | 2019-03-10 15:06:07 +0100 |
---|---|---|
committer | Thomas White <taw@bitwiz.me.uk> | 2019-03-10 15:06:07 +0100 |
commit | 0e88cfed0e00a34436c4db3c9b2b8ad422c5a2df (patch) | |
tree | 9d221e5db2b6a123adf21271f61fe3d88d3871e2 | |
parent | 528d0c29049546e130ab61dcc3f67d0ebc9a38cc (diff) |
Implement selection
-rw-r--r-- | libstorycode/gtk/gtknarrativeview.c | 97 | ||||
-rw-r--r-- | libstorycode/gtk/gtknarrativeview.h | 10 | ||||
-rw-r--r-- | libstorycode/narrative_render_cairo.c | 109 | ||||
-rw-r--r-- | libstorycode/narrative_render_cairo.h | 13 |
4 files changed, 170 insertions, 59 deletions
diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c index bf0d22c..211da32 100644 --- a/libstorycode/gtk/gtknarrativeview.c +++ b/libstorycode/gtk/gtknarrativeview.c @@ -139,7 +139,7 @@ static void rewrap_range(GtkNarrativeView *e, int min, int max) presentation_get_stylesheet(e->p), lang, pc, e->w, presentation_get_imagestore(e->p), - min, max); + min, max, e->sel_start, e->sel_end); } @@ -722,6 +722,35 @@ static void cursor_moveh(Narrative *n, struct edit_pos *cp, signed int dir) } +static void unset_selection(GtkNarrativeView *e) +{ + int a, b; + + a = e->sel_start.para; + b = e->sel_end.para; + if ( a > b ) { + a = e->sel_end.para; + b = e->sel_start.para; + } + e->sel_start.para = 0; + e->sel_start.pos = 0; + e->sel_start.trail = 0; + e->sel_end.para = 0; + e->sel_end.pos = 0; + e->sel_end.trail = 0; + rewrap_range(e, a, b); +} + + +static int positions_equal(struct edit_pos a, struct edit_pos b) +{ + if ( a.para != b.para ) return 0; + if ( a.pos != b.pos ) return 0; + if ( a.trail != b.trail ) return 0; + return 1; +} + + static void do_backspace(GtkNarrativeView *e, signed int dir) { Narrative *n; @@ -730,7 +759,7 @@ static void do_backspace(GtkNarrativeView *e, signed int dir) n = presentation_get_narrative(e->p); - if ( e->sel_active ) { + if ( !positions_equal(e->sel_start, e->sel_end) ) { /* Block delete */ p1 = e->sel_start; @@ -749,13 +778,13 @@ static void do_backspace(GtkNarrativeView *e, signed int dir) o2 = pos_trail_to_offset(&n->items[p2.para], p2.pos, p2.trail); narrative_delete_block(n, p1.para, o1, p2.para, o2); e->cpos = p1; - e->sel_active = 0; /* The only paragraphs which still exist and might have been * affected by the deletion are sel_start.para and the one * immediately afterwards. */ rewrap_range(e, p1.para, p1.para+1); update_size(e); + unset_selection(e); emit_change_sig(e); redraw(e); } @@ -780,7 +809,7 @@ static void insert_text(char *t, GtkNarrativeView *e) Narrative *n; struct narrative_item *item; - if ( e->sel_active ) { + if ( !positions_equal(e->sel_start, e->sel_end) ) { do_backspace(e, 0); } @@ -826,22 +855,6 @@ static gboolean im_commit_sig(GtkIMContext *im, gchar *str, } -static void unset_selection(GtkNarrativeView *e) -{ - int a, b; - - if ( !e->sel_active ) return; - - a = e->sel_start.para; - b = e->sel_end.para; - if ( a > b ) { - a = e->sel_end.para; - b = e->sel_start.para; - } - e->sel_active = 0; -} - - static int find_cursor(Narrative *n, double x, double y, struct edit_pos *pos) { double cur_y; @@ -891,21 +904,47 @@ static gboolean button_press_sig(GtkWidget *da, GdkEventButton *event, } +static void sorti(int *a, int *b) +{ + if ( *a > *b ) { + int tmp = *a; + *a = *b; + *b = tmp; + } +} + + static gboolean motion_sig(GtkWidget *da, GdkEventMotion *event, GtkNarrativeView *e) { + Narrative *n; + gdouble x, y; + struct edit_pos old_sel_end; + int minp, maxp; + + x = event->x; + y = event->y + e->scroll_pos; + if ( e->drag_status == DRAG_STATUS_COULD_DRAG ) { /* We just got a motion signal, and the status was "could drag", * therefore the drag has started. */ e->drag_status = DRAG_STATUS_DRAGGING; } - //unset_selection(e); - //find_cursor(fr, x-fr->x, y-fr->y, &e->sel_end); - //rewrap_paragraph_range(fr, e->sel_start.para, e->sel_end.para, - // e->sel_start, e->sel_end, 1); - //find_cursor(fr, x-fr->x, y-fr->y, &e->cpos); - //e->sel_active = !positions_equal(e->sel_start, e->sel_end); + old_sel_end = e->sel_end; + n = presentation_get_narrative(e->p); + find_cursor(n, x, y, &e->sel_end); + + minp = e->sel_start.para; + maxp = e->sel_end.para; + sorti(&minp, &maxp); + if ( !positions_equal(e->sel_start, old_sel_end) ) { + if ( old_sel_end.para > maxp ) maxp = old_sel_end.para; + if ( old_sel_end.para < minp ) minp = old_sel_end.para; + } + + rewrap_range(e, minp, maxp); + find_cursor(n, x, y, &e->cpos); redraw(e); gdk_event_request_motions(event); @@ -1044,12 +1083,6 @@ static gint realise_sig(GtkWidget *da, GtkNarrativeView *e) } -static void update_size_request(GtkNarrativeView *e) -{ - gtk_widget_set_size_request(GTK_WIDGET(e), 0, e->h); -} - - GtkNarrativeView *gtk_narrative_view_new(Presentation *p) { GtkNarrativeView *nview; diff --git a/libstorycode/gtk/gtknarrativeview.h b/libstorycode/gtk/gtknarrativeview.h index 13400db..942044e 100644 --- a/libstorycode/gtk/gtknarrativeview.h +++ b/libstorycode/gtk/gtknarrativeview.h @@ -34,6 +34,7 @@ #include <narrative.h> #include <presentation.h> #include <imagestore.h> +#include <narrative_render_cairo.h> #define GTK_TYPE_NARRATIVE_VIEW (gtk_narrative_view_get_type()) @@ -70,14 +71,6 @@ enum drag_status }; -struct edit_pos -{ - int para; /* Paragraph number (corresponding to narrative items) */ - int pos; /* Byte position within paragraph (yes, really) */ - int trail; /* 1 = end of character, 0 = before */ -}; - - struct _gtknarrativeview { GtkDrawingArea parent_instance; @@ -105,7 +98,6 @@ struct _gtknarrativeview /* Rubber band boxes and related stuff */ enum drag_status drag_status; - int sel_active; struct edit_pos sel_start; /* Where the user dragged from */ struct edit_pos sel_end; }; diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c index 6293c44..dc5fb2a 100644 --- a/libstorycode/narrative_render_cairo.c +++ b/libstorycode/narrative_render_cairo.c @@ -38,6 +38,7 @@ #include "stylesheet.h" #include "imagestore.h" #include "slide_render_cairo.h" +#include "narrative_render_cairo.h" #include "narrative_priv.h" @@ -66,7 +67,8 @@ static PangoAlignment to_pangoalignment(enum alignment align) static void wrap_text(struct narrative_item *item, PangoContext *pc, - Stylesheet *ss, enum style_element el, double w) + Stylesheet *ss, enum style_element el, double w, + size_t sel_start, size_t sel_end) { PangoAlignment palignment; PangoRectangle rect; @@ -109,6 +111,15 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc, attr = pango_attr_foreground_new(r, g, b); pango_attr_list_insert(attrs, attr); + /* Add attributes for selected text */ + if ( sel_start > 0 || sel_end > 0 ) { + PangoAttribute *attr; + attr = pango_attr_background_new(42919, 58853, 65535); + attr->start_index = sel_start; + attr->end_index = sel_end; + pango_attr_list_insert(attrs, attr); + } + if ( item->layout == NULL ) { item->layout = pango_layout_new(pc); } @@ -189,12 +200,59 @@ static void wrap_slide(struct narrative_item *item, Stylesheet *ss, ImageStore * } +static size_t pos_trail_to_offset(struct narrative_item *item, int offs, int trail) +{ + glong char_offs; + char *ptr; + + if ( item->type == NARRATIVE_ITEM_SLIDE ) { + return offs; + } + + char_offs = g_utf8_pointer_to_offset(item->text, item->text+offs); + char_offs += trail; + ptr = g_utf8_offset_to_pointer(item->text, char_offs); + return ptr - item->text; +} + + +static int positions_equal(struct edit_pos a, struct edit_pos b) +{ + if ( a.para != b.para ) return 0; + if ( a.pos != b.pos ) return 0; + if ( a.trail != b.trail ) return 0; + return 1; +} + + +static void sort_positions(struct edit_pos *a, struct edit_pos *b) +{ + if ( a->para > b->para ) { + size_t tpos; + int tpara, ttrail; + tpara = b->para; tpos = b->pos; ttrail = b->trail; + b->para = a->para; b->pos = a->pos; b->trail = a->trail; + a->para = tpara; a->pos = tpos; a->trail = ttrail; + } + + if ( (a->para == b->para) && (a->pos > b->pos) ) + { + size_t tpos = b->pos; + int ttrail = b->trail; + b->pos = a->pos; b->trail = a->trail; + a->pos = tpos; a->trail = ttrail; + } +} + + int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang, PangoContext *pc, double w, ImageStore *is, - int min, int max) + int min, int max, + struct edit_pos sel_start, struct edit_pos sel_end) { int i; struct length pad[4]; + int sel_s, sel_e; if ( stylesheet_get_padding(stylesheet, STYEL_NARRATIVE, pad) ) return 1; n->space_l = lcalc(pad[0], w); @@ -205,23 +263,56 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la n->w = w; w -= n->space_l + n->space_r; + sort_positions(&sel_start, &sel_end); + + if ( !positions_equal(sel_start, sel_end) ) { + struct narrative_item *item; + item = &n->items[sel_start.para]; + sel_s = pos_trail_to_offset(item, sel_start.pos, sel_start.trail); + item = &n->items[sel_end.para]; + sel_e = pos_trail_to_offset(item, sel_end.pos, sel_end.trail); + } else { + sel_s = 0; + sel_e = 0; + } + for ( i=min; i<=max; i++ ) { + size_t srt, end; + if ( i >= sel_start.para && i <= sel_end.para ) { + if ( i == sel_start.para ) { + srt = sel_s; + } else { + srt = 0; + } + if ( i == sel_end.para ) { + end = sel_e; + } else { + end = G_MAXUINT; + } + if ( i > sel_start.para && i < sel_end.para ) { + end = G_MAXUINT; + } + } else { + srt = 0; + end = 0; + } + switch ( n->items[i].type ) { case NARRATIVE_ITEM_TEXT : wrap_text(&n->items[i], pc, stylesheet, - STYEL_NARRATIVE, w); + STYEL_NARRATIVE, w, srt, end); break; case NARRATIVE_ITEM_BP : wrap_text(&n->items[i], pc, stylesheet, - STYEL_NARRATIVE_BP, w); + STYEL_NARRATIVE_BP, w, srt, end); break; case NARRATIVE_ITEM_PRESTITLE : wrap_text(&n->items[i], pc, stylesheet, - STYEL_NARRATIVE_PRESTITLE, w); + STYEL_NARRATIVE_PRESTITLE, w, srt, end); break; case NARRATIVE_ITEM_SLIDE : @@ -238,14 +329,6 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la } -int narrative_wrap(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang, - PangoContext *pc, double w, ImageStore *is) -{ - return narrative_wrap_range(n, stylesheet, lang, pc, w, is, - 0, n->n_items-1); -} - - double narrative_get_height(Narrative *n) { int i; diff --git a/libstorycode/narrative_render_cairo.h b/libstorycode/narrative_render_cairo.h index 93941df..690517d 100644 --- a/libstorycode/narrative_render_cairo.h +++ b/libstorycode/narrative_render_cairo.h @@ -30,14 +30,17 @@ #include "presentation.h" #include "imagestore.h" +struct edit_pos +{ + int para; /* Paragraph number (corresponding to narrative items) */ + int pos; /* Byte position within paragraph (yes, really) */ + int trail; /* 1 = end of character, 0 = before */ +}; extern int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang, PangoContext *pc, double w, - ImageStore *is, int min, int max); - -extern int narrative_wrap(Narrative *n, Stylesheet *stylesheet, - PangoLanguage *lang, PangoContext *pc, double w, - ImageStore *is); + ImageStore *is, int min, int max, + struct edit_pos sel_start, struct edit_pos sel_end); extern double narrative_get_height(Narrative *n); |