textview: add extend-selection signal

To be able to customize the double-click and triple-click behaviors, to
provide custom selection boundaries.

https://bugzilla.gnome.org/show_bug.cgi?id=111503
This commit is contained in:
Sébastien Wilmet 2014-12-15 14:53:29 +01:00
parent 7ff3c6df80
commit 020258f85a
3 changed files with 134 additions and 26 deletions

View File

@ -3825,6 +3825,7 @@ GtkTextView
GtkTextViewClass GtkTextViewClass
GtkTextViewLayer GtkTextViewLayer
GtkTextWindowType GtkTextWindowType
GtkTextExtendSelection
GtkWrapMode GtkWrapMode
gtk_text_view_new gtk_text_view_new
gtk_text_view_new_with_buffer gtk_text_view_new_with_buffer

View File

@ -281,6 +281,7 @@ enum
SELECT_ALL, SELECT_ALL,
TOGGLE_CURSOR_VISIBLE, TOGGLE_CURSOR_VISIBLE,
PREEDIT_CHANGED, PREEDIT_CHANGED,
EXTEND_SELECTION,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -561,6 +562,12 @@ static void gtk_text_view_queue_draw_region (GtkWidget *widget,
static void gtk_text_view_get_rendered_rect (GtkTextView *text_view, static void gtk_text_view_get_rendered_rect (GtkTextView *text_view,
GdkRectangle *rect); GdkRectangle *rect);
static gboolean gtk_text_view_extend_selection (GtkTextView *text_view,
GtkTextExtendSelection granularity,
const GtkTextIter *location,
GtkTextIter *start,
GtkTextIter *end);
/* FIXME probably need the focus methods. */ /* FIXME probably need the focus methods. */
@ -714,6 +721,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
klass->paste_clipboard = gtk_text_view_paste_clipboard; klass->paste_clipboard = gtk_text_view_paste_clipboard;
klass->toggle_overwrite = gtk_text_view_toggle_overwrite; klass->toggle_overwrite = gtk_text_view_toggle_overwrite;
klass->create_buffer = gtk_text_view_create_buffer; klass->create_buffer = gtk_text_view_create_buffer;
klass->extend_selection = gtk_text_view_extend_selection;
/* /*
* Properties * Properties
@ -1278,6 +1286,34 @@ G_GNUC_END_IGNORE_DEPRECATIONS
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
G_TYPE_STRING); G_TYPE_STRING);
/**
* GtkTextView::extend-selection:
* @text_view: the object which received the signal
* @granularity: the granularity type
* @location: the location where to extend the selection
* @start: where the selection should start
* @end: where the selection should end
*
* The ::extend-selection signal is emitted when the selection needs to be
* extended at @location.
*
* Returns: %GDK_EVENT_STOP to stop other handlers from being invoked for the
* event. %GDK_EVENT_PROPAGATE to propagate the event further.
* Since: 3.16
*/
signals[EXTEND_SELECTION] =
g_signal_new (I_("extend-selection"),
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTextViewClass, extend_selection),
_gtk_boolean_handled_accumulator, NULL,
NULL, /* generic marshaller */
G_TYPE_BOOLEAN, 4,
GTK_TYPE_TEXT_EXTEND_SELECTION,
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
/* /*
* Key bindings * Key bindings
*/ */
@ -6869,23 +6905,63 @@ drag_scan_timeout (gpointer data)
return TRUE; return TRUE;
} }
/*
* Move @start and @end to the boundaries of the selection unit (indicated by
* @granularity) which contained @start initially.
* If the selction unit is SELECT_WORDS and @start is not contained in a word
* the selection is extended to all the white spaces between the end of the
* word preceding @start and the start of the one following.
*/
static void static void
extend_selection (GtkTextView *text_view, extend_selection (GtkTextView *text_view,
SelectionGranularity granularity, SelectionGranularity granularity,
const GtkTextIter *location,
GtkTextIter *start, GtkTextIter *start,
GtkTextIter *end) GtkTextIter *end)
{ {
*end = *start; GtkTextExtendSelection extend_selection_granularity;
gboolean handled = FALSE;
if (granularity == SELECT_WORDS) switch (granularity)
{ {
case SELECT_CHARACTERS:
*start = *location;
*end = *location;
return;
case SELECT_WORDS:
extend_selection_granularity = GTK_TEXT_EXTEND_SELECTION_WORD;
break;
case SELECT_LINES:
extend_selection_granularity = GTK_TEXT_EXTEND_SELECTION_LINE;
break;
default:
g_assert_not_reached ();
}
g_signal_emit (text_view,
signals[EXTEND_SELECTION], 0,
extend_selection_granularity,
location,
start,
end,
&handled);
if (!handled)
{
*start = *location;
*end = *location;
}
}
static gboolean
gtk_text_view_extend_selection (GtkTextView *text_view,
GtkTextExtendSelection granularity,
const GtkTextIter *location,
GtkTextIter *start,
GtkTextIter *end)
{
*start = *location;
*end = *location;
switch (granularity)
{
case GTK_TEXT_EXTEND_SELECTION_WORD:
if (gtk_text_iter_inside_word (start)) if (gtk_text_iter_inside_word (start))
{ {
if (!gtk_text_iter_starts_word (start)) if (!gtk_text_iter_starts_word (start))
@ -6901,6 +6977,11 @@ extend_selection (GtkTextView *text_view,
{ {
GtkTextIter tmp; GtkTextIter tmp;
/* @start is not contained in a word: the selection is extended to all
* the white spaces between the end of the word preceding @start and
* the start of the one following.
*/
tmp = *start; tmp = *start;
if (gtk_text_iter_backward_visible_word_start (&tmp)) if (gtk_text_iter_backward_visible_word_start (&tmp))
gtk_text_iter_forward_visible_word_end (&tmp); gtk_text_iter_forward_visible_word_end (&tmp);
@ -6922,9 +7003,9 @@ extend_selection (GtkTextView *text_view,
else else
gtk_text_iter_forward_to_line_end (end); gtk_text_iter_forward_to_line_end (end);
} }
} break;
else if (granularity == SELECT_LINES)
{ case GTK_TEXT_EXTEND_SELECTION_LINE:
if (gtk_text_view_starts_display_line (text_view, start)) if (gtk_text_view_starts_display_line (text_view, start))
{ {
/* If on a display line boundary, we assume the user /* If on a display line boundary, we assume the user
@ -6943,9 +7024,14 @@ extend_selection (GtkTextView *text_view,
if (!gtk_text_view_starts_display_line (text_view, end)) if (!gtk_text_view_starts_display_line (text_view, end))
gtk_text_view_forward_display_line_end (text_view, end); gtk_text_view_forward_display_line_end (text_view, end);
} }
} break;
default:
g_return_val_if_reached (GDK_EVENT_STOP);
} }
return GDK_EVENT_STOP;
}
typedef struct typedef struct
{ {
@ -7061,8 +7147,8 @@ gtk_text_view_drag_gesture_update (GtkGestureDrag *gesture,
get_iter_from_gesture (text_view, text_view->priv->drag_gesture, get_iter_from_gesture (text_view, text_view->priv->drag_gesture,
&cursor, NULL, NULL); &cursor, NULL, NULL);
start = cursor;
extend_selection (text_view, data->granularity, &start, &end); extend_selection (text_view, data->granularity, &cursor, &start, &end);
/* either the selection extends to the front, or end (or not) */ /* either the selection extends to the front, or end (or not) */
if (gtk_text_iter_compare (&cursor, &orig_start) < 0) if (gtk_text_iter_compare (&cursor, &orig_start) < 0)
@ -7193,9 +7279,8 @@ gtk_text_view_start_selection_drag (GtkTextView *text_view,
buffer = get_buffer (text_view); buffer = get_buffer (text_view);
cursor = *iter; cursor = *iter;
ins = cursor; extend_selection (text_view, data->granularity, &cursor, &ins, &bound);
extend_selection (text_view, data->granularity, &ins, &bound);
orig_start = ins; orig_start = ins;
orig_end = bound; orig_end = bound;
gdk_event_get_state (event, &state); gdk_event_get_state (event, &state);

View File

@ -81,6 +81,24 @@ typedef enum
GTK_TEXT_VIEW_LAYER_ABOVE GTK_TEXT_VIEW_LAYER_ABOVE
} GtkTextViewLayer; } GtkTextViewLayer;
/**
* GtkTextExtendSelection:
* @GTK_TEXT_EXTEND_SELECTION_WORD: Selects the current word. It is triggered by
* a double-click for example.
* @GTK_TEXT_EXTEND_SELECTION_LINE: Selects the current line. It is triggered by
* a triple-click for example.
*
* Granularity types that extend the text selection. Use the
* #GtkTextView::extend-selection signal to customize the selection.
*
* Since: 3.16
*/
typedef enum
{
GTK_TEXT_EXTEND_SELECTION_WORD,
GTK_TEXT_EXTEND_SELECTION_LINE
} GtkTextExtendSelection;
/** /**
* GTK_TEXT_VIEW_PRIORITY_VALIDATE: * GTK_TEXT_VIEW_PRIORITY_VALIDATE:
* *
@ -160,6 +178,11 @@ struct _GtkTextViewClass
void (* draw_layer) (GtkTextView *text_view, void (* draw_layer) (GtkTextView *text_view,
GtkTextViewLayer layer, GtkTextViewLayer layer,
cairo_t *cr); cairo_t *cr);
gboolean (* extend_selection) (GtkTextView *text_view,
GtkTextExtendSelection granularity,
const GtkTextIter *location,
GtkTextIter *start,
GtkTextIter *end);
/*< private >*/ /*< private >*/
@ -169,7 +192,6 @@ struct _GtkTextViewClass
void (*_gtk_reserved3) (void); void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void); void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void); void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
}; };
GDK_AVAILABLE_IN_ALL GDK_AVAILABLE_IN_ALL