diff --git a/MAINTAINERS b/MAINTAINERS index d317d0212..ef0954d26 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -180,6 +180,12 @@ M: Matthew Brush W: http://plugins.geany.org/multiterm.html S: Maintained +overview +P: Matthew Brush +M: Matthew Brush +W: https://github.com/codebrainz/overview-plugin +S: Maintained + pairtaghighlighter P: Volodymyr Kononenko M: Volodymyr Kononenko diff --git a/Makefile.am b/Makefile.am index 089b71bc5..8cf163431 100644 --- a/Makefile.am +++ b/Makefile.am @@ -115,6 +115,10 @@ if ENABLE_MULTITERM SUBDIRS += multiterm endif +if ENABLE_OVERVIEW +SUBDIRS += overview +endif + if ENABLE_PAIRTAGHIGHLIGHTER SUBDIRS += pairtaghighlighter endif diff --git a/build/overview.m4 b/build/overview.m4 new file mode 100644 index 000000000..a59e06fa4 --- /dev/null +++ b/build/overview.m4 @@ -0,0 +1,12 @@ +AC_DEFUN([GP_CHECK_OVERVIEW], +[ + GP_ARG_DISABLE([overview], [auto]) + + GP_COMMIT_PLUGIN_STATUS([Overview]) + + AC_CONFIG_FILES([ + overview/Makefile + overview/data/Makefile + overview/overview/Makefile + ]) +]) diff --git a/configure.ac b/configure.ac index 7b5efaf88..d2b5450ae 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,7 @@ GP_CHECK_GENIUSPASTE GP_CHECK_GITCHANGEBAR GP_CHECK_MARKDOWN GP_CHECK_MULTITERM +GP_CHECK_OVERVIEW GP_CHECK_PAIRTAGHIGHLIGHTER GP_CHECK_POHELPER GP_CHECK_PRETTYPRINTER diff --git a/overview/AUTHORS b/overview/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/overview/COPYING b/overview/COPYING new file mode 100644 index 000000000..e69de29bb diff --git a/overview/ChangeLog b/overview/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/overview/Makefile.am b/overview/Makefile.am new file mode 100644 index 000000000..214620af7 --- /dev/null +++ b/overview/Makefile.am @@ -0,0 +1,3 @@ +include $(top_srcdir)/build/vars.auxfiles.mk +SUBDIRS = overview data +plugin = overview diff --git a/overview/NEWS b/overview/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/overview/README b/overview/README new file mode 100644 index 000000000..e69de29bb diff --git a/overview/data/Makefile.am b/overview/data/Makefile.am new file mode 100644 index 000000000..0e1f23495 --- /dev/null +++ b/overview/data/Makefile.am @@ -0,0 +1,2 @@ +overviewdatadir = $(pkgdatadir)/overview +overviewdata_DATA = prefs.ui diff --git a/overview/data/prefs.ui b/overview/data/prefs.ui new file mode 100644 index 000000000..69ab60671 --- /dev/null +++ b/overview/data/prefs.ui @@ -0,0 +1,356 @@ + + + + + + 100 + 1 + 1 + 10 + + + 16 + 512 + 120 + 1 + 10 + + + -10 + 20 + -10 + 1 + 10 + + + True + False + 12 + 5 + 2 + 4 + 2 + + + True + False + The amount to zoom the overview sidebar. This should probably negative if you want the sidebar zoomed out. + 0 + Zoom Level: + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + True + The amount to zoom the overview sidebar. This should probably negative if you want the sidebar zoomed out. + + False + False + True + True + overview-zoom-adjustment + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + False + The width of the overview sidebar. + 0 + Width: + + + GTK_FILL + GTK_FILL + + + + + True + True + The width of the overview sidebar. + + False + False + True + True + overview-width-adjustment + + + 1 + 2 + GTK_FILL + + + + + True + True + The number of lines to scroll at a time when scrolling the overview sidebar. + + False + False + True + True + overview-scroll-lines-adjustment + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + False + The number of lines to scroll at a time when scrolling the overview sidebar. + 0 + Scroll Lines: + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + in + + + True + False + 6 + 6 + 6 + 6 + + + True + False + 2 + + + Position on left + True + True + False + Position the overview bar on the left rather than the right (requires Geany 1.25 or greater). + True + + + True + True + 0 + + + + + Hide tooltip + True + True + False + Hide the tooltip that is displayed when mousing over the overview that shows line, column and position information. + True + + + True + True + 1 + + + + + Hide editor scrollbar + True + True + False + Whether to hide Geany's regular editor scrollbar while the overview bar is visible. + True + + + True + True + 2 + + + + + Disable overlay + True + True + False + Turn off drawing overlay, which shows the region of the main editor view that is currently in view, ontop of the overview bar. + True + + + True + True + 3 + + + + + + + + + True + False + Options + True + + + + + 2 + 3 + 4 + GTK_FILL + + + + + True + False + 0 + in + + + True + False + 6 + 6 + 6 + 6 + + + True + False + 3 + 2 + 4 + 2 + + + True + False + The color and opacity of the overlay drawn ontop of the overlay sidebar. + 0 + Color: + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + The color and opacity of the border drawn around the revealed area in the overview sidebar. Set to the same as Overlay Color to disable. + 0 + Outline Color: + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + True + True + The color and opacity of the border drawn around the revealed area in the overview sidebar. Set to the same as Overlay Color to disable. + True + #000000000000 + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + True + True + The color and opacity of the overlay drawn ontop of the overlay sidebar. + True + #000000000000 + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + Draw over visible area + True + True + False + When checked it will draw the overlay ontop of the area that is visible in the main editor view, when unckecked, it will do the opposite and draw the overlay everywhere but the visible area, "revealing" the visible part. + True + True + + + 2 + GTK_FILL + GTK_FILL + + + + + + + + + True + False + Overlay + True + + + + + 2 + 4 + 5 + GTK_FILL + + + + diff --git a/overview/overview/Makefile.am b/overview/overview/Makefile.am new file mode 100644 index 000000000..17cd2b2cb --- /dev/null +++ b/overview/overview/Makefile.am @@ -0,0 +1,29 @@ +include $(top_srcdir)/build/vars.build.mk + +plugin = overview + +geanyplugins_LTLIBRARIES = overview.la + +overview_la_SOURCES = \ + overviewcolor.c \ + overviewcolor.h \ + overviewplugin.c \ + overviewplugin.h \ + overviewprefs.c \ + overviewprefs.h \ + overviewprefspanel.c \ + overviewprefspanel.h \ + overviewscintilla.c \ + overviewscintilla.h \ + overviewui.c \ + overviewui.h + +overview_la_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(srcdir)/.. \ + -DOVERVIEW_PREFS_UI_FILE=\""$(pkgdatadir)/overview/prefs.ui"\" + +overview_la_LIBADD = \ + $(COMMONLIBS) + +include $(top_srcdir)/build/cppcheck.mk diff --git a/overview/overview/overviewcolor.c b/overview/overview/overviewcolor.c new file mode 100644 index 000000000..d11a39894 --- /dev/null +++ b/overview/overview/overviewcolor.c @@ -0,0 +1,305 @@ +/* + * overviewcolor.c - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "overviewcolor.h" +#include + +OverviewColor * +overview_color_copy (OverviewColor *color) +{ + OverviewColor *new_color = g_slice_new0 (OverviewColor); + memcpy (new_color, color, sizeof (OverviewColor)); + return new_color; +} + +void +overview_color_free (OverviewColor *color) +{ + if (color != NULL) + g_slice_free (OverviewColor, color); +} + +gboolean +overview_color_equal (const OverviewColor *color1, + const OverviewColor *color2) +{ + return (color1->red == color2->red && + color1->green == color2->green && + color1->blue == color2->blue && + color1->alpha == color2->alpha); +} + +gboolean +overview_color_parse (OverviewColor *color, + const gchar *color_str) +{ + g_return_val_if_fail (color != NULL, FALSE); + g_return_val_if_fail (color_str != NULL, FALSE); + +#if GTK_CHECK_VERSION (3, 0, 0) + GdkRGBA gcolor; + if (gdk_rgba_parse (&gcolor, color_str)) + { + overview_color_from_rgba (color, &gcolor); + return TRUE; + } +#else + GdkColor gcolor; + if (gdk_color_parse (color_str, &gcolor)) + { + overview_color_from_gdk_color (color, &gcolor, 1.0); + return TRUE; + } +#endif + + return FALSE; +} + +gchar * +overview_color_to_string (const OverviewColor *color) +{ + g_return_val_if_fail (color != NULL, NULL); + +#if GTK_CHECK_VERSION (3, 0, 0) + GdkRGBA gcolor; + overview_color_to_rgba (color, &gcolor); + return gdk_rgba_to_string (&gcolor); +#else + GdkColor gcolor; + overview_color_to_gdk_color (color, &gcolor); + return gdk_color_to_string (&gcolor); +#endif +} + +void +overview_color_from_gdk_color (OverviewColor *color, + const GdkColor *gcolor, + gdouble alpha) +{ + g_return_if_fail (color != NULL); + g_return_if_fail (gcolor != NULL); + + color->red = (gdouble) gcolor->red / G_MAXUINT16; + color->green = (gdouble) gcolor->green / G_MAXUINT16; + color->blue = (gdouble) gcolor->blue / G_MAXUINT16; + color->alpha = alpha; +} + +void +overview_color_to_gdk_color (const OverviewColor *color, + GdkColor *gcolor) +{ + g_return_if_fail (color != NULL); + g_return_if_fail (gcolor != NULL); + + gcolor->red = (guint16)(color->red * G_MAXUINT16); + gcolor->green = (guint16)(color->green * G_MAXUINT16); + gcolor->blue = (guint16)(color->blue * G_MAXUINT16); +} + +#if GTK_CHECK_VERSION (3, 0, 0) +void +overview_color_from_rgba (OverviewColor *color, + const GdkRGBA *rgba) +{ + g_return_if_fail (color != NULL); + g_return_if_fail (rgba != NULL); + + color->red = rgba->red; + color->green = rgba->green; + color->blue = rgba->blue; + color->alpha = rgba->alpha; +} + +void +overview_color_to_rgba (const OverviewColor *color, + GdkRGBA *rgba) +{ + g_return_if_fail (color != NULL); + g_return_if_fail (rgba != NULL); + + rgba->red = color->red; + rgba->green = color->green; + rgba->blue = color->blue; + rgba->alpha = color->alpha; +} +#endif + +void +overview_color_from_int (OverviewColor *color, + guint32 abgr, + gboolean with_alpha) +{ + g_return_if_fail (color != NULL); + guint8 r = abgr & 0xFF; + guint8 g = (abgr>>8) & 0xFF; + guint8 b = (abgr>>16) & 0xFF; + guint8 a = 255; + + if (with_alpha) + a = (abgr>>24) & 0xFF; + + color->red = (gdouble)r / G_MAXUINT8; + color->green = (gdouble)g / G_MAXUINT8; + color->blue = (gdouble)b / G_MAXUINT8; + color->alpha = (gdouble)a / G_MAXUINT8; +} + +guint32 +overview_color_to_int (const OverviewColor *color, + gboolean with_alpha) +{ + g_return_val_if_fail (color != NULL, 0); + + guint32 r = (guint8)(color->red * 255.0); + guint32 g = (guint8)(color->green * 255.0); + guint32 b = (guint8)(color->blue * 255.0); + guint32 a = 0; + + if (with_alpha) + a = (guint8)(color->alpha * 255.0); + + return (a<<24) | (b<<16) | (g<<8) | r; +} + +gboolean +overview_color_from_keyfile (OverviewColor *color, + GKeyFile *keyfile, + const gchar *section, + const gchar *option, + GError **error) +{ + gchar *color_key; + gchar *alpha_key; + gchar *clr_str; + gdouble alpha; + + g_return_val_if_fail (color != NULL, FALSE); + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (section != NULL, FALSE); + g_return_val_if_fail (option != NULL, FALSE); + + color_key = g_strdup_printf ("%s-color", option); + alpha_key = g_strdup_printf ("%s-alpha", option); + + clr_str = g_key_file_get_string (keyfile, section, color_key, error); + if (*error != NULL) + { + g_free (color_key); + g_free (alpha_key); + return FALSE; + } + + g_free (color_key); + + alpha = g_key_file_get_double (keyfile, section, alpha_key, error); + if (*error != NULL) + { + g_free (alpha_key); + g_free (clr_str); + return FALSE; + } + + g_free (alpha_key); + + if (alpha < 0.0 || alpha > 1.0) + g_warning ("alpha value '%g' from keyfile out of 0-1 range", alpha); + + overview_color_parse (color, clr_str); + color->alpha = alpha; + + g_free (clr_str); + + return TRUE; +} + +gboolean +overview_color_to_keyfile (const OverviewColor *color, + GKeyFile *keyfile, + const gchar *section, + const gchar *option) +{ + gchar *color_key; + gchar *alpha_key; + gchar *clr_str; + + g_return_val_if_fail (color != NULL, FALSE); + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (section != NULL, FALSE); + g_return_val_if_fail (option != NULL, FALSE); + + color_key = g_strdup_printf ("%s-color", option); + alpha_key = g_strdup_printf ("%s-alpha", option); + + clr_str = overview_color_to_string (color); + g_key_file_set_string (keyfile, section, color_key, clr_str); + g_free (color_key); + g_free (clr_str); + + g_key_file_set_double (keyfile, section, alpha_key, color->alpha); + g_free (alpha_key); + + return TRUE; +} + +void +overview_color_from_color_button (OverviewColor *color, + GtkColorButton *button) +{ + GdkColor gcolor; + guint16 alpha; + gdouble falpha; + gtk_color_button_get_color (button, &gcolor); + alpha = gtk_color_button_get_alpha (button); + falpha = (gdouble) alpha / (gdouble) G_MAXUINT16; + overview_color_from_gdk_color (color, &gcolor, falpha); +} + +void +overview_color_to_color_button (const OverviewColor *color, + GtkColorButton *button) +{ + GdkColor gcolor; + guint16 alpha; + overview_color_to_gdk_color (color, &gcolor); + gtk_color_button_set_color (button, &gcolor); + alpha = (guint16)(color->alpha * (gdouble) G_MAXUINT16); + gtk_color_button_set_alpha (button, alpha); +} + +GType +overview_color_get_type (void) +{ + static GType type = 0; + if (type == 0) + { + type = + g_boxed_type_register_static ("OverviewColor", + (GBoxedCopyFunc) overview_color_copy, + (GBoxedFreeFunc) overview_color_free); + } + return type; +} diff --git a/overview/overview/overviewcolor.h b/overview/overview/overviewcolor.h new file mode 100644 index 000000000..e682649d7 --- /dev/null +++ b/overview/overview/overviewcolor.h @@ -0,0 +1,79 @@ +/* + * overviewcolor.h - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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 OVERVIEW_COLOR_H_ +#define OVERVIEW_COLOR_H_ + +#include + +#define OVERVIEW_TYPE_COLOR (overview_color_get_type ()) +#define OVERVIEW_COLOR_INIT { 0.0, 0.0, 0.0, 1.0 } + +typedef struct +{ + gdouble red; + gdouble green; + gdouble blue; + gdouble alpha; +} +OverviewColor; + +GType overview_color_get_type (void); +OverviewColor *overview_color_copy (OverviewColor *color); +void overview_color_free (OverviewColor *color); +gboolean overview_color_equal (const OverviewColor *color1, + const OverviewColor *color2); +gboolean overview_color_parse (OverviewColor *color, + const gchar *color_str); +gchar *overview_color_to_string (const OverviewColor *color); +void overview_color_from_gdk_color (OverviewColor *color, + const GdkColor *gcolor, + gdouble alpha); +void overview_color_to_gdk_color (const OverviewColor *color, + GdkColor *gcolor); +#if GTK_CHECK_VERSION (3, 0, 0) +void overview_color_from_rgba (OverviewColor *color, + const GdkRGBA *rgba); +void overview_color_to_rgba (const OverviewColor *color, + GdkRGBA *rgba); +#endif +void overview_color_from_int (OverviewColor *color, + guint32 abgr, + gboolean with_alpha); +guint32 overview_color_to_int (const OverviewColor *color, + gboolean with_alpha); +gboolean overview_color_from_keyfile (OverviewColor *color, + GKeyFile *keyfile, + const gchar *section, + const gchar *option, + GError **error); +gboolean overview_color_to_keyfile (const OverviewColor *color, + GKeyFile *keyfile, + const gchar *section, + const gchar *option); + +void overview_color_from_color_button (OverviewColor *color, + GtkColorButton *button); +void overview_color_to_color_button (const OverviewColor *color, + GtkColorButton *button); + +#endif /* OVERVIEW_COLOR_H_ */ diff --git a/overview/overview/overviewplugin.c b/overview/overview/overviewplugin.c new file mode 100644 index 000000000..0f22af668 --- /dev/null +++ b/overview/overview/overviewplugin.c @@ -0,0 +1,232 @@ +/* + * overviewplugin.c - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "overviewplugin.h" +#include "overviewscintilla.h" +#include "overviewprefs.h" +#include "overviewprefspanel.h" +#include "overviewui.h" +#include + +GeanyPlugin *geany_plugin; +GeanyData *geany_data; +GeanyFunctions *geany_functions; + +PLUGIN_VERSION_CHECK (224) + +PLUGIN_SET_INFO ( + "Overview", + _("Provides an overview of the active document"), + "0.01", + "Matthew Brush ") + +static OverviewPrefs *overview_prefs = NULL; + +static void write_config (void); + +static void +on_visible_pref_notify (OverviewPrefs *prefs, + GParamSpec *pspec, + gpointer user_data) +{ + write_config (); +} + +static void +toggle_visibility (void) +{ + gboolean visible = TRUE; + g_object_get (overview_prefs, "visible", &visible, NULL); + g_object_set (overview_prefs, "visible", !visible, NULL); +} + +enum +{ + KB_TOGGLE_VISIBLE, + KB_TOGGLE_POSITION, + KB_TOGGLE_INVERTED, + NUM_KB +}; + +static gboolean +on_kb_activate (guint keybinding_id) +{ + switch (keybinding_id) + { + case KB_TOGGLE_VISIBLE: + toggle_visibility (); + break; + case KB_TOGGLE_POSITION: + { + GtkPositionType pos; + g_object_get (overview_prefs, "position", &pos, NULL); + pos = (pos == GTK_POS_LEFT) ? GTK_POS_RIGHT : GTK_POS_LEFT; + g_object_set (overview_prefs, "position", pos, NULL); + break; + } + case KB_TOGGLE_INVERTED: + { + gboolean inv = FALSE; + g_object_get (overview_prefs, "overlay-inverted", &inv, NULL); + g_object_set (overview_prefs, "overlay-inverted", !inv, NULL); + break; + } + default: + break; + } + return TRUE; +} + +static gchar * +get_config_file (void) +{ + gchar *dir; + gchar *fn; + static const gchar *def_config = OVERVIEW_PREFS_DEFAULT_CONFIG; + + dir = g_build_filename (geany_data->app->configdir, "plugins", "overview", NULL); + fn = g_build_filename (dir, "prefs.conf", NULL); + + if (! g_file_test (fn, G_FILE_TEST_IS_DIR)) + { + if (g_mkdir_with_parents (dir, 0755) != 0) + { + g_critical ("failed to create config dir '%s': %s", dir, g_strerror (errno)); + g_free (dir); + g_free (fn); + return NULL; + } + } + + g_free (dir); + + if (! g_file_test (fn, G_FILE_TEST_EXISTS)) + { + GError *error = NULL; + if (!g_file_set_contents (fn, def_config, -1, &error)) + { + g_critical ("failed to save default config to file '%s': %s", + fn, error->message); + g_error_free (error); + g_free (fn); + return NULL; + } + } + + return fn; +} + +static void +write_config (void) +{ + gchar *conf_file; + GError *error = NULL; + conf_file = get_config_file (); + if (! overview_prefs_save (overview_prefs, conf_file, &error)) + { + g_critical ("failed to save preferences to file '%s': %s", conf_file, error->message); + g_error_free (error); + } + g_free (conf_file); +} + +void +plugin_init (G_GNUC_UNUSED GeanyData *data) +{ + gchar *conf_file; + GError *error = NULL; + GeanyKeyGroup *key_group; + + plugin_module_make_resident (geany_plugin); + + overview_prefs = overview_prefs_new (); + conf_file = get_config_file (); + if (! overview_prefs_load (overview_prefs, conf_file, &error)) + { + g_critical ("failed to load preferences file '%s': %s", conf_file, error->message); + g_error_free (error); + } + g_free (conf_file); + + overview_ui_init (overview_prefs); + + key_group = plugin_set_key_group (geany_plugin, + "overview", + NUM_KB, + on_kb_activate); + + keybindings_set_item (key_group, + KB_TOGGLE_VISIBLE, + NULL, 0, 0, + "toggle-visibility", + _("Toggle Visibility"), + overview_ui_get_menu_item ()); + + keybindings_set_item (key_group, + KB_TOGGLE_POSITION, + NULL, 0, 0, + "toggle-position", + _("Toggle Left/Right Position"), + NULL); + + keybindings_set_item (key_group, + KB_TOGGLE_INVERTED, + NULL, 0, 0, + "toggle-inverted", + _("Toggle Overlay Inversion"), + NULL); + + g_signal_connect (overview_prefs, "notify::visible", G_CALLBACK (on_visible_pref_notify), NULL); +} + +void +plugin_cleanup (void) +{ + write_config (); + overview_ui_deinit (); + + if (OVERVIEW_IS_PREFS (overview_prefs)) + g_object_unref (overview_prefs); + overview_prefs = NULL; +} + +static void +on_prefs_stored (OverviewPrefsPanel *panel, + OverviewPrefs *prefs, + gpointer user_data) +{ + write_config (); + overview_ui_queue_update (); +} + +GtkWidget * +plugin_configure (GtkDialog *dialog) +{ + GtkWidget *panel; + panel = overview_prefs_panel_new (overview_prefs, dialog); + g_signal_connect (panel, "prefs-stored", G_CALLBACK (on_prefs_stored), NULL); + return panel; +} diff --git a/overview/overview/overviewplugin.h b/overview/overview/overviewplugin.h new file mode 100644 index 000000000..72596dde1 --- /dev/null +++ b/overview/overview/overviewplugin.h @@ -0,0 +1,37 @@ +/* + * overviewplugin.h - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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 OVERVIEW_PLUGIN_H +#define OVERVIEW_PLUGIN_H + +#include +#include +#include + +extern GeanyData *geany_data; +extern GeanyPlugin *geany_plugin; +extern GeanyFunctions *geany_functions; + +void overview_plugin_queue_update (void); +gboolean overview_geany_supports_left_position (void); + +#endif // OVERVIEW_PLUGIN_H diff --git a/overview/overview/overviewprefs.c b/overview/overview/overviewprefs.c new file mode 100644 index 000000000..2a23c7eea --- /dev/null +++ b/overview/overview/overviewprefs.c @@ -0,0 +1,447 @@ +/* + * overviewprefs.c - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "overviewprefs.h" +#include "overviewcolor.h" +#include "overviewscintilla.h" +#include +#include + +enum +{ + PROP_0, + PROP_WIDTH, + PROP_ZOOM, + PROP_SHOW_TOOLTIP, + PROP_SHOW_SCROLLBAR, + PROP_DOUBLE_BUFFERED, + PROP_SCROLL_LINES, + PROP_OVERLAY_ENABLED, + PROP_OVERLAY_COLOR, + PROP_OVERLAY_OUTLINE_COLOR, + PROP_OVERLAY_INVERTED, + PROP_POSITION, + PROP_VISIBLE, + N_PROPERTIES +}; + +struct OverviewPrefs_ +{ + GObject parent; + guint width; + gint zoom; + gboolean show_tt; + gboolean show_sb; + gboolean dbl_buf; + gint scr_lines; + gboolean ovl_en; + OverviewColor ovl_clr; + OverviewColor out_clr; + gboolean ovl_inv; + GtkPositionType position; + gboolean visible; +}; + +struct OverviewPrefsClass_ +{ + GObjectClass parent_class; +}; + +static void overview_prefs_finalize (GObject *object); +static void overview_prefs_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void overview_prefs_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + + +static GParamSpec *pspecs[N_PROPERTIES] = { NULL }; + +G_DEFINE_TYPE (OverviewPrefs, overview_prefs, G_TYPE_OBJECT) + +static void +overview_prefs_class_init (OverviewPrefsClass *klass) +{ + GObjectClass *g_object_class; + + g_object_class = G_OBJECT_CLASS (klass); + + g_object_class->finalize = overview_prefs_finalize; + g_object_class->set_property = overview_prefs_set_property; + g_object_class->get_property = overview_prefs_get_property; + + pspecs[PROP_WIDTH] = g_param_spec_uint ("width", "Width", "Width of the overview", 16, 512, 120, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_ZOOM] = g_param_spec_int ("zoom", "Zoom", "Zoom level of the view", -10, 20, -10, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_SHOW_TOOLTIP] = g_param_spec_boolean ("show-tooltip", "ShowTooltip", "Whether to show informational tooltip over the overview", TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_SHOW_SCROLLBAR] = g_param_spec_boolean ("show-scrollbar", "ShowScrollbar", "Whether to show the normal editor scrollbar", TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_DOUBLE_BUFFERED] = g_param_spec_boolean ("double-buffered", "DoubleBuffered", "Whether the overview drawing is double-buffered", TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_SCROLL_LINES] = g_param_spec_uint ("scroll-lines", "ScrollLines", "The number of lines to scroll the overview by", 1, 512, 1, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_OVERLAY_ENABLED] = g_param_spec_boolean ("overlay-enabled", "OverlayEnabled", "Whether an overlay is drawn overtop the overview", TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_OVERLAY_COLOR] = g_param_spec_boxed ("overlay-color", "OverlayColor", "The color of the overlay", OVERVIEW_TYPE_COLOR, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_OVERLAY_OUTLINE_COLOR] = g_param_spec_boxed ("overlay-outline-color", "OverlayOutlineColor", "The color of the outlines drawn around the overlay", OVERVIEW_TYPE_COLOR, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_OVERLAY_INVERTED] = g_param_spec_boolean ("overlay-inverted", "OverlayInverted", "Whether to invert the drawing of the overlay", TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_POSITION] = g_param_spec_enum ("position", "Position", "Where to draw the overview", GTK_TYPE_POSITION_TYPE, GTK_POS_RIGHT, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + pspecs[PROP_VISIBLE] = g_param_spec_boolean ("visible", "Visible", "Whether the overview is shown", TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + g_object_class_install_properties (g_object_class, N_PROPERTIES, pspecs); +} + +static void +overview_prefs_finalize (GObject *object) +{ + g_return_if_fail (OVERVIEW_IS_PREFS (object)); + G_OBJECT_CLASS (overview_prefs_parent_class)->finalize (object); +} + +static void +overview_prefs_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OverviewPrefs *self = OVERVIEW_PREFS (object); + + switch (prop_id) + { + case PROP_WIDTH: + self->width = g_value_get_uint (value); + g_object_notify (object, "width"); + break; + case PROP_ZOOM: + self->zoom = g_value_get_int (value); + g_object_notify (object, "zoom"); + break; + case PROP_SHOW_TOOLTIP: + self->show_tt = g_value_get_boolean (value); + g_object_notify (object, "show-tooltip"); + break; + case PROP_SHOW_SCROLLBAR: + self->show_sb = g_value_get_boolean (value); + g_object_notify (object, "show-scrollbar"); + break; + case PROP_DOUBLE_BUFFERED: + self->dbl_buf = g_value_get_boolean (value); + g_object_notify (object, "double-buffered"); + break; + case PROP_SCROLL_LINES: + self->scr_lines = g_value_get_uint (value); + g_object_notify (object, "scroll-lines"); + break; + case PROP_OVERLAY_ENABLED: + self->ovl_en = g_value_get_boolean (value); + g_object_notify (object, "overlay-enabled"); + break; + case PROP_OVERLAY_COLOR: + { + OverviewColor *src = g_value_get_boxed (value); + if (src != NULL) + memcpy (&self->ovl_clr, src, sizeof (OverviewColor)); + g_object_notify (object, "overlay-color"); + break; + } + case PROP_OVERLAY_OUTLINE_COLOR: + { + OverviewColor *src = g_value_get_boxed (value); + if (src != NULL) + memcpy (&self->out_clr, src, sizeof (OverviewColor)); + g_object_notify (object, "overlay-outline-color"); + break; + } + case PROP_OVERLAY_INVERTED: + self->ovl_inv = g_value_get_boolean (value); + g_object_notify (G_OBJECT (self), "overlay-inverted"); + break; + case PROP_POSITION: + self->position = g_value_get_enum (value); + g_object_notify (G_OBJECT (self), "position"); + break; + case PROP_VISIBLE: + self->visible = g_value_get_boolean (value); + g_object_notify (G_OBJECT (self), "visible"); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +overview_prefs_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OverviewPrefs *self = OVERVIEW_PREFS (object); + + switch (prop_id) + { + case PROP_WIDTH: + g_value_set_uint (value, self->width); + break; + case PROP_ZOOM: + g_value_set_int (value, self->zoom); + break; + case PROP_SHOW_TOOLTIP: + g_value_set_boolean (value, self->show_tt); + break; + case PROP_SHOW_SCROLLBAR: + g_value_set_boolean (value, self->show_sb); + break; + case PROP_DOUBLE_BUFFERED: + g_value_set_boolean (value, self->dbl_buf); + break; + case PROP_SCROLL_LINES: + g_value_set_uint (value, self->scr_lines); + break; + case PROP_OVERLAY_ENABLED: + g_value_set_boolean (value, self->ovl_en); + break; + case PROP_OVERLAY_COLOR: + g_value_set_boxed (value, &self->ovl_clr); + break; + case PROP_OVERLAY_OUTLINE_COLOR: + g_value_set_boxed (value, &self->out_clr); + break; + case PROP_OVERLAY_INVERTED: + g_value_set_boolean (value, self->ovl_inv); + break; + case PROP_POSITION: + g_value_set_enum (value, self->position); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, self->visible); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +overview_prefs_init (OverviewPrefs *self) +{ + self->position = GTK_POS_RIGHT; + self->visible = TRUE; +} + +OverviewPrefs * +overview_prefs_new (void) +{ + return g_object_new (OVERVIEW_TYPE_PREFS, NULL); +} + +gboolean +overview_prefs_load (OverviewPrefs *self, + const gchar *filename, + GError **error) +{ + gchar *contents = NULL; + gsize size = 0; + g_return_val_if_fail (OVERVIEW_IS_PREFS (self), FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + if (! g_file_get_contents (filename, &contents, &size, error)) + return FALSE; + if (! overview_prefs_from_data (self, contents, size, error)) + { + g_free (contents); + return FALSE; + } + g_free (contents); + return TRUE; +} + +gboolean +overview_prefs_save (OverviewPrefs *self, + const gchar *filename, + GError **error) + +{ + gchar *contents = NULL; + gsize size = 0; + g_return_val_if_fail (OVERVIEW_IS_PREFS (self), FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + contents = overview_prefs_to_data (self, &size, error); + if (contents == NULL) + return FALSE; + if (! g_file_set_contents (filename, contents, size, error)) + { + g_free (contents); + return FALSE; + } + g_free (contents); + return TRUE; +} + +#define GET(T, k, v) \ + do { \ + if (g_key_file_has_key (kf, "overview", k, NULL)) { \ + v = g_key_file_get_##T (kf, "overview", k, error); \ + if (error != NULL && *error != NULL) { \ + g_key_file_free (kf); \ + return FALSE; \ + } else { \ + g_object_notify (G_OBJECT (self), k); \ + } \ + } \ + } while (0) + +gboolean +overview_prefs_from_data (OverviewPrefs *self, + const gchar *contents, + gssize size, + GError **error) +{ + GKeyFile *kf; + gchar *pos; + + g_return_val_if_fail (OVERVIEW_IS_PREFS (self), FALSE); + g_return_val_if_fail (contents != NULL, FALSE); + + kf = g_key_file_new (); + + if (! g_key_file_load_from_data (kf, contents, size, + G_KEY_FILE_KEEP_COMMENTS | + G_KEY_FILE_KEEP_TRANSLATIONS, + error)) + { + g_key_file_free (kf); + return FALSE; + } + + GET (uint64, "width", self->width); + GET (integer, "zoom", self->zoom); + GET (boolean, "show-tooltip", self->show_tt); + GET (boolean, "show-scrollbar", self->show_sb); + GET (boolean, "double-buffered", self->dbl_buf); + GET (uint64, "scroll-lines", self->scr_lines); + GET (boolean, "overlay-enabled", self->ovl_en); + GET (boolean, "overlay-inverted", self->ovl_inv); + GET (boolean, "visible", self->visible); + + if (g_key_file_has_key (kf, "overview", "position", NULL)) + { + pos = g_key_file_get_string (kf, "overview", "position", error); + if (error != NULL && *error != NULL) + return FALSE; + if (g_ascii_strcasecmp (pos, "right") == 0) + self->position = GTK_POS_RIGHT; + else if (g_ascii_strcasecmp (pos, "left") == 0) + self->position = GTK_POS_LEFT; + else + { + g_warning ("unknown value '%s' for 'position' key", pos); + self->position = GTK_POS_RIGHT; + } + g_free (pos); + } + + if (g_key_file_has_key (kf, "overview", "overlay-color", NULL) && + g_key_file_has_key (kf, "overview", "overlay-alpha", NULL)) + { + if (! overview_color_from_keyfile (&self->ovl_clr, kf, "overview", "overlay", error)) + { + g_key_file_free (kf); + return FALSE; + } + g_object_notify (G_OBJECT (self), "overlay-color"); + } + + if (g_key_file_has_key (kf, "overview", "overlay-outline-color", NULL) && + g_key_file_has_key (kf, "overview", "overlay-outline-alpha", NULL)) + { + if (! overview_color_from_keyfile (&self->out_clr, kf, "overview", "overlay-outline", error)) + { + g_key_file_free (kf); + return FALSE; + } + g_object_notify (G_OBJECT (self), "overlay-outline-color"); + } + + g_key_file_free (kf); + + return TRUE; +} + +#define SET(T, k, v) g_key_file_set_##T (kf, "overview", k, v) + +gchar * +overview_prefs_to_data (OverviewPrefs *self, + gsize *size, + GError **error) +{ + GKeyFile *kf; + gchar *contents; + + g_return_val_if_fail (OVERVIEW_IS_PREFS (self), NULL); + + kf = g_key_file_new (); + + SET (uint64, "width", self->width); + SET (integer, "zoom", self->zoom); + SET (boolean, "show-tooltip", self->show_tt); + SET (boolean, "show-scrollbar", self->show_sb); + SET (boolean, "double-buffered", self->dbl_buf); + SET (uint64, "scroll-lines", self->scr_lines); + SET (boolean, "overlay-enabled", self->ovl_en); + SET (boolean, "overlay-inverted", self->ovl_inv); + SET (boolean, "visible", self->visible); + + g_key_file_set_string (kf, "overview", "position", + self->position == GTK_POS_LEFT ? "left" : "right"); + + overview_color_to_keyfile (&self->ovl_clr, kf, "overview", "overlay"); + overview_color_to_keyfile (&self->out_clr, kf, "overview", "overlay-outline"); + + contents = g_key_file_to_data (kf, size, error); + g_key_file_free (kf); + return contents; +} + +#define BIND(prop) \ + g_object_bind_property (self, prop, sci, prop, G_BINDING_SYNC_CREATE) + +void +overview_prefs_bind_scintilla (OverviewPrefs *self, + GObject *sci) +{ + g_return_if_fail (OVERVIEW_IS_PREFS (self)); + g_return_if_fail (OVERVIEW_IS_SCINTILLA (sci)); + + BIND ("width"); + BIND ("zoom"); + BIND ("show-tooltip"); + BIND ("show-scrollbar"); + BIND ("double-buffered"); + BIND ("scroll-lines"); + BIND ("overlay-enabled"); + BIND ("overlay-color"); + BIND ("overlay-outline-color"); + BIND ("overlay-inverted"); + BIND ("visible"); +} diff --git a/overview/overview/overviewprefs.h b/overview/overview/overviewprefs.h new file mode 100644 index 000000000..78c48fae3 --- /dev/null +++ b/overview/overview/overviewprefs.h @@ -0,0 +1,78 @@ +/* + * overviewprefs.h - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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 OVERVIEWPREFS_H_ +#define OVERVIEWPREFS_H_ 1 + +#include + +G_BEGIN_DECLS + +#define OVERVIEW_TYPE_PREFS (overview_prefs_get_type ()) +#define OVERVIEW_PREFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OVERVIEW_TYPE_PREFS, OverviewPrefs)) +#define OVERVIEW_PREFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OVERVIEW_TYPE_PREFS, OverviewPrefsClass)) +#define OVERVIEW_IS_PREFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OVERVIEW_TYPE_PREFS)) +#define OVERVIEW_IS_PREFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OVERVIEW_TYPE_PREFS)) +#define OVERVIEW_PREFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OVERVIEW_TYPE_PREFS, OverviewPrefsClass)) + +typedef struct OverviewPrefs_ OverviewPrefs; +typedef struct OverviewPrefsClass_ OverviewPrefsClass; + +GType overview_prefs_get_type (void); +OverviewPrefs *overview_prefs_new (void); +gboolean overview_prefs_load (OverviewPrefs *prefs, + const gchar *filename, + GError **error); +gboolean overview_prefs_save (OverviewPrefs *prefs, + const gchar *filename, + GError **error); +gboolean overview_prefs_from_data (OverviewPrefs *prefs, + const gchar *contents, + gssize size, + GError **error); +gchar* overview_prefs_to_data (OverviewPrefs *prefs, + gsize *size, + GError **error); +void overview_prefs_bind_scintilla (OverviewPrefs *prefs, + GObject *sci); + +#define OVERVIEW_PREFS_DEFAULT_CONFIG \ + "[overview]\n" \ + "width = 120\n" \ + "zoom = -10\n" \ + "show-tooltip = true\n" \ + "double-buffered = true\n" \ + "scroll-lines = 4\n" \ + "show-scrollbar = true\n" \ + "overlay-enabled = true\n" \ + "overlay-color = #000000\n" \ + "overlay-alpha = 0.10\n" \ + "overlay-outline-color = #000000\n" \ + "overlay-outline-alpha = 0.10\n" \ + "overlay-inverted = true\n" \ + "position = right\n" \ + "visible = true\n" \ + "\n" + +G_END_DECLS + +#endif /* OVERVIEWPREFS_H_ */ diff --git a/overview/overview/overviewprefspanel.c b/overview/overview/overviewprefspanel.c new file mode 100644 index 000000000..c385dbd76 --- /dev/null +++ b/overview/overview/overviewprefspanel.c @@ -0,0 +1,264 @@ +/* + * overviewprefspanel.c - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "overviewprefspanel.h" +#include "overviewcolor.h" +#include "overviewplugin.h" +#include "overviewui.h" + +struct OverviewPrefsPanel_ +{ + GtkFrame parent; + OverviewPrefs *prefs; + GtkWidget *prefs_table; + GtkWidget *width_spin; + GtkWidget *zoom_spin; + GtkWidget *scr_lines_spin; + GtkWidget *pos_left_check; + GtkWidget *hide_tt_check; + GtkWidget *hide_sb_check; + GtkWidget *ovl_dis_check; + GtkWidget *ovl_inv_check; + GtkWidget *ovl_clr_btn; + GtkWidget *out_clr_btn; +}; + +struct OverviewPrefsPanelClass_ +{ + GtkFrameClass parent_class; +}; + +static void overview_prefs_panel_finalize (GObject *object); + +G_DEFINE_TYPE (OverviewPrefsPanel, overview_prefs_panel, GTK_TYPE_FRAME) + +static void +overview_prefs_panel_class_init (OverviewPrefsPanelClass *klass) +{ + GObjectClass *g_object_class; + + g_object_class = G_OBJECT_CLASS (klass); + + g_object_class->finalize = overview_prefs_panel_finalize; + + g_signal_new ("prefs-stored", + G_TYPE_FROM_CLASS (g_object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, OVERVIEW_TYPE_PREFS); + + g_signal_new ("prefs-loaded", + G_TYPE_FROM_CLASS (g_object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, OVERVIEW_TYPE_PREFS); +} + +static void +overview_prefs_panel_finalize (GObject *object) +{ + OverviewPrefsPanel *self; + + g_return_if_fail (OVERVIEW_IS_PREFS_PANEL (object)); + + self = OVERVIEW_PREFS_PANEL (object); + + g_object_unref (self->prefs); + + G_OBJECT_CLASS (overview_prefs_panel_parent_class)->finalize (object); +} + +static GtkWidget * +builder_get_widget (GtkBuilder *builder, + const gchar *name) +{ + GObject *result = NULL; + gchar *real_name; + + real_name = g_strdup_printf ("overview-%s", name); + result = gtk_builder_get_object (builder, real_name); + + if (! G_IS_OBJECT (result)) + g_critical ("unable to find widget '%s' in UI file", real_name); + else if (! GTK_IS_WIDGET (result)) + g_critical ("object '%s' in UI file is not a widget", real_name); + + g_free (real_name); + + return (GtkWidget*) result; +} + +static void +overview_prefs_panel_store_prefs (OverviewPrefsPanel *self) +{ + guint width; + gint zoom; + guint scr_lines; + gboolean pos_left = FALSE; + OverviewColor ovl_clr = {0,0,0,0}; + OverviewColor out_clr = {0,0,0,0}; + + width = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->width_spin)); + zoom = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->zoom_spin)); + scr_lines = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->scr_lines_spin)); + pos_left = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->pos_left_check)); + overview_color_from_color_button (&ovl_clr, GTK_COLOR_BUTTON (self->ovl_clr_btn)); + overview_color_from_color_button (&out_clr, GTK_COLOR_BUTTON (self->out_clr_btn)); + + g_object_set (self->prefs, + "width", width, + "zoom", zoom, + "scroll-lines", scr_lines, + "position", pos_left ? GTK_POS_LEFT : GTK_POS_RIGHT, + "show-tooltip", !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->hide_tt_check)), + "show-scrollbar", !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->hide_sb_check)), + "overlay-enabled", !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->ovl_dis_check)), + "overlay-inverted", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->ovl_inv_check)), + "overlay-color", &ovl_clr, + "overlay-outline-color", &out_clr, + NULL); + + g_signal_emit_by_name (self, "prefs-stored", self->prefs); +} + +static void +overview_prefs_panel_load_prefs (OverviewPrefsPanel *self) +{ + gint zoom = 0; + guint width = 0; + guint scr_lines = 0; + gboolean show_tt = FALSE; + gboolean show_sb = FALSE; + gboolean ovl_en = FALSE; + gboolean ovl_inv = FALSE; + GtkPositionType pos = FALSE; + OverviewColor *ovl_clr = NULL; + OverviewColor *out_clr = NULL; + + g_object_get (self->prefs, + "width", &width, + "zoom", &zoom, + "scroll-lines", &scr_lines, + "position", &pos, + "show-tooltip", &show_tt, + "show-scrollbar", &show_sb, + "overlay-enabled", &ovl_en, + "overlay-inverted", &ovl_inv, + "overlay-color", &ovl_clr, + "overlay-outline-color", &out_clr, + NULL); + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->width_spin), width); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->zoom_spin), zoom); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->scr_lines_spin), scr_lines); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->pos_left_check), (pos == GTK_POS_LEFT)); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->hide_tt_check), !show_tt); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->hide_sb_check), !show_sb); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->ovl_inv_check), ovl_inv); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->ovl_dis_check), !ovl_en); + overview_color_to_color_button (ovl_clr, GTK_COLOR_BUTTON (self->ovl_clr_btn)); + overview_color_to_color_button (out_clr, GTK_COLOR_BUTTON (self->out_clr_btn)); + + overview_color_free (ovl_clr); + overview_color_free (out_clr); + + g_signal_emit_by_name (self, "prefs-loaded", self->prefs); +} + +static void +overview_prefs_panel_init (OverviewPrefsPanel *self) +{ + GtkBuilder *builder; + GError *error = NULL; + GtkWidget *overlay_frame; + + builder = gtk_builder_new (); + if (! gtk_builder_add_from_file (builder, OVERVIEW_PREFS_UI_FILE, &error)) + { + g_critical ("failed to open UI file '%s': %s", OVERVIEW_PREFS_UI_FILE, error->message); + g_error_free (error); + g_object_unref (builder); + return; + } + + self->prefs_table = builder_get_widget (builder, "prefs-table"); + self->width_spin = builder_get_widget (builder, "width-spin"); + self->zoom_spin = builder_get_widget (builder, "zoom-spin"); + self->scr_lines_spin = builder_get_widget (builder, "scroll-lines-spin"); + self->pos_left_check = builder_get_widget (builder, "position-left-check"); + self->hide_tt_check = builder_get_widget (builder, "hide-tooltip-check"); + self->hide_sb_check = builder_get_widget (builder, "hide-scrollbar-check"); + self->ovl_inv_check = builder_get_widget (builder, "overlay-inverted-check"); + self->ovl_clr_btn = builder_get_widget (builder, "overlay-color"); + self->out_clr_btn = builder_get_widget (builder, "overlay-outline-color"); + + // The "Draw over visible area" checkbox hides/shows the "Overlay" frame + self->ovl_dis_check = builder_get_widget (builder, "overlay-disable-check"); + overlay_frame = builder_get_widget (builder, "overlay-frame"); + g_object_bind_property (self->ovl_dis_check, "active", overlay_frame, "sensitive", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); + + gtk_widget_show_all (self->prefs_table); + gtk_container_add (GTK_CONTAINER (self), self->prefs_table); + g_object_unref (builder); + +#ifndef OVERVIEW_UI_SUPPORTS_LEFT_POSITION + gtk_widget_set_no_show_all (self->pos_left_check, TRUE); + gtk_widget_hide (self->pos_left_check); +#endif +} + +static void +on_host_dialog_response (GtkDialog *dialog, + gint response_id, + OverviewPrefsPanel *self) +{ + switch (response_id) + { + case GTK_RESPONSE_APPLY: + case GTK_RESPONSE_OK: + overview_prefs_panel_store_prefs (self); + break; + case GTK_RESPONSE_CANCEL: + default: + break; + } +} + +GtkWidget * +overview_prefs_panel_new (OverviewPrefs *prefs, + GtkDialog *host_dialog) +{ + OverviewPrefsPanel *self; + self = g_object_new (OVERVIEW_TYPE_PREFS_PANEL, NULL); + self->prefs = g_object_ref (prefs); + g_signal_connect (host_dialog, "response", G_CALLBACK (on_host_dialog_response), self); + overview_prefs_panel_load_prefs (self); + return GTK_WIDGET (self); +} diff --git a/overview/overview/overviewprefspanel.h b/overview/overview/overviewprefspanel.h new file mode 100644 index 000000000..5f0a2a4a9 --- /dev/null +++ b/overview/overview/overviewprefspanel.h @@ -0,0 +1,47 @@ +/* + * overviewprefspanel.h - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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 OVERVIEWPREFSPANEL_H_ +#define OVERVIEWPREFSPANEL_H_ 1 + +#include "overviewprefs.h" +#include + +G_BEGIN_DECLS + +#define OVERVIEW_TYPE_PREFS_PANEL (overview_prefs_panel_get_type ()) +#define OVERVIEW_PREFS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OVERVIEW_TYPE_PREFS_PANEL, OverviewPrefsPanel)) +#define OVERVIEW_PREFS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OVERVIEW_TYPE_PREFS_PANEL, OverviewPrefsPanelClass)) +#define OVERVIEW_IS_PREFS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OVERVIEW_TYPE_PREFS_PANEL)) +#define OVERVIEW_IS_PREFS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OVERVIEW_TYPE_PREFS_PANEL)) +#define OVERVIEW_PREFS_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OVERVIEW_TYPE_PREFS_PANEL, OverviewPrefsPanelClass)) + +typedef struct OverviewPrefsPanel_ OverviewPrefsPanel; +typedef struct OverviewPrefsPanelClass_ OverviewPrefsPanelClass; + +GType overview_prefs_panel_get_type (void); +GtkWidget *overview_prefs_panel_new (OverviewPrefs *prefs, + GtkDialog *host_dialog); + +G_END_DECLS + +#endif /* OVERVIEWPREFSPANEL_H_ */ diff --git a/overview/overview/overviewscintilla.c b/overview/overview/overviewscintilla.c new file mode 100644 index 000000000..9ec14eea3 --- /dev/null +++ b/overview/overview/overviewscintilla.c @@ -0,0 +1,1299 @@ +/* + * overviewscintilla.c - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "overviewscintilla.h" +#include "overviewplugin.h" +#include + +#define OVERVIEW_SCINTILLA_CURSOR GDK_ARROW +#define OVERVIEW_SCINTILLA_CURSOR_CLICK GDK_ARROW +#define OVERVIEW_SCINTILLA_CURSOR_SCROLL GDK_SB_V_DOUBLE_ARROW +#define OVERVIEW_SCINTILLA_ZOOM_MIN -100 +#define OVERVIEW_SCINTILLA_ZOOM_MAX 100 +#define OVERVIEW_SCINTILLA_ZOOM_DEF -20 +#define OVERVIEW_SCINTILLA_WIDTH_MIN 16 +#define OVERVIEW_SCINTILLA_WIDTH_MAX 512 +#define OVERVIEW_SCINTILLA_WIDTH_DEF 120 +#define OVERVIEW_SCINTILLA_SCROLL_LINES 1 + +#ifndef SC_MAX_MARGIN +# define SC_MAX_MARGIN 4 +#endif + +#define sci_send(sci, msg, wParam, lParam) \ + scintilla_send_message (SCINTILLA (sci), SCI_##msg, (uptr_t)(wParam), (sptr_t)(lParam)) + +static const OverviewColor def_overlay_color = { 0.0, 0.0, 0.0, 0.25 }; +static const OverviewColor def_overlay_outline_color = { 0.0, 0.0, 0.0, 0.0 }; + +enum +{ + PROP_0, + PROP_SCINTILLA, + PROP_CURSOR, + PROP_VISIBLE_RECT, + PROP_WIDTH, + PROP_ZOOM, + PROP_SHOW_TOOLTIP, + PROP_OVERLAY_ENABLED, + PROP_OVERLAY_COLOR, + PROP_OVERLAY_OUTLINE_COLOR, + PROP_OVERLAY_INVERTED, + PROP_DOUBLE_BUFFERED, + PROP_SCROLL_LINES, + PROP_SHOW_SCROLLBAR, + N_PROPERTIES, +}; + +struct OverviewScintilla_ +{ + ScintillaObject parent; + ScintillaObject *sci; // source scintilla + GtkWidget *canvas; // internal GtkDrawingArea of scintilla + GdkCursorType cursor; // the chosen mouse cursor to use over the scintilla + GdkCursorType active_cursor; // the cursor to draw + GdkRectangle visible_rect; // visible region rectangle + guint width; // width of the overview + gint zoom; // zoom level of scintilla + gboolean show_tooltip; // whether tooltip shown on hover + gboolean overlay_enabled; // whether the visible overlay is drawn + OverviewColor overlay_color; // the color of the visible overlay + OverviewColor overlay_outline_color; // the color of the outline of the overlay + gboolean overlay_inverted;// draw overlay over the visible area instead of around it + gboolean double_buffered; // whether to enable double-buffering on internal scintilla canvas + gint scroll_lines; // number of lines to scroll each scroll-event + gboolean show_scrollbar; // show the main scintilla's scrollbar + gboolean mouse_down; // whether the mouse is down + gulong update_rect; // signal id of idle rect handler + gulong conf_event; // signal id of the configure event on scintilla internal drawing area + GtkWidget *src_canvas; // internal drawing area of main scintilla +}; + +struct OverviewScintillaClass_ +{ + ScintillaClass parent_class; +}; + +static GParamSpec *pspecs[N_PROPERTIES] = { NULL }; + +static void overview_scintilla_finalize (GObject *object); +static void overview_scintilla_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void overview_scintilla_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void overview_scintilla_set_src_sci (OverviewScintilla *self, + ScintillaObject *sci); + +#if GTK_CHECK_VERSION (3, 0, 0) +static gboolean overview_scintilla_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data); +#else +static gboolean overview_scintilla_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data); +#endif + +G_DEFINE_TYPE (OverviewScintilla, overview_scintilla, scintilla_get_type()) + +static void +overview_scintilla_class_init (OverviewScintillaClass *klass) +{ + GObjectClass *g_object_class; + + g_object_class = G_OBJECT_CLASS (klass); + + g_object_class->finalize = overview_scintilla_finalize; + g_object_class->set_property = overview_scintilla_set_property; + g_object_class->get_property = overview_scintilla_get_property; + + pspecs[PROP_SCINTILLA] = + g_param_spec_object ("scintilla", + "Scintilla", + "The source ScintillaObject", + scintilla_get_type (), + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + pspecs[PROP_CURSOR] = + g_param_spec_enum ("cursor", + "Cursor", + "The GdkCursorType to use for the mouse cursor", + GDK_TYPE_CURSOR_TYPE, + OVERVIEW_SCINTILLA_CURSOR, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_VISIBLE_RECT] = + g_param_spec_boxed ("visible-rect", + "VisibleRect", + "The visible area indication rectangle to draw", + GDK_TYPE_RECTANGLE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_WIDTH] = + g_param_spec_uint ("width", + "Width", + "Width of the overview", + OVERVIEW_SCINTILLA_WIDTH_MIN, + OVERVIEW_SCINTILLA_WIDTH_MAX, + OVERVIEW_SCINTILLA_WIDTH_DEF, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_ZOOM] = + g_param_spec_int ("zoom", + "Zoom", + "The zoom-level of the overview", + OVERVIEW_SCINTILLA_ZOOM_MIN, + OVERVIEW_SCINTILLA_ZOOM_MAX, + OVERVIEW_SCINTILLA_ZOOM_DEF, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_SHOW_TOOLTIP] = + g_param_spec_boolean ("show-tooltip", + "ShowTooltip", + "Whether to show a tooltip with addition info on mouse over", + TRUE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_OVERLAY_ENABLED] = + g_param_spec_boolean ("overlay-enabled", + "OverlayEnabled", + "Whether an overlay is drawn ontop of the overview", + TRUE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_OVERLAY_COLOR] = + g_param_spec_boxed ("overlay-color", + "OverlayColor", + "The color of the overlay, if enabled", + OVERVIEW_TYPE_COLOR, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_OVERLAY_OUTLINE_COLOR] = + g_param_spec_boxed ("overlay-outline-color", + "OverlayOutlineColor", + "The color of the overlay's outline, if enabled", + OVERVIEW_TYPE_COLOR, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_OVERLAY_INVERTED] = + g_param_spec_boolean ("overlay-inverted", + "OverlayInverted", + "Whether to draw the overlay over the visible area", + TRUE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_DOUBLE_BUFFERED] = + g_param_spec_boolean ("double-buffered", + "DoubleBuffered", + "Whether the overview Scintilla's internal canvas is double-buffered", + TRUE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_SCROLL_LINES] = + g_param_spec_int ("scroll-lines", + "ScrollLines", + "The number of lines to move each scroll, -1 for default, 0 to disable.", + -1, 100, OVERVIEW_SCINTILLA_SCROLL_LINES, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + pspecs[PROP_SHOW_SCROLLBAR] = + g_param_spec_boolean ("show-scrollbar", + "ShowScrollbar", + "Whether to show the scrollbar in the main Scintilla", + TRUE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + g_object_class_install_properties (g_object_class, N_PROPERTIES, pspecs); +} + +static void +overview_scintilla_finalize (GObject *object) +{ + OverviewScintilla *self; + + g_return_if_fail (OVERVIEW_IS_SCINTILLA (object)); + + self = OVERVIEW_SCINTILLA (object); + + if (GTK_IS_WIDGET (self->src_canvas) && self->conf_event != 0) + g_signal_handler_disconnect (self->src_canvas, self->conf_event); + + g_object_unref (self->sci); + + G_OBJECT_CLASS (overview_scintilla_parent_class)->finalize (object); +} + +static inline void +cairo_set_source_overlay_color_ (cairo_t *cr, + const OverviewColor *color) +{ + cairo_set_source_rgba (cr, color->red, color->green, color->blue, color->alpha); +} + +static inline void +overview_scintilla_draw_real (OverviewScintilla *self, + cairo_t *cr) +{ + if (! self->overlay_enabled) + return; + + GtkAllocation alloc; + + gtk_widget_get_allocation (GTK_WIDGET (self->canvas), &alloc); + + cairo_save (cr); + + cairo_set_line_width (cr, 1.0); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_GOOD); + + if (self->overlay_inverted) + { + cairo_set_source_overlay_color_ (cr, &self->overlay_color); + cairo_rectangle (cr, + 0, + self->visible_rect.y, + alloc.width, + self->visible_rect.height); + cairo_fill (cr); + } + else + { + // draw a rectangle at the top and bottom to obscure the non-visible area + cairo_set_source_overlay_color_ (cr, &self->overlay_color); + cairo_rectangle (cr, 0, 0, alloc.width, self->visible_rect.y); + cairo_rectangle (cr, + 0, + self->visible_rect.y + self->visible_rect.height, + alloc.width, + alloc.height - (self->visible_rect.y + self->visible_rect.height)); + cairo_fill (cr); + } + + // draw a highlighting border at top and bottom of visible rect + cairo_set_source_overlay_color_ (cr, &self->overlay_outline_color); + cairo_move_to (cr, self->visible_rect.x + 0.5, self->visible_rect.y + 0.5); + cairo_line_to (cr, self->visible_rect.width, self->visible_rect.y + 0.5); + cairo_move_to (cr, self->visible_rect.x + 0.5, self->visible_rect.y + 0.5 + self->visible_rect.height); + cairo_line_to (cr, self->visible_rect.width, self->visible_rect.y + 0.5 + self->visible_rect.height); + cairo_stroke (cr); + + // draw a left border if there's no scrollbar + if (! overview_scintilla_get_show_scrollbar (self)) + { + cairo_move_to (cr, 0.5, 0.5); + cairo_line_to (cr, 0.5, alloc.height); + cairo_stroke (cr); + } + + cairo_restore (cr); +} + +#if GTK_CHECK_VERSION (3, 0, 0) +static gboolean +overview_scintilla_draw (GtkWidget *widget, + cairo_t *cr, + gpointer user_data) +{ + overview_scintilla_draw_real (OVERVIEW_SCINTILLA (user_data), cr); + return FALSE; +} +#else +static gboolean +overview_scintilla_expose_event (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + cairo_t *cr; + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + overview_scintilla_draw_real (OVERVIEW_SCINTILLA (user_data), cr); + cairo_destroy (cr); + return FALSE; +} +#endif + +static gboolean +on_focus_in_event (OverviewScintilla *self, + GdkEventFocus *event, + ScintillaObject *sci) +{ + sci_send (self, SETREADONLY, 1, 0); + return TRUE; +} + +static gboolean +on_focus_out_event (OverviewScintilla *self, + GdkEventFocus *event, + ScintillaObject *sci) +{ + GeanyDocument *doc = g_object_get_data (G_OBJECT (sci), "document"); + if (DOC_VALID (doc)) + sci_send (self, SETREADONLY, doc->readonly, 0); + else + sci_send (self, SETREADONLY, 0, 0); + return TRUE; +} + +static gboolean +on_enter_notify_event (OverviewScintilla *self, + GdkEventCrossing *event, + ScintillaObject *sci) +{ + return TRUE; +} + +static gboolean +on_leave_notify_event (OverviewScintilla *self, + GdkEventCrossing *event, + ScintillaObject *sci) +{ + return TRUE; +} + +static void +on_each_child (GtkWidget *child, + GList **list) +{ + *list = g_list_prepend (*list, child); +} + +static GList * +gtk_container_get_internal_children_ (GtkContainer *cont) +{ + GList *list = NULL; + gtk_container_forall (cont, (GtkCallback) on_each_child, &list); + return g_list_reverse (list); +} + +static GtkWidget * +overview_scintilla_find_drawing_area (GtkWidget *root) +{ + GtkWidget *da = NULL; + if (GTK_IS_DRAWING_AREA (root)) + da = root; + else if (GTK_IS_CONTAINER (root)) + { + GList *children = gtk_container_get_internal_children_ (GTK_CONTAINER (root)); + for (GList *iter = children; iter != NULL; iter = g_list_next (iter)) + { + GtkWidget *wid = overview_scintilla_find_drawing_area (iter->data); + if (GTK_IS_DRAWING_AREA (wid)) + { + da = wid; + break; + } + } + g_list_free (children); + } + return da; +} + +static gboolean +on_scroll_event (OverviewScintilla *self, + GdkEventScroll *event, + GtkWidget *widget) +{ + gint delta = 0; + + if (self->scroll_lines == 0) + return TRUE; + + if (event->direction == GDK_SCROLL_UP) + delta = -(self->scroll_lines); + else if (event->direction == GDK_SCROLL_DOWN) + delta = self->scroll_lines; + + if (delta != 0) + sci_send (self->sci, LINESCROLL, 0, delta); + + return TRUE; +} + +static void +overview_scintilla_goto_point (OverviewScintilla *self, + gint x, + gint y) +{ + gint pos; + pos = sci_send (self, POSITIONFROMPOINT, x, y); + if (pos >= 0) + sci_send (self->sci, GOTOPOS, pos, 0); +} + +static void +overview_scintilla_update_cursor (OverviewScintilla *self) +{ + if (GTK_IS_WIDGET (self->canvas) && gtk_widget_get_mapped (self->canvas)) + { + GdkCursor *cursor = gdk_cursor_new (self->active_cursor); + gdk_window_set_cursor (gtk_widget_get_window (self->canvas), cursor); + gdk_cursor_unref (cursor); + } +} + +static gboolean +on_button_press_event (OverviewScintilla *self, + GdkEventButton *event, + GtkWidget *widget) +{ + self->mouse_down = TRUE; + self->active_cursor = OVERVIEW_SCINTILLA_CURSOR_CLICK; + overview_scintilla_update_cursor (self); + return TRUE; +} + +static gboolean +on_button_release_event (OverviewScintilla *self, + GdkEventButton *event, + GtkWidget *widget) +{ + self->mouse_down = FALSE; + self->active_cursor = OVERVIEW_SCINTILLA_CURSOR; + overview_scintilla_update_cursor (self); + overview_scintilla_goto_point (self, event->x, event->y); + return TRUE; +} + +static gboolean +on_motion_notify_event (OverviewScintilla *self, + GdkEventMotion *event, + GtkWidget *widget) +{ + if (self->mouse_down) + { + if (self->active_cursor != OVERVIEW_SCINTILLA_CURSOR_SCROLL) + { + self->active_cursor = OVERVIEW_SCINTILLA_CURSOR_SCROLL; + overview_scintilla_update_cursor (self); + } + overview_scintilla_goto_point (self, event->x, event->y); + } + return TRUE; +} + +static gboolean +overview_scintilla_setup_tooltip (OverviewScintilla *self, + gint x, + gint y, + GtkTooltip *tooltip) +{ + gint pos; + + if (!self->show_tooltip) + return FALSE; + + pos = sci_send (self, POSITIONFROMPOINT, x, y); + if (pos >= 0) + { + gint line = sci_send (self, LINEFROMPOSITION, pos, 0); + gint column = sci_send (self, GETCOLUMN, pos, 0); + gchar *text = + g_strdup_printf (_("Line %d, Column %d, Position %d"), + line, column, pos); + gtk_tooltip_set_markup (tooltip, text); + g_free (text); + } + else + gtk_tooltip_set_text (tooltip, NULL); + + return TRUE; +} + +static gboolean +on_query_tooltip (OverviewScintilla *self, + gint x, + gint y, + gboolean kbd_mode, + GtkTooltip *tooltip, + GtkWidget *widget) +{ + if (!kbd_mode) + return overview_scintilla_setup_tooltip (self, x, y, tooltip); + return FALSE; +} + +static void +overview_scintilla_setup_canvas (OverviewScintilla *self) +{ + if (!GTK_IS_WIDGET (self->canvas)) + { + self->canvas = overview_scintilla_find_drawing_area (GTK_WIDGET (self)); + + gtk_widget_add_events (self->canvas, + GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_SCROLL_MASK); + + g_signal_connect_swapped (self->canvas, + "scroll-event", + G_CALLBACK (on_scroll_event), + self); + g_signal_connect_swapped (self->canvas, + "button-press-event", + G_CALLBACK (on_button_press_event), + self); + g_signal_connect_swapped (self->canvas, + "button-release-event", + G_CALLBACK (on_button_release_event), + self); + g_signal_connect_swapped (self->canvas, + "motion-notify-event", + G_CALLBACK (on_motion_notify_event), + self); + g_signal_connect_swapped (self->canvas, + "query-tooltip", + G_CALLBACK (on_query_tooltip), + self); + + gtk_widget_set_has_tooltip (self->canvas, self->show_tooltip); + +#if GTK_CHECK_VERSION (3, 0, 0) + g_signal_connect_after (self->canvas, + "draw", + G_CALLBACK (overview_scintilla_draw), + self); +#else + g_signal_connect_after (self->canvas, + "expose-event", + G_CALLBACK (overview_scintilla_expose_event), + self); +#endif + + } +} + +static void +overview_scintilla_update_rect (OverviewScintilla *self) +{ + GtkAllocation alloc; + GdkRectangle rect; + gint first_line, n_lines, last_line; + gint pos_start, pos_end; + gint ystart, yend; + + gtk_widget_get_allocation (GTK_WIDGET (self), &alloc); + + first_line = sci_send (self->sci, GETFIRSTVISIBLELINE, 0, 0); + n_lines = sci_send (self->sci, LINESONSCREEN, 0, 0); + last_line = first_line + n_lines; + + pos_start = sci_send (self, POSITIONFROMLINE, first_line, 0); + pos_end = sci_send (self, POSITIONFROMLINE, last_line, 0); + + ystart = sci_send (self, POINTYFROMPOSITION, 0, pos_start); + yend = sci_send (self, POINTYFROMPOSITION, 0, pos_end); + + if (yend >= alloc.height || yend == 0) + { + n_lines = sci_send (self, GETLINECOUNT, 0, 0); + last_line = n_lines - 1; + pos_end = sci_send (self, POSITIONFROMLINE, last_line, 0); + yend = sci_send (self, POINTYFROMPOSITION, 0, pos_end); + } + + rect.x = 0; + rect.width = alloc.width - 1; + rect.y = ystart; + rect.height = yend - ystart; + + overview_scintilla_set_visible_rect (self, &rect); +} + +static gint +sci_get_midline_ (gpointer sci) +{ + gint first, count; + first = sci_send (sci, GETFIRSTVISIBLELINE, 0, 0); + count = sci_send (sci, LINESONSCREEN, 0, 0); + return first + (count / 2); +} + +static void +overview_scintilla_sync_center (OverviewScintilla *self) +{ + gint mid_src = sci_get_midline_ (self->sci); + gint mid_dst = sci_get_midline_ (self); + gint delta = mid_src - mid_dst; + sci_send (self, LINESCROLL, 0, delta); + overview_scintilla_update_rect (self); +} + +static gboolean +on_map_event (OverviewScintilla *self, + GdkEventAny *event, + ScintillaObject *sci) +{ + overview_scintilla_setup_canvas (self); + + if (GTK_IS_WIDGET (self->canvas) && + gtk_widget_get_double_buffered (self->canvas) != self->double_buffered) + { + gtk_widget_set_double_buffered (self->canvas, self->double_buffered); + self->double_buffered = gtk_widget_get_double_buffered (self->canvas); + } + + overview_scintilla_update_cursor (self); + overview_scintilla_update_rect (self); + + return FALSE; +} + +#define self_connect(name, cb) \ + g_signal_connect_swapped (self, name, G_CALLBACK (cb), self) + +static void +overview_scintilla_init (OverviewScintilla *self) +{ + self->sci = NULL; + self->canvas = NULL; + self->cursor = OVERVIEW_SCINTILLA_CURSOR; + self->active_cursor = OVERVIEW_SCINTILLA_CURSOR; + self->update_rect = 0; + self->conf_event = 0; + self->src_canvas = NULL; + self->width = OVERVIEW_SCINTILLA_WIDTH_DEF; + self->zoom = OVERVIEW_SCINTILLA_ZOOM_DEF; + self->mouse_down = FALSE; + self->show_tooltip = TRUE; + self->double_buffered = TRUE; + self->scroll_lines = OVERVIEW_SCINTILLA_SCROLL_LINES; + self->show_scrollbar = TRUE; + self->overlay_inverted = TRUE; + + memset (&self->visible_rect, 0, sizeof (GdkRectangle)); + memcpy (&self->overlay_color, &def_overlay_color, sizeof (OverviewColor)); + memcpy (&self->overlay_outline_color, &def_overlay_outline_color, sizeof (OverviewColor)); + + gtk_widget_add_events (GTK_WIDGET (self), + GDK_EXPOSURE_MASK | + GDK_FOCUS_CHANGE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_STRUCTURE_MASK); + + self_connect ("focus-in-event", on_focus_in_event); + self_connect ("focus-out-event", on_focus_out_event); + self_connect ("enter-notify-event", on_enter_notify_event); + self_connect ("leave-notify-event", on_leave_notify_event); + self_connect ("map-event", on_map_event); +} + +static void +overview_scintilla_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OverviewScintilla *self = OVERVIEW_SCINTILLA (object); + + switch (prop_id) + { + case PROP_SCINTILLA: + overview_scintilla_set_src_sci (self, g_value_get_object (value)); + break; + case PROP_CURSOR: + overview_scintilla_set_cursor (self, g_value_get_enum (value)); + break; + case PROP_VISIBLE_RECT: + overview_scintilla_set_visible_rect (self, g_value_get_boxed (value)); + break; + case PROP_WIDTH: + overview_scintilla_set_width (self, g_value_get_uint (value)); + break; + case PROP_ZOOM: + overview_scintilla_set_zoom (self, g_value_get_int (value)); + break; + case PROP_SHOW_TOOLTIP: + overview_scintilla_set_show_tooltip (self, g_value_get_boolean (value)); + break; + case PROP_OVERLAY_ENABLED: + overview_scintilla_set_overlay_enabled (self, g_value_get_boolean (value)); + break; + case PROP_OVERLAY_COLOR: + overview_scintilla_set_overlay_color (self, g_value_get_boxed (value)); + break; + case PROP_OVERLAY_OUTLINE_COLOR: + overview_scintilla_set_overlay_outline_color (self, g_value_get_boxed (value)); + break; + case PROP_OVERLAY_INVERTED: + overview_scintilla_set_overlay_inverted (self, g_value_get_boolean (value)); + break; + case PROP_DOUBLE_BUFFERED: + overview_scintilla_set_double_buffered (self, g_value_get_boolean (value)); + break; + case PROP_SCROLL_LINES: + overview_scintilla_set_scroll_lines (self, g_value_get_int (value)); + break; + case PROP_SHOW_SCROLLBAR: + overview_scintilla_set_show_scrollbar (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +overview_scintilla_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OverviewScintilla *self = OVERVIEW_SCINTILLA (object); + + switch (prop_id) + { + case PROP_SCINTILLA: + g_value_set_object (value, self->sci); + break; + case PROP_CURSOR: + g_value_set_enum (value, overview_scintilla_get_cursor (self)); + break; + case PROP_VISIBLE_RECT: + { + GdkRectangle rect; + overview_scintilla_get_visible_rect (self, &rect); + g_value_set_boxed (value, &rect); + break; + } + case PROP_WIDTH: + g_value_set_uint (value, overview_scintilla_get_width (self)); + break; + case PROP_ZOOM: + g_value_set_int (value, overview_scintilla_get_zoom (self)); + break; + case PROP_SHOW_TOOLTIP: + g_value_set_boolean (value, overview_scintilla_get_show_tooltip (self)); + break; + case PROP_OVERLAY_ENABLED: + g_value_set_boolean (value, overview_scintilla_get_overlay_enabled (self)); + break; + case PROP_OVERLAY_COLOR: + { + OverviewColor color; + overview_scintilla_get_overlay_color (self, &color); + g_value_set_boxed (value, &color); + break; + } + case PROP_OVERLAY_OUTLINE_COLOR: + { + OverviewColor color; + overview_scintilla_get_overlay_outline_color (self, &color); + g_value_set_boxed (value, &color); + break; + } + case PROP_OVERLAY_INVERTED: + g_value_set_boolean (value, overview_scintilla_get_overlay_inverted (self)); + break; + case PROP_DOUBLE_BUFFERED: + g_value_set_boolean (value, overview_scintilla_get_double_buffered (self)); + break; + case PROP_SCROLL_LINES: + g_value_set_int (value, overview_scintilla_get_scroll_lines (self)); + break; + case PROP_SHOW_SCROLLBAR: + g_value_set_boolean (value, overview_scintilla_get_show_scrollbar (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +GtkWidget * +overview_scintilla_new (ScintillaObject *src_sci) +{ + return g_object_new (OVERVIEW_TYPE_SCINTILLA, "scintilla", src_sci, NULL); +} + +static gchar * +sci_get_font (ScintillaObject *sci, + gint style) +{ + gsize len = sci_send (sci, STYLEGETFONT, style, 0); + gchar *name = g_malloc0 (len + 1); + sci_send (sci, STYLEGETFONT, style, name); + return name; +} + +static gboolean +on_src_sci_configure_event (GtkWidget *widget, + GdkEventConfigure *event, + OverviewScintilla *self) +{ + overview_scintilla_sync_center (self); + return FALSE; +} + +static gboolean +on_src_sci_map_event (ScintillaObject *sci, + GdkEvent *event, + OverviewScintilla *self) +{ + if (self->conf_event == 0) + { + GtkWidget *internal; + internal = overview_scintilla_find_drawing_area (GTK_WIDGET (sci)); + if (GTK_IS_DRAWING_AREA (internal)) + { + self->src_canvas = internal; + self->conf_event = g_signal_connect (self->src_canvas, + "configure-event", + G_CALLBACK (on_src_sci_configure_event), + self); + } + } + return FALSE; +} + +static void +on_src_sci_notify (ScintillaObject *sci, + gpointer unused, + SCNotification *nt, + OverviewScintilla *self) +{ + if (nt->nmhdr.code == SCN_UPDATEUI && nt->updated & SC_UPDATE_V_SCROLL) + { + overview_scintilla_sync_center (self); + if (GTK_IS_WIDGET (self->canvas)) + gtk_widget_queue_draw (self->canvas); + } +} + +static void +overview_scintilla_clone_styles (OverviewScintilla *self) +{ + ScintillaObject *sci = SCINTILLA (self); + ScintillaObject *src_sci = self->sci; + + for (gint i = 0; i < STYLE_MAX; i++) + { + gchar *font_name = sci_get_font (src_sci, i); + gint font_size = sci_send (src_sci, STYLEGETSIZE, i, 0); + gint weight = sci_send (src_sci, STYLEGETWEIGHT, i, 0); + gboolean italic = sci_send (src_sci, STYLEGETITALIC, i, 0); + gint fg_color = sci_send (src_sci, STYLEGETFORE, i, 0); + gint bg_color = sci_send (src_sci, STYLEGETBACK, i, 0); + + sci_send (sci, STYLESETFONT, i, font_name); + sci_send (sci, STYLESETSIZE, i, font_size); + sci_send (sci, STYLESETWEIGHT, i, weight); + sci_send (sci, STYLESETITALIC, i, italic); + sci_send (sci, STYLESETFORE, i, fg_color); + sci_send (sci, STYLESETBACK, i, bg_color); + sci_send (sci, STYLESETCHANGEABLE, i, 0); + + g_free (font_name); + } +} + +static void +overview_scintilla_queue_draw (OverviewScintilla *self) +{ + if (GTK_IS_WIDGET (self->canvas)) + gtk_widget_queue_draw (self->canvas); + else + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +void +overview_scintilla_sync (OverviewScintilla *self) +{ + sptr_t doc_ptr; + + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + doc_ptr = sci_send (self->sci, GETDOCPOINTER, 0, 0); + sci_send (self, SETDOCPOINTER, 0, doc_ptr); + + overview_scintilla_clone_styles (self); + + for (gint i = 0; i < SC_MAX_MARGIN; i++) + sci_send (self, SETMARGINWIDTHN, i, 0); + + sci_send (self, SETVIEWEOL, 0, 0); + sci_send (self, SETVIEWWS, 0, 0); + sci_send (self, SETHSCROLLBAR, 0, 0); + sci_send (self, SETVSCROLLBAR, 0, 0); + sci_send (self, SETZOOM, self->zoom, 0); + sci_send (self, SETCURSOR, SC_CURSORARROW, 0); + sci_send (self, SETENDATLASTLINE, sci_send (self->sci, GETENDATLASTLINE, 0, 0), 0); + sci_send (self, SETMOUSEDOWNCAPTURES, 0, 0); + sci_send (self, SETCARETPERIOD, 0, 0); + sci_send (self, SETCARETWIDTH, 0, 0); + sci_send (self, SETEXTRAASCENT, 0, 0); + sci_send (self, SETEXTRADESCENT, 0, 0); + + sci_send (self->sci, SETVSCROLLBAR, self->show_scrollbar, 0); + + overview_scintilla_update_cursor (self); + overview_scintilla_update_rect (self); + overview_scintilla_sync_center (self); + + overview_scintilla_queue_draw (self); +} + +static void +overview_scintilla_set_src_sci (OverviewScintilla *self, + ScintillaObject *sci) +{ + + g_assert (! IS_SCINTILLA (self->sci)); + + self->sci = g_object_ref (sci); + + overview_scintilla_sync (self); + sci_send (self->sci, SETVSCROLLBAR, self->show_scrollbar, 0); + + gtk_widget_add_events (GTK_WIDGET (self->sci), GDK_STRUCTURE_MASK); + plugin_signal_connect (geany_plugin, + G_OBJECT (self->sci), + "map-event", + TRUE, + G_CALLBACK (on_src_sci_map_event), + self); + + plugin_signal_connect (geany_plugin, + G_OBJECT (self->sci), + "sci-notify", + TRUE, + G_CALLBACK (on_src_sci_notify), + self); + + g_object_notify (G_OBJECT (self), "scintilla"); +} + +GdkCursorType +overview_scintilla_get_cursor (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), GDK_ARROW); + return self->cursor; +} + +void +overview_scintilla_set_cursor (OverviewScintilla *self, + GdkCursorType cursor_type) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + if (cursor_type != self->cursor) + { + self->cursor = cursor_type; + self->active_cursor = cursor_type; + overview_scintilla_update_cursor (self); + g_object_notify (G_OBJECT (self), "cursor"); + } +} + +void +overview_scintilla_get_visible_rect (OverviewScintilla *self, + GdkRectangle *rect) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + g_return_if_fail (rect != NULL); + + memcpy (rect, &self->visible_rect, sizeof (GdkRectangle)); +} + +void +overview_scintilla_set_visible_rect (OverviewScintilla *self, + const GdkRectangle *rect) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (rect == NULL) + { + memset (&self->visible_rect, 0, sizeof (GdkRectangle)); + g_object_notify (G_OBJECT (self), "visible-rect"); + return; + } + + if (rect->x != self->visible_rect.x || + rect->y != self->visible_rect.y || + rect->width != self->visible_rect.width || + rect->height != self->visible_rect.height) + { + memcpy (&self->visible_rect, rect, sizeof (GdkRectangle)); + if (GTK_IS_WIDGET (self->canvas)) + gtk_widget_queue_draw (self->canvas); + g_object_notify (G_OBJECT (self), "visible-rect"); + } +} + +guint +overview_scintilla_get_width (OverviewScintilla *self) +{ + GtkAllocation alloc; + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), 0); + gtk_widget_get_allocation (GTK_WIDGET (self), &alloc); + return alloc.width; +} + +void +overview_scintilla_set_width (OverviewScintilla *self, + guint width) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + gtk_widget_set_size_request (GTK_WIDGET (self), width, -1); +} + +gint +overview_scintilla_get_zoom (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), 0); + self->zoom = sci_send (self, GETZOOM, 0, 0); + return self->zoom; +} + +void +overview_scintilla_set_zoom (OverviewScintilla *self, + gint zoom) +{ + gint old_zoom; + + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + g_return_if_fail (zoom >= OVERVIEW_SCINTILLA_ZOOM_MIN && + zoom <= OVERVIEW_SCINTILLA_ZOOM_MAX); + + old_zoom = sci_send (self, GETZOOM, 0, 0); + if (zoom != old_zoom) + { + sci_send (self, SETZOOM, zoom, 0); + self->zoom = sci_send (self, GETZOOM, 0, 0); + if (self->zoom != old_zoom) + { + overview_scintilla_sync_center (self); + g_object_notify (G_OBJECT (self), "zoom"); + } + } +} + +gboolean +overview_scintilla_get_show_tooltip (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE); + return self->show_tooltip; +} + +void +overview_scintilla_set_show_tooltip (OverviewScintilla *self, + gboolean show) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (show != self->show_tooltip) + { + self->show_tooltip = show; + if (GTK_IS_WIDGET (self->canvas)) + gtk_widget_set_has_tooltip (self->canvas, self->show_tooltip); + g_object_notify (G_OBJECT (self), "show-tooltip"); + } +} + +gboolean +overview_scintilla_get_overlay_enabled (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE); + return self->overlay_enabled; +} + +void +overview_scintilla_set_overlay_enabled (OverviewScintilla *self, + gboolean enabled) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (enabled != self->overlay_enabled) + { + self->overlay_enabled = enabled; + if (GTK_IS_WIDGET (self->canvas)) + gtk_widget_queue_draw (self->canvas); + g_object_notify (G_OBJECT (self), "overlay-enabled"); + } +} + +void +overview_scintilla_get_overlay_color (OverviewScintilla *self, + OverviewColor *color) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + g_return_if_fail (color != NULL); + memcpy (color, &self->overlay_color, sizeof (OverviewColor)); +} + +void +overview_scintilla_set_overlay_color (OverviewScintilla *self, + const OverviewColor *color) +{ + gboolean changed = FALSE; + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (color == NULL) + { + memcpy (&self->overlay_color, &def_overlay_color, sizeof (OverviewColor)); + changed = TRUE; + } + else if (!overview_color_equal (color, &self->overlay_color)) + { + memcpy (&self->overlay_color, color, sizeof (OverviewColor)); + changed = TRUE; + } + + if (changed) + { + if (GTK_IS_WIDGET (self->canvas)) + gtk_widget_queue_draw (self->canvas); + g_object_notify (G_OBJECT (self), "overlay-color"); + } +} + +void +overview_scintilla_get_overlay_outline_color (OverviewScintilla *self, + OverviewColor *color) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + g_return_if_fail (color != NULL); + memcpy (color, &self->overlay_outline_color, sizeof (OverviewColor)); +} + +void +overview_scintilla_set_overlay_outline_color (OverviewScintilla *self, + const OverviewColor *color) +{ + gboolean changed = FALSE; + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (color == NULL) + { + memcpy (&self->overlay_outline_color, &def_overlay_outline_color, sizeof (OverviewColor)); + changed = TRUE; + } + else if (!overview_color_equal (color, &self->overlay_outline_color)) + { + memcpy (&self->overlay_outline_color, color, sizeof (OverviewColor)); + changed = TRUE; + } + + if (changed) + { + if (GTK_IS_WIDGET (self->canvas)) + gtk_widget_queue_draw (self->canvas); + g_object_notify (G_OBJECT (self), "overlay-outline-color"); + } +} + +gboolean +overview_scintilla_get_overlay_inverted (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE); + return self->overlay_inverted; +} + +void +overview_scintilla_set_overlay_inverted (OverviewScintilla *self, + gboolean inverted) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (inverted != self->overlay_inverted) + { + self->overlay_inverted = inverted; + overview_scintilla_queue_draw (self); + g_object_notify (G_OBJECT (self), "overlay-inverted"); + } +} + +gboolean +overview_scintilla_get_double_buffered (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE); + if (GTK_IS_WIDGET (self->canvas)) + self->double_buffered = gtk_widget_get_double_buffered (self->canvas); + return self->double_buffered; +} + +void +overview_scintilla_set_double_buffered (OverviewScintilla *self, + gboolean enabled) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (enabled != self->double_buffered) + { + self->double_buffered = enabled; + if (GTK_IS_WIDGET (self->canvas)) + { + gtk_widget_set_double_buffered (self->canvas, self->double_buffered); + self->double_buffered = gtk_widget_get_double_buffered (self->canvas); + } + if (self->double_buffered == enabled) + g_object_notify (G_OBJECT (self), "double-buffered"); + } +} + +gint +overview_scintilla_get_scroll_lines (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), -1); + return self->scroll_lines; +} + +void +overview_scintilla_set_scroll_lines (OverviewScintilla *self, + gint lines) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (lines < 0) + lines = OVERVIEW_SCINTILLA_SCROLL_LINES; + + if (lines != self->scroll_lines) + { + self->scroll_lines = lines; + g_object_notify (G_OBJECT (self), "scroll-lines"); + } +} + +gboolean +overview_scintilla_get_show_scrollbar (OverviewScintilla *self) +{ + g_return_val_if_fail (OVERVIEW_IS_SCINTILLA (self), FALSE); + return self->show_scrollbar; +} + +void +overview_scintilla_set_show_scrollbar (OverviewScintilla *self, + gboolean show) +{ + g_return_if_fail (OVERVIEW_IS_SCINTILLA (self)); + + if (show != self->show_scrollbar) + { + self->show_scrollbar = show; + sci_send (self->sci, SETVSCROLLBAR, self->show_scrollbar, 0); + gtk_widget_queue_draw (GTK_WIDGET (self->sci)); + g_object_notify (G_OBJECT (self), "show-scrollbar"); + } +} diff --git a/overview/overview/overviewscintilla.h b/overview/overview/overviewscintilla.h new file mode 100644 index 000000000..46615e343 --- /dev/null +++ b/overview/overview/overviewscintilla.h @@ -0,0 +1,86 @@ +/* + * overviewscintilla.h - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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 OVERVIEWSCINTILLA_H_ +#define OVERVIEWSCINTILLA_H_ 1 + +#include "overviewplugin.h" +#include "overviewcolor.h" + +G_BEGIN_DECLS + +#define OVERVIEW_TYPE_SCINTILLA (overview_scintilla_get_type ()) +#define OVERVIEW_SCINTILLA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OVERVIEW_TYPE_SCINTILLA, OverviewScintilla)) +#define OVERVIEW_SCINTILLA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OVERVIEW_TYPE_SCINTILLA, OverviewScintillaClass)) +#define OVERVIEW_IS_SCINTILLA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OVERVIEW_TYPE_SCINTILLA)) +#define OVERVIEW_IS_SCINTILLA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OVERVIEW_TYPE_SCINTILLA)) +#define OVERVIEW_SCINTILLA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OVERVIEW_TYPE_SCINTILLA, OverviewScintillaClass)) + +typedef struct OverviewScintilla_ OverviewScintilla; +typedef struct OverviewScintillaClass_ OverviewScintillaClass; + +GType overview_scintilla_get_type (void); +GtkWidget *overview_scintilla_new (ScintillaObject *src_sci); +void overview_scintilla_sync (OverviewScintilla *sci); +GdkCursorType overview_scintilla_get_cursor (OverviewScintilla *sci); +void overview_scintilla_set_cursor (OverviewScintilla *sci, + GdkCursorType cursor_type); +void overview_scintilla_get_visible_rect (OverviewScintilla *sci, + GdkRectangle *rect); +void overview_scintilla_set_visible_rect (OverviewScintilla *sci, + const GdkRectangle *rect); +guint overview_scintilla_get_width (OverviewScintilla *sci); +void overview_scintilla_set_width (OverviewScintilla *sci, + guint width); +gint overview_scintilla_get_zoom (OverviewScintilla *sci); +void overview_scintilla_set_zoom (OverviewScintilla *sci, + gint zoom); +gboolean overview_scintilla_get_show_tooltip (OverviewScintilla *sci); +void overview_scintilla_set_show_tooltip (OverviewScintilla *sci, + gboolean show); +gboolean overview_scintilla_get_overlay_enabled (OverviewScintilla *sci); +void overview_scintilla_set_overlay_enabled (OverviewScintilla *sci, + gboolean enabled); +void overview_scintilla_get_overlay_color (OverviewScintilla *sci, + OverviewColor *color); +void overview_scintilla_set_overlay_color (OverviewScintilla *sci, + const OverviewColor *color); +void overview_scintilla_get_overlay_outline_color (OverviewScintilla *sci, + OverviewColor *color); +void overview_scintilla_set_overlay_outline_color (OverviewScintilla *sci, + const OverviewColor *color); +gboolean overview_scintilla_get_overlay_inverted (OverviewScintilla *sci); +void overview_scintilla_set_overlay_inverted (OverviewScintilla *sci, + gboolean inverted); +gboolean overview_scintilla_get_double_buffered (OverviewScintilla *sci); +void overview_scintilla_set_double_buffered (OverviewScintilla *sci, + gboolean enabled); +gint overview_scintilla_get_scroll_lines (OverviewScintilla *sci); +void overview_scintilla_set_scroll_lines (OverviewScintilla *sci, + gint lines); +gboolean overview_scintilla_get_show_scrollbar (OverviewScintilla *sci); +void overview_scintilla_set_show_scrollbar (OverviewScintilla *sci, + gboolean show); + +G_END_DECLS + +#endif /* OVERVIEWSCINTILLA_H_ */ diff --git a/overview/overview/overviewui.c b/overview/overview/overviewui.c new file mode 100644 index 000000000..a7b01f50a --- /dev/null +++ b/overview/overview/overviewui.c @@ -0,0 +1,376 @@ +/* + * overviewui.c - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "overviewui.h" +#include "overviewplugin.h" +#include "overviewscintilla.h" + +typedef void (*DocForEachFunc) (ScintillaObject *src_sci, + OverviewScintilla *overview); + +static void overview_ui_hijack_all_editor_views (void); +static void overview_ui_restore_all_editor_views (void); +static void overview_ui_update_all_editor_views (void); + +static OverviewPrefs *overview_ui_prefs = NULL; +static GtkWidget *overview_ui_menu_sep = NULL; +static GtkWidget *overview_ui_menu_item = NULL; + +static inline void +overview_ui_scintilla_foreach (DocForEachFunc callback) +{ + guint i; + foreach_document (i) + { + GeanyDocument *doc = documents[i]; + ScintillaObject *src_sci; + OverviewScintilla *overview; + src_sci = doc->editor->sci; + overview = g_object_get_data (G_OBJECT (src_sci), "overview"); + if (IS_SCINTILLA (doc->editor->sci)) + callback (src_sci, overview); + else + g_critical ("enumerating invalid scintilla editor widget"); + } +} + +static inline gboolean +overview_ui_position_is_left (void) +{ + GtkPositionType position; + g_object_get (overview_ui_prefs, "position", &position, NULL); + return (position == GTK_POS_LEFT); +} + +static inline void +overview_ui_container_add_expanded (GtkContainer *container, + GtkWidget *widget) +{ + gtk_container_add (container, widget); + /* GTK+ 3 doesn't expand by default anymore */ +#if GTK_CHECK_VERSION (3, 0, 0) + g_object_set (widget, "expand", TRUE, NULL); +#endif +} + +static void +overview_ui_hijack_editor_view (ScintillaObject *src_sci, + OverviewScintilla *null_and_unused) +{ + GtkWidget *parent; + GtkWidget *container; + GtkWidget *overview; + gboolean on_left; + + g_assert (g_object_get_data (G_OBJECT (src_sci), "overview") == NULL); + + parent = gtk_widget_get_parent (GTK_WIDGET (src_sci)); + container = gtk_hbox_new (FALSE, 0); + overview = overview_scintilla_new (src_sci); + + overview_prefs_bind_scintilla (overview_ui_prefs, G_OBJECT (overview)); + gtk_widget_set_no_show_all (overview, TRUE); + + g_object_set_data (G_OBJECT (src_sci), "overview", overview); + + on_left = overview_ui_position_is_left (); +#ifndef OVERVIEW_UI_SUPPORTS_LEFT_POSITION + if (on_left) + { + g_critical ("Refusing to add Overview into left position because " + "your Geany version isn't new enough to support this " + "without crashing hard."); + on_left = FALSE; + } +#endif + + g_object_ref (src_sci); + gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (src_sci)); + + if (on_left) + { + gtk_box_pack_start (GTK_BOX (container), overview, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (container), GTK_WIDGET (src_sci), TRUE, TRUE, 0); + } + else + { + gtk_box_pack_start (GTK_BOX (container), GTK_WIDGET (src_sci), TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (container), overview, FALSE, TRUE, 0); + } + + overview_ui_container_add_expanded (GTK_CONTAINER (parent), container); + g_object_unref (src_sci); + + gtk_widget_show_all (container); +} + +static void +overview_ui_hijack_all_editor_views (void) +{ + overview_ui_scintilla_foreach (overview_ui_hijack_editor_view); +} + +static void +overview_ui_restore_editor_view (ScintillaObject *src_sci, + OverviewScintilla *overview) +{ + GtkWidget *old_parent = gtk_widget_get_parent (GTK_WIDGET (src_sci)); + GtkWidget *new_parent = gtk_widget_get_parent (old_parent); + g_object_ref (src_sci); + g_object_set_data (G_OBJECT (src_sci), "overview", NULL); + gtk_container_remove (GTK_CONTAINER (old_parent), GTK_WIDGET (src_sci)); + gtk_container_remove (GTK_CONTAINER (new_parent), old_parent); + overview_ui_container_add_expanded (GTK_CONTAINER (new_parent), GTK_WIDGET (src_sci)); + g_object_unref (src_sci); +} + +static void +overview_ui_restore_all_editor_views (void) +{ + overview_ui_scintilla_foreach (overview_ui_restore_editor_view); +} + +static void +overview_ui_update_editor_view (ScintillaObject *src_sci, + OverviewScintilla *overview) +{ + GtkWidget *parent; + gboolean on_left; + + on_left = overview_ui_position_is_left (); +#ifndef OVERVIEW_UI_SUPPORTS_LEFT_POSITION + if (on_left) + { + g_critical ("Refusing to swap Overview into left position because " + "your Geany version isn't new enough to support this " + "without crashing hard."); + on_left = FALSE; + } +#endif + + parent = gtk_widget_get_parent (GTK_WIDGET (src_sci)); + + g_object_ref (src_sci); + g_object_ref (overview); + + gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (src_sci)); + gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (overview)); + + if (on_left) + { + gtk_box_pack_start (GTK_BOX (parent), GTK_WIDGET (overview), FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (parent), GTK_WIDGET (src_sci), TRUE, TRUE, 0); + } + else + { + gtk_box_pack_start (GTK_BOX (parent), GTK_WIDGET (src_sci), TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (parent), GTK_WIDGET (overview), FALSE, TRUE, 0); + } + + gtk_widget_show_all (parent); + + g_object_unref (overview); + g_object_unref (src_sci); + + overview_scintilla_sync (overview); +} + +void +overview_ui_update_all_editor_views (void) +{ + overview_ui_scintilla_foreach (overview_ui_update_editor_view); +} + +GtkWidget * +overview_ui_get_menu_item (void) +{ + g_return_val_if_fail (GTK_IS_MENU_ITEM (overview_ui_menu_item), NULL); + return overview_ui_menu_item; +} + +static inline OverviewScintilla * +overview_scintilla_from_document (GeanyDocument *doc) +{ + if (DOC_VALID (doc)) + { + ScintillaObject *src_sci = doc->editor->sci; + if (IS_SCINTILLA (src_sci)) + return g_object_get_data (G_OBJECT (src_sci), "overview"); + } + return NULL; +} + +static void +on_document_open_new (G_GNUC_UNUSED GObject *unused, + GeanyDocument *doc, + G_GNUC_UNUSED gpointer user_data) +{ + g_object_set_data (G_OBJECT (doc->editor->sci), "overview-document", doc); + overview_ui_hijack_editor_view (doc->editor->sci, NULL); + overview_ui_queue_update (); +} + +static void +on_document_activate_reload (G_GNUC_UNUSED GObject *unused, + G_GNUC_UNUSED GeanyDocument *doc, + G_GNUC_UNUSED gpointer user_data) +{ + overview_ui_queue_update (); +} + +static void +on_document_close (G_GNUC_UNUSED GObject *unused, + GeanyDocument *doc, + G_GNUC_UNUSED gpointer user_data) +{ + OverviewScintilla *overview; + overview = overview_scintilla_from_document (doc); + overview_ui_restore_editor_view (doc->editor->sci, overview); +} + +static gint +overview_ui_get_menu_item_pos (GtkWidget *menu, + GtkWidget *item_before) +{ + GList *children; + gint pos = 0; + children = gtk_container_get_children (GTK_CONTAINER (menu)); + for (GList *iter = children; iter != NULL; iter = g_list_next (iter), pos++) + { + if (iter->data == item_before) + break; + } + g_list_free (children); + return pos + 1; +} + +static void +overview_ui_add_menu_item (void) +{ + static const gchar *view_menu_name = "menu_view1_menu"; + static const gchar *prev_item_name = "menu_show_sidebar1"; + GtkWidget *main_window = geany_data->main_widgets->window; + GtkWidget *view_menu; + GtkWidget *prev_item; + gint item_pos; + gboolean visible = FALSE; + + view_menu = ui_lookup_widget (main_window, view_menu_name); + if (! GTK_IS_MENU (view_menu)) + { + g_critical ("failed to locate the View menu (%s) in Geany's main menu", + view_menu_name); + return; + } + + overview_ui_menu_item = gtk_check_menu_item_new_with_label (_("Show Overview")); + prev_item = ui_lookup_widget (main_window, prev_item_name); + if (! GTK_IS_MENU_ITEM (prev_item)) + { + g_critical ("failed to locate the Show Sidebar menu item (%s) in Geany's UI", + prev_item_name); + overview_ui_menu_sep = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (view_menu), overview_ui_menu_sep); + gtk_menu_shell_append (GTK_MENU_SHELL (view_menu), overview_ui_menu_item); + gtk_widget_show (overview_ui_menu_sep); + } + else + { + item_pos = overview_ui_get_menu_item_pos (view_menu, prev_item); + overview_ui_menu_sep = NULL; + gtk_menu_shell_insert (GTK_MENU_SHELL (view_menu), overview_ui_menu_item, item_pos); + } + + g_object_get (overview_ui_prefs, "visible", &visible, NULL); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (overview_ui_menu_item), visible); + g_object_bind_property (overview_ui_menu_item, "active", + overview_ui_prefs, "visible", + G_BINDING_DEFAULT); + + gtk_widget_show (overview_ui_menu_item); +} + +static void +on_position_pref_notify (OverviewPrefs *prefs, + GParamSpec *pspec, + gpointer user_data) +{ + overview_ui_update_all_editor_views (); +} + +void +overview_ui_init (OverviewPrefs *prefs) +{ + overview_ui_prefs = g_object_ref (prefs); + + overview_ui_add_menu_item (); + overview_ui_hijack_all_editor_views (); + + g_signal_connect (prefs, "notify::position", + G_CALLBACK (on_position_pref_notify), NULL); + + plugin_signal_connect (geany_plugin, NULL, "document-new", TRUE, G_CALLBACK (on_document_open_new), NULL); + plugin_signal_connect (geany_plugin, NULL, "document-open", TRUE, G_CALLBACK (on_document_open_new), NULL); + plugin_signal_connect (geany_plugin, NULL, "document-activate", TRUE, G_CALLBACK (on_document_activate_reload), NULL); + plugin_signal_connect (geany_plugin, NULL, "document-reload", TRUE, G_CALLBACK (on_document_activate_reload), NULL); + plugin_signal_connect (geany_plugin, NULL, "document-close", TRUE, G_CALLBACK (on_document_close), NULL); + +} + +void +overview_ui_deinit (void) +{ + overview_ui_restore_all_editor_views (); + + if (GTK_IS_WIDGET (overview_ui_menu_sep)) + gtk_widget_destroy (overview_ui_menu_sep); + gtk_widget_destroy (overview_ui_menu_item); + + if (OVERVIEW_IS_PREFS (overview_ui_prefs)) + g_object_unref (overview_ui_prefs); + overview_ui_prefs = NULL; +} + +static gboolean +on_update_overview_later (gpointer user_data) +{ + GeanyDocument *doc; + doc = document_get_current (); + if (DOC_VALID (doc)) + { + OverviewScintilla *overview; + overview = g_object_get_data (G_OBJECT (doc->editor->sci), "overview"); + if (OVERVIEW_IS_SCINTILLA (overview)) + overview_scintilla_sync (overview); + } + return FALSE; +} + +void +overview_ui_queue_update (void) +{ + g_idle_add_full (G_PRIORITY_LOW, on_update_overview_later, NULL, NULL); +} diff --git a/overview/overview/overviewui.h b/overview/overview/overviewui.h new file mode 100644 index 000000000..62afebcdb --- /dev/null +++ b/overview/overview/overviewui.h @@ -0,0 +1,42 @@ +/* + * overviewui.h - This file is part of the Geany Overview plugin + * + * Copyright (c) 2015 Matthew Brush + * + * 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 OVERVIEWUI_H_ +#define OVERVIEWUI_H_ + +#include "overviewprefs.h" +#include "overviewplugin.h" + +// This should match the API version of when the patch gets applied to +// make putting overview on left work. +#define OVERVIEW_SCI_HUNTING_PATCH_API 224 + +#if GEANY_API_VERSION >= OVERVIEW_SCI_HUNTING_PATCH_API +# define OVERVIEW_UI_SUPPORTS_LEFT_POSITION 1 +#endif + +void overview_ui_init (OverviewPrefs *prefs); +void overview_ui_deinit (void); +GtkWidget *overview_ui_get_menu_item (void); +void overview_ui_queue_update (void); + +#endif // OVERVIEWUI_H_ diff --git a/overview/wscript_build b/overview/wscript_build new file mode 100644 index 000000000..032a0995f --- /dev/null +++ b/overview/wscript_build @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# +# WAF build script for geany-plugins - Overview +# +# Copyright 2015 Matthew Brush +# +# 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. +# + +from build.wafutils import build_plugin + +name = 'Overview' +sources = [ + 'overview/overviewcolor.c', + 'overview/overviewplugin.c', + 'overview/overviewprefs.c', + 'overview/overviewprefspanel.c', + 'overview/overviewscintilla.c', + 'overview/overviewui.c', +] +includes = ['overview'] +packages = [ 'gtk+-2.0', 'glib-2.0', 'geany' ] +libraries = [ 'GTK', 'GLIB', 'GEANY' ] +defines = [ subst_vars('OVERVIEW_PREFS_UI_FILE="${PKGDATADIR}/overview/prefs.ui"', bld.env) ] + +build_plugin(bld, name, + sources=sources, + includes=includes, + packages=packages, + libraries=libraries, + defines=defines) diff --git a/po/POTFILES.in b/po/POTFILES.in index 0d01cd566..ddff2fcf0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -224,6 +224,15 @@ git-changebar/src/gcb-plugin.c markdown/src/conf.c markdown/src/plugin.c +# Overview +overview/overview/overviewcolor.c +overview/overview/overviewplugin.c +overview/overview/overviewprefs.c +overview/overview/overviewprefspanel.c +overview/overview/overviewscintilla.c +overview/overview/overviewui.c +[type: gettext/glade]overview/data/prefs.ui + # Pairtaghighlighter pairtaghighlighter/src/pair_tag_highlighter.c