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:
parent
d1c40196e3
commit
fd95c729d5
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue