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
This commit is contained in:
Farow 2014-08-23 21:08:10 +03:00 committed by TingPing
parent d1c40196e3
commit fd95c729d5
2 changed files with 81 additions and 78 deletions

View File

@ -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_textentry_fini (gpointer, gpointer);
static void gtk_xtext_search_fini (xtext_buffer *); 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 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 */ /* Avoid warning messages for this unused function */
#if 0 #if 0
@ -934,7 +935,7 @@ gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int subline,
static textentry * static textentry *
gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, 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; textentry *ent;
int line; int line;
@ -952,6 +953,9 @@ gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off,
if (off) if (off)
*off = gtk_xtext_find_x (xtext, x, ent, subline, line, out_of_bounds); *off = gtk_xtext_find_x (xtext, x, ent, subline, line, out_of_bounds);
if (ret_subline)
*ret_subline = subline;
return ent; return ent;
} }
@ -1045,14 +1049,14 @@ gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area)
return; 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) if (!ent_start)
{ {
xtext_draw_bg (xtext, area->x, area->y, area->width, area->height); xtext_draw_bg (xtext, area->x, area->y, area->width, area->height);
goto xit; goto xit;
} }
ent_end = gtk_xtext_find_char (xtext, area->x + area->width, 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) if (!ent_end)
ent_end = xtext->buffer->text_last; ent_end = xtext->buffer->text_last;
@ -1297,84 +1301,95 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren
textentry *ent_start; textentry *ent_start;
int offset_start; int offset_start;
int offset_end; int offset_end;
int low_x; int subline_start;
int low_y; int subline_end;
int high_x;
int high_y;
int tmp;
int oob; int oob;
int marking_up; int marking_up = FALSE;
int len_start;
int len_end;
if (xtext->select_start_y > xtext->select_end_y) 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);
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, low_x, low_y, &offset_start, &oob); if ((!ent_start || !ent_end) && !xtext->buffer->text_last && xtext->adj->value != xtext->buffer->old_value)
if (!ent_start)
{ {
if (xtext->adj->value != xtext->buffer->old_value)
gtk_xtext_render_page (xtext); gtk_xtext_render_page (xtext);
return; 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) if (!ent_end)
{ {
ent_end = xtext->buffer->text_last; 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; 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? */ /* word selection */
/* make sure "start" is smaller than "end" (swap them if need be) */ if (xtext->word_select)
if (ent_start == ent_end && offset_start > offset_end)
{ {
tmp = offset_start; /* 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)
{
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_start = offset_end;
offset_end = tmp; offset_end = temp;
} }
/* set all the old mark_ fields to -1 */ /* set all the old mark_ fields to -1 */
gtk_xtext_selection_clear (xtext->buffer); gtk_xtext_selection_clear (xtext->buffer);
ent_start->mark_start = offset_start; /* set the default values */
ent_start->mark_end = offset_end;
if (ent_start != ent_end)
{
ent_start->mark_end = ent_start->str_len; ent_start->mark_end = ent_start->str_len;
if (offset_end != 0)
{
ent_end->mark_start = 0; 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_end->mark_end = offset_end; ent_end->mark_end = offset_end;
}
/* set all the mark_ fields of the ents within the selection */ /* set all the mark_ fields of the ents within the selection */
if (ent_start != ent_end)
{
ent = ent_start->next; ent = ent_start->next;
while (ent && ent != ent_end) while (ent && ent != ent_end)
{ {
@ -1383,11 +1398,6 @@ gtk_xtext_selection_draw (GtkXText * xtext, GdkEventMotion * event, gboolean ren
ent = ent->next; ent = ent->next;
} }
} }
else
{
if (xtext->mark_stamp)
offset_start = 0;
}
if (render) if (render)
gtk_xtext_selection_render (xtext, ent_start, ent_end); 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 out_of_bounds = 0;
int len_to_offset = 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) if (ent == NULL || out_of_bounds || offset < 0 || offset >= ent->str_len)
return NULL; return NULL;
@ -1907,13 +1917,6 @@ gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event)
return FALSE; return FALSE;
} }
if (xtext->word_or_line_select)
{
xtext->word_or_line_select = FALSE;
xtext->button_down = FALSE;
return FALSE;
}
if (event->button == 1) if (event->button == 1)
{ {
xtext->button_down = FALSE; 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 && if (xtext->select_start_x == event->x &&
xtext->select_start_y == event->y && xtext->select_start_y == event->y &&
xtext->buffer->last_ent_start) xtext->buffer->last_ent_start)
@ -1998,11 +2008,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
ent->mark_start = offset; ent->mark_start = offset;
ent->mark_end = offset + len; ent->mark_end = offset + len;
gtk_xtext_selection_render (xtext, ent, ent); gtk_xtext_selection_render (xtext, ent, ent);
xtext->word_or_line_select = TRUE; xtext->word_select = TRUE;
if (prefs.hex_text_autocopy_text)
{
gtk_xtext_set_clip_owner (GTK_WIDGET (xtext), event);
}
} }
return FALSE; return FALSE;
@ -2017,11 +2023,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
ent->mark_start = 0; ent->mark_start = 0;
ent->mark_end = ent->str_len; ent->mark_end = ent->str_len;
gtk_xtext_selection_render (xtext, ent, ent); gtk_xtext_selection_render (xtext, ent, ent);
xtext->word_or_line_select = TRUE; xtext->line_select = TRUE;
if (prefs.hex_text_autocopy_text)
{
gtk_xtext_set_clip_owner (GTK_WIDGET (xtext), event);
}
} }
return FALSE; return FALSE;

View File

@ -216,7 +216,8 @@ struct _GtkXText
/* various state information */ /* various state information */
unsigned int moving_separator:1; 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 button_down:1;
unsigned int hilighting:1; unsigned int hilighting:1;
unsigned int dont_render:1; unsigned int dont_render:1;