diff options
author | Farow <farow.the.time.traveler@gmail.com> | 2014-08-23 21:08:10 +0300 |
---|---|---|
committer | TingPing <tingping@tingping.se> | 2014-09-01 17:53:03 -0400 |
commit | fd95c729d5ecdb8a65497ae9b6049748d5a3c127 (patch) | |
tree | 09dcf3e294977a829572bf36e8a323a5cf8a01ef | |
parent | d1c40196e3a5087980c67b1a35928a3fff81c0ae (diff) |
xtext: Add word and line selection modes
Similar to a GtkTextView if you double click you enter word selection mode and if you triple click you enter line selection mode. Allowing you to drag and select more than a single character. Closes #1108
-rw-r--r-- | src/fe-gtk/xtext.c | 154 | ||||
-rw-r--r-- | src/fe-gtk/xtext.h | 3 |
2 files changed, 80 insertions, 77 deletions
diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index 6a3c1ac9..6a499f52 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -138,6 +138,7 @@ static void gtk_xtext_search_textentry_del (xtext_buffer *, textentry *); static void gtk_xtext_search_textentry_fini (gpointer, gpointer); static void gtk_xtext_search_fini (xtext_buffer *); static gboolean gtk_xtext_search_init (xtext_buffer *buf, const gchar *text, gtk_xtext_search_flags flags, GError **perr); +static char * gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, int *ret_off, int *ret_len, GSList **slp); /* Avoid warning messages for this unused function */ #if 0 @@ -934,7 +935,7 @@ gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int subline, static textentry * gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, - int *out_of_bounds) + int *out_of_bounds, int *ret_subline) { textentry *ent; int line; @@ -952,6 +953,9 @@ gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, if (off) *off = gtk_xtext_find_x (xtext, x, ent, subline, line, out_of_bounds); + if (ret_subline) + *ret_subline = subline; + return ent; } @@ -1045,14 +1049,14 @@ gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area) return; } - ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL); + ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL, NULL); if (!ent_start) { xtext_draw_bg (xtext, area->x, area->y, area->width, area->height); goto xit; } ent_end = gtk_xtext_find_char (xtext, area->x + area->width, - area->y + area->height, NULL, NULL); + area->y + area->height, NULL, NULL, NULL); if (!ent_end) ent_end = xtext->buffer->text_last; @@ -1297,84 +1301,95 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren textentry *ent_start; int offset_start; int offset_end; - int low_x; - int low_y; - int high_x; - int high_y; - int tmp; + int subline_start; + int subline_end; int oob; - int marking_up; + int marking_up = FALSE; + int len_start; + int len_end; - if (xtext->select_start_y > xtext->select_end_y) - { - low_x = xtext->select_end_x; - low_y = xtext->select_end_y; - marking_up = TRUE; - high_x = xtext->select_start_x; - high_y = xtext->select_start_y; - } else - { - low_x = xtext->select_start_x; - low_y = xtext->select_start_y; - high_x = xtext->select_end_x; - high_y = xtext->select_end_y; - marking_up = FALSE; - } + ent_start = gtk_xtext_find_char (xtext, xtext->select_start_x, xtext->select_start_y, &offset_start, &oob, &subline_start); + ent_end = gtk_xtext_find_char (xtext, xtext->select_end_x, xtext->select_end_y, &offset_end, &oob, &subline_end); - ent_start = gtk_xtext_find_char (xtext, low_x, low_y, &offset_start, &oob); - if (!ent_start) + if ((!ent_start || !ent_end) && !xtext->buffer->text_last && xtext->adj->value != xtext->buffer->old_value) { - if (xtext->adj->value != xtext->buffer->old_value) - gtk_xtext_render_page (xtext); + gtk_xtext_render_page (xtext); return; } - else if (oob) + + if (!ent_start) { - offset_start = marking_up == TRUE? 0: xtext->buffer->last_offset_start; + ent_start = xtext->buffer->text_last; + offset_start = ent_start->str_len; } - ent_end = gtk_xtext_find_char (xtext, high_x, high_y, &offset_end, &oob); if (!ent_end) { ent_end = xtext->buffer->text_last; - if (!ent_end) - { - if (xtext->adj->value != xtext->buffer->old_value) - gtk_xtext_render_page (xtext); - return; - } offset_end = ent_end->str_len; } - else if (oob) + + if ((ent_start != ent_end && xtext->select_start_y > xtext->select_end_y) || /* different entries */ + (ent_start == ent_end && subline_start > subline_end) || /* different lines */ + (ent_start == ent_end && subline_start == subline_end && xtext->select_start_x > xtext->select_end_x)) /* marking to the left */ { - offset_end = marking_up == FALSE? ent_end->str_len: xtext->buffer->last_offset_end; + marking_up = TRUE; } - /* marking less than a complete line? */ - /* make sure "start" is smaller than "end" (swap them if need be) */ - if (ent_start == ent_end && offset_start > offset_end) + /* word selection */ + if (xtext->word_select) + { + /* a word selection cannot be started if the cursor is out of bounds in gtk_xtext_button_press */ + gtk_xtext_get_word (xtext, xtext->select_start_x, xtext->select_start_y, NULL, &offset_start, &len_start, NULL); + + /* in case the cursor is out of bounds we keep offset_end from gtk_xtext_find_char and fix the length */ + if (gtk_xtext_get_word (xtext, xtext->select_end_x, xtext->select_end_y, NULL, &offset_end, &len_end, NULL) == NULL) + len_end = offset_end == ent_end->str_len? 0: -1; /* -1 for the space, 0 if at the end */ + + if (!marking_up) + offset_end += len_end; + else + offset_start += len_start; + } + /* line/ent selection */ + else if (xtext->line_select) { - tmp = offset_start; + offset_start = marking_up? ent_start->str_len: 0; + offset_end = marking_up? 0: ent_end->str_len; + } + + if (marking_up) + { + int temp; + + /* ensure ent_start is above ent_end */ + if (ent_start != ent_end) + { + ent = ent_start; + ent_start = ent_end; + ent_end = ent; + } + + /* switch offsets as well */ + temp = offset_start; offset_start = offset_end; - offset_end = tmp; + offset_end = temp; } /* set all the old mark_ fields to -1 */ gtk_xtext_selection_clear (xtext->buffer); + /* set the default values */ + ent_start->mark_end = ent_start->str_len; + ent_end->mark_start = 0; + + /* set the calculated values (this overwrites the default values if we're on the same ent) */ ent_start->mark_start = offset_start; - ent_start->mark_end = offset_end; + ent_end->mark_end = offset_end; + /* set all the mark_ fields of the ents within the selection */ if (ent_start != ent_end) { - ent_start->mark_end = ent_start->str_len; - if (offset_end != 0) - { - ent_end->mark_start = 0; - ent_end->mark_end = offset_end; - } - - /* set all the mark_ fields of the ents within the selection */ ent = ent_start->next; while (ent && ent != ent_end) { @@ -1383,11 +1398,6 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren ent = ent->next; } } - else - { - if (xtext->mark_stamp) - offset_start = 0; - } if (render) gtk_xtext_selection_render (xtext, ent_start, ent_end); @@ -1522,7 +1532,7 @@ gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, int out_of_bounds = 0; int len_to_offset = 0; - ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds); + ent = gtk_xtext_find_char (xtext, x, y, &offset, &out_of_bounds, NULL); if (ent == NULL || out_of_bounds || offset < 0 || offset >= ent->str_len) return NULL; @@ -1907,13 +1917,6 @@ gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event) return FALSE; } - if (xtext->word_or_line_select) - { - xtext->word_or_line_select = FALSE; - xtext->button_down = FALSE; - return FALSE; - } - if (event->button == 1) { xtext->button_down = FALSE; @@ -1938,6 +1941,13 @@ gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event) } } + if (xtext->word_select || xtext->line_select) + { + xtext->word_select = FALSE; + xtext->line_select = FALSE; + return FALSE; + } + if (xtext->select_start_x == event->x && xtext->select_start_y == event->y && xtext->buffer->last_ent_start) @@ -1998,11 +2008,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event) ent->mark_start = offset; ent->mark_end = offset + len; gtk_xtext_selection_render (xtext, ent, ent); - xtext->word_or_line_select = TRUE; - if (prefs.hex_text_autocopy_text) - { - gtk_xtext_set_clip_owner (GTK_WIDGET (xtext), event); - } + xtext->word_select = TRUE; } return FALSE; @@ -2017,11 +2023,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event) ent->mark_start = 0; ent->mark_end = ent->str_len; gtk_xtext_selection_render (xtext, ent, ent); - xtext->word_or_line_select = TRUE; - if (prefs.hex_text_autocopy_text) - { - gtk_xtext_set_clip_owner (GTK_WIDGET (xtext), event); - } + xtext->line_select = TRUE; } return FALSE; diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h index 0a4215c5..73f5b52d 100644 --- a/src/fe-gtk/xtext.h +++ b/src/fe-gtk/xtext.h @@ -216,7 +216,8 @@ struct _GtkXText /* various state information */ unsigned int moving_separator:1; - unsigned int word_or_line_select:1; + unsigned int word_select:1; + unsigned int line_select:1; unsigned int button_down:1; unsigned int hilighting:1; unsigned int dont_render:1; |