Branch: refs/heads/master Author: LarsDW223 lars_paulsen@web.de Committer: LarsDW223 lars_paulsen@web.de Date: Thu, 21 Dec 2017 10:17:43 UTC Commit: da2917860f5bb059d117de1ddd36110660bc470a https://github.com/geany/geany-plugins/commit/da2917860f5bb059d117de1ddd3611...
Log Message: ----------- addons: show color tip and start Color Chooser with double click
This new feature shows a color tip if the mouse is hovered over a color value like e.g. '#fff' or '#ffffff'. If a color value is double clicked, then the Color Chooser is started. Both (showing the color tip and starting the Color Chooser) can be enabled and disabled via the plugin preferences. See #663.
Modified Paths: -------------- addons/src/Makefile.am addons/src/addons.c addons/src/ao_colortip.c addons/src/ao_colortip.h
Modified: addons/src/Makefile.am 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -25,7 +25,8 @@ addons_la_SOURCES = \ ao_tasks.c \ ao_xmltagging.c \ ao_wrapwords.c \ - ao_copyfilepath.c + ao_copyfilepath.c \ + ao_colortip.c
addons_la_CPPFLAGS = $(AM_CPPFLAGS) \ -DG_LOG_DOMAIN="Addons"
Modified: addons/src/addons.c 42 lines changed, 42 insertions(+), 0 deletions(-) =================================================================== @@ -39,6 +39,7 @@ #include "ao_xmltagging.h" #include "ao_wrapwords.h" #include "ao_copyfilepath.h" +#include "ao_colortip.h"
GeanyPlugin *geany_plugin; @@ -82,6 +83,8 @@ typedef struct gboolean enable_enclose_words; gboolean enable_enclose_words_auto; gboolean strip_trailing_blank_lines; + gboolean enable_colortip; + gboolean enable_double_click_color_chooser;
gchar *tasks_token_list; gboolean tasks_scan_all_documents; @@ -96,6 +99,7 @@ typedef struct AoMarkWord *markword; AoTasks *tasks; AoCopyFilePath *copyfilepath; + AoColorTip *colortip; } AddonsInfo; static AddonsInfo *ao_info = NULL;
@@ -181,6 +185,8 @@ gboolean ao_editor_notify_cb(GObject *object, GeanyEditor *editor, ao_mark_editor_notify(ao_info->markword, editor, nt);
+ ao_color_tip_editor_notify(ao_info->colortip, editor, nt); + return FALSE; }
@@ -208,6 +214,7 @@ static void ao_document_new_cb(GObject *obj, GeanyDocument *doc, gpointer data) g_return_if_fail(doc != NULL && doc->is_valid);
ao_mark_document_new(ao_info->markword, doc); + ao_color_tip_document_new(ao_info->colortip, doc); }
@@ -217,6 +224,7 @@ static void ao_document_open_cb(GObject *obj, GeanyDocument *doc, gpointer data)
ao_tasks_update(ao_info->tasks, doc); ao_mark_document_open(ao_info->markword, doc); + ao_color_tip_document_open(ao_info->colortip, doc); }
@@ -226,6 +234,7 @@ static void ao_document_close_cb(GObject *obj, GeanyDocument *doc, gpointer data
ao_tasks_remove(ao_info->tasks, doc); ao_mark_document_close(ao_info->markword, doc); + ao_color_tip_document_close(ao_info->colortip, doc); }
@@ -304,6 +313,10 @@ void plugin_init(GeanyData *data) "enable_enclose_words", FALSE); ao_info->enable_enclose_words_auto = utils_get_setting_boolean(config, "addons", "enable_enclose_words_auto", FALSE); + ao_info->enable_colortip = utils_get_setting_boolean(config, + "addons", "enable_colortip", FALSE); + ao_info->enable_double_click_color_chooser = utils_get_setting_boolean(config, + "addons", "enable_double_click_color_chooser", FALSE);
plugin_module_make_resident(geany_plugin);
@@ -316,6 +329,8 @@ void plugin_init(GeanyData *data) 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(); + ao_info->colortip = ao_color_tip_new(ao_info->enable_colortip, + ao_info->enable_double_click_color_chooser);
ao_blanklines_set_enable(ao_info->strip_trailing_blank_lines);
@@ -415,6 +430,10 @@ static void ao_configure_response_cb(GtkDialog *dialog, gint response, gpointer g_object_get_data(G_OBJECT(dialog), "check_enclose_words")))); ao_info->enable_enclose_words_auto = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( g_object_get_data(G_OBJECT(dialog), "check_enclose_words_auto")))); + ao_info->enable_colortip = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + g_object_get_data(G_OBJECT(dialog), "check_colortip")))); + ao_info->enable_double_click_color_chooser = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + g_object_get_data(G_OBJECT(dialog), "check_double_click_color_chooser"))));
ao_enclose_words_set_enabled (ao_info->enable_enclose_words, ao_info->enable_enclose_words_auto);
@@ -441,6 +460,9 @@ static void ao_configure_response_cb(GtkDialog *dialog, gint response, gpointer ao_info->enable_enclose_words); g_key_file_set_boolean(config, "addons", "enable_enclose_words_auto", ao_info->enable_enclose_words_auto); + g_key_file_set_boolean(config, "addons", "enable_colortip", ao_info->enable_colortip); + g_key_file_set_boolean(config, "addons", "enable_double_click_color_chooser", + ao_info->enable_double_click_color_chooser);
g_object_set(ao_info->doclist, "enable-doclist", ao_info->enable_doclist, NULL); g_object_set(ao_info->doclist, "sort-mode", ao_info->doclist_sort_mode, NULL); @@ -458,6 +480,10 @@ static void ao_configure_response_cb(GtkDialog *dialog, gint response, gpointer "tokens", ao_info->tasks_token_list, NULL); ao_blanklines_set_enable(ao_info->strip_trailing_blank_lines); + g_object_set(ao_info->colortip, + "enable-colortip", ao_info->enable_colortip, + "enable-double-click-color-chooser", ao_info->enable_double_click_color_chooser, + NULL);
if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0) { @@ -487,6 +513,7 @@ GtkWidget *plugin_configure(GtkDialog *dialog) 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; + GtkWidget *check_colortip, *check_double_click_color_chooser;
vbox = gtk_vbox_new(FALSE, 6);
@@ -633,6 +660,17 @@ GtkWidget *plugin_configure(GtkDialog *dialog) ao_info->enable_enclose_words_auto); gtk_box_pack_start(GTK_BOX(vbox), check_enclose_words_auto, FALSE, FALSE, 3);
+ check_colortip = gtk_check_button_new_with_label( + _("Show a calltip when hovering over a color value")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_colortip), + ao_info->enable_colortip); + gtk_box_pack_start(GTK_BOX(vbox), check_colortip, FALSE, FALSE, 3); + + check_double_click_color_chooser = gtk_check_button_new_with_label( + _("Open Color Chooser when double-clicking a color value")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_double_click_color_chooser), + ao_info->enable_double_click_color_chooser); + gtk_box_pack_start(GTK_BOX(vbox), check_double_click_color_chooser, FALSE, FALSE, 3);
g_object_set_data(G_OBJECT(dialog), "check_doclist", check_doclist); g_object_set_data(G_OBJECT(dialog), "radio_doclist_name", radio_doclist_name); @@ -653,6 +691,9 @@ GtkWidget *plugin_configure(GtkDialog *dialog) g_object_set_data(G_OBJECT(dialog), "check_enclose_words", check_enclose_words); g_object_set_data(G_OBJECT(dialog), "check_enclose_words_auto", check_enclose_words_auto); g_object_set_data(G_OBJECT(dialog), "enclose_words_config_button", enclose_words_config_button); + g_object_set_data(G_OBJECT(dialog), "check_colortip", check_colortip); + g_object_set_data(G_OBJECT(dialog), "check_double_click_color_chooser", + check_double_click_color_chooser); g_signal_connect(dialog, "response", G_CALLBACK(ao_configure_response_cb), NULL);
ao_configure_tasks_toggled_cb(GTK_TOGGLE_BUTTON(check_tasks), dialog); @@ -678,6 +719,7 @@ void plugin_cleanup(void) g_object_unref(ao_info->markword); g_object_unref(ao_info->tasks); g_object_unref(ao_info->copyfilepath); + g_object_unref(ao_info->colortip); g_free(ao_info->tasks_token_list);
ao_blanklines_set_enable(FALSE);
Modified: addons/src/ao_colortip.c 397 lines changed, 397 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,397 @@ +/* + * ao_colortip.c - this file is part of Addons, a Geany plugin + * + * Copyright 2017 LarsGit223 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + + +#include <gtk/gtk.h> +#include <glib-object.h> + +#include "geanyplugin.h" + +#include "addons.h" +#include "ao_colortip.h" + +typedef struct _AoColorTipPrivate AoColorTipPrivate; + +#define AO_COLORTIP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj),\ + AO_COLORTIP_TYPE, AoColorTipPrivate)) + +struct _AoColorTip +{ + GObject parent; +}; + +struct _AoColorTipClass +{ + GObjectClass parent_class; +}; + +struct _AoColorTipPrivate +{ + gboolean enable_colortip; + gboolean enable_double_click_color_chooser; +}; + +enum +{ + PROP_0, + PROP_ENABLE_COLORTIP, + PROP_ENABLE_DOUBLE_CLICK_COLOR_CHOOSER, +}; + +G_DEFINE_TYPE(AoColorTip, ao_color_tip, G_TYPE_OBJECT) + +# define SSM(s, m, w, l) scintilla_send_message (s, m, w, l) + + +/* Find a color value (short or long form, e.g. #fff or #ffffff) in the + given string. position must be inside the found color or at maximum + maxdist bytes in front of it (in front of the start of the color value) + or behind it (behind the end of the color value). */ +static gint contains_color_value(gchar *string, gint position, gint maxdist) +{ + gchar *start; + gint end, value, offset, color = -1; + guint length; + + start = strchr(string, '#'); + if (start == NULL) + { + return color; + } + end = start - string + 1; + while (g_ascii_isxdigit (string[end])) + { + end++; + } + end--; + length = &(string[end]) - start + 1; + + if (maxdist != -1) + { + offset = start - string + 1; + if (position < offset && + (offset - position) > maxdist) + { + return color; + } + + offset = end; + if (position > offset && + (position - offset) > maxdist) + { + return color; + } + } + + + if (length == 4) + { + start++; + color = (g_ascii_xdigit_value (*start) << 4) + | g_ascii_xdigit_value (*start); + + start++; + value = (g_ascii_xdigit_value (*start) << 4) + | g_ascii_xdigit_value (*start); + color += value << 8; + + start++; + value = (g_ascii_xdigit_value (*start) << 4) + | g_ascii_xdigit_value (*start); + color += value << 16; + } + else if (length == 7) + { + start++; + color = (g_ascii_xdigit_value (start[0]) << 4) + | g_ascii_xdigit_value (start[1]); + + start += 2; + value = (g_ascii_xdigit_value (start[0]) << 4) + | g_ascii_xdigit_value (start[1]); + color += value << 8; + + start += 2; + value = (g_ascii_xdigit_value (start[0]) << 4) + | g_ascii_xdigit_value (start[1]); + color += value << 16; + } + + return color; +} + + +static gint get_color_value_at_current_doc_position(void) +{ + gchar *subtext; + gint start, end, pos, max, color = -1; + GeanyDocument *doc = document_get_current(); + + g_return_val_if_fail(doc != NULL, FALSE); + + /* Is position valid? */ + pos = sci_get_current_position(doc->editor->sci); + if (pos < 0) + { + return color; + } + max = SSM(doc->editor->sci, SCI_GETTEXTLENGTH, 0, 0); + + /* Calculate range */ + start = pos; + if (start >= 7) + { + start -= 7; + } + else + { + start = 0; + } + end = pos + 7; + if (end > max) + { + end = max; + } + + /* Get text in range and examine it */ + subtext = sci_get_contents_range(doc->editor->sci, start, end); + if (subtext != NULL) + { + pos = pos - start; + color = contains_color_value(subtext, pos, 1); + g_free(subtext); + } + + return color; +} + +static gboolean on_editor_button_press_event(GtkWidget *widget, GdkEventButton *event, + AoColorTip *colortip) +{ + if (event->button == 1) + { + if (event->type == GDK_2BUTTON_PRESS) + { + AoColorTipPrivate *priv = AO_COLORTIP_GET_PRIVATE(colortip); + + if (!priv->enable_double_click_color_chooser) + return FALSE; + + if (get_color_value_at_current_doc_position() != -1) + { + keybindings_send_command + (GEANY_KEY_GROUP_TOOLS, GEANY_KEYS_TOOLS_OPENCOLORCHOOSER); + } + } + } + return FALSE; +} + + +void ao_color_tip_editor_notify(AoColorTip *colortip, GeanyEditor *editor, SCNotification *nt) +{ + ScintillaObject *sci = editor->sci; + AoColorTipPrivate *priv = AO_COLORTIP_GET_PRIVATE(colortip); + + if (!priv->enable_colortip) + { + /* Ignore all events if color tips are disabled in preferences */ + return; + } + + switch (nt->nmhdr.code) + { + case SCN_DWELLSTART: + { + gchar *subtext; + gint start, end, pos, max; + + /* Is position valid? */ + if (nt->position < 0) + break; + + /* Calculate range */ + start = nt->position; + if (start >= 7) + { + start -= 7; + } + else + { + start = 0; + } + pos = nt->position - start; + end = nt->position + 7; + max = SSM(sci, SCI_GETTEXTLENGTH, 0, 0); + if (end > max) + { + end = max; + } + + /* Get text in range and examine it */ + subtext = sci_get_contents_range(sci, start, end); + if (subtext != NULL) + { + gint color; + + color = contains_color_value (subtext, pos, 2); + if (color != -1) + { + SSM(sci, SCI_CALLTIPSETBACK, color, 0); + SSM(sci, SCI_CALLTIPSHOW, nt->position, (sptr_t)" "); + } + g_free(subtext); + } + } + break; + + case SCN_DWELLEND: + SSM(sci, SCI_CALLTIPCANCEL, 0, 0); + break; + } +} + + +static void connect_document_button_press_signal_handler(AoColorTip *colortip, 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), + colortip); +} + + +static void connect_documents_button_press_signal_handler(AoColorTip *colortip) +{ + guint i = 0; + /* connect the button-press event for all open documents */ + foreach_document(i) + { + connect_document_button_press_signal_handler(colortip, documents[i]); + } +} + + +static void ao_color_tip_finalize(GObject *object) +{ + g_return_if_fail(object != NULL); + g_return_if_fail(IS_AO_COLORTIP(object)); + + G_OBJECT_CLASS(ao_color_tip_parent_class)->finalize(object); +} + + +static void ao_color_tip_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + AoColorTipPrivate *priv = AO_COLORTIP_GET_PRIVATE(object); + + switch (prop_id) + { + case PROP_ENABLE_COLORTIP: + priv->enable_colortip = g_value_get_boolean(value); + break; + case PROP_ENABLE_DOUBLE_CLICK_COLOR_CHOOSER: + priv->enable_double_click_color_chooser = g_value_get_boolean(value); + + /* If the plugin is loaded while Geany is already running, we need to connect the + * button press signal for open documents, if Geany is just booting, + * it happens automatically */ + if (priv->enable_double_click_color_chooser && main_is_realized()) + { + connect_documents_button_press_signal_handler(AO_COLORTIP(object)); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + + +void ao_color_tip_document_new(AoColorTip *colortip, GeanyDocument *document) +{ + connect_document_button_press_signal_handler(colortip, document); +} + + +void ao_color_tip_document_open(AoColorTip *colortip, GeanyDocument *document) +{ + connect_document_button_press_signal_handler(colortip, document); +} + + +void ao_color_tip_document_close(AoColorTip *colortip, GeanyDocument *document) +{ + g_return_if_fail(DOC_VALID(document)); + + g_signal_handlers_disconnect_by_func(document->editor->sci, on_editor_button_press_event, colortip); +} + + +static void ao_color_tip_class_init(AoColorTipClass *klass) +{ + GObjectClass *g_object_class; + + g_object_class = G_OBJECT_CLASS(klass); + g_object_class->finalize = ao_color_tip_finalize; + g_object_class->set_property = ao_color_tip_set_property; + g_type_class_add_private(klass, sizeof(AoColorTipPrivate)); + + g_object_class_install_property(g_object_class, + PROP_ENABLE_COLORTIP, + g_param_spec_boolean( + "enable-colortip", + "enable-colortip", + "Whether to show a calltip when hovering over a color value", + TRUE, + G_PARAM_WRITABLE)); + + g_object_class_install_property(g_object_class, + PROP_ENABLE_DOUBLE_CLICK_COLOR_CHOOSER, + g_param_spec_boolean( + "enable-double-click-color-chooser", + "enable-double-click-color-chooser", + "Enable starting the Color Chooser when double clicking on a color value", + TRUE, + G_PARAM_WRITABLE)); +} + +static void ao_color_tip_init(AoColorTip *self) +{ + AoColorTipPrivate *priv = AO_COLORTIP_GET_PRIVATE(self); + memset(priv, 0, sizeof(*priv)); +} + +AoColorTip *ao_color_tip_new(gboolean enable_tip, gboolean double_click_color_chooser) +{ + return g_object_new( + AO_COLORTIP_TYPE, + "enable-colortip", enable_tip, + "enable-double-click-color-chooser", double_click_color_chooser, + NULL); +}
Modified: addons/src/ao_colortip.h 51 lines changed, 51 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,51 @@ +/* + * ao_markword.h - this file is part of Addons, a Geany plugin + * + * Copyright 2017 LarsGit223 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + + +#ifndef __AO_COLORTIP_H__ +#define __AO_COLORTIP_H__ + +G_BEGIN_DECLS + +#define AO_COLORTIP_TYPE (ao_color_tip_get_type()) +#define AO_COLORTIP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ + AO_COLORTIP_TYPE, AoColorTip)) +#define AO_COLORTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\ + AO_COLORTIP_TYPE, AoColorTipClass)) +#define IS_AO_COLORTIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\ + AO_COLORTIP_TYPE)) +#define IS_AO_COLORTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\ + AO_COLORTIP_TYPE)) + +typedef struct _AoColorTip AoColorTip; +typedef struct _AoColorTipClass AoColorTipClass; + +GType ao_color_tip_get_type (void); +AoColorTip* ao_color_tip_new (gboolean enable_tip, gboolean double_click_color_chooser); +void ao_color_tip_document_new (AoColorTip *colortip, GeanyDocument *document); +void ao_color_tip_document_open (AoColorTip *colortip, GeanyDocument *document); +void ao_color_tip_document_close (AoColorTip *colortip, GeanyDocument *document); +void ao_color_tip_editor_notify (AoColorTip *colortip, GeanyEditor *editor, SCNotification *nt); + +G_END_DECLS + +#endif /* __AO_COLORTIP_H__ */
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
plugins-commits@lists.geany.org