Branch: refs/heads/master Author: Frank Lanitz frank@frank.uvena.de Committer: GitHub noreply@github.com Date: Mon, 29 Jan 2018 17:56:09 UTC Commit: 5d66d039c5e938880dde19c4f005f7fd29a8e975 https://github.com/geany/geany-plugins/commit/5d66d039c5e938880dde19c4f005f7...
Log Message: ----------- Merge pull request #664 from LarsGit223/addons-colortip
addons: show color tip and start Color Chooser with double click
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 385 lines changed, 385 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,385 @@ +/* + * 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. + */ + + +#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) +{ + gint color = -1; + GeanyDocument *doc = document_get_current(); + gchar *word = editor_get_word_at_pos(doc->editor, -1, "0123456789abcdefABCDEF"); + + if (word) + { + switch (strlen (word)) + { + case 3: + color = ((g_ascii_xdigit_value(word[0]) * 0x11) << 16 | + (g_ascii_xdigit_value(word[1]) * 0x11) << 8 | + (g_ascii_xdigit_value(word[2]) * 0x11) << 0); + break; + case 6: + color = (g_ascii_xdigit_value(word[0]) << 20 | + g_ascii_xdigit_value(word[1]) << 16 | + g_ascii_xdigit_value(word[2]) << 12 | + g_ascii_xdigit_value(word[3]) << 8 | + g_ascii_xdigit_value(word[4]) << 4 | + g_ascii_xdigit_value(word[5]) << 0); + break; + default: + /* invalid color or other format */ + break; + } + } + + 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); + SSM(document->editor->sci, SCI_SETMOUSEDWELLTIME, 300, 0); +} + + +void ao_color_tip_document_open(AoColorTip *colortip, GeanyDocument *document) +{ + connect_document_button_press_signal_handler(colortip, document); + SSM(document->editor->sci, SCI_SETMOUSEDWELLTIME, 300, 0); +} + + +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 49 lines changed, 49 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,49 @@ +/* + * ao_colortip.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. + */ + + +#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).