[geany/geany-plugins] 26e690: Addons: Implement unselect with single click

Enrico Tröger git-noreply at xxxxx
Wed Sep 7 19:44:15 UTC 2016


Branch:      refs/heads/master
Author:      Enrico Tröger <enrico.troeger at uvena.de>
Committer:   Enrico Tröger <enrico.troeger at uvena.de>
Date:        Wed, 07 Sep 2016 19:44:15 UTC
Commit:      26e6906ed5eeab0adf5c7ad0ea177f99a3e49ea5
             https://github.com/geany/geany-plugins/commit/26e6906ed5eeab0adf5c7ad0ea177f99a3e49ea5

Log Message:
-----------
Addons: Implement unselect with single click

For this to work, we need to connect to the "button-press-event" for
each document, then process each single click and delay the detected
double click event by 50ms before processing it.
This way all markers will be removed (in case of double click
actually twice) and new markers will be set on double click.

Due to the new behaviour introduced here, the feature is disabled
by default.

Closes #445.


Modified Paths:
--------------
    addons/src/addons.c
    addons/src/ao_markword.c
    addons/src/ao_markword.h

Modified: addons/src/addons.c
45 lines changed, 40 insertions(+), 5 deletions(-)
===================================================================
@@ -77,6 +77,7 @@ typedef struct
 	gboolean enable_systray;
 	gboolean enable_bookmarklist;
 	gboolean enable_markword;
+	gboolean enable_markword_single_click_deselect;
 	gboolean enable_xmltagging;
 	gboolean enable_enclose_words;
 	gboolean enable_enclose_words_auto;
@@ -175,7 +176,6 @@ gboolean ao_editor_notify_cb(GObject *object, GeanyEditor *editor,
 							 SCNotification *nt, gpointer data)
 {
 	ao_bookmark_list_update_marker(ao_info->bookmarklist, editor, nt);
-	ao_mark_word_check(ao_info->markword, editor, nt);
 
 	return FALSE;
 }
@@ -204,6 +204,7 @@ static void ao_document_open_cb(GObject *obj, GeanyDocument *doc, gpointer data)
 	g_return_if_fail(doc != NULL && doc->is_valid);
 
 	ao_tasks_update(ao_info->tasks, doc);
+	ao_mark_document_open(ao_info->markword, doc);
 }
 
 
@@ -212,6 +213,7 @@ static void ao_document_close_cb(GObject *obj, GeanyDocument *doc, gpointer data
 	g_return_if_fail(doc != NULL && doc->is_valid);
 
 	ao_tasks_remove(ao_info->tasks, doc);
+	ao_mark_document_close(ao_info->markword, doc);
 }
 
 
@@ -280,6 +282,8 @@ void plugin_init(GeanyData *data)
 		"addons", "enable_bookmarklist", FALSE);
 	ao_info->enable_markword = utils_get_setting_boolean(config,
 		"addons", "enable_markword", FALSE);
+	ao_info->enable_markword_single_click_deselect = utils_get_setting_boolean(config,
+		"addons", "enable_markword_single_click_deselect", FALSE);
 	ao_info->strip_trailing_blank_lines = utils_get_setting_boolean(config,
 		"addons", "strip_trailing_blank_lines", FALSE);
 	ao_info->enable_xmltagging = utils_get_setting_boolean(config, "addons",
@@ -295,7 +299,8 @@ void plugin_init(GeanyData *data)
 	ao_info->openuri = ao_open_uri_new(ao_info->enable_openuri);
 	ao_info->systray = ao_systray_new(ao_info->enable_systray);
 	ao_info->bookmarklist = ao_bookmark_list_new(ao_info->enable_bookmarklist);
-	ao_info->markword = ao_mark_word_new(ao_info->enable_markword);
+	ao_info->markword = ao_mark_word_new(ao_info->enable_markword,
+		ao_info->enable_markword_single_click_deselect);
 	ao_info->tasks = ao_tasks_new(ao_info->enable_tasks,
 						ao_info->tasks_token_list, ao_info->tasks_scan_all_documents);
 	ao_info->copyfilepath = ao_copy_file_path_new();
@@ -332,6 +337,15 @@ static void ao_configure_tasks_toggled_cb(GtkToggleButton *togglebutton, gpointe
 }
 
 
+static void ao_configure_markword_toggled_cb(GtkToggleButton *togglebutton, gpointer data)
+{
+	gboolean sens = gtk_toggle_button_get_active(togglebutton);
+
+	gtk_widget_set_sensitive(g_object_get_data(
+		G_OBJECT(data), "check_markword_single_click_deselect"), sens);
+}
+
+
 static void ao_configure_doclist_toggled_cb(GtkToggleButton *togglebutton, gpointer data)
 {
 	gboolean sens = gtk_toggle_button_get_active(togglebutton);
@@ -379,6 +393,8 @@ static void ao_configure_response_cb(GtkDialog *dialog, gint response, gpointer
 			g_object_get_data(G_OBJECT(dialog), "check_bookmarklist"))));
 		ao_info->enable_markword = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
 			g_object_get_data(G_OBJECT(dialog), "check_markword"))));
+		ao_info->enable_markword_single_click_deselect = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+			g_object_get_data(G_OBJECT(dialog), "check_markword_single_click_deselect"))));
 		ao_info->strip_trailing_blank_lines = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
 			g_object_get_data(G_OBJECT(dialog), "check_blanklines"))));
 		ao_info->enable_xmltagging = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
@@ -403,6 +419,8 @@ static void ao_configure_response_cb(GtkDialog *dialog, gint response, gpointer
 		g_key_file_set_boolean(config, "addons", "enable_bookmarklist",
 			ao_info->enable_bookmarklist);
 		g_key_file_set_boolean(config, "addons", "enable_markword", ao_info->enable_markword);
+		g_key_file_set_boolean(config, "addons", "enable_markword_single_click_deselect",
+			ao_info->enable_markword_single_click_deselect);
 		g_key_file_set_boolean(config, "addons", "strip_trailing_blank_lines",
 		  ao_info->strip_trailing_blank_lines);
 		g_key_file_set_boolean(config, "addons", "enable_xmltagging",
@@ -418,7 +436,10 @@ static void ao_configure_response_cb(GtkDialog *dialog, gint response, gpointer
 		g_object_set(ao_info->systray, "enable-systray", ao_info->enable_systray, NULL);
 		g_object_set(ao_info->bookmarklist, "enable-bookmarklist",
 			ao_info->enable_bookmarklist, NULL);
-		g_object_set(ao_info->markword, "enable-markword", ao_info->enable_markword, NULL);
+		g_object_set(ao_info->markword,
+			"enable-markword", ao_info->enable_markword,
+			"enable-single-click-deselect", ao_info->enable_markword_single_click_deselect,
+			NULL);
 		g_object_set(ao_info->tasks,
 			"enable-tasks", ao_info->enable_tasks,
 			"scan-all-documents", ao_info->tasks_scan_all_documents,
@@ -449,7 +470,8 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 	GtkWidget *vbox, *check_openuri, *check_tasks, *check_systray;
 	GtkWidget *check_doclist, *vbox_doclist, *frame_doclist;
 	GtkWidget *radio_doclist_name, *radio_doclist_tab_order, *radio_doclist_tab_order_reversed;
-	GtkWidget *check_bookmarklist, *check_markword, *frame_tasks, *vbox_tasks;
+	GtkWidget *check_bookmarklist, *check_markword, *check_markword_single_click_deselect;
+	GtkWidget *frame_markword, *frame_tasks, *vbox_tasks;
 	GtkWidget *check_tasks_scan_mode, *entry_tasks_tokens, *label_tasks_tokens, *tokens_hbox;
 	GtkWidget *check_blanklines, *check_xmltagging;
 	GtkWidget *check_enclose_words, *check_enclose_words_auto, *enclose_words_config_button, *enclose_words_hbox;
@@ -557,7 +579,17 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 		_("Mark all occurrences of a word when double-clicking it"));
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_markword),
 		ao_info->enable_markword);
-	gtk_box_pack_start(GTK_BOX(vbox), check_markword, FALSE, FALSE, 3);
+	g_signal_connect(check_markword, "toggled", G_CALLBACK(ao_configure_markword_toggled_cb), dialog);
+
+	check_markword_single_click_deselect = gtk_check_button_new_with_label(
+		_("Deselect a previous highlight by single click"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_markword_single_click_deselect),
+		ao_info->enable_markword_single_click_deselect);
+
+	frame_markword = gtk_frame_new(NULL);
+	gtk_frame_set_label_widget(GTK_FRAME(frame_markword), check_markword);
+	gtk_container_add(GTK_CONTAINER(frame_markword), check_markword_single_click_deselect);
+	gtk_box_pack_start(GTK_BOX(vbox), frame_markword, FALSE, FALSE, 3);
 
 	check_blanklines = gtk_check_button_new_with_label(
 		_("Strip trailing blank lines"));
@@ -602,6 +634,8 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 	g_object_set_data(G_OBJECT(dialog), "check_systray", check_systray);
 	g_object_set_data(G_OBJECT(dialog), "check_bookmarklist", check_bookmarklist);
 	g_object_set_data(G_OBJECT(dialog), "check_markword", check_markword);
+	g_object_set_data(G_OBJECT(dialog), "check_markword_single_click_deselect",
+		check_markword_single_click_deselect);
 	g_object_set_data(G_OBJECT(dialog), "check_blanklines", check_blanklines);
 	g_object_set_data(G_OBJECT(dialog), "check_xmltagging", check_xmltagging);
 	g_object_set_data(G_OBJECT(dialog), "check_enclose_words", check_enclose_words);
@@ -610,6 +644,7 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 	g_signal_connect(dialog, "response", G_CALLBACK(ao_configure_response_cb), NULL);
 
 	ao_configure_tasks_toggled_cb(GTK_TOGGLE_BUTTON(check_tasks), dialog);
+	ao_configure_markword_toggled_cb(GTK_TOGGLE_BUTTON(check_markword), dialog);
 	ao_configure_doclist_toggled_cb(GTK_TOGGLE_BUTTON(check_doclist), dialog);
 
 	gtk_widget_show_all(vbox);


Modified: addons/src/ao_markword.c
94 lines changed, 85 insertions(+), 9 deletions(-)
===================================================================
@@ -32,6 +32,9 @@
 
 typedef struct _AoMarkWordPrivate			AoMarkWordPrivate;
 
+#define DOUBLE_CLICK_DELAY 50
+
+
 #define AO_MARKWORD_GET_PRIVATE(obj)		(G_TYPE_INSTANCE_GET_PRIVATE((obj),\
 			AO_MARKWORD_TYPE, AoMarkWordPrivate))
 
@@ -48,12 +51,16 @@ struct _AoMarkWordClass
 struct _AoMarkWordPrivate
 {
 	gboolean enable_markword;
+	gboolean enable_single_click_deselect;
+
+	guint double_click_timer_id;
 };
 
 enum
 {
 	PROP_0,
-	PROP_ENABLE_MARKWORD
+	PROP_ENABLE_MARKWORD,
+	PROP_ENABLE_MARKWORD_SINGLE_CLICK_DESELECT
 };
 
 
@@ -72,6 +79,9 @@ static void ao_mark_word_set_property(GObject *object, guint prop_id,
 		case PROP_ENABLE_MARKWORD:
 			priv->enable_markword = g_value_get_boolean(value);
 			break;
+		case PROP_ENABLE_MARKWORD_SINGLE_CLICK_DESELECT:
+			priv->enable_single_click_deselect = g_value_get_boolean(value);
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 			break;
@@ -96,6 +106,15 @@ static void ao_mark_word_class_init(AoMarkWordClass *klass)
 									"Whether to mark all occurrences of a word when double-clicking it",
 									TRUE,
 									G_PARAM_WRITABLE));
+
+	g_object_class_install_property(g_object_class,
+									PROP_ENABLE_MARKWORD_SINGLE_CLICK_DESELECT,
+									g_param_spec_boolean(
+									"enable-single-click-deselect",
+									"enable-single-click-deselect",
+									"Enable deselecting a previous highlight by single click",
+									TRUE,
+									G_PARAM_WRITABLE));
 }
 
 
@@ -108,28 +127,85 @@ static void ao_mark_word_finalize(GObject *object)
 }
 
 
-void ao_mark_word_check(AoMarkWord *bm, GeanyEditor *editor, SCNotification *nt)
+static void clear_marker(void)
+{
+	/* There might be a small risk that the current document is not the one we want
+	 * but this is very unlikely. */
+	GeanyDocument *document = document_get_current();
+	/* clear current search indicators */
+	if (DOC_VALID(document))
+		editor_indicator_clear(document->editor, GEANY_INDICATOR_SEARCH);
+}
+
+
+static gboolean mark_word(gpointer bm)
 {
 	AoMarkWordPrivate *priv = AO_MARKWORD_GET_PRIVATE(bm);
+	keybindings_send_command(GEANY_KEY_GROUP_SEARCH, GEANY_KEYS_SEARCH_MARKALL);
+	/* unset and remove myself */
+	priv->double_click_timer_id = 0;
+	return FALSE;
+}
 
-	if (priv->enable_markword)
+
+static gboolean on_editor_button_press_event(GtkWidget *widget, GdkEventButton *event,
+											 AoMarkWord *bm)
+{
+	if (event->button == 1)
 	{
-		switch (nt->nmhdr.code)
+		AoMarkWordPrivate *priv = AO_MARKWORD_GET_PRIVATE(bm);
+		if (! priv->enable_markword)
+			return FALSE;
+
+		if (event->type == GDK_BUTTON_PRESS)
 		{
-			case SCN_DOUBLECLICK:
-				keybindings_send_command(GEANY_KEY_GROUP_SEARCH, GEANY_KEYS_SEARCH_MARKALL);
-				break;
+			if (priv->enable_single_click_deselect)
+				clear_marker();
+		}
+		else if (event->type == GDK_2BUTTON_PRESS)
+		{
+			if (priv->double_click_timer_id == 0)
+				priv->double_click_timer_id = g_timeout_add(DOUBLE_CLICK_DELAY, mark_word, bm);
 		}
 	}
+	return FALSE;
+}
+
+
+void ao_mark_document_open(AoMarkWord *mw, GeanyDocument *document)
+{
+	g_return_if_fail(DOC_VALID(document));
+
+	plugin_signal_connect(
+		geany_plugin,
+		G_OBJECT(document->editor->sci),
+		"button-press-event",
+		FALSE,
+		G_CALLBACK(on_editor_button_press_event),
+		mw);
+}
+
+
+void ao_mark_document_close(AoMarkWord *mw, GeanyDocument *document)
+{
+	g_return_if_fail(DOC_VALID(document));
+
+	g_signal_handlers_disconnect_by_func(document->editor->sci, on_editor_button_press_event, mw);
 }
 
 
 static void ao_mark_word_init(AoMarkWord *self)
 {
+	AoMarkWordPrivate *priv = AO_MARKWORD_GET_PRIVATE(self);
+	priv->double_click_timer_id = 0;
 }
 
 
-AoMarkWord *ao_mark_word_new(gboolean enable)
+AoMarkWord *ao_mark_word_new(gboolean enable, gboolean single_click_deselect)
 {
-	return g_object_new(AO_MARKWORD_TYPE, "enable-markword", enable, NULL);
+	return g_object_new(
+		AO_MARKWORD_TYPE,
+		"enable-markword", enable,
+		"enable-single-click-deselect", single_click_deselect,
+		NULL);
 }


Modified: addons/src/ao_markword.h
6 lines changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -40,9 +40,9 @@ typedef struct _AoMarkWord				AoMarkWord;
 typedef struct _AoMarkWordClass			AoMarkWordClass;
 
 GType			ao_mark_word_get_type		(void);
-AoMarkWord*		ao_mark_word_new			(gboolean enable);
-void			ao_mark_word_check			(AoMarkWord *bm, GeanyEditor *editor,
-											 SCNotification *nt);
+AoMarkWord*		ao_mark_word_new			(gboolean enable, gboolean single_click_deselect);
+void			ao_mark_document_open		(AoMarkWord *mw, GeanyDocument *document);
+void			ao_mark_document_close		(AoMarkWord *mw, GeanyDocument *document);
 
 G_END_DECLS
 



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Plugins-Commits mailing list