summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorFarow <farow.the.time.traveler@gmail.com>2014-08-23 21:08:10 +0300
committerTingPing <tingping@tingping.se>2014-09-01 17:53:03 -0400
commitfd95c729d5ecdb8a65497ae9b6049748d5a3c127 (patch)
tree09dcf3e294977a829572bf36e8a323a5cf8a01ef
parentd1c40196e3a5087980c67b1a35928a3fff81c0ae (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.c154
-rw-r--r--src/fe-gtk/xtext.h3
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;