summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
authorLiam P. White <inkscapebrony@gmail.com>2014-10-08 02:22:03 +0000
committerLiam P. White <inkscapebrony@gmail.com>2014-10-08 02:22:03 +0000
commitf3840fe9d0d423f6ddf5a68d776a903d57ffb7b5 (patch)
treec8e28b27f5885928ccf866a69eb6cbc99fde599c /src/widgets
parentUpdate to experimental r13565 (diff)
parentSome template cleanup... (diff)
downloadinkscape-f3840fe9d0d423f6ddf5a68d776a903d57ffb7b5.tar.gz
inkscape-f3840fe9d0d423f6ddf5a68d776a903d57ffb7b5.zip
Update to experimental r13598
(bzr r13341.5.17)
Diffstat (limited to 'src/widgets')
-rw-r--r--src/widgets/CMakeLists.txt10
-rw-r--r--src/widgets/Makefile_insert10
-rw-r--r--src/widgets/arc-toolbar.cpp8
-rw-r--r--src/widgets/box3d-toolbar.cpp4
-rw-r--r--src/widgets/button.cpp2
-rw-r--r--src/widgets/calligraphy-toolbar.cpp6
-rw-r--r--src/widgets/connector-toolbar.cpp4
-rw-r--r--src/widgets/desktop-widget.cpp4
-rw-r--r--src/widgets/dropper-toolbar.cpp4
-rw-r--r--src/widgets/ege-adjustment-action.cpp1113
-rw-r--r--src/widgets/ege-adjustment-action.h192
-rw-r--r--src/widgets/ege-output-action.cpp245
-rw-r--r--src/widgets/ege-output-action.h120
-rw-r--r--src/widgets/ege-select-one-action.cpp1153
-rw-r--r--src/widgets/ege-select-one-action.h245
-rw-r--r--src/widgets/eraser-toolbar.cpp6
-rw-r--r--src/widgets/gradient-toolbar.cpp8
-rw-r--r--src/widgets/ink-action.cpp638
-rw-r--r--src/widgets/ink-action.h159
-rw-r--r--src/widgets/ink-comboboxentry-action.cpp958
-rw-r--r--src/widgets/ink-comboboxentry-action.h106
-rw-r--r--src/widgets/lpe-toolbar.cpp6
-rw-r--r--src/widgets/measure-toolbar.cpp4
-rw-r--r--src/widgets/mesh-toolbar.cpp10
-rw-r--r--src/widgets/node-toolbar.cpp6
-rw-r--r--src/widgets/paintbucket-toolbar.cpp4
-rw-r--r--src/widgets/pencil-toolbar.cpp10
-rw-r--r--src/widgets/rect-toolbar.cpp8
-rw-r--r--src/widgets/select-toolbar.cpp4
-rw-r--r--src/widgets/sp-color-notebook.cpp2
-rw-r--r--src/widgets/sp-widget.h2
-rw-r--r--src/widgets/spiral-toolbar.cpp6
-rw-r--r--src/widgets/spray-toolbar.cpp6
-rw-r--r--src/widgets/star-toolbar.cpp8
-rw-r--r--src/widgets/stroke-marker-selector.cpp4
-rw-r--r--src/widgets/stroke-style.h2
-rw-r--r--src/widgets/text-toolbar.cpp8
-rw-r--r--src/widgets/toolbox.cpp14
-rw-r--r--src/widgets/tweak-toolbar.cpp8
39 files changed, 5027 insertions, 80 deletions
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index fe4433153..072b905a2 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -24,6 +24,9 @@ set(widgets_SRC
desktop-widget.cpp
eek-preview.cpp
ege-paint-def.cpp
+ ege-adjustment-action.cpp
+ ege-output-action.cpp
+ ege-select-one-action.cpp
fill-style.cpp
font-selector.cpp
gradient-image.cpp
@@ -31,6 +34,8 @@ set(widgets_SRC
gradient-toolbar.cpp
gradient-vector.cpp
icon.cpp
+ ink-action.cpp
+ ink-comboboxentry-action.cpp
paint-selector.cpp
ruler.cpp
select-toolbar.cpp
@@ -80,6 +85,9 @@ set(widgets_SRC
desktop-widget.h
eek-preview.h
ege-paint-def.h
+ ege-adjustment-action.h
+ ege-output-action.h
+ ege-select-one-action.h
fill-n-stroke-factory.h
fill-style.h
font-selector.h
@@ -88,6 +96,8 @@ set(widgets_SRC
gradient-toolbar.h
gradient-vector.h
icon.h
+ ink-action.h
+ ink-comboboxentry-action.h
paint-selector.h
ruler.h
select-toolbar.h
diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert
index 97713cbee..dc4c12967 100644
--- a/src/widgets/Makefile_insert
+++ b/src/widgets/Makefile_insert
@@ -19,8 +19,14 @@ ink_common_sources += \
widgets/dropper-toolbar.h \
widgets/eek-preview.cpp \
widgets/eek-preview.h \
+ widgets/ege-adjustment-action.cpp \
+ widgets/ege-adjustment-action.h \
widgets/ege-paint-def.cpp \
widgets/ege-paint-def.h \
+ widgets/ege-output-action.cpp \
+ widgets/ege-output-action.h \
+ widgets/ege-select-one-action.cpp \
+ widgets/ege-select-one-action.h \
widgets/eraser-toolbar.cpp \
widgets/eraser-toolbar.h \
widgets/fill-style.cpp \
@@ -38,6 +44,10 @@ ink_common_sources += \
widgets/gradient-vector.h \
widgets/icon.cpp \
widgets/icon.h \
+ widgets/ink-action.cpp \
+ widgets/ink-action.h \
+ widgets/ink-comboboxentry-action.cpp \
+ widgets/ink-comboboxentry-action.h \
widgets/lpe-toolbar.cpp \
widgets/lpe-toolbar.h \
widgets/measure-toolbar.cpp \
diff --git a/src/widgets/arc-toolbar.cpp b/src/widgets/arc-toolbar.cpp
index 1005de70d..ca582924b 100644
--- a/src/widgets/arc-toolbar.cpp
+++ b/src/widgets/arc-toolbar.cpp
@@ -34,10 +34,10 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-output-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
#include "mod360.h"
#include "preferences.h"
#include "selection.h"
diff --git a/src/widgets/box3d-toolbar.cpp b/src/widgets/box3d-toolbar.cpp
index 052eb230b..f6e303d58 100644
--- a/src/widgets/box3d-toolbar.cpp
+++ b/src/widgets/box3d-toolbar.cpp
@@ -36,8 +36,8 @@
#include "desktop.h"
#include "document-undo.h"
#include "document.h"
-#include "ege-adjustment-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ink-action.h"
#include "inkscape.h"
#include "persp3d.h"
#include "selection.h"
diff --git a/src/widgets/button.cpp b/src/widgets/button.cpp
index cda97654e..1776e28c4 100644
--- a/src/widgets/button.cpp
+++ b/src/widgets/button.cpp
@@ -16,7 +16,7 @@
#include "button.h"
#include "helper/action-context.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "shortcuts.h"
#include "helper/action.h"
diff --git a/src/widgets/calligraphy-toolbar.cpp b/src/widgets/calligraphy-toolbar.cpp
index 9c0393cd9..4ae6427ad 100644
--- a/src/widgets/calligraphy-toolbar.cpp
+++ b/src/widgets/calligraphy-toolbar.cpp
@@ -34,9 +34,9 @@
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
#include "preferences.h"
#include "toolbox.h"
#include "ui/icon-names.h"
diff --git a/src/widgets/connector-toolbar.cpp b/src/widgets/connector-toolbar.cpp
index 9bbc1bbb4..6ce926dc1 100644
--- a/src/widgets/connector-toolbar.cpp
+++ b/src/widgets/connector-toolbar.cpp
@@ -35,10 +35,10 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
+#include "widgets/ege-adjustment-action.h"
#include "enums.h"
#include "graphlayout.h"
-#include "ink-action.h"
+#include "widgets/ink-action.h"
#include "inkscape.h"
#include "preferences.h"
#include "selection.h"
diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp
index 9b7ac2f42..ef3b29478 100644
--- a/src/widgets/desktop-widget.cpp
+++ b/src/widgets/desktop-widget.cpp
@@ -38,7 +38,7 @@
#include "display/canvas-arena.h"
#include "document.h"
#include "ege-color-prof-tracker.h"
-#include "ege-select-one-action.h"
+#include "widgets/ege-select-one-action.h"
#include <extension/db.h>
#include "file.h"
#include "helper/action.h"
@@ -46,7 +46,7 @@
#include "util/units.h"
#include "ui/widget/unit-tracker.h"
#include "inkscape.h"
-#include "interface.h"
+#include "ui/interface.h"
#include "macros.h"
#include "preferences.h"
#include "sp-image.h"
diff --git a/src/widgets/dropper-toolbar.cpp b/src/widgets/dropper-toolbar.cpp
index 478d0c1a4..45ed9ead4 100644
--- a/src/widgets/dropper-toolbar.cpp
+++ b/src/widgets/dropper-toolbar.cpp
@@ -32,8 +32,8 @@
#include "dropper-toolbar.h"
#include "document-undo.h"
-#include "ege-output-action.h"
-#include "ink-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ink-action.h"
#include "preferences.h"
#include "widgets/spinbutton-events.h"
diff --git a/src/widgets/ege-adjustment-action.cpp b/src/widgets/ege-adjustment-action.cpp
new file mode 100644
index 000000000..d89a6e3f1
--- /dev/null
+++ b/src/widgets/ege-adjustment-action.cpp
@@ -0,0 +1,1113 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is EGE Adjustment Action.
+ *
+ * The Initial Developer of the Original Code is
+ * Jon A. Cruz.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Note: this file should be kept compilable as both .cpp and .c */
+
+#include <cmath>
+#include <string.h>
+
+#include "widgets/icon.h"
+#include <gdk/gdkkeysyms.h>
+
+#include "icon-size.h"
+#include "widgets/ege-adjustment-action.h"
+#include "ui/widget/gimpspinscale.h"
+#include "ui/icon-names.h"
+
+
+static void ege_adjustment_action_finalize( GObject* object );
+static void ege_adjustment_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
+static void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
+
+static GtkWidget* create_menu_item( GtkAction* action );
+static GtkWidget* create_tool_item( GtkAction* action );
+static void connect_proxy( GtkAction *action, GtkWidget *proxy );
+static void disconnect_proxy( GtkAction *action, GtkWidget *proxy );
+
+static gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
+static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
+static gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
+
+static void ege_adjustment_action_defocus( EgeAdjustmentAction* action );
+
+static void egeAct_free_description( gpointer data, gpointer user_data );
+static void egeAct_free_all_descriptions( EgeAdjustmentAction* action );
+
+static EgeCreateAdjWidgetCB gFactoryCb = 0;
+static GQuark gDataName = 0;
+
+enum {
+ APPEARANCE_UNKNOWN = -1,
+ APPEARANCE_NONE = 0,
+ APPEARANCE_FULL, /* label, then all choices represented by separate buttons */
+ APPEARANCE_COMPACT, /* label, then choices in a drop-down menu */
+ APPEARANCE_MINIMAL, /* no label, just choices in a drop-down menu */
+};
+
+/* TODO need to have appropriate icons setup for these: */
+static const gchar *floogles[] = {
+ INKSCAPE_ICON("list-remove"),
+ INKSCAPE_ICON("list-add"),
+ INKSCAPE_ICON("go-down"),
+ INKSCAPE_ICON("help-about"),
+ INKSCAPE_ICON("go-up"),
+ 0};
+
+typedef struct _EgeAdjustmentDescr EgeAdjustmentDescr;
+
+struct _EgeAdjustmentDescr
+{
+ gchar* descr;
+ gdouble value;
+};
+
+struct _EgeAdjustmentActionPrivate
+{
+ GtkAdjustment* adj;
+ GtkWidget* focusWidget;
+ gdouble climbRate;
+ guint digits;
+ gdouble epsilon;
+ gchar* format;
+ gchar* selfId;
+ EgeWidgetFixup toolPost;
+ gdouble lastVal;
+ gdouble step;
+ gdouble page;
+ gint appearanceMode;
+ gboolean transferFocus;
+ GList* descriptions;
+ gchar* appearance;
+ gchar* iconId;
+ Inkscape::IconSize iconSize;
+ Inkscape::UI::Widget::UnitTracker *unitTracker;
+};
+
+#define EGE_ADJUSTMENT_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionPrivate ) )
+
+enum {
+ PROP_ADJUSTMENT = 1,
+ PROP_FOCUS_WIDGET,
+ PROP_CLIMB_RATE,
+ PROP_DIGITS,
+ PROP_SELFID,
+ PROP_TOOL_POST,
+ PROP_APPEARANCE,
+ PROP_ICON_ID,
+ PROP_ICON_SIZE,
+ PROP_UNIT_TRACKER
+};
+
+enum {
+ BUMP_TOP = 0,
+ BUMP_PAGE_UP,
+ BUMP_UP,
+ BUMP_NONE,
+ BUMP_DOWN,
+ BUMP_PAGE_DOWN,
+ BUMP_BOTTOM,
+ BUMP_CUSTOM = 100
+};
+
+G_DEFINE_TYPE(EgeAdjustmentAction, ege_adjustment_action, GTK_TYPE_ACTION);
+
+static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass )
+{
+ if ( klass ) {
+ GObjectClass * objClass = G_OBJECT_CLASS( klass );
+
+ gDataName = g_quark_from_string("ege-adj-action");
+
+
+ objClass->finalize = ege_adjustment_action_finalize;
+
+ objClass->get_property = ege_adjustment_action_get_property;
+ objClass->set_property = ege_adjustment_action_set_property;
+
+ klass->parent_class.create_menu_item = create_menu_item;
+ klass->parent_class.create_tool_item = create_tool_item;
+ klass->parent_class.connect_proxy = connect_proxy;
+ klass->parent_class.disconnect_proxy = disconnect_proxy;
+
+ g_object_class_install_property( objClass,
+ PROP_ADJUSTMENT,
+ g_param_spec_object( "adjustment",
+ "Adjustment",
+ "The adjustment to change",
+ GTK_TYPE_ADJUSTMENT,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_FOCUS_WIDGET,
+ g_param_spec_pointer( "focus-widget",
+ "Focus Widget",
+ "The widget to return focus to",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_CLIMB_RATE,
+ g_param_spec_double( "climb-rate",
+ "Climb Rate",
+ "The acelleraton rate",
+ 0.0, G_MAXDOUBLE, 0.0,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_DIGITS,
+ g_param_spec_uint( "digits",
+ "Digits",
+ "The number of digits to show",
+ 0, 20, 0,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_SELFID,
+ g_param_spec_string( "self-id",
+ "Self ID",
+ "Marker for self pointer",
+ 0,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_TOOL_POST,
+ g_param_spec_pointer( "tool-post",
+ "Tool Widget post process",
+ "Function for final adjustments",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_APPEARANCE,
+ g_param_spec_string( "appearance",
+ "Appearance hint",
+ "A hint for how to display",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_ICON_ID,
+ g_param_spec_string( "iconId",
+ "Icon ID",
+ "The id for the icon",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_ICON_SIZE,
+ g_param_spec_int( "iconSize",
+ "Icon Size",
+ "The size the icon",
+ (int)Inkscape::ICON_SIZE_MENU,
+ (int)Inkscape::ICON_SIZE_DECORATION,
+ (int)Inkscape::ICON_SIZE_SMALL_TOOLBAR,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_UNIT_TRACKER,
+ g_param_spec_pointer( "unit_tracker",
+ "Unit Tracker",
+ "The widget that keeps track of the unit",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_type_class_add_private( klass, sizeof(EgeAdjustmentActionClass) );
+ }
+}
+
+void ege_adjustment_action_set_compact_tool_factory( EgeCreateAdjWidgetCB factoryCb )
+{
+ gFactoryCb = factoryCb;
+}
+
+static void ege_adjustment_action_init( EgeAdjustmentAction* action )
+{
+ action->private_data = EGE_ADJUSTMENT_ACTION_GET_PRIVATE( action );
+ action->private_data->adj = 0;
+ action->private_data->focusWidget = 0;
+ action->private_data->climbRate = 0.0;
+ action->private_data->digits = 2;
+ action->private_data->epsilon = 0.009;
+ action->private_data->format = g_strdup_printf("%%0.%df%%s%%s", action->private_data->digits);
+ action->private_data->selfId = 0;
+ action->private_data->toolPost = 0;
+ action->private_data->lastVal = 0.0;
+ action->private_data->step = 0.0;
+ action->private_data->page = 0.0;
+ action->private_data->appearanceMode = APPEARANCE_NONE;
+ action->private_data->transferFocus = FALSE;
+ action->private_data->descriptions = 0;
+ action->private_data->appearance = 0;
+ action->private_data->iconId = 0;
+ action->private_data->iconSize = Inkscape::ICON_SIZE_SMALL_TOOLBAR;
+ action->private_data->unitTracker = NULL;
+}
+
+static void ege_adjustment_action_finalize( GObject* object )
+{
+ EgeAdjustmentAction* action = 0;
+ g_return_if_fail( object != NULL );
+ g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(object) );
+
+ action = EGE_ADJUSTMENT_ACTION( object );
+
+ // g_free(NULL) does nothing
+ g_free( action->private_data->format );
+ g_free( action->private_data->selfId );
+ g_free( action->private_data->appearance );
+ g_free( action->private_data->iconId );
+
+ egeAct_free_all_descriptions( action );
+
+ if ( G_OBJECT_CLASS(ege_adjustment_action_parent_class)->finalize ) {
+ (*G_OBJECT_CLASS(ege_adjustment_action_parent_class)->finalize)(object);
+ }
+}
+
+EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment,
+ const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id,
+ gdouble climb_rate,
+ guint digits,
+ Inkscape::UI::Widget::UnitTracker *unit_tracker )
+{
+ GObject* obj = (GObject*)g_object_new( EGE_ADJUSTMENT_ACTION_TYPE,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "stock_id", stock_id,
+ "adjustment", adjustment,
+ "climb-rate", climb_rate,
+ "digits", digits,
+ "unit_tracker", unit_tracker,
+ NULL );
+
+ EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
+
+ return action;
+}
+
+static void ege_adjustment_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
+{
+ EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
+ switch ( propId ) {
+ case PROP_ADJUSTMENT:
+ g_value_set_object( value, action->private_data->adj );
+ break;
+
+ case PROP_FOCUS_WIDGET:
+ g_value_set_pointer( value, action->private_data->focusWidget );
+ break;
+
+ case PROP_CLIMB_RATE:
+ g_value_set_double( value, action->private_data->climbRate );
+ break;
+
+ case PROP_DIGITS:
+ g_value_set_uint( value, action->private_data->digits );
+ break;
+
+ case PROP_SELFID:
+ g_value_set_string( value, action->private_data->selfId );
+ break;
+
+ case PROP_TOOL_POST:
+ g_value_set_pointer( value, (void*)action->private_data->toolPost );
+ break;
+
+ case PROP_APPEARANCE:
+ g_value_set_string( value, action->private_data->appearance );
+ break;
+
+ case PROP_ICON_ID:
+ g_value_set_string( value, action->private_data->iconId );
+ break;
+
+ case PROP_ICON_SIZE:
+ g_value_set_int( value, action->private_data->iconSize );
+ break;
+
+ case PROP_UNIT_TRACKER:
+ g_value_set_pointer( value, action->private_data->unitTracker );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
+{
+ EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
+ switch ( propId ) {
+ case PROP_ADJUSTMENT:
+ {
+ action->private_data->adj = GTK_ADJUSTMENT( g_value_get_object( value ) );
+ g_object_get( G_OBJECT(action->private_data->adj),
+ "step-increment", &action->private_data->step,
+ "page-increment", &action->private_data->page,
+ NULL );
+ }
+ break;
+
+ case PROP_FOCUS_WIDGET:
+ {
+ /* TODO unhook prior */
+ action->private_data->focusWidget = (GtkWidget*)g_value_get_pointer( value );
+ }
+ break;
+
+ case PROP_CLIMB_RATE:
+ {
+ /* TODO pass on */
+ action->private_data->climbRate = g_value_get_double( value );
+ }
+ break;
+
+ case PROP_DIGITS:
+ {
+ /* TODO pass on */
+ action->private_data->digits = g_value_get_uint( value );
+ switch ( action->private_data->digits ) {
+ case 0: action->private_data->epsilon = 0.9; break;
+ case 1: action->private_data->epsilon = 0.09; break;
+ case 2: action->private_data->epsilon = 0.009; break;
+ case 3: action->private_data->epsilon = 0.0009; break;
+ case 4: action->private_data->epsilon = 0.00009; break;
+ }
+ if ( action->private_data->format ) {
+ g_free( action->private_data->format );
+ }
+ action->private_data->format = g_strdup_printf("%%0.%df%%s%%s", action->private_data->digits);
+ }
+ break;
+
+ case PROP_SELFID:
+ {
+ /* TODO pass on */
+ gchar* prior = action->private_data->selfId;
+ action->private_data->selfId = g_value_dup_string( value );
+ g_free( prior );
+ }
+ break;
+
+ case PROP_TOOL_POST:
+ {
+ action->private_data->toolPost = (EgeWidgetFixup)g_value_get_pointer( value );
+ }
+ break;
+
+ case PROP_APPEARANCE:
+ {
+ gchar* tmp = action->private_data->appearance;
+ gchar* newVal = g_value_dup_string( value );
+ action->private_data->appearance = newVal;
+ g_free( tmp );
+
+ if ( !action->private_data->appearance || (strcmp("", newVal) == 0) ) {
+ action->private_data->appearanceMode = APPEARANCE_NONE;
+ } else if ( strcmp("full", newVal) == 0 ) {
+ action->private_data->appearanceMode = APPEARANCE_FULL;
+ } else if ( strcmp("compact", newVal) == 0 ) {
+ action->private_data->appearanceMode = APPEARANCE_COMPACT;
+ } else if ( strcmp("minimal", newVal) == 0 ) {
+ action->private_data->appearanceMode = APPEARANCE_MINIMAL;
+ } else {
+ action->private_data->appearanceMode = APPEARANCE_UNKNOWN;
+ }
+ }
+ break;
+
+ case PROP_ICON_ID:
+ {
+ gchar* tmp = action->private_data->iconId;
+ action->private_data->iconId = g_value_dup_string( value );
+ g_free( tmp );
+ }
+ break;
+
+ case PROP_ICON_SIZE:
+ {
+ action->private_data->iconSize = (Inkscape::IconSize)g_value_get_int( value );
+ }
+ break;
+
+ case PROP_UNIT_TRACKER:
+ {
+ action->private_data->unitTracker = (Inkscape::UI::Widget::UnitTracker*)g_value_get_pointer( value );
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+GtkAdjustment* ege_adjustment_action_get_adjustment( EgeAdjustmentAction* action )
+{
+ g_return_val_if_fail( IS_EGE_ADJUSTMENT_ACTION(action), NULL );
+
+ return action->private_data->adj;
+}
+
+void ege_adjustment_action_set_focuswidget( EgeAdjustmentAction* action, GtkWidget* widget )
+{
+ g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(action) );
+
+ /* TODO unhook prior */
+
+ action->private_data->focusWidget = widget;
+}
+
+GtkWidget* ege_adjustment_action_get_focuswidget( EgeAdjustmentAction* action )
+{
+ g_return_val_if_fail( IS_EGE_ADJUSTMENT_ACTION(action), NULL );
+
+ return action->private_data->focusWidget;
+}
+
+static void egeAct_free_description( gpointer data, gpointer user_data ) {
+ (void)user_data;
+ if ( data ) {
+ EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)data;
+ if ( descr->descr ) {
+ g_free( descr->descr );
+ descr->descr = 0;
+ }
+ g_free( descr );
+ }
+}
+
+static void egeAct_free_all_descriptions( EgeAdjustmentAction* action )
+{
+ if ( action->private_data->descriptions ) {
+ g_list_foreach( action->private_data->descriptions, egeAct_free_description, 0 );
+ g_list_free( action->private_data->descriptions );
+ action->private_data->descriptions = 0;
+ }
+}
+
+static gint egeAct_compare_descriptions( gconstpointer a, gconstpointer b )
+{
+ gint val = 0;
+
+ EgeAdjustmentDescr const * aa = (EgeAdjustmentDescr const *)a;
+ EgeAdjustmentDescr const * bb = (EgeAdjustmentDescr const *)b;
+
+ if ( aa && bb ) {
+ if ( aa->value < bb->value ) {
+ val = -1;
+ } else if ( aa->value > bb->value ) {
+ val = 1;
+ }
+ }
+
+ return val;
+}
+
+void ege_adjustment_action_set_descriptions( EgeAdjustmentAction* action, gchar const** descriptions, gdouble const* values, guint count )
+{
+ g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(action) );
+
+ egeAct_free_all_descriptions( action );
+
+ if ( count && descriptions && values ) {
+ guint i = 0;
+ for ( i = 0; i < count; i++ ) {
+ EgeAdjustmentDescr* descr = g_new0( EgeAdjustmentDescr, 1 );
+ descr->descr = descriptions[i] ? g_strdup( descriptions[i] ) : 0;
+ descr->value = values[i];
+ action->private_data->descriptions = g_list_insert_sorted( action->private_data->descriptions, (gpointer)descr, egeAct_compare_descriptions );
+ }
+ }
+}
+
+void ege_adjustment_action_set_appearance( EgeAdjustmentAction* action, gchar const* val )
+{
+ g_object_set( G_OBJECT(action), "appearance", val, NULL );
+}
+
+static void process_menu_action( GtkWidget* obj, gpointer data )
+{
+ GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(obj);
+ if ( gtk_check_menu_item_get_active (item)) {
+ EgeAdjustmentAction* act = (EgeAdjustmentAction*)g_object_get_qdata( G_OBJECT(obj), gDataName );
+ gint what = GPOINTER_TO_INT(data);
+
+
+ gdouble base = gtk_adjustment_get_value( act->private_data->adj );
+ gdouble lower = 0.0;
+ gdouble upper = 0.0;
+ gdouble step = 0.0;
+ gdouble page = 0.0;
+ g_object_get( G_OBJECT(act->private_data->adj),
+ "lower", &lower,
+ "upper", &upper,
+ "step-increment", &step,
+ "page-increment", &page,
+ NULL );
+
+ switch ( what ) {
+ case BUMP_TOP:
+ gtk_adjustment_set_value( act->private_data->adj, upper );
+ break;
+
+ case BUMP_PAGE_UP:
+ gtk_adjustment_set_value( act->private_data->adj, base + page );
+ break;
+
+ case BUMP_UP:
+ gtk_adjustment_set_value( act->private_data->adj, base + step );
+ break;
+
+ case BUMP_DOWN:
+ gtk_adjustment_set_value( act->private_data->adj, base - step );
+ break;
+
+ case BUMP_PAGE_DOWN:
+ gtk_adjustment_set_value( act->private_data->adj, base - page );
+ break;
+
+ case BUMP_BOTTOM:
+ gtk_adjustment_set_value( act->private_data->adj, lower );
+ break;
+
+ default:
+ if ( what >= BUMP_CUSTOM ) {
+ guint index = what - BUMP_CUSTOM;
+ if ( index < g_list_length( act->private_data->descriptions ) ) {
+ EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)g_list_nth_data( act->private_data->descriptions, index );
+ if ( descr ) {
+ gtk_adjustment_set_value( act->private_data->adj, descr->value );
+ }
+ }
+ }
+ }
+ }
+}
+
+static void create_single_menu_item( GCallback toggleCb, int val, GtkWidget* menu, EgeAdjustmentAction* act, GtkWidget** dst, GSList** group, gdouble num, gboolean active )
+{
+ char* str = 0;
+ EgeAdjustmentDescr* marker = 0;
+ GList* cur = act->private_data->descriptions;
+
+ while ( cur ) {
+ EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)cur->data;
+ gdouble delta = num - descr->value;
+ if ( delta < 0.0 ) {
+ delta = -delta;
+ }
+ if ( delta < act->private_data->epsilon ) {
+ marker = descr;
+ break;
+ }
+ cur = g_list_next( cur );
+ }
+
+ str = g_strdup_printf( act->private_data->format, num,
+ ((marker && marker->descr) ? ": " : ""),
+ ((marker && marker->descr) ? marker->descr : ""));
+
+ *dst = gtk_radio_menu_item_new_with_label( *group, str );
+ if ( !*group) {
+ *group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(*dst) );
+ }
+ if ( active ) {
+ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(*dst), TRUE );
+ }
+ gtk_menu_shell_append( GTK_MENU_SHELL(menu), *dst );
+ g_object_set_qdata( G_OBJECT(*dst), gDataName, act );
+
+ g_signal_connect( G_OBJECT(*dst), "toggled", toggleCb, GINT_TO_POINTER(val) );
+
+ g_free(str);
+}
+
+static GList* flush_explicit_items( GList* descriptions,
+ GCallback toggleCb,
+ int val,
+ GtkWidget* menu,
+ EgeAdjustmentAction* act,
+ GtkWidget** dst,
+ GSList** group,
+ gdouble num )
+{
+ GList* cur = descriptions;
+
+ if ( cur ) {
+ gdouble valUpper = num + act->private_data->epsilon;
+ gdouble valLower = num - act->private_data->epsilon;
+
+ EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)cur->data;
+
+ while ( cur && descr && (descr->value >= valLower) ) {
+ if ( descr->value > valUpper ) {
+ create_single_menu_item( toggleCb, val + g_list_position(act->private_data->descriptions, cur), menu, act, dst, group, descr->value, FALSE );
+ }
+
+ cur = g_list_previous( cur );
+ descr = cur ? (EgeAdjustmentDescr*)cur->data : 0;
+ }
+ }
+
+ return cur;
+}
+
+static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act )
+{
+ GtkWidget* menu = gtk_menu_new();
+
+ GSList* group = 0;
+ GtkWidget* single = 0;
+
+ GList* addOns = g_list_last( act->private_data->descriptions );
+
+ gdouble base = gtk_adjustment_get_value( act->private_data->adj );
+ gdouble lower = 0.0;
+ gdouble upper = 0.0;
+ gdouble step = 0.0;
+ gdouble page = 0.0;
+ g_object_get( G_OBJECT(act->private_data->adj),
+ "lower", &lower,
+ "upper", &upper,
+ "step-increment", &step,
+ "page-increment", &page,
+ NULL );
+
+
+ if ( base < upper ) {
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, upper );
+ create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_TOP, menu, act, &single, &group, upper, FALSE );
+ if ( (base + page) < upper ) {
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base + page );
+ create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_PAGE_UP, menu, act, &single, &group, base + page, FALSE );
+ }
+ if ( (base + step) < upper ) {
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base + step );
+ create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_UP, menu, act, &single, &group, base + step, FALSE );
+ }
+ }
+
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base );
+ create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_NONE, menu, act, &single, &group, base, TRUE );
+
+ if ( base > lower ) {
+ if ( (base - step) > lower ) {
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base - step );
+ create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_DOWN, menu, act, &single, &group, base - step, FALSE );
+ }
+ if ( (base - page) > lower ) {
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base - page );
+ create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_PAGE_DOWN, menu, act, &single, &group, base - page, FALSE );
+ }
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, lower );
+ create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_BOTTOM, menu, act, &single, &group, lower, FALSE );
+ }
+
+ if ( act->private_data->descriptions ) {
+ gdouble value = ((EgeAdjustmentDescr*)act->private_data->descriptions->data)->value;
+ addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, value );
+ }
+
+ return menu;
+}
+
+static GtkWidget* create_menu_item( GtkAction* action )
+{
+ GtkWidget* item = 0;
+
+ if ( IS_EGE_ADJUSTMENT_ACTION(action) ) {
+ EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action );
+ GValue value;
+ GtkWidget* subby = 0;
+
+ memset( &value, 0, sizeof(value) );
+ g_value_init( &value, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(action), "label", &value );
+
+ item = gtk_menu_item_new_with_label( g_value_get_string( &value ) );
+
+ subby = create_popup_number_menu( act );
+ gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby );
+ gtk_widget_show_all( subby );
+ g_value_unset( &value );
+ } else {
+ item = GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->create_menu_item( action );
+ }
+
+ return item;
+}
+
+static void value_changed_cb( GtkSpinButton* spin, EgeAdjustmentAction* act )
+{
+ if ( gtk_widget_has_focus( GTK_WIDGET(spin) ) ) {
+ gint start = 0, end = 0;
+ if (GTK_IS_EDITABLE(spin) && gtk_editable_get_selection_bounds (GTK_EDITABLE(spin), &start, &end)
+ && start != end) {
+ // #167846, #363000 If the spin button has a selection, its probably
+ // because we got here from a Tab key from another spin, if so dont defocus
+ return;
+ }
+ ege_adjustment_action_defocus( act );
+ }
+}
+
+static gboolean event_cb( EgeAdjustmentAction* act, GdkEvent* evt )
+{
+ gboolean handled = FALSE;
+ if ( evt->type == GDK_BUTTON_PRESS ) {
+ if ( evt->button.button == 3 ) {
+ if ( IS_EGE_ADJUSTMENT_ACTION(act) ) {
+ GdkEventButton* btnevt = (GdkEventButton*)evt;
+ GtkWidget* menu = create_popup_number_menu(act);
+ gtk_widget_show_all( menu );
+ gtk_menu_popup( GTK_MENU(menu), NULL, NULL, NULL, NULL, btnevt->button, btnevt->time );
+ }
+ handled = TRUE;
+ }
+ }
+
+ return handled;
+}
+
+static GtkWidget* create_tool_item( GtkAction* action )
+{
+ GtkWidget* item = 0;
+
+ if ( IS_EGE_ADJUSTMENT_ACTION(action) ) {
+ EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action );
+ GtkWidget* spinbutton = 0;
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkWidget* hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
+ gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
+#else
+ GtkWidget* hb = gtk_hbox_new( FALSE, 5 );
+#endif
+ GValue value;
+ memset( &value, 0, sizeof(value) );
+ g_value_init( &value, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(action), "short_label", &value );
+
+ if ( act->private_data->appearanceMode == APPEARANCE_FULL ) {
+ /* Slider */
+ spinbutton = gimp_spin_scale_new (act->private_data->adj, g_value_get_string( &value ), 0);
+ gtk_widget_set_size_request(spinbutton, 100, -1);
+
+ } else if ( act->private_data->appearanceMode == APPEARANCE_MINIMAL ) {
+ spinbutton = gtk_scale_button_new( GTK_ICON_SIZE_MENU, 0, 100, 2, 0 );
+ gtk_scale_button_set_adjustment( GTK_SCALE_BUTTON(spinbutton), act->private_data->adj );
+ gtk_scale_button_set_icons( GTK_SCALE_BUTTON(spinbutton), floogles );
+ } else {
+ if ( gFactoryCb ) {
+ spinbutton = gFactoryCb( act->private_data->adj, act->private_data->climbRate, act->private_data->digits, act->private_data->unitTracker );
+ } else {
+ spinbutton = gtk_spin_button_new( act->private_data->adj, act->private_data->climbRate, act->private_data->digits );
+ }
+ }
+
+ item = GTK_WIDGET( gtk_tool_item_new() );
+
+ {
+ GValue tooltip;
+ memset( &tooltip, 0, sizeof(tooltip) );
+ g_value_init( &tooltip, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(action), "tooltip", &tooltip );
+ const gchar* tipstr = g_value_get_string( &tooltip );
+ if ( tipstr && *tipstr ) {
+ gtk_widget_set_tooltip_text( spinbutton, tipstr );
+ }
+ g_value_unset( &tooltip );
+ }
+
+ if ( act->private_data->appearanceMode != APPEARANCE_FULL ) {
+ GtkWidget* filler1 = gtk_label_new(" ");
+ gtk_box_pack_start( GTK_BOX(hb), filler1, FALSE, FALSE, 0 );
+
+ /* Use an icon if available or use short-label */
+ if ( act->private_data->iconId && strcmp( act->private_data->iconId, "" ) != 0 ) {
+ GtkWidget* icon = sp_icon_new( act->private_data->iconSize, act->private_data->iconId );
+ gtk_box_pack_start( GTK_BOX(hb), icon, FALSE, FALSE, 0 );
+ } else {
+ GtkWidget* lbl = gtk_label_new( g_value_get_string( &value ) ? g_value_get_string( &value ) : "wwww" );
+ gtk_misc_set_alignment( GTK_MISC(lbl), 1.0, 0.5 );
+ gtk_box_pack_start( GTK_BOX(hb), lbl, FALSE, FALSE, 0 );
+ }
+ }
+
+ if ( act->private_data->appearanceMode == APPEARANCE_FULL ) {
+ gtk_box_pack_start( GTK_BOX(hb), spinbutton, TRUE, TRUE, 0 );
+ } else {
+ gtk_box_pack_start( GTK_BOX(hb), spinbutton, FALSE, FALSE, 0 );
+ }
+
+ gtk_container_add( GTK_CONTAINER(item), hb );
+
+ if ( act->private_data->selfId ) {
+ g_object_set_data( G_OBJECT(spinbutton), act->private_data->selfId, spinbutton );
+ }
+
+ g_signal_connect( G_OBJECT(spinbutton), "focus-in-event", G_CALLBACK(focus_in_cb), action );
+ g_signal_connect( G_OBJECT(spinbutton), "focus-out-event", G_CALLBACK(focus_out_cb), action );
+ g_signal_connect( G_OBJECT(spinbutton), "key-press-event", G_CALLBACK(keypress_cb), action );
+
+ g_signal_connect( G_OBJECT(spinbutton), "value-changed", G_CALLBACK(value_changed_cb), action );
+
+ g_signal_connect_swapped( G_OBJECT(spinbutton), "event", G_CALLBACK(event_cb), action );
+ if ( act->private_data->appearanceMode == APPEARANCE_FULL ) {
+ /* */
+ } else if ( act->private_data->appearanceMode == APPEARANCE_MINIMAL ) {
+ /* */
+ } else {
+ gtk_entry_set_width_chars( GTK_ENTRY(spinbutton), act->private_data->digits + 3 );
+ }
+
+ gtk_widget_show_all( item );
+
+ /* Shrink or whatnot after shown */
+ if ( act->private_data->toolPost ) {
+ act->private_data->toolPost( item );
+ }
+
+ g_value_unset( &value );
+ } else {
+ item = GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->create_tool_item( action );
+ }
+
+ return item;
+}
+
+static void connect_proxy( GtkAction *action, GtkWidget *proxy )
+{
+ GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->connect_proxy( action, proxy );
+}
+
+static void disconnect_proxy( GtkAction *action, GtkWidget *proxy )
+{
+ GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->disconnect_proxy( action, proxy );
+}
+
+void ege_adjustment_action_defocus( EgeAdjustmentAction* action )
+{
+ if ( action->private_data->transferFocus ) {
+ if ( action->private_data->focusWidget ) {
+ gtk_widget_grab_focus( action->private_data->focusWidget );
+ }
+ }
+}
+
+gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
+{
+ (void)event;
+ if ( IS_EGE_ADJUSTMENT_ACTION(data) ) {
+ EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data );
+ if ( GTK_IS_SPIN_BUTTON(widget) ) {
+ action->private_data->lastVal = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+ } else if ( GTK_IS_SCALE_BUTTON(widget) ) {
+ action->private_data->lastVal = gtk_scale_button_get_value( GTK_SCALE_BUTTON(widget) );
+ } else if (GTK_IS_RANGE(widget) ) {
+ action->private_data->lastVal = gtk_range_get_value( GTK_RANGE(widget) );
+ }
+ action->private_data->transferFocus = TRUE;
+ }
+
+ return FALSE; /* report event not consumed */
+}
+
+static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
+{
+ (void)widget;
+ (void)event;
+ if ( IS_EGE_ADJUSTMENT_ACTION(data) ) {
+ EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data );
+ action->private_data->transferFocus = FALSE;
+ }
+
+ return FALSE; /* report event not consumed */
+}
+
+
+static gboolean process_tab( GtkWidget* widget, int direction )
+{
+ gboolean handled = FALSE;
+ GtkWidget* parent = gtk_widget_get_parent(widget);
+ GtkWidget* gp = parent ? gtk_widget_get_parent(parent) : 0;
+ GtkWidget* ggp = gp ? gtk_widget_get_parent(gp) : 0;
+
+ if ( ggp && GTK_IS_TOOLBAR(ggp) ) {
+ GList* kids = gtk_container_get_children( GTK_CONTAINER(ggp) );
+ if ( kids ) {
+ GtkWidget* curr = widget;
+ while ( curr && (gtk_widget_get_parent(curr) != ggp) ) {
+ curr = gtk_widget_get_parent( curr );
+ }
+ if ( curr ) {
+ GList* mid = g_list_find( kids, curr );
+ while ( mid ) {
+ mid = ( direction < 0 ) ? g_list_previous(mid) : g_list_next(mid);
+ if ( mid && GTK_IS_TOOL_ITEM(mid->data) ) {
+ /* potential target */
+ GtkWidget* child = gtk_bin_get_child( GTK_BIN(mid->data) );
+ if ( child && GTK_IS_BOX(child) ) { /* could be ours */
+ GList* subChildren = gtk_container_get_children( GTK_CONTAINER(child) );
+ if ( subChildren ) {
+ GList* last = g_list_last(subChildren);
+ if ( last && GTK_IS_SPIN_BUTTON(last->data) && gtk_widget_is_sensitive( GTK_WIDGET(last->data) ) ) {
+ gtk_widget_grab_focus( GTK_WIDGET(last->data) );
+ handled = TRUE;
+ mid = 0; /* to stop loop */
+ }
+
+ g_list_free(subChildren);
+ }
+ }
+ }
+ }
+ }
+ g_list_free( kids );
+ }
+ }
+
+ return handled;
+}
+
+gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
+{
+ gboolean wasConsumed = FALSE; /* default to report event not consumed */
+ EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION(data);
+ guint key = 0;
+ gdk_keymap_translate_keyboard_state( gdk_keymap_get_for_display( gdk_display_get_default() ),
+ event->hardware_keycode, (GdkModifierType)event->state,
+ 0, &key, 0, 0, 0 );
+
+ switch ( key ) {
+ case GDK_KEY_Escape:
+ {
+ action->private_data->transferFocus = TRUE;
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal );
+ ege_adjustment_action_defocus( action );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ {
+ action->private_data->transferFocus = TRUE;
+ ege_adjustment_action_defocus( action );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ case GDK_KEY_Tab:
+ {
+ action->private_data->transferFocus = FALSE;
+ wasConsumed = process_tab( widget, 1 );
+ }
+ break;
+
+ case GDK_KEY_ISO_Left_Tab:
+ {
+ action->private_data->transferFocus = FALSE;
+ wasConsumed = process_tab( widget, -1 );
+ }
+ break;
+
+ case GDK_KEY_Up:
+ case GDK_KEY_KP_Up:
+ {
+ action->private_data->transferFocus = FALSE;
+ gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + action->private_data->step );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ case GDK_KEY_Down:
+ case GDK_KEY_KP_Down:
+ {
+ action->private_data->transferFocus = FALSE;
+ gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - action->private_data->step );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ case GDK_KEY_Page_Up:
+ case GDK_KEY_KP_Page_Up:
+ {
+ action->private_data->transferFocus = FALSE;
+ gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + action->private_data->page );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ case GDK_KEY_Page_Down:
+ case GDK_KEY_KP_Page_Down:
+ {
+ action->private_data->transferFocus = FALSE;
+ gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - action->private_data->page );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ case GDK_KEY_z:
+ case GDK_KEY_Z:
+ {
+ action->private_data->transferFocus = FALSE;
+ gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ }
+
+ return wasConsumed;
+}
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/widgets/ege-adjustment-action.h b/src/widgets/ege-adjustment-action.h
new file mode 100644
index 000000000..8cfaa3e52
--- /dev/null
+++ b/src/widgets/ege-adjustment-action.h
@@ -0,0 +1,192 @@
+#ifndef SEEN_EGE_ADJUSTMENT_ACTION
+#define SEEN_EGE_ADJUSTMENT_ACTION
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is EGE Adjustment Action.
+ *
+ * The Initial Developer of the Original Code is
+ * Jon A. Cruz.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/** \file
+ * GtkAction subclass that represents a GtkAdjustment value.
+ */
+
+/* Note: this file should be kept compilable as both .cpp and .c */
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+
+#define EGE_ADJUSTMENT_ACTION_TYPE ( ege_adjustment_action_get_type() )
+#define EGE_ADJUSTMENT_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentAction) )
+#define EGE_ADJUSTMENT_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionClass) )
+#define IS_EGE_ADJUSTMENT_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), EGE_ADJUSTMENT_ACTION_TYPE) )
+#define IS_EGE_ADJUSTMENT_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), EGE_ADJUSTMENT_ACTION_TYPE) )
+#define EGE_ADJUSTMENT_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionClass) )
+
+typedef struct _EgeAdjustmentAction EgeAdjustmentAction;
+typedef struct _EgeAdjustmentActionClass EgeAdjustmentActionClass;
+typedef struct _EgeAdjustmentActionPrivate EgeAdjustmentActionPrivate;
+
+namespace Inkscape {
+ namespace UI {
+ namespace Widget {
+ class UnitTracker;
+ }
+ }
+}
+
+/**
+ * Instance structure of EgeAdjustmentAction.
+ */
+struct _EgeAdjustmentAction
+{
+ /** Parent instance structure. */
+ GtkAction action;
+
+ /** Pointer to private instance data. */
+ EgeAdjustmentActionPrivate *private_data;
+};
+
+/**
+ * Class structure of EgeAdjustmentAction.
+ */
+struct _EgeAdjustmentActionClass
+{
+ /** Parent class structure. */
+ GtkActionClass parent_class;
+};
+
+/** Standard Gtk type function */
+GType ege_adjustment_action_get_type( void );
+
+
+/*
+ * Note: This normally could be implemented via a GType property for the class to construct,
+ * but gtkmm classes implemented in C++ only will often not funciton properly.
+ *
+ */
+
+/** Callback type for widgets creation factory */
+typedef GtkWidget* (*EgeCreateAdjWidgetCB)( GtkAdjustment *adjustment, gdouble climb_rate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker );
+
+/**
+ * Sets a factory callback to be used to create the specific widget.
+ *
+ * @param factoryCb the callback to use to create custom widgets, NULL to use the default.
+ */
+void ege_adjustment_action_set_compact_tool_factory( EgeCreateAdjWidgetCB factoryCb );
+
+
+/**
+ * Creates a new EgeAdjustmentAction instance.
+ * This is a GtkAction subclass that manages a value stored in a
+ * GtkAdjustment.
+ *
+ * @param adjustment The GtkAdjustment to manage.
+ * @param name Functional name for the action.
+ * @param label Display label for the action.
+ * @param tooltip Tooltip for the action.
+ * @param stock_id Icon id to use.
+ * @param climb_rate Used for created widgets.
+ * @param digits Used for created widgets.
+ * @param unit_tracker Used to store unit.
+ */
+EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment,
+ const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id,
+ gdouble climb_rate,
+ guint digits,
+ Inkscape::UI::Widget::UnitTracker *unit_tracker
+ );
+/**
+ * Returns a pointer to the GtkAdjustment represented by the given
+ * EgeAdjustmentAction.
+ *
+ * @param action The action to fetch the GtkAdjustment for.
+ */
+GtkAdjustment* ege_adjustment_action_get_adjustment( EgeAdjustmentAction* action );
+
+/**
+ * Sets the GtkWidget to return focus to.
+ * This is used to be able to transfer focus back out of a toolbar.
+ *
+ * @param action The action to set the widget for.
+ * @param widget The widget to return focus to after editing.
+ * @see ege_adjustment_action_get_focuswidget
+ */
+void ege_adjustment_action_set_focuswidget( EgeAdjustmentAction* action, GtkWidget* widget );
+
+/**
+ * Returns a pointer to the GtkWidget to return focus to after changing
+ * the value.
+ *
+ * @param action The action to fetch the focus widget for.
+ * @returns A pointer to the widget to return focus to, NULL if none set.
+ * @see ege_adjustment_action_set_focuswidget
+ */
+GtkWidget* ege_adjustment_action_get_focuswidget( EgeAdjustmentAction* action );
+
+/**
+ * Set a list of values with labels to explicitly include in menus.
+ *
+ * @param action The action to set explicit entries for.
+ * @param descriptions Array of descriptions to include.
+ * Descriptions will be matched one-for-one with numbers in the 'values' array.
+ * @param values Array of values to include.
+ * Values will be matched one-for-one with numbers in the 'descriptions' array.
+ * @param count Number of items in the 'descriptions' and 'values' arrays.
+ */
+void ege_adjustment_action_set_descriptions( EgeAdjustmentAction* action, gchar const** descriptions, gdouble const* values, guint count );
+
+/**
+ * Sets a hint to be used in determining the display form.
+ * This is the XForms style 'appearance' hint: "full", "compact", "minimal".
+ *
+ * @param action The action to set the tooltip column for.
+ * @param val The value of the appearance hint.
+ */
+void ege_adjustment_action_set_appearance( EgeAdjustmentAction* action, gchar const* val );
+
+/** Callback type for post-creation 'fixup' pass on generated widgets */
+typedef void (*EgeWidgetFixup)(GtkWidget *widget);
+
+
+G_END_DECLS
+
+#endif /* SEEN_EGE_ADJUSTMENT_ACTION */
diff --git a/src/widgets/ege-output-action.cpp b/src/widgets/ege-output-action.cpp
new file mode 100644
index 000000000..5dece8e91
--- /dev/null
+++ b/src/widgets/ege-output-action.cpp
@@ -0,0 +1,245 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is EGE Output Action.
+ *
+ * The Initial Developer of the Original Code is
+ * Jon A. Cruz.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Note: this file should be kept compilable as both .cpp and .c */
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "widgets/ege-output-action.h"
+
+
+static void ege_output_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
+static void ege_output_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
+static void fixup_labels( GObject *gobject, GParamSpec *arg1, gpointer user_data );
+
+/* static GtkWidget* create_menu_item( GtkAction* action ); */
+static GtkWidget* create_tool_item( GtkAction* action );
+
+struct _EgeOutputActionPrivate
+{
+ gboolean useMarkup;
+};
+
+#define EGE_OUTPUT_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_OUTPUT_ACTION_TYPE, EgeOutputActionPrivate ) )
+
+enum {
+ PROP_USE_MARKUP = 1,
+};
+
+G_DEFINE_TYPE(EgeOutputAction, ege_output_action, GTK_TYPE_ACTION);
+
+void ege_output_action_class_init( EgeOutputActionClass* klass )
+{
+ if ( klass ) {
+ GObjectClass* objClass = G_OBJECT_CLASS( klass );
+
+ objClass->get_property = ege_output_action_get_property;
+ objClass->set_property = ege_output_action_set_property;
+
+/* klass->parent_class.create_menu_item = create_menu_item; */
+ klass->parent_class.create_tool_item = create_tool_item;
+
+ g_object_class_install_property( objClass,
+ PROP_USE_MARKUP,
+ g_param_spec_boolean( "use-markup",
+ "UseMarkup",
+ "If markup should be used",
+ FALSE,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_type_class_add_private( klass, sizeof(EgeOutputActionClass) );
+ }
+}
+
+
+void ege_output_action_init( EgeOutputAction* action )
+{
+ action->private_data = EGE_OUTPUT_ACTION_GET_PRIVATE( action );
+ action->private_data->useMarkup = FALSE;
+
+ g_signal_connect( action, "notify", G_CALLBACK( fixup_labels ), NULL );
+}
+
+EgeOutputAction* ege_output_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id )
+{
+ GObject* obj = (GObject*)g_object_new( EGE_OUTPUT_ACTION_TYPE,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "stock_id", stock_id,
+ "use-markup", FALSE,
+ NULL );
+
+ EgeOutputAction* action = EGE_OUTPUT_ACTION( obj );
+
+ return action;
+}
+
+gboolean ege_output_action_get_use_markup( EgeOutputAction* action )
+{
+ g_return_val_if_fail( IS_EGE_OUTPUT_ACTION(action), FALSE );
+
+ return action->private_data->useMarkup;
+}
+
+void ege_output_action_set_use_markup( EgeOutputAction* action, gboolean setting )
+{
+ g_object_set( G_OBJECT(action), "use-markup", setting, NULL );
+}
+
+void ege_output_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
+{
+ EgeOutputAction* action = EGE_OUTPUT_ACTION( obj );
+ switch ( propId ) {
+ case PROP_USE_MARKUP:
+ g_value_set_boolean( value, action->private_data->useMarkup );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+void ege_output_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
+{
+ EgeOutputAction* action = EGE_OUTPUT_ACTION( obj );
+ switch ( propId ) {
+ case PROP_USE_MARKUP:
+ {
+ action->private_data->useMarkup = g_value_get_boolean( value );
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+
+/* static GtkWidget* create_menu_item( GtkAction* action ) */
+
+GtkWidget* create_tool_item( GtkAction* action )
+{
+ GtkWidget* item = 0;
+
+ if ( IS_EGE_OUTPUT_ACTION(action) )
+ {
+ GValue value;
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkWidget* hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
+ gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
+#else
+ GtkWidget* hb = gtk_hbox_new( FALSE, 5 );
+#endif
+ GtkWidget* lbl = 0;
+ memset( &value, 0, sizeof(value) );
+
+ g_value_init( &value, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(action), "short_label", &value );
+ const gchar* sss = g_value_get_string( &value );
+
+ item = GTK_WIDGET( gtk_tool_item_new() );
+
+ lbl = gtk_label_new( " " );
+ gtk_container_add( GTK_CONTAINER(hb), lbl );
+
+ if ( EGE_OUTPUT_ACTION(action)->private_data->useMarkup ) {
+ lbl = gtk_label_new(NULL);
+ gtk_label_set_markup( GTK_LABEL(lbl), sss ? sss : " " );
+ } else {
+ lbl = gtk_label_new( sss ? sss : " " );
+ }
+ gtk_container_add( GTK_CONTAINER(hb), lbl );
+
+ lbl = gtk_label_new( " " );
+ gtk_container_add( GTK_CONTAINER(hb), lbl );
+
+ gtk_container_add( GTK_CONTAINER(item), hb );
+
+ gtk_widget_show_all( item );
+
+ g_value_unset( &value );
+ } else {
+ item = GTK_ACTION_CLASS(ege_output_action_parent_class)->create_tool_item( action );
+ }
+
+ return item;
+}
+
+void fixup_labels( GObject *gobject, GParamSpec *arg1, gpointer user_data )
+{
+ /* TODO: handle 'use-markup' getting changed also */
+
+ if ( arg1 && arg1->name && (strcmp("label", arg1->name) == 0) ) {
+ GSList* proxies = gtk_action_get_proxies( GTK_ACTION(gobject) );
+ gchar* str = 0;
+ g_object_get( gobject, "label", &str, NULL );
+ (void)user_data;
+ while ( proxies ) {
+ if ( GTK_IS_TOOL_ITEM(proxies->data) ) {
+ /* Search for the things we built up in create_tool_item() */
+ GList* children = gtk_container_get_children( GTK_CONTAINER(proxies->data) );
+ if ( children && children->data ) {
+ if ( GTK_IS_BOX(children->data) ) {
+ children = gtk_container_get_children( GTK_CONTAINER(children->data) );
+ if ( children && g_list_next(children) ) {
+ GtkWidget* child = GTK_WIDGET( g_list_next(children)->data );
+ if ( GTK_IS_LABEL(child) ) {
+ GtkLabel* lbl = GTK_LABEL(child);
+ if ( EGE_OUTPUT_ACTION(gobject)->private_data->useMarkup ) {
+ gtk_label_set_markup( lbl, str );
+ } else {
+ gtk_label_set_text( lbl, str );
+ }
+ }
+ }
+ }
+ }
+ }
+ proxies = g_slist_next( proxies );
+ }
+ g_free( str );
+ }
+}
+
diff --git a/src/widgets/ege-output-action.h b/src/widgets/ege-output-action.h
new file mode 100644
index 000000000..0f4e21805
--- /dev/null
+++ b/src/widgets/ege-output-action.h
@@ -0,0 +1,120 @@
+#ifndef SEEN_EGE_OUTPUT_ACTION
+#define SEEN_EGE_OUTPUT_ACTION
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is EGE Output Action.
+ *
+ * The Initial Developer of the Original Code is
+ * Jon A. Cruz.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/** \file
+ * GtkAction subclass that represents a string for output.
+ */
+
+/* Note: this file should be kept compilable as both .cpp and .c */
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+
+#define EGE_OUTPUT_ACTION_TYPE ( ege_output_action_get_type() )
+#define EGE_OUTPUT_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), EGE_OUTPUT_ACTION_TYPE, EgeOutputAction) )
+#define EGE_OUTPUT_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), EGE_OUTPUT_ACTION_TYPE, EgeOutputActionClass) )
+#define IS_EGE_OUTPUT_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), EGE_OUTPUT_ACTION_TYPE) )
+#define IS_EGE_OUTPUT_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), EGE_OUTPUT_ACTION_TYPE) )
+#define EGE_OUTPUT_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), EGE_OUTPUT_ACTION_TYPE, EgeOutputActionClass) )
+
+typedef struct _EgeOutputAction EgeOutputAction;
+typedef struct _EgeOutputActionClass EgeOutputActionClass;
+typedef struct _EgeOutputActionPrivate EgeOutputActionPrivate;
+
+/**
+ * Instance structure of EgeOutputAction.
+ */
+struct _EgeOutputAction
+{
+ /** Parent instance structure. */
+ GtkAction action;
+
+ /** Pointer to private instance data. */
+ EgeOutputActionPrivate *private_data;
+};
+
+/**
+ * Class structure of EgeOutputAction.
+ */
+struct _EgeOutputActionClass
+{
+ /** Parent class structure. */
+ GtkActionClass parent_class;
+};
+
+/** Standard Gtk type function */
+GType ege_output_action_get_type( void );
+
+/**
+ * Creates a new EgeOutputAction instance.
+ * This is a GtkAction subclass that displays a string.
+ *
+ * @param name Functional name for the action.
+ * @param label Display label for the action.
+ * @param tooltip Tooltip for the action.
+ * @param stock_id Icon id to use.
+ */
+EgeOutputAction* ege_output_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id );
+
+/**
+ * Return whether or not the displayed text is interpreted as markup.
+ *
+ * @param action The action to fetch the markup state for.
+ * @return True if the text is to be interpreted as markup, false otherwise.
+ */
+gboolean ege_output_action_get_use_markup( EgeOutputAction* action );
+
+/**
+ * Sets whether or not the displayed text is interpreted as markup.
+ *
+ * @param action The action to set the markup state for.
+ * @param setting True if the text is to be interpreted as markup, false otherwise.
+ */
+void ege_output_action_set_use_markup( EgeOutputAction* action, gboolean setting );
+
+G_END_DECLS
+
+#endif /* SEEN_EGE_OUTPUT_ACTION */
diff --git a/src/widgets/ege-select-one-action.cpp b/src/widgets/ege-select-one-action.cpp
new file mode 100644
index 000000000..ab86c49f8
--- /dev/null
+++ b/src/widgets/ege-select-one-action.cpp
@@ -0,0 +1,1153 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is EGE Select One Action.
+ *
+ * The Initial Developer of the Original Code is
+ * Jon A. Cruz.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Note: this file should be kept compilable as both .cpp and .c */
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "widgets/ege-select-one-action.h"
+
+enum {
+ CHANGED = 0,
+ LAST_SIGNAL};
+
+static void ege_select_one_action_finalize( GObject* action );
+static void ege_select_one_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
+static void ege_select_one_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
+
+static gint find_text_index(EgeSelectOneAction *act, gchar const* text);
+static void commit_pending_change(EgeSelectOneAction *act);
+static void resync_active( EgeSelectOneAction* act, gint active, gboolean override );
+static void resync_sensitive( EgeSelectOneAction* act );
+static void combo_entry_changed_cb( GtkEntry* widget, gpointer user_data );
+static gboolean combo_entry_focus_lost_cb( GtkWidget *widget, GdkEventFocus *event, gpointer data );
+static void combo_changed_cb( GtkComboBox* widget, gpointer user_data );
+static void menu_toggled_cb( GtkWidget* obj, gpointer data );
+static void proxy_action_chagned_cb( GtkRadioAction* action, GtkRadioAction* current, gpointer user_data );
+
+static GtkWidget* create_menu_item( GtkAction* action );
+static GtkWidget* create_tool_item( GtkAction* action );
+static void connect_proxy( GtkAction *action, GtkWidget *proxy );
+static void disconnect_proxy( GtkAction *action, GtkWidget *proxy );
+
+static int scan_max_width( GtkTreeModel *model, gint labelColumn );
+
+static guint signals[LAST_SIGNAL] = {0};
+static GQuark gDataName = 0;
+
+
+enum {
+ APPEARANCE_UNKNOWN = -1,
+ APPEARANCE_NONE = 0,
+ APPEARANCE_FULL, /* label, then all choices represented by separate buttons */
+ APPEARANCE_COMPACT, /* label, then choices in a drop-down menu */
+ APPEARANCE_MINIMAL, /* no label, just choices in a drop-down menu */
+};
+
+enum {
+ SELECTION_UNKNOWN = -1,
+ SELECTION_CLOSED = 0,
+ SELECTION_OPEN,
+};
+
+struct _EgeSelectOneActionPrivate
+{
+ gint active;
+ gint labelColumn;
+ gint iconColumn;
+ gint tooltipColumn;
+ gint sensitiveColumn;
+ gint appearanceMode;
+ gint selectionMode;
+ gint iconSize;
+ GType radioActionType;
+ GtkTreeModel* model;
+ gchar *iconProperty;
+ gchar *appearance;
+ gchar *selection;
+ gchar *activeText;
+ gchar *pendingText;
+};
+
+#define EGE_SELECT_ONE_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_SELECT_ONE_ACTION_TYPE, EgeSelectOneActionPrivate ) )
+
+enum {
+ PROP_MODEL = 1,
+ PROP_ACTIVE,
+ PROP_LABEL_COLUMN,
+ PROP_ICON_COLUMN,
+ PROP_TOOLTIP_COLUMN,
+ PROP_SENSITIVE_COLUMN,
+ PROP_ICON_PROP,
+ PROP_ICON_SIZE,
+ PROP_APPEARANCE,
+ PROP_SELECTION
+};
+
+G_DEFINE_TYPE(EgeSelectOneAction, ege_select_one_action, GTK_TYPE_ACTION);
+
+GtkTreeModel *ege_select_one_action_get_model(EgeSelectOneAction* action ){
+ return GTK_TREE_MODEL(action->private_data->model);
+}
+void ege_select_one_action_class_init( EgeSelectOneActionClass* klass )
+{
+ if ( klass ) {
+ GObjectClass* objClass = G_OBJECT_CLASS( klass );
+
+ gDataName = g_quark_from_string("ege-select1-action");
+
+ objClass->finalize = ege_select_one_action_finalize;
+ objClass->get_property = ege_select_one_action_get_property;
+ objClass->set_property = ege_select_one_action_set_property;
+
+ klass->parent_class.create_menu_item = create_menu_item;
+ klass->parent_class.create_tool_item = create_tool_item;
+ klass->parent_class.connect_proxy = connect_proxy;
+ klass->parent_class.disconnect_proxy = disconnect_proxy;
+
+ g_object_class_install_property( objClass,
+ PROP_MODEL,
+ g_param_spec_object( "model",
+ "Tree Model",
+ "Tree model of possible items",
+ GTK_TYPE_TREE_MODEL,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_ACTIVE,
+ g_param_spec_int( "active",
+ "Active Selection",
+ "The index of the selected item",
+ -1, G_MAXINT, 0,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_LABEL_COLUMN,
+ g_param_spec_int( "label-column",
+ "Display Column",
+ "The column of the model that holds display strings",
+ 0, G_MAXINT, 0,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_ICON_COLUMN,
+ g_param_spec_int( "icon-column",
+ "Icon Column",
+ "The column of the model that holds display icon name",
+ -1, G_MAXINT, -1,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_TOOLTIP_COLUMN,
+ g_param_spec_int( "tooltip-column",
+ "Tooltip Column",
+ "The column of the model that holds tooltip strings",
+ -1, G_MAXINT, -1,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_SENSITIVE_COLUMN,
+ g_param_spec_int( "sensitive-column",
+ "Sensitive Column",
+ "The column of the model that holds sensitive state",
+ -1, G_MAXINT, -1,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_ICON_PROP,
+ g_param_spec_string( "icon-property",
+ "Icon Property",
+ "Target icon property",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_ICON_SIZE,
+ g_param_spec_int( "icon-size",
+ "Icon Size",
+ "Target icon size",
+ -1, G_MAXINT, -1,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_APPEARANCE,
+ g_param_spec_string( "appearance",
+ "Appearance hint",
+ "A hint for how to display",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_SELECTION,
+ g_param_spec_string( "selection",
+ "Selection set open or closed",
+ "'open' to allow edits/additions, 'closed' to disallow.",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ signals[CHANGED] = g_signal_new( "changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(EgeSelectOneActionClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private( klass, sizeof(EgeSelectOneActionClass) );
+ }
+}
+
+
+void ege_select_one_action_init( EgeSelectOneAction* action )
+{
+ action->private_data = EGE_SELECT_ONE_ACTION_GET_PRIVATE( action );
+ action->private_data->active = 0;
+ action->private_data->labelColumn = 0;
+ action->private_data->iconColumn = -1;
+ action->private_data->tooltipColumn = -1;
+ action->private_data->sensitiveColumn = -1;
+ action->private_data->appearanceMode = APPEARANCE_NONE;
+ action->private_data->selectionMode = SELECTION_CLOSED;
+ action->private_data->radioActionType = 0;
+ action->private_data->model = 0;
+ action->private_data->iconProperty = g_strdup("stock-id");
+ action->private_data->iconSize = -1;
+ action->private_data->appearance = 0;
+ action->private_data->selection = 0;
+ action->private_data->activeText = 0;
+ action->private_data->pendingText = 0;
+
+/* g_signal_connect( action, "notify", G_CALLBACK( fixup_labels ), NULL ); */
+}
+
+void ege_select_one_action_finalize( GObject* object )
+{
+ EgeSelectOneAction *action = EGE_SELECT_ONE_ACTION( object );
+
+ g_free( action->private_data->iconProperty );
+ g_free( action->private_data->appearance );
+ g_free( action->private_data->selection );
+
+ if ( G_OBJECT_CLASS(ege_select_one_action_parent_class)->finalize ) {
+ (*G_OBJECT_CLASS(ege_select_one_action_parent_class)->finalize)(object);
+ }
+}
+
+EgeSelectOneAction* ege_select_one_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id,
+ GtkTreeModel* model )
+{
+ GObject* obj = (GObject*)g_object_new( EGE_SELECT_ONE_ACTION_TYPE,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "stock_id", stock_id,
+ "model", model,
+ "active", 0,
+ "icon-property", "stock-id",
+ NULL );
+
+ EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
+
+ return action;
+}
+
+
+gint ege_select_one_action_get_active( EgeSelectOneAction* action )
+{
+ g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
+ return action->private_data->active;
+}
+
+gchar *ege_select_one_action_get_active_text( EgeSelectOneAction* action )
+{
+ GtkTreeIter iter;
+ gchar *str = 0;
+ g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
+
+ if ( action->private_data->active >= 0) {
+ if ( gtk_tree_model_iter_nth_child( action->private_data->model, &iter, NULL, action->private_data->active ) ) {
+ gtk_tree_model_get( action->private_data->model, &iter,
+ action->private_data->labelColumn, &str,
+ -1 );
+ }
+ } else if ( (action->private_data->active == -1) && action->private_data->activeText ) {
+ str = g_strdup(action->private_data->activeText);
+ }
+
+ return str;
+}
+
+void ege_select_one_action_set_active_text( EgeSelectOneAction* action, gchar const *text )
+{
+ g_return_if_fail( IS_EGE_SELECT_ONE_ACTION(action) );
+
+ if (action->private_data->activeText) {
+ g_free( action->private_data->activeText );
+ }
+ action->private_data->activeText = g_strdup(text);
+
+ if (action->private_data->active != -1) {
+ g_object_set( G_OBJECT(action), "active", -1, NULL );
+ } else {
+ resync_active( action, -1, TRUE );
+ }
+}
+
+void ege_select_one_action_set_active( EgeSelectOneAction* action, gint val )
+{
+ g_object_set( G_OBJECT(action), "active", val, NULL );
+}
+
+void ege_select_one_action_update_sensitive( EgeSelectOneAction* action )
+{
+ if( action->private_data->sensitiveColumn < 0 ) {
+ g_warning( "ege_select_one_action: Attempt to update sensitivity of item without sensitive column\n" );
+ return;
+ }
+ resync_sensitive( action );
+}
+
+gint ege_select_one_action_get_label_column( EgeSelectOneAction* action )
+{
+ g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
+ return action->private_data->labelColumn;
+}
+
+void ege_select_one_action_set_label_column( EgeSelectOneAction* action, gint col )
+{
+ g_object_set( G_OBJECT(action), "label-column", col, NULL );
+}
+
+gint ege_select_one_action_get_icon_column( EgeSelectOneAction* action )
+{
+ g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
+ return action->private_data->iconColumn;
+}
+
+void ege_select_one_action_set_icon_column( EgeSelectOneAction* action, gint col )
+{
+ g_object_set( G_OBJECT(action), "icon-column", col, NULL );
+}
+
+gint ege_select_one_action_get_icon_size( EgeSelectOneAction* action )
+{
+ g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
+ return action->private_data->iconSize;
+}
+
+void ege_select_one_action_set_icon_size( EgeSelectOneAction* action, gint size )
+{
+ g_object_set( G_OBJECT(action), "icon-size", size, NULL );
+}
+
+gint ege_select_one_action_get_tooltip_column( EgeSelectOneAction* action )
+{
+ g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
+ return action->private_data->tooltipColumn;
+}
+
+void ege_select_one_action_set_tooltip_column( EgeSelectOneAction* action, gint col )
+{
+ g_object_set( G_OBJECT(action), "tooltip-column", col, NULL );
+}
+
+gint ege_select_one_action_get_sensitive_column( EgeSelectOneAction* action )
+{
+ g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
+ return action->private_data->sensitiveColumn;
+}
+
+void ege_select_one_action_set_sensitive_column( EgeSelectOneAction* action, gint col )
+{
+ g_object_set( G_OBJECT(action), "sensitive-column", col, NULL );
+}
+
+void ege_select_one_action_set_appearance( EgeSelectOneAction* action, gchar const* val )
+{
+ g_object_set( G_OBJECT(action), "appearance", val, NULL );
+}
+
+void ege_select_one_action_set_selection( EgeSelectOneAction* action, gchar const* val )
+{
+ g_object_set( G_OBJECT(action), "selection", val, NULL );
+}
+
+void ege_select_one_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
+{
+ EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
+ switch ( propId ) {
+ case PROP_MODEL:
+ g_value_set_object( value, action->private_data->model );
+ break;
+
+ case PROP_ACTIVE:
+ g_value_set_int( value, action->private_data->active );
+ break;
+
+ case PROP_LABEL_COLUMN:
+ g_value_set_int( value, action->private_data->labelColumn );
+ break;
+
+ case PROP_ICON_COLUMN:
+ g_value_set_int( value, action->private_data->iconColumn );
+ break;
+
+ case PROP_TOOLTIP_COLUMN:
+ g_value_set_int( value, action->private_data->tooltipColumn );
+ break;
+
+ case PROP_SENSITIVE_COLUMN:
+ g_value_set_int( value, action->private_data->sensitiveColumn );
+ break;
+
+ case PROP_ICON_PROP:
+ g_value_set_string( value, action->private_data->iconProperty );
+ break;
+
+ case PROP_ICON_SIZE:
+ g_value_set_int( value, action->private_data->iconSize );
+ break;
+
+ case PROP_APPEARANCE:
+ g_value_set_string( value, action->private_data->appearance );
+ break;
+
+ case PROP_SELECTION:
+ g_value_set_string( value, action->private_data->selection );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+void ege_select_one_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
+{
+ EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
+ switch ( propId ) {
+ case PROP_MODEL:
+ {
+ action->private_data->model = GTK_TREE_MODEL( g_value_get_object( value ) );
+ }
+ break;
+
+ case PROP_ACTIVE:
+ {
+ resync_active( action, g_value_get_int( value ), FALSE );
+ }
+ break;
+
+ case PROP_LABEL_COLUMN:
+ {
+ action->private_data->labelColumn = g_value_get_int( value );
+ }
+ break;
+
+ case PROP_ICON_COLUMN:
+ {
+ action->private_data->iconColumn = g_value_get_int( value );
+ }
+ break;
+
+ case PROP_TOOLTIP_COLUMN:
+ {
+ action->private_data->tooltipColumn = g_value_get_int( value );
+ }
+ break;
+
+ case PROP_SENSITIVE_COLUMN:
+ {
+ action->private_data->sensitiveColumn = g_value_get_int( value );
+ }
+ break;
+
+ case PROP_ICON_PROP:
+ {
+ gchar* tmp = action->private_data->iconProperty;
+ gchar* newVal = g_value_dup_string( value );
+ action->private_data->iconProperty = newVal;
+ g_free( tmp );
+ }
+ break;
+
+ case PROP_ICON_SIZE:
+ {
+ action->private_data->iconSize = g_value_get_int( value );
+ }
+ break;
+
+ case PROP_APPEARANCE:
+ {
+ gchar* tmp = action->private_data->appearance;
+ gchar* newVal = g_value_dup_string( value );
+ action->private_data->appearance = newVal;
+ g_free( tmp );
+
+ if ( !action->private_data->appearance || (strcmp("", newVal) == 0) ) {
+ action->private_data->appearanceMode = APPEARANCE_NONE;
+ } else if ( strcmp("full", newVal) == 0 ) {
+ action->private_data->appearanceMode = APPEARANCE_FULL;
+ } else if ( strcmp("compact", newVal) == 0 ) {
+ action->private_data->appearanceMode = APPEARANCE_COMPACT;
+ } else if ( strcmp("minimal", newVal) == 0 ) {
+ action->private_data->appearanceMode = APPEARANCE_MINIMAL;
+ } else {
+ action->private_data->appearanceMode = APPEARANCE_UNKNOWN;
+ }
+ }
+ break;
+
+ case PROP_SELECTION:
+ {
+ gchar* tmp = action->private_data->selection;
+ gchar* newVal = g_value_dup_string( value );
+ action->private_data->selection = newVal;
+ g_free( tmp );
+
+ if ( !action->private_data->selection || (strcmp("closed", newVal) == 0) ) {
+ action->private_data->selectionMode = SELECTION_CLOSED;
+ } else if ( strcmp("open", newVal) == 0 ) {
+ action->private_data->selectionMode = SELECTION_OPEN;
+ } else {
+ action->private_data->selectionMode = SELECTION_UNKNOWN;
+ }
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+GtkWidget* create_menu_item( GtkAction* action )
+{
+ GtkWidget* item = 0;
+
+ if ( IS_EGE_SELECT_ONE_ACTION(action) ) {
+ EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION( action );
+ gchar* sss = 0;
+ gint index = 0;
+ GtkTreeIter iter;
+ GSList* group = 0;
+ GtkWidget* subby = gtk_menu_new();
+
+ g_object_get( G_OBJECT(action), "label", &sss, NULL );
+
+ item = gtk_menu_item_new_with_label( sss );
+
+ gboolean valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
+ while ( valid ) {
+ gchar* str = 0;
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->labelColumn, &str,
+ -1 );
+
+ GtkWidget *item = gtk_radio_menu_item_new_with_label( group, str );
+ group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item) );
+ gtk_menu_shell_append( GTK_MENU_SHELL(subby), item );
+ g_object_set_qdata( G_OBJECT(item), gDataName, act );
+
+ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), index == act->private_data->active );
+
+ g_free(str);
+ str = 0;
+
+ g_signal_connect( G_OBJECT(item), "toggled", G_CALLBACK(menu_toggled_cb), GINT_TO_POINTER(index) );
+
+ index++;
+ valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
+ }
+
+ gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby );
+ gtk_widget_show_all( subby );
+
+ g_free(sss);
+ } else {
+ item = GTK_ACTION_CLASS(ege_select_one_action_parent_class)->create_menu_item( action );
+ }
+
+ return item;
+}
+
+
+void ege_select_one_action_set_radio_action_type( EgeSelectOneAction* action, GType radioActionType )
+{
+ (void)action;
+
+ if ( g_type_is_a( radioActionType, GTK_TYPE_RADIO_ACTION ) ) {
+ action->private_data->radioActionType = radioActionType;
+ } else {
+ g_warning("Passed in type '%s' is not derived from '%s'", g_type_name(radioActionType), g_type_name(GTK_TYPE_RADIO_ACTION) );
+ }
+}
+
+GtkWidget* create_tool_item( GtkAction* action )
+{
+ GtkWidget* item = 0;
+
+ if ( IS_EGE_SELECT_ONE_ACTION(action) && EGE_SELECT_ONE_ACTION(action)->private_data->model )
+ {
+ EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(action);
+ item = GTK_WIDGET( gtk_tool_item_new() );
+
+ if ( act->private_data->appearanceMode == APPEARANCE_FULL ) {
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkWidget* holder = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous(GTK_BOX(holder), FALSE);
+#else
+ GtkWidget* holder = gtk_hbox_new( FALSE, 0 );
+#endif
+
+ GtkRadioAction* ract = 0;
+ GSList* group = 0;
+ GtkTreeIter iter;
+ gboolean valid = FALSE;
+ gint index = 0;
+
+ {
+ gchar* sss = 0;
+ g_object_get( G_OBJECT(action), "short_label", &sss, NULL );
+ // If short_label not defined, g_object_get will return label.
+ // This hack allows a label to be used with a drop-down menu when
+ // no label is used with a set of icons that are self-explanatory.
+ if (sss && strcmp( sss, "NotUsed" ) != 0 ) {
+ GtkWidget* lbl = gtk_label_new(sss);
+ gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 );
+ }
+ g_free( sss );
+ sss = 0;
+ }
+
+ valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
+ while ( valid ) {
+ gchar* str = 0;
+ gchar* tip = 0;
+ gchar* iconId = 0;
+ gboolean sens = true;
+ /*
+ gint size = 0;
+ */
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->labelColumn, &str,
+ -1 );
+ if ( act->private_data->iconColumn >= 0 ) {
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->iconColumn, &iconId,
+ -1 );
+ }
+ if ( act->private_data->tooltipColumn >= 0 ) {
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->tooltipColumn, &tip,
+ -1 );
+ }
+ if ( act->private_data->sensitiveColumn >= 0 ) {
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->sensitiveColumn, &sens,
+ -1 );
+ }
+
+ if ( act->private_data->radioActionType ) {
+ void* obj = g_object_new( act->private_data->radioActionType,
+ "name", "Name 1",
+ "label", str,
+ "tooltip", tip,
+ "value", index,
+ /*
+ "iconId", iconId,
+ "iconSize", size,
+ */
+ NULL );
+ if ( iconId ) {
+ g_object_set( G_OBJECT(obj), act->private_data->iconProperty, iconId, NULL );
+ }
+
+ if ( act->private_data->iconProperty ) {
+ /* TODO get this string to be set instead of hardcoded */
+ if ( act->private_data->iconSize >= 0 ) {
+ g_object_set( G_OBJECT(obj), "iconSize", act->private_data->iconSize, NULL );
+ }
+ }
+
+ ract = GTK_RADIO_ACTION(obj);
+ } else {
+ ract = gtk_radio_action_new( "Name 1", str, tip, iconId, index );
+ }
+
+ if ( act->private_data->sensitiveColumn >= 0 ) {
+ gtk_action_set_sensitive( GTK_ACTION(ract), sens );
+ }
+
+ gtk_radio_action_set_group( ract, group );
+ group = gtk_radio_action_get_group( ract );
+
+ if ( index == act->private_data->active ) {
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(ract), TRUE );
+ }
+ g_signal_connect( G_OBJECT(ract), "changed", G_CALLBACK( proxy_action_chagned_cb ), act );
+
+ GtkWidget* sub = gtk_action_create_tool_item( GTK_ACTION(ract) );
+ gtk_activatable_set_related_action( GTK_ACTIVATABLE (sub), GTK_ACTION(ract) );
+ gtk_tool_item_set_tooltip_text( GTK_TOOL_ITEM(sub), tip );
+
+ gtk_box_pack_start( GTK_BOX(holder), sub, FALSE, FALSE, 0 );
+
+ g_free( str );
+ g_free( tip );
+ g_free( iconId );
+
+ index++;
+ valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
+ }
+
+ g_object_set_data( G_OBJECT(holder), "ege-proxy_action-group", group );
+
+ gtk_container_add( GTK_CONTAINER(item), holder );
+ } else {
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkWidget* holder = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
+ gtk_box_set_homogeneous(GTK_BOX(holder), FALSE);
+#else
+ GtkWidget *holder = gtk_hbox_new( FALSE, 4 );
+#endif
+
+ GtkEntry *entry = 0;
+ GtkWidget *normal;
+
+ if (act->private_data->selectionMode == SELECTION_OPEN) {
+ normal = gtk_combo_box_new_with_model_and_entry (act->private_data->model);
+ gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (normal), act->private_data->labelColumn);
+
+ GtkWidget *child = gtk_bin_get_child( GTK_BIN(normal) );
+ if (GTK_IS_ENTRY(child)) {
+ int maxUsed = scan_max_width( act->private_data->model, act->private_data->labelColumn );
+ GtkEntryCompletion *complete = 0;
+ entry = GTK_ENTRY(child);
+ gtk_entry_set_width_chars(entry, maxUsed); /* replace with property */
+
+ complete = gtk_entry_completion_new();
+ gtk_entry_completion_set_model( complete, act->private_data->model );
+ gtk_entry_completion_set_text_column( complete, act->private_data->labelColumn );
+ gtk_entry_completion_set_inline_completion( complete, FALSE );
+ gtk_entry_completion_set_inline_selection( complete, FALSE );
+ gtk_entry_completion_set_popup_completion( complete, TRUE );
+ gtk_entry_completion_set_popup_set_width( complete, FALSE );
+ gtk_entry_set_completion( entry, complete );
+
+ g_signal_connect( G_OBJECT(child), "activate", G_CALLBACK(combo_entry_changed_cb), act );
+ g_signal_connect( G_OBJECT(child), "focus-out-event", G_CALLBACK(combo_entry_focus_lost_cb), act );
+ }
+ }
+ else {
+ GtkCellRenderer * renderer = NULL;
+ normal = gtk_combo_box_new_with_model( act->private_data->model );
+ if ( act->private_data->iconColumn >= 0 ) {
+ renderer = gtk_cell_renderer_pixbuf_new();
+ gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(normal), renderer, TRUE );
+
+ /* "icon-name" */
+ gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(normal), renderer, "stock-id", act->private_data->iconColumn );
+ }
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(normal), renderer, TRUE );
+ gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(normal), renderer, "text", act->private_data->labelColumn );
+ }
+
+ gtk_combo_box_set_active( GTK_COMBO_BOX(normal), act->private_data->active );
+ if ( entry && (act->private_data->active == -1) ) {
+ gtk_entry_set_text( entry, act->private_data->activeText );
+ }
+
+ g_signal_connect( G_OBJECT(normal), "changed", G_CALLBACK(combo_changed_cb), action );
+
+ g_object_set_data( G_OBJECT(holder), "ege-combo-box", normal );
+ g_object_set_data( G_OBJECT(act), "ege-combo-box", normal );
+
+ if (act->private_data->appearanceMode == APPEARANCE_COMPACT) {
+ gchar* sss = 0;
+ g_object_get( G_OBJECT(action), "short_label", &sss, NULL );
+ if (sss) {
+ GtkWidget* lbl = gtk_label_new(sss);
+ gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 );
+ g_free( sss );
+ sss = 0;
+ }
+ }
+
+ gtk_box_pack_start( GTK_BOX(holder), normal, FALSE, FALSE, 0 );
+
+ {
+ GtkWidget *align = gtk_alignment_new(0, 0.5, 0, 0);
+ gtk_container_add( GTK_CONTAINER(align), holder);
+ gtk_container_add( GTK_CONTAINER(item), align );
+ }
+ }
+
+ gtk_widget_show_all( item );
+ } else {
+ item = GTK_ACTION_CLASS(ege_select_one_action_parent_class)->create_tool_item( action );
+ }
+
+ return item;
+}
+
+
+void connect_proxy( GtkAction *action, GtkWidget *proxy )
+{
+ GTK_ACTION_CLASS(ege_select_one_action_parent_class)->connect_proxy( action, proxy );
+}
+
+void disconnect_proxy( GtkAction *action, GtkWidget *proxy )
+{
+ GTK_ACTION_CLASS(ege_select_one_action_parent_class)->disconnect_proxy( action, proxy );
+}
+
+
+void resync_active( EgeSelectOneAction* act, gint active, gboolean override )
+{
+ if ( override || (act->private_data->active != active) ) {
+ act->private_data->active = active;
+ GSList* proxies = gtk_action_get_proxies( GTK_ACTION(act) );
+ while ( proxies ) {
+ if ( GTK_IS_TOOL_ITEM(proxies->data) ) {
+ /* Search for the things we built up in create_tool_item() */
+ GList* children = gtk_container_get_children( GTK_CONTAINER(proxies->data) );
+ if ( children && children->data ) {
+ gpointer combodata = g_object_get_data( G_OBJECT(children->data), "ege-combo-box" );
+ if (!combodata && GTK_IS_ALIGNMENT(children->data)) {
+ GList *other = gtk_container_get_children( GTK_CONTAINER(children->data) );
+ combodata = g_object_get_data( G_OBJECT(other->data), "ege-combo-box" );
+ }
+ if ( GTK_IS_COMBO_BOX(combodata) ) {
+ GtkComboBox* combo = GTK_COMBO_BOX(combodata);
+ if ((active == -1) && (gtk_combo_box_get_has_entry(combo))) {
+ gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo))), act->private_data->activeText);
+ } else if ( gtk_combo_box_get_active(combo) != active ) {
+ gtk_combo_box_set_active( combo, active );
+ }
+ } else if ( GTK_IS_BOX(children->data) ) {
+ gpointer data = g_object_get_data( G_OBJECT(children->data), "ege-proxy_action-group" );
+ if ( data ) {
+ GSList* group = (GSList*)data;
+ GtkRadioAction* oneAction = GTK_RADIO_ACTION(group->data);
+ gint hot = gtk_radio_action_get_current_value( oneAction );
+ if ( hot != active ) {
+ /*gtk_radio_action_set_current_value( oneAction, active );*/
+ gint value = 0;
+ while ( group ) {
+ GtkRadioAction* possible = GTK_RADIO_ACTION(group->data);
+ g_object_get( G_OBJECT(possible), "value", &value, NULL );
+ if ( value == active ) {
+ /* Found the group member to set active */
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(possible), TRUE );
+ break;
+ }
+
+ group = g_slist_next(group);
+ }
+ }
+ }
+ }
+ }
+ } else if ( GTK_IS_MENU_ITEM(proxies->data) ) {
+ GtkWidget* subMenu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(proxies->data) );
+ GList* children = gtk_container_get_children( GTK_CONTAINER(subMenu) );
+ if ( children && (g_list_length(children) > (guint)active) ) {
+ gpointer data = g_list_nth_data( children, active );
+ gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(data), TRUE );
+ }
+ }
+
+ proxies = g_slist_next( proxies );
+ }
+
+ g_signal_emit( G_OBJECT(act), signals[CHANGED], 0);
+ }
+}
+
+void resync_sensitive( EgeSelectOneAction* act )
+{
+ GSList* proxies = gtk_action_get_proxies( GTK_ACTION(act) );
+ while ( proxies ) {
+ if ( GTK_IS_TOOL_ITEM(proxies->data) ) {
+ /* Search for the things we built up in create_tool_item() */
+ GList* children = gtk_container_get_children( GTK_CONTAINER(proxies->data) );
+ if ( children && children->data ) {
+ gpointer combodata = g_object_get_data( G_OBJECT(children->data), "ege-combo-box" );
+ if (!combodata && GTK_IS_ALIGNMENT(children->data)) {
+ GList *other = gtk_container_get_children( GTK_CONTAINER(children->data) );
+ combodata = g_object_get_data( G_OBJECT(other->data), "ege-combo-box" );
+ }
+ if ( GTK_IS_COMBO_BOX(combodata) ) {
+ /* Not implemented */
+ } else if ( GTK_IS_BOX(children->data) ) {
+ gpointer data = g_object_get_data( G_OBJECT(children->data), "ege-proxy_action-group" );
+ if ( data ) {
+ GSList* group = (GSList*)data;
+ // List is backwards in group as compared to GtkTreeModel, we better do matching.
+ while ( group ) {
+ GtkRadioAction* ract = GTK_RADIO_ACTION(group->data);
+ const gchar* label = gtk_action_get_label( GTK_ACTION( ract ) );
+
+ // Search for matching GtkTreeModel entry
+ GtkTreeIter iter;
+ gboolean valid;
+ valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
+ gboolean sens = true;
+
+ while( valid ) {
+
+ gchar* str = 0;
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->labelColumn, &str,
+ -1 );
+
+ if( strcmp( label, str ) == 0 ) {
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->sensitiveColumn, &sens,
+ -1 );
+ break;
+ }
+ g_free( str );
+
+ valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
+ }
+
+ gtk_action_set_sensitive( GTK_ACTION(ract), sens );
+ group = g_slist_next(group);
+ }
+ }
+ }
+ }
+ } else if ( GTK_IS_MENU_ITEM(proxies->data) ) {
+ /* Not implemented */
+ }
+
+ proxies = g_slist_next( proxies );
+ }
+
+ g_signal_emit( G_OBJECT(act), signals[CHANGED], 0);
+}
+
+void combo_changed_cb( GtkComboBox* widget, gpointer user_data )
+{
+ EgeSelectOneAction *act = EGE_SELECT_ONE_ACTION(user_data);
+ gchar *text = 0;
+ GtkComboBox *cb = GTK_COMBO_BOX (widget);
+ gint newActive = gtk_combo_box_get_active(widget);
+
+ if (gtk_combo_box_get_has_entry (cb)) {
+ GtkBin *bin = GTK_BIN (cb);
+ GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (bin));
+
+ text = g_strdup (gtk_entry_get_text (entry));
+ }
+ else {
+ GtkTreeIter iter;
+
+ if (gtk_combo_box_get_active_iter (cb, &iter)) {
+ GtkTreeModel *model = gtk_combo_box_get_model (cb);
+
+ gtk_tree_model_get (model, &iter, 0, &text, -1);
+ }
+ }
+
+ if (!text) {
+ /* User probably deleted the data in the model */
+ return;
+ }
+
+ if (newActive == -1) {
+ /* indicates the user is entering text for a custom aka "open" value */
+ if (act->private_data->pendingText && text && (strcmp(act->private_data->pendingText, text) == 0) ) {
+ /* The currently entered data matches the last seen */
+ } else {
+ if (act->private_data->pendingText) {
+ g_free(act->private_data->pendingText);
+ }
+ act->private_data->pendingText = text;
+ text = 0;
+ }
+ } else if (newActive != act->private_data->active) {
+ if (act->private_data->pendingText) {
+ g_free(act->private_data->pendingText);
+ act->private_data->pendingText = 0;
+ }
+ g_object_set( G_OBJECT(act), "active", newActive, NULL );
+ }
+
+ if (text) {
+ g_free(text);
+ text = 0;
+ }
+}
+
+gboolean combo_entry_focus_lost_cb( GtkWidget *widget, GdkEventFocus *event, gpointer data )
+{
+ EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(data);
+ (void)widget;
+ (void)event;
+
+ commit_pending_change(act);
+
+ return FALSE;
+}
+
+void combo_entry_changed_cb( GtkEntry* widget, gpointer user_data )
+{
+ EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(user_data);
+ (void)widget;
+ commit_pending_change(act);
+}
+
+void commit_pending_change(EgeSelectOneAction *act)
+{
+ if (act->private_data->pendingText) {
+ if (act->private_data->activeText && (strcmp(act->private_data->pendingText, act->private_data->activeText) == 0)) {
+ /* Was the same value */
+ g_free(act->private_data->pendingText);
+ act->private_data->pendingText = 0;
+ } else {
+ gint matching = find_text_index(act, act->private_data->pendingText);
+
+ if (act->private_data->activeText) {
+ g_free(act->private_data->activeText);
+ }
+ act->private_data->activeText = act->private_data->pendingText;
+ act->private_data->pendingText = 0;
+
+ if (matching >= 0) {
+ g_free(act->private_data->activeText);
+ act->private_data->activeText = 0;
+ g_object_set( G_OBJECT(act), "active", matching, NULL );
+ } else if (act->private_data->active != -1) {
+ g_object_set( G_OBJECT(act), "active", -1, NULL );
+ } else {
+ resync_active( act, -1, TRUE );
+ }
+ }
+ }
+}
+
+gint find_text_index(EgeSelectOneAction *act, gchar const* text)
+{
+ gint index = -1;
+
+ if (text) {
+ GtkTreeIter iter;
+ gboolean valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
+ gint curr = 0;
+ while ( valid && (index < 0) ) {
+ gchar* str = 0;
+ gtk_tree_model_get( act->private_data->model, &iter,
+ act->private_data->labelColumn, &str,
+ -1 );
+
+ if (str && (strcmp(text, str) == 0)) {
+ index = curr;
+ }
+
+ g_free(str);
+ str = 0;
+
+ curr++;
+ valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
+ }
+ }
+
+ return index;
+}
+
+void menu_toggled_cb( GtkWidget* obj, gpointer data )
+{
+ GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(obj);
+ EgeSelectOneAction* act = (EgeSelectOneAction*)g_object_get_qdata( G_OBJECT(obj), gDataName );
+ gint newActive = GPOINTER_TO_INT(data);
+ if ( gtk_check_menu_item_get_active(item) && (newActive != act->private_data->active) ) {
+ g_object_set( G_OBJECT(act), "active", newActive, NULL );
+ }
+}
+
+void proxy_action_chagned_cb( GtkRadioAction* action, GtkRadioAction* current, gpointer user_data )
+{
+ (void)current;
+ if ( gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(action) ) ) {
+ EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(user_data);
+ gint newActive = gtk_radio_action_get_current_value( action );
+ if ( newActive != act->private_data->active ) {
+ g_object_set( G_OBJECT(act), "active", newActive, NULL );
+ }
+ }
+}
+
+int scan_max_width( GtkTreeModel *model, gint labelColumn )
+{
+ int maxUsed = 0;
+ GtkTreeIter iter;
+ gboolean valid = gtk_tree_model_get_iter_first( model, &iter );
+ while ( valid ) {
+ gchar* str = NULL;
+ gtk_tree_model_get( model, &iter, labelColumn, &str, -1 );
+ if (str != NULL){
+ int count = strlen(str);
+ if (count > maxUsed) {
+ maxUsed = count;
+ }
+ g_free(str);
+ }
+ valid = gtk_tree_model_iter_next( model, &iter );
+ }
+ return maxUsed;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/widgets/ege-select-one-action.h b/src/widgets/ege-select-one-action.h
new file mode 100644
index 000000000..0c5cecaa3
--- /dev/null
+++ b/src/widgets/ege-select-one-action.h
@@ -0,0 +1,245 @@
+#ifndef SEEN_EGE_SELECT_ONE_ACTION
+#define SEEN_EGE_SELECT_ONE_ACTION
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is EGE Select One Action.
+ *
+ * The Initial Developer of the Original Code is
+ * Jon A. Cruz.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/** \file
+ * GtkAction subclass that represents a set of values the user may select
+ * one from at a given time.
+ * This can manifest as a popup menu, a ComboBox, a set of toggle buttons,
+ * etc.
+ */
+
+/* Note: this file should be kept compilable as both .cpp and .c */
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+
+#define EGE_SELECT_ONE_ACTION_TYPE ( ege_select_one_action_get_type() )
+#define EGE_SELECT_ONE_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), EGE_SELECT_ONE_ACTION_TYPE, EgeSelectOneAction) )
+#define EGE_SELECT_ONE_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), EGE_SELECT_ONE_ACTION_TYPE, EgeSelectOneActionClass) )
+#define IS_EGE_SELECT_ONE_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), EGE_SELECT_ONE_ACTION_TYPE) )
+#define IS_EGE_SELECT_ONE_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), EGE_SELECT_ONE_ACTION_TYPE) )
+#define EGE_SELECT_ONE_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), EGE_SELECT_ONE_ACTION_TYPE, EgeSelectOneActionClass) )
+
+typedef struct _EgeSelectOneAction EgeSelectOneAction;
+typedef struct _EgeSelectOneActionClass EgeSelectOneActionClass;
+typedef struct _EgeSelectOneActionPrivate EgeSelectOneActionPrivate;
+
+/**
+ * Instance structure of EgeSelectOneAction.
+ */
+struct _EgeSelectOneAction
+{
+ /** Parent instance structure. */
+ GtkAction action;
+
+ /** Pointer to private instance data. */
+ EgeSelectOneActionPrivate *private_data;
+};
+
+/**
+ * Class structure of EgeSelectOneAction.
+ */
+struct _EgeSelectOneActionClass
+{
+ /** Parent class structure. */
+ GtkActionClass parent_class;
+
+ void (*changed) (EgeSelectOneAction* action);
+};
+
+/** Standard Gtk type function */
+GType ege_select_one_action_get_type( void );
+
+/**
+ * Creates a new EgeSelectOneAction instance.
+ * This is a GtkAction subclass that represents a set of values the user
+ * may select one from at a given time.
+ * This can manifest as a popup menu, a ComboBox, a set of toggle buttons,
+ * etc.
+ *
+ * @param name Functional name for the action.
+ * @param label Display label for the action.
+ * @param tooltip Tooltip for the action.
+ * @param stock_id Icon id to use.
+ * @param model the source of choices to present.
+ */
+EgeSelectOneAction* ege_select_one_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id,
+ GtkTreeModel* model );
+
+GtkTreeModel *ege_select_one_action_get_model(EgeSelectOneAction* action );
+
+/**
+ * Returns the index of the currently selected item.
+ *
+ * @param action The action to fetch the selected index for.
+ */
+gint ege_select_one_action_get_active( EgeSelectOneAction* action );
+
+/**
+ * Returns the text of the currently selected item.
+ *
+ * @param action The action to fetch the text for.
+ * @return the selected text. The caller is responsible to call g_free() on it when done.
+ */
+gchar *ege_select_one_action_get_active_text( EgeSelectOneAction* action );
+
+/**
+ * Sets the text of the currently selected item.
+ *
+ * @param action The action to fetch the text for.
+ * @param text the text to set.
+ */
+void ege_select_one_action_set_active_text( EgeSelectOneAction* action, gchar const *text );
+
+/**
+ * Sets the currently selected item.
+ *
+ * @param action The action to fetch the selected index for.
+ * @param val index of the item to make selected.
+ */
+void ege_select_one_action_set_active( EgeSelectOneAction* action, gint val );
+
+//void ege_select_one_action_set_sensitive( EgeSelectOneAction *action, gint val, gboolean sensitive );
+
+/**
+ * Update sensitive parameters.
+ * @param action The action to update.
+ */
+void ege_select_one_action_update_sensitive( EgeSelectOneAction *action );
+
+/**
+ * Returns the column used for the display label.
+ *
+ * @param action The action to fetch the label column for.
+ */
+gint ege_select_one_action_get_label_column( EgeSelectOneAction* action );
+
+/**
+ * Sets the column used for the display label.
+ *
+ * @param action The action to set the label column for.
+ * @param col column to use.
+ */
+void ege_select_one_action_set_label_column( EgeSelectOneAction* action, gint col );
+
+
+/**
+ * Returns the column used for the display icon.
+ *
+ * @param action The action to fetch the icon column for.
+ */
+gint ege_select_one_action_get_icon_column( EgeSelectOneAction* action );
+
+/**
+ * Sets the column used for the display icon.
+ *
+ * @param action The action to set the icon column for.
+ * @param col column to use.
+ */
+void ege_select_one_action_set_icon_column( EgeSelectOneAction* action, gint col );
+
+gint ege_select_one_action_get_icon_size( EgeSelectOneAction* action );
+
+void ege_select_one_action_set_icon_size( EgeSelectOneAction* action, gint size );
+
+
+/**
+ * Returns the column used for the tooltip.
+ *
+ * @param action The action to fetch the tooltip column for.
+ */
+gint ege_select_one_action_get_tooltip_column( EgeSelectOneAction* action );
+
+/**
+ * Sets the column used for the tooltip.
+ *
+ * @param action The action to set the tooltip column for.
+ * @param col column to use.
+ */
+void ege_select_one_action_set_tooltip_column( EgeSelectOneAction* action, gint col );
+
+
+/**
+ * Returns the column used for tracking sensitivity.
+ *
+ * @param action The action to fetch the sensitive column for.
+ */
+gint ege_select_one_action_get_sensitive_column( EgeSelectOneAction* action );
+
+/**
+ * Sets the column used for sensitivity (if any).
+ *
+ * @param action The action to set the sensitive column for.
+ * @param col column to use.
+ */
+void ege_select_one_action_set_sensitive_column( EgeSelectOneAction* action, gint col );
+
+
+/**
+ * Sets a hint to be used in determining the display form.
+ * This is the XForms style 'appearance' hint: "full", "compact", "minimal".
+ *
+ * @param action The action to set the tooltip column for.
+ * @param val The value of the appearance hint.
+ */
+void ege_select_one_action_set_appearance( EgeSelectOneAction* action, gchar const* val );
+
+/**
+ * Sets to allow or disallow free entry additions to the list.
+ * The default is "closed" selections that do not allow additions/edits.
+ * This is the XForms functional 'selection' attribute: "open", "closed".
+ *
+ * @param action The action to set the tooltip column for.
+ * @param val The value of the selection attribute.
+ */
+void ege_select_one_action_set_selection( EgeSelectOneAction *action, gchar const* val );
+
+/* bit of a work-around */
+void ege_select_one_action_set_radio_action_type( EgeSelectOneAction* action, GType radioActionType );
+
+G_END_DECLS
+
+#endif /* SEEN_EGE_SELECT_ONE_ACTION */
diff --git a/src/widgets/eraser-toolbar.cpp b/src/widgets/eraser-toolbar.cpp
index 14e7cbf4e..f547cbd8b 100644
--- a/src/widgets/eraser-toolbar.cpp
+++ b/src/widgets/eraser-toolbar.cpp
@@ -35,9 +35,9 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
#include "preferences.h"
#include "toolbox.h"
#include "ui/icon-names.h"
diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp
index f5a99f3e7..b6378b251 100644
--- a/src/widgets/gradient-toolbar.cpp
+++ b/src/widgets/gradient-toolbar.cpp
@@ -22,12 +22,12 @@
#include "desktop.h"
#include "document-undo.h"
#include "document.h"
-#include "ege-adjustment-action.h"
-#include "ege-select-one-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-select-one-action.h"
#include "gradient-chemistry.h"
#include "gradient-drag.h"
#include "gradient-toolbar.h"
-#include "ink-action.h"
+#include "widgets/ink-action.h"
#include "macros.h"
#include "preferences.h"
#include "selection.h"
@@ -1109,7 +1109,7 @@ void sp_gradient_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions,
GtkTreeIter iter;
gtk_list_store_append( model, &iter );
- gtk_list_store_set( model, &iter, 0, _("None"), 1, SP_GRADIENT_SPREAD_PAD, -1 );
+ gtk_list_store_set( model, &iter, 0, C_("Gradient repeat type", "None"), 1, SP_GRADIENT_SPREAD_PAD, -1 );
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter, 0, _("Reflected"), 1, SP_GRADIENT_SPREAD_REFLECT, -1 );
diff --git a/src/widgets/ink-action.cpp b/src/widgets/ink-action.cpp
new file mode 100644
index 000000000..5941c31e4
--- /dev/null
+++ b/src/widgets/ink-action.cpp
@@ -0,0 +1,638 @@
+#include "widgets/icon.h"
+#include "icon-size.h"
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "widgets/ink-action.h"
+
+#include "widgets/button.h"
+
+static void ink_action_finalize( GObject* obj );
+static void ink_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
+static void ink_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
+
+static GtkWidget* ink_action_create_menu_item( GtkAction* action );
+static GtkWidget* ink_action_create_tool_item( GtkAction* action );
+
+struct _InkActionPrivate
+{
+ gchar* iconId;
+ Inkscape::IconSize iconSize;
+};
+
+#define INK_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), INK_ACTION_TYPE, InkActionPrivate ) )
+
+G_DEFINE_TYPE(InkAction, ink_action, GTK_TYPE_ACTION);
+
+enum {
+ PROP_INK_ID = 1,
+ PROP_INK_SIZE
+};
+
+static void ink_action_class_init( InkActionClass* klass )
+{
+ if ( klass ) {
+ GObjectClass * objClass = G_OBJECT_CLASS( klass );
+
+ objClass->finalize = ink_action_finalize;
+ objClass->get_property = ink_action_get_property;
+ objClass->set_property = ink_action_set_property;
+
+ klass->parent_class.create_menu_item = ink_action_create_menu_item;
+ klass->parent_class.create_tool_item = ink_action_create_tool_item;
+ /*klass->parent_class.connect_proxy = connect_proxy;*/
+ /*klass->parent_class.disconnect_proxy = disconnect_proxy;*/
+
+ g_object_class_install_property( objClass,
+ PROP_INK_ID,
+ g_param_spec_string( "iconId",
+ "Icon ID",
+ "The id for the icon",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_INK_SIZE,
+ g_param_spec_int( "iconSize",
+ "Icon Size",
+ "The size the icon",
+ (int)Inkscape::ICON_SIZE_MENU,
+ (int)Inkscape::ICON_SIZE_DECORATION,
+ (int)Inkscape::ICON_SIZE_SMALL_TOOLBAR,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_type_class_add_private( klass, sizeof(InkActionClass) );
+ }
+}
+
+static void ink_action_init( InkAction* action )
+{
+ action->private_data = INK_ACTION_GET_PRIVATE( action );
+ action->private_data->iconId = 0;
+ action->private_data->iconSize = Inkscape::ICON_SIZE_SMALL_TOOLBAR;
+}
+
+static void ink_action_finalize( GObject* obj )
+{
+ InkAction* action = INK_ACTION( obj );
+
+ g_free( action->private_data->iconId );
+ g_free( action->private_data );
+
+}
+
+//Any strings passed in should already be localised
+InkAction* ink_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size )
+{
+ GObject* obj = (GObject*)g_object_new( INK_ACTION_TYPE,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "iconId", inkId,
+ "iconSize", size,
+ NULL );
+
+ InkAction* action = INK_ACTION( obj );
+
+ return action;
+}
+
+static void ink_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
+{
+ InkAction* action = INK_ACTION( obj );
+ (void)action;
+ switch ( propId ) {
+ case PROP_INK_ID:
+ {
+ g_value_set_string( value, action->private_data->iconId );
+ }
+ break;
+
+ case PROP_INK_SIZE:
+ {
+ g_value_set_int( value, action->private_data->iconSize );
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+void ink_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
+{
+ InkAction* action = INK_ACTION( obj );
+ (void)action;
+ switch ( propId ) {
+ case PROP_INK_ID:
+ {
+ gchar* tmp = action->private_data->iconId;
+ action->private_data->iconId = g_value_dup_string( value );
+ g_free( tmp );
+ }
+ break;
+
+ case PROP_INK_SIZE:
+ {
+ action->private_data->iconSize = (Inkscape::IconSize)g_value_get_int( value );
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+ }
+}
+
+static GtkWidget* ink_action_create_menu_item( GtkAction* action )
+{
+ InkAction* act = INK_ACTION( action );
+ GtkWidget* item = 0;
+
+ if ( act->private_data->iconId ) {
+ gchar* label = 0;
+ g_object_get( G_OBJECT(act), "label", &label, NULL );
+
+ item = gtk_image_menu_item_new_with_mnemonic( label );
+ GtkWidget* child = sp_icon_new( Inkscape::ICON_SIZE_MENU, act->private_data->iconId );
+ // TODO this work-around is until SPIcon will live properly inside of a popup menu
+ if ( SP_IS_ICON(child) ) {
+ SPIcon* icon = SP_ICON(child);
+ sp_icon_fetch_pixbuf( icon );
+ GdkPixbuf* target = icon->pb;
+ if ( target ) {
+ child = gtk_image_new_from_pixbuf( target );
+ gtk_widget_set_sensitive(child, gtk_action_is_sensitive(action));
+ gtk_widget_destroy( GTK_WIDGET(icon) );
+ }
+ }
+ gtk_widget_show_all( child );
+ gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(item), child );
+
+ g_free( label );
+ label = 0;
+ } else {
+ item = GTK_ACTION_CLASS(ink_action_parent_class)->create_menu_item( action );
+ }
+
+ return item;
+}
+
+static GtkWidget* ink_action_create_tool_item( GtkAction* action )
+{
+ InkAction* act = INK_ACTION( action );
+ GtkWidget* item = GTK_ACTION_CLASS(ink_action_parent_class)->create_tool_item(action);
+
+ if ( act->private_data->iconId ) {
+ if ( GTK_IS_TOOL_BUTTON(item) ) {
+ GtkToolButton* button = GTK_TOOL_BUTTON(item);
+
+ GtkWidget* child = sp_icon_new( act->private_data->iconSize, act->private_data->iconId );
+ gtk_tool_button_set_icon_widget( button, child );
+ } else {
+ // For now trigger a warning but don't do anything else
+ GtkToolButton* button = GTK_TOOL_BUTTON(item);
+ (void)button;
+ }
+ }
+
+ // TODO investigate if needed
+ gtk_widget_show_all( item );
+
+ return item;
+}
+
+
+
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+
+
+static void ink_toggle_action_finalize( GObject* obj );
+static void ink_toggle_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
+static void ink_toggle_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
+
+static GtkWidget* ink_toggle_action_create_menu_item( GtkAction* action );
+static GtkWidget* ink_toggle_action_create_tool_item( GtkAction* action );
+
+static void ink_toggle_action_update_icon( InkToggleAction* action );
+
+struct _InkToggleActionPrivate
+{
+ gchar* iconId;
+ Inkscape::IconSize iconSize;
+};
+
+#define INK_TOGGLE_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), INK_TOGGLE_ACTION_TYPE, InkToggleActionPrivate ) )
+
+G_DEFINE_TYPE(InkToggleAction, ink_toggle_action, GTK_TYPE_TOGGLE_ACTION);
+
+static void ink_toggle_action_class_init( InkToggleActionClass* klass )
+{
+ if ( klass ) {
+ GObjectClass * objClass = G_OBJECT_CLASS( klass );
+
+ objClass->finalize = ink_toggle_action_finalize;
+ objClass->get_property = ink_toggle_action_get_property;
+ objClass->set_property = ink_toggle_action_set_property;
+
+ klass->parent_class.parent_class.create_menu_item = ink_toggle_action_create_menu_item;
+ klass->parent_class.parent_class.create_tool_item = ink_toggle_action_create_tool_item;
+ /*klass->parent_class.connect_proxy = connect_proxy;*/
+ /*klass->parent_class.disconnect_proxy = disconnect_proxy;*/
+
+ g_object_class_install_property( objClass,
+ PROP_INK_ID,
+ g_param_spec_string( "iconId",
+ "Icon ID",
+ "The id for the icon",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_INK_SIZE,
+ g_param_spec_int( "iconSize",
+ "Icon Size",
+ "The size the icon",
+ (int)Inkscape::ICON_SIZE_MENU,
+ (int)99,
+ (int)Inkscape::ICON_SIZE_SMALL_TOOLBAR,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_type_class_add_private( klass, sizeof(InkToggleActionClass) );
+ }
+}
+
+static void ink_toggle_action_init( InkToggleAction* action )
+{
+ action->private_data = INK_TOGGLE_ACTION_GET_PRIVATE( action );
+ action->private_data->iconId = 0;
+ action->private_data->iconSize = Inkscape::ICON_SIZE_SMALL_TOOLBAR;
+}
+
+static void ink_toggle_action_finalize( GObject* obj )
+{
+ InkToggleAction* action = INK_TOGGLE_ACTION( obj );
+
+ g_free( action->private_data->iconId );
+ g_free( action->private_data );
+
+}
+
+InkToggleAction* ink_toggle_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size,
+ SPAttributeEnum attr)
+{
+ GObject* obj = (GObject*)g_object_new( INK_TOGGLE_ACTION_TYPE,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "iconId", inkId,
+ "iconSize", Inkscape::getRegisteredIconSize(size),
+ //"SP_ATTR_INKSCAPE", attr, // Why doesn't this work and do I need to use g_object_set_data below?
+ NULL );
+
+ g_object_set_data(obj, "SP_ATTR_INKSCAPE", GINT_TO_POINTER(attr));
+ InkToggleAction* action = INK_TOGGLE_ACTION( obj );
+
+ return action;
+}
+
+static void ink_toggle_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
+{
+ InkToggleAction* action = INK_TOGGLE_ACTION( obj );
+ (void)action;
+ switch ( propId ) {
+ case PROP_INK_ID:
+ {
+ g_value_set_string( value, action->private_data->iconId );
+ }
+ break;
+
+ case PROP_INK_SIZE:
+ {
+ g_value_set_int( value, action->private_data->iconSize );
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+void ink_toggle_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
+{
+ InkToggleAction* action = INK_TOGGLE_ACTION( obj );
+ (void)action;
+ switch ( propId ) {
+ case PROP_INK_ID:
+ {
+ gchar* tmp = action->private_data->iconId;
+ action->private_data->iconId = g_value_dup_string( value );
+ g_free( tmp );
+
+ ink_toggle_action_update_icon( action );
+ }
+ break;
+
+ case PROP_INK_SIZE:
+ {
+ action->private_data->iconSize = (Inkscape::IconSize)g_value_get_int( value );
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+ }
+}
+
+static GtkWidget* ink_toggle_action_create_menu_item( GtkAction* action )
+{
+ GtkWidget* item = GTK_TOGGLE_ACTION_CLASS(ink_toggle_action_parent_class)->parent_class.create_menu_item(action);
+
+ return item;
+}
+
+static GtkWidget* ink_toggle_action_create_tool_item( GtkAction* action )
+{
+ InkToggleAction* act = INK_TOGGLE_ACTION( action );
+
+ GtkWidget* item = GTK_TOGGLE_ACTION_CLASS(ink_toggle_action_parent_class)->parent_class.create_tool_item(action);
+ if ( GTK_IS_TOOL_BUTTON(item) ) {
+ GtkToolButton* button = GTK_TOOL_BUTTON(item);
+ if ( act->private_data->iconId ) {
+ GtkWidget* child = sp_icon_new( act->private_data->iconSize, act->private_data->iconId );
+ GtkWidget* align = gtk_alignment_new( 0.5, 0.5, 0.0, 0.0 );
+ gtk_container_add( GTK_CONTAINER(align), child );
+ gtk_tool_button_set_icon_widget( button, align );
+ } else {
+ gchar *label = 0;
+ g_object_get( G_OBJECT(action), "short_label", &label, NULL );
+ gtk_tool_button_set_label( button, label );
+ g_free( label );
+ label = 0;
+ }
+ } else {
+ // For now trigger a warning but don't do anything else
+ GtkToolButton* button = GTK_TOOL_BUTTON(item);
+ (void)button;
+ }
+ gtk_widget_show_all( item );
+
+ return item;
+}
+
+
+static void ink_toggle_action_update_icon( InkToggleAction* action )
+{
+ if ( action ) {
+ GSList* proxies = gtk_action_get_proxies( GTK_ACTION(action) );
+ while ( proxies ) {
+ if ( GTK_IS_TOOL_ITEM(proxies->data) ) {
+ if ( GTK_IS_TOOL_BUTTON(proxies->data) ) {
+ GtkToolButton* button = GTK_TOOL_BUTTON(proxies->data);
+
+ GtkWidget* child = sp_icon_new( action->private_data->iconSize, action->private_data->iconId );
+ GtkWidget* align = gtk_alignment_new( 0.5, 0.5, 0.0, 0.0 );
+ gtk_container_add( GTK_CONTAINER(align), child );
+ gtk_widget_show_all( align );
+ gtk_tool_button_set_icon_widget( button, align );
+ }
+ }
+
+ proxies = g_slist_next( proxies );
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+
+
+static void ink_radio_action_finalize( GObject* obj );
+static void ink_radio_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
+static void ink_radio_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
+
+static GtkWidget* ink_radio_action_create_menu_item( GtkAction* action );
+static GtkWidget* ink_radio_action_create_tool_item( GtkAction* action );
+
+struct _InkRadioActionPrivate
+{
+ gchar* iconId;
+ Inkscape::IconSize iconSize;
+};
+
+#define INK_RADIO_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), INK_RADIO_ACTION_TYPE, InkRadioActionPrivate ) )
+
+G_DEFINE_TYPE(InkRadioAction, ink_radio_action, GTK_TYPE_RADIO_ACTION);
+
+static void ink_radio_action_class_init( InkRadioActionClass* klass )
+{
+ if ( klass ) {
+ GObjectClass * objClass = G_OBJECT_CLASS( klass );
+
+ objClass->finalize = ink_radio_action_finalize;
+ objClass->get_property = ink_radio_action_get_property;
+ objClass->set_property = ink_radio_action_set_property;
+
+ klass->parent_class.parent_class.parent_class.create_menu_item = ink_radio_action_create_menu_item;
+ klass->parent_class.parent_class.parent_class.create_tool_item = ink_radio_action_create_tool_item;
+ /*klass->parent_class.connect_proxy = connect_proxy;*/
+ /*klass->parent_class.disconnect_proxy = disconnect_proxy;*/
+
+ g_object_class_install_property( objClass,
+ PROP_INK_ID,
+ g_param_spec_string( "iconId",
+ "Icon ID",
+ "The id for the icon",
+ "",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_object_class_install_property( objClass,
+ PROP_INK_SIZE,
+ g_param_spec_int( "iconSize",
+ "Icon Size",
+ "The size the icon",
+ (int)Inkscape::ICON_SIZE_MENU,
+ (int)Inkscape::ICON_SIZE_DECORATION,
+ (int)Inkscape::ICON_SIZE_SMALL_TOOLBAR,
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ g_type_class_add_private( klass, sizeof(InkRadioActionClass) );
+ }
+}
+
+static void ink_radio_action_init( InkRadioAction* action )
+{
+ action->private_data = INK_RADIO_ACTION_GET_PRIVATE( action );
+ action->private_data->iconId = 0;
+ action->private_data->iconSize = Inkscape::ICON_SIZE_SMALL_TOOLBAR;
+}
+
+static void ink_radio_action_finalize( GObject* obj )
+{
+ InkRadioAction* action = INK_RADIO_ACTION( obj );
+
+ g_free( action->private_data->iconId );
+ g_free( action->private_data );
+
+}
+
+InkRadioAction* ink_radio_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size )
+{
+ GObject* obj = (GObject*)g_object_new( INK_RADIO_ACTION_TYPE,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "iconId", inkId,
+ "iconSize", Inkscape::getRegisteredIconSize(size),
+ NULL );
+
+ InkRadioAction* action = INK_RADIO_ACTION( obj );
+
+ return action;
+}
+
+static void ink_radio_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
+{
+ InkRadioAction* action = INK_RADIO_ACTION( obj );
+ (void)action;
+ switch ( propId ) {
+ case PROP_INK_ID:
+ {
+ g_value_set_string( value, action->private_data->iconId );
+ }
+ break;
+
+ case PROP_INK_SIZE:
+ {
+ g_value_set_int( value, action->private_data->iconSize );
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+}
+
+void ink_radio_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
+{
+ InkRadioAction* action = INK_RADIO_ACTION( obj );
+ (void)action;
+ switch ( propId ) {
+ case PROP_INK_ID:
+ {
+ gchar* tmp = action->private_data->iconId;
+ action->private_data->iconId = g_value_dup_string( value );
+ g_free( tmp );
+ }
+ break;
+
+ case PROP_INK_SIZE:
+ {
+ action->private_data->iconSize = (Inkscape::IconSize)g_value_get_int( value );
+ }
+ break;
+
+ default:
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
+ }
+ }
+}
+
+static GtkWidget* ink_radio_action_create_menu_item( GtkAction* action )
+{
+ GtkWidget* item = GTK_RADIO_ACTION_CLASS(ink_radio_action_parent_class)->parent_class.parent_class.create_menu_item(action);
+
+ return item;
+}
+
+static GtkWidget* ink_radio_action_create_tool_item( GtkAction* action )
+{
+ InkRadioAction* act = INK_RADIO_ACTION( action );
+ GtkWidget* item = GTK_RADIO_ACTION_CLASS(ink_radio_action_parent_class)->parent_class.parent_class.create_tool_item(action);
+
+ if ( act->private_data->iconId ) {
+ if ( GTK_IS_TOOL_BUTTON(item) ) {
+ GtkToolButton* button = GTK_TOOL_BUTTON(item);
+
+ GtkWidget* child = sp_icon_new( act->private_data->iconSize, act->private_data->iconId );
+ GtkWidget* align = gtk_alignment_new( 0.5, 0.5, 0.0, 0.0 );
+ gtk_container_add( GTK_CONTAINER(align), child );
+ gtk_tool_button_set_icon_widget( button, align );
+ } else {
+ // For now trigger a warning but don't do anything else
+ GtkToolButton* button = GTK_TOOL_BUTTON(item);
+ (void)button;
+ }
+ }
+
+ // TODO investigate if needed
+ gtk_widget_show_all( item );
+
+ return item;
+}
+
+
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+
+// ToolMenu Action is happily derived from http://www.gtkforums.com/viewtopic.php?t=4215
+
+G_DEFINE_TYPE(InkToolMenuAction, ink_tool_menu_action, INK_ACTION_TYPE);
+
+static void
+ink_tool_menu_action_class_init (InkToolMenuActionClass *klass)
+{
+ GtkActionClass *action_class = GTK_ACTION_CLASS (klass);
+ action_class->toolbar_item_type = GTK_TYPE_MENU_TOOL_BUTTON;
+}
+
+static void
+ink_tool_menu_action_init (InkToolMenuAction* /*tma*/)
+{
+}
+
+InkToolMenuAction *
+ink_tool_menu_action_new (const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size )
+{
+ g_return_val_if_fail (name != NULL, NULL);
+
+ GObject* obj = (GObject*)g_object_new( INK_TOOL_MENU_ACTION_TYPE,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "iconId", inkId,
+ "iconSize", size,
+ NULL );
+
+ InkToolMenuAction* action = INK_TOOL_MENU_ACTION( obj );
+
+ return action;
+}
diff --git a/src/widgets/ink-action.h b/src/widgets/ink-action.h
new file mode 100644
index 000000000..ac5cb9873
--- /dev/null
+++ b/src/widgets/ink-action.h
@@ -0,0 +1,159 @@
+#ifndef SEEN_INK_ACTION
+#define SEEN_INK_ACTION
+
+
+#include <gtk/gtk.h>
+#include "icon-size.h"
+#include "attributes.h"
+
+/* Equivalent to GTK Actions of the same type, but can support Inkscape SVG icons */
+
+G_BEGIN_DECLS
+
+#define INK_ACTION_TYPE ( ink_action_get_type() )
+#define INK_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), INK_ACTION_TYPE, InkAction) )
+#define INK_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), INK_ACTION_TYPE, InkActionClass) )
+#define IS_INK_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), INK_ACTION_TYPE) )
+#define IS_INK_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), INK_ACTION_TYPE) )
+#define INK_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), INK_ACTION_TYPE, InkActionClass) )
+
+typedef struct _InkAction InkAction;
+typedef struct _InkActionClass InkActionClass;
+typedef struct _InkActionPrivate InkActionPrivate;
+
+struct _InkAction
+{
+ GtkAction action;
+ InkActionPrivate *private_data;
+};
+
+struct _InkActionClass
+{
+ GtkActionClass parent_class;
+};
+
+GType ink_action_get_type( void );
+
+InkAction* ink_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size );
+
+
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+
+
+#define INK_TOGGLE_ACTION_TYPE ( ink_toggle_action_get_type() )
+#define INK_TOGGLE_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), INK_TOGGLE_ACTION_TYPE, InkToggleAction) )
+#define INK_TOGGLE_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), INK_TOGGLE_ACTION_TYPE, InkToggleActionClass) )
+#define IS_INK_TOGGLE_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), INK_TOGGLE_ACTION_TYPE) )
+#define IS_INK_TOGGLE_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), INK_TOGGLE_ACTION_TYPE) )
+#define INK_TOGGLE_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), INK_TOGGLE_ACTION_TYPE, InkToggleActionClass) )
+
+typedef struct _InkToggleAction InkToggleAction;
+typedef struct _InkToggleActionClass InkToggleActionClass;
+typedef struct _InkToggleActionPrivate InkToggleActionPrivate;
+
+struct _InkToggleAction
+{
+ GtkToggleAction action;
+ InkToggleActionPrivate *private_data;
+};
+
+struct _InkToggleActionClass
+{
+ GtkToggleActionClass parent_class;
+};
+
+GType ink_toggle_action_get_type( void );
+
+InkToggleAction* ink_toggle_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size,
+ SPAttributeEnum attr = SP_ATTR_INVALID);
+
+
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+
+
+#define INK_RADIO_ACTION_TYPE ( ink_radio_action_get_type() )
+#define INK_RADIO_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), INK_RADIO_ACTION_TYPE, InkRadioAction) )
+#define INK_RADIO_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), INK_RADIO_ACTION_TYPE, InkRadioActionClass) )
+#define IS_INK_RADIO_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), INK_RADIO_ACTION_TYPE) )
+#define IS_INK_RADIO_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), INK_RADIO_ACTION_TYPE) )
+#define INK_RADIO_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), INK_RADIO_ACTION_TYPE, InkRadioActionClass) )
+
+typedef struct _InkRadioAction InkRadioAction;
+typedef struct _InkRadioActionClass InkRadioActionClass;
+typedef struct _InkRadioActionPrivate InkRadioActionPrivate;
+
+struct _InkRadioAction
+{
+ GtkRadioAction action;
+ InkRadioActionPrivate *private_data;
+};
+
+struct _InkRadioActionClass
+{
+ GtkRadioActionClass parent_class;
+};
+
+GType ink_radio_action_get_type( void );
+
+InkRadioAction* ink_radio_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size );
+
+
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+/* --------------------------------------------------------------- */
+
+// ToolMenu Action is happily derived from http://www.gtkforums.com/viewtopic.php?t=4215
+
+#define INK_TOOL_MENU_ACTION_TYPE ( ink_tool_menu_action_get_type() )
+#define INK_TOOL_MENU_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), INK_TOOL_MENU_ACTION_TYPE, InkToolMenuAction) )
+#define INK_TOOL_MENU_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), INK_TOOL_MENU_ACTION_TYPE, InkToolMenuActionClass) )
+#define IS_INK_TOOL_MENU_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), INK_TOOL_MENU_ACTION_TYPE) )
+#define IS_INK_TOOL_MENU_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), INK_TOOL_MENU_ACTION_TYPE) )
+#define INK_TOOL_MENU_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), INK_TOOL_MENU_ACTION_TYPE, InkToolMenuActionClass) )
+
+typedef struct _InkToolMenuAction InkToolMenuAction;
+typedef struct _InkToolMenuActionClass InkToolMenuActionClass;
+typedef struct _InkToolMenuActionPrivate InkToolMenuActionPrivate;
+
+struct _InkToolMenuAction
+{
+ InkAction action;
+};
+
+struct _InkToolMenuActionClass
+{
+ InkActionClass parent_class;
+};
+
+GType ink_tool_menu_action_get_type( void );
+
+InkToolMenuAction* ink_tool_menu_action_new( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *inkId,
+ Inkscape::IconSize size );
+
+
+
+G_END_DECLS
+
+#endif /* SEEN_INK_ACTION */
diff --git a/src/widgets/ink-comboboxentry-action.cpp b/src/widgets/ink-comboboxentry-action.cpp
new file mode 100644
index 000000000..5c59f6961
--- /dev/null
+++ b/src/widgets/ink-comboboxentry-action.cpp
@@ -0,0 +1,958 @@
+/*
+ * A subclass of GtkAction that wraps a GtkComboBoxEntry.
+ * Features:
+ * Setting GtkEntryBox width in characters.
+ * Passing a function for formatting cells.
+ * Displaying a warning if entry text isn't in list.
+ * Check comma separated values in text against list. (Useful for font-family fallbacks.)
+ * Setting names for GtkComboBoxEntry and GtkEntry (actionName_combobox, actionName_entry)
+ * to allow setting resources.
+ *
+ * Author(s):
+ * Tavmjong Bah
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Copyright (C) 2010 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+/*
+ * We must provide for both a toolbar item and a menu item.
+ * As we don't know which widgets are used (or even constructed),
+ * we must keep track of things like active entry ourselves.
+ */
+
+#include <iostream>
+#include <string.h>
+#include <glibmm/ustring.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "widgets/ink-comboboxentry-action.h"
+#include "ui/icon-names.h"
+
+// Must handle both tool and menu items!
+static GtkWidget* create_tool_item( GtkAction* action );
+static GtkWidget* create_menu_item( GtkAction* action );
+
+// Internal
+static gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude = false, gboolean ignore_case = false );
+static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* action );
+
+// Callbacks
+static void combo_box_changed_cb( GtkComboBox* widget, gpointer data );
+static void entry_activate_cb( GtkEntry* widget, gpointer data );
+static gboolean match_selected_cb( GtkEntryCompletion* widget, GtkTreeModel* model, GtkTreeIter* iter, gpointer data );
+static gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
+
+enum {
+ PROP_MODEL = 1,
+ PROP_COMBOBOX,
+ PROP_ENTRY,
+ PROP_ENTRY_WIDTH,
+ PROP_EXTRA_WIDTH,
+ PROP_CELL_DATA_FUNC,
+ PROP_SEPARATOR_FUNC,
+ PROP_POPUP,
+ PROP_FOCUS_WIDGET
+};
+
+enum {
+ CHANGED = 0,
+ ACTIVATED,
+ N_SIGNALS
+};
+static guint signals[N_SIGNALS] = {0};
+
+static GQuark gDataName = 0;
+
+static void ink_comboboxentry_action_init (Ink_ComboBoxEntry_Action *action);
+static void ink_comboboxentry_action_class_init (Ink_ComboBoxEntry_ActionClass *klass);
+
+G_DEFINE_TYPE(Ink_ComboBoxEntry_Action, ink_comboboxentry_action, GTK_TYPE_ACTION);
+
+static void ink_comboboxentry_action_finalize (GObject *object)
+{
+ // Free any allocated resources.
+
+ G_OBJECT_CLASS (ink_comboboxentry_action_parent_class)->finalize (object);
+}
+
+
+static void ink_comboboxentry_action_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION (object);
+
+ switch(property_id) {
+
+ case PROP_MODEL:
+ action->model = GTK_TREE_MODEL( g_value_get_object( value ));
+ break;
+
+ case PROP_COMBOBOX:
+ action->combobox = GTK_COMBO_BOX (g_value_get_object (value));
+ break;
+
+ case PROP_ENTRY:
+ action->entry = GTK_ENTRY( g_value_get_object( value ));
+ break;
+
+ case PROP_ENTRY_WIDTH:
+ action->entry_width = g_value_get_int( value );
+ break;
+
+ case PROP_EXTRA_WIDTH:
+ action->extra_width = g_value_get_int( value );
+ break;
+
+ case PROP_CELL_DATA_FUNC:
+ action->cell_data_func = g_value_get_pointer( value );
+ break;
+
+ case PROP_SEPARATOR_FUNC:
+ action->separator_func = g_value_get_pointer( value );
+ break;
+
+ case PROP_POPUP:
+ action->popup = g_value_get_boolean( value );
+ break;
+
+ case PROP_FOCUS_WIDGET:
+ action->focusWidget = (GtkWidget*)g_value_get_pointer( value );
+ break;
+
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+
+static void ink_comboboxentry_action_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION (object);
+
+ switch(property_id) {
+
+ case PROP_MODEL:
+ g_value_set_object (value, action->model);
+ break;
+
+ case PROP_COMBOBOX:
+ g_value_set_object (value, action->combobox);
+ break;
+
+ case PROP_ENTRY:
+ g_value_set_object (value, action->entry);
+ break;
+
+ case PROP_ENTRY_WIDTH:
+ g_value_set_int (value, action->entry_width);
+ break;
+
+ case PROP_EXTRA_WIDTH:
+ g_value_set_int (value, action->extra_width);
+ break;
+
+ case PROP_CELL_DATA_FUNC:
+ g_value_set_pointer (value, action->cell_data_func);
+ break;
+
+ case PROP_SEPARATOR_FUNC:
+ g_value_set_pointer (value, action->separator_func);
+ break;
+
+ case PROP_POPUP:
+ g_value_set_boolean (value, action->popup);
+ break;
+
+ case PROP_FOCUS_WIDGET:
+ g_value_set_pointer (value, action->focusWidget);
+ break;
+
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+ink_comboboxentry_action_connect_proxy (GtkAction *action,
+ GtkWidget *proxy)
+{
+ /* Override any proxy properties. */
+ // if (GTK_IS_MENU_ITEM (proxy)) {
+ // }
+
+ GTK_ACTION_CLASS (ink_comboboxentry_action_parent_class)->connect_proxy (action, proxy);
+}
+
+static void
+ink_comboboxentry_action_class_init (Ink_ComboBoxEntry_ActionClass *klass)
+{
+
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkActionClass *gtkaction_class = GTK_ACTION_CLASS (klass);
+
+ gtkaction_class->connect_proxy = ink_comboboxentry_action_connect_proxy;
+
+ gobject_class->finalize = ink_comboboxentry_action_finalize;
+ gobject_class->set_property = ink_comboboxentry_action_set_property;
+ gobject_class->get_property = ink_comboboxentry_action_get_property;
+
+ gDataName = g_quark_from_string("ink_comboboxentry-action");
+
+ klass->parent_class.create_tool_item = create_tool_item;
+ klass->parent_class.create_menu_item = create_menu_item;
+
+ g_object_class_install_property (
+ gobject_class,
+ PROP_MODEL,
+ g_param_spec_object ("model",
+ "Tree Model",
+ "Tree Model",
+ GTK_TYPE_TREE_MODEL,
+ (GParamFlags)G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_COMBOBOX,
+ g_param_spec_object ("combobox",
+ "GtkComboBoxEntry",
+ "GtkComboBoxEntry",
+ GTK_TYPE_WIDGET,
+ (GParamFlags)G_PARAM_READABLE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_ENTRY,
+ g_param_spec_object ("entry",
+ "GtkEntry",
+ "GtkEntry",
+ GTK_TYPE_WIDGET,
+ (GParamFlags)G_PARAM_READABLE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_ENTRY_WIDTH,
+ g_param_spec_int ("entry_width",
+ "EntryBox width",
+ "EntryBox width (characters)",
+ -1.0, 100, -1.0,
+ (GParamFlags)G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ gobject_class,
+ PROP_EXTRA_WIDTH,
+ g_param_spec_int ("extra_width",
+ "Extra width",
+ "Extra width (px)",
+ -1.0, 500, -1.0,
+ (GParamFlags)G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ gobject_class,
+ PROP_CELL_DATA_FUNC,
+ g_param_spec_pointer ("cell_data_func",
+ "Cell Data Func",
+ "Cell Deta Function",
+ (GParamFlags)G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ gobject_class,
+ PROP_SEPARATOR_FUNC,
+ g_param_spec_pointer ("separator_func",
+ "Separator Func",
+ "Separator Function",
+ (GParamFlags)G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ gobject_class,
+ PROP_POPUP,
+ g_param_spec_boolean ("popup",
+ "Entry Popup",
+ "Entry Popup",
+ false,
+ (GParamFlags)G_PARAM_READWRITE));
+
+ g_object_class_install_property( gobject_class,
+ PROP_FOCUS_WIDGET,
+ g_param_spec_pointer( "focus-widget",
+ "Focus Widget",
+ "The widget to return focus to",
+ (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+ // We need to know when GtkComboBoxEvent or Menu ready for reading
+ signals[CHANGED] = g_signal_new( "changed",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(Ink_ComboBoxEntry_ActionClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ // Probably not needed... originally to keep track of key-presses.
+ signals[ACTIVATED] = g_signal_new( "activated",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(Ink_ComboBoxEntry_ActionClass, activated),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+}
+
+static void ink_comboboxentry_action_init (Ink_ComboBoxEntry_Action *action)
+{
+ action->active = -1;
+ action->text = strdup("");
+ action->entry_completion = NULL;
+ action->indicator = NULL;
+ action->popup = false;
+ action->info = NULL;
+ action->info_cb = NULL;
+ action->info_cb_id = 0;
+ action->info_cb_blocked = false;
+ action->warning = NULL;
+ action->warning_cb = NULL;
+ action->warning_cb_id = 0;
+ action->warning_cb_blocked = false;
+ action->altx_name = NULL;
+ action->focusWidget = NULL;
+}
+
+Ink_ComboBoxEntry_Action *ink_comboboxentry_action_new (const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id,
+ GtkTreeModel *model,
+ gint entry_width,
+ gint extra_width,
+ void *cell_data_func,
+ void *separator_func,
+ GtkWidget *focusWidget)
+{
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return (Ink_ComboBoxEntry_Action*)g_object_new (INK_COMBOBOXENTRY_TYPE_ACTION,
+ "name", name,
+ "label", label,
+ "tooltip", tooltip,
+ "stock-id", stock_id,
+ "model", model,
+ "entry_width", entry_width,
+ "extra_width", extra_width,
+ "cell_data_func", cell_data_func,
+ "separator_func", separator_func,
+ "focus-widget", focusWidget,
+ NULL);
+}
+
+// Create a widget for a toolbar.
+GtkWidget* create_tool_item( GtkAction* action )
+{
+ GtkWidget* item = 0;
+
+ if ( INK_COMBOBOXENTRY_IS_ACTION( action ) && INK_COMBOBOXENTRY_ACTION(action)->model ) {
+
+ Ink_ComboBoxEntry_Action* ink_comboboxentry_action = INK_COMBOBOXENTRY_ACTION( action );
+
+ gchar *action_name = g_strdup( gtk_action_get_name( action ) );
+ gchar *combobox_name = g_strjoin( NULL, action_name, "_combobox", NULL );
+ gchar *entry_name = g_strjoin( NULL, action_name, "_entry", NULL );
+ g_free( action_name );
+
+ item = GTK_WIDGET( gtk_tool_item_new() );
+
+ GtkWidget* comboBoxEntry = gtk_combo_box_new_with_model_and_entry (ink_comboboxentry_action->model);
+ gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (comboBoxEntry), 0);
+
+ // Name it so we can muck with it using an RC file
+ gtk_widget_set_name( comboBoxEntry, combobox_name );
+ g_free( combobox_name );
+
+ {
+ GtkWidget *align = gtk_alignment_new(0, 0.5, 0, 0);
+ gtk_container_add( GTK_CONTAINER(align), comboBoxEntry );
+ gtk_container_add( GTK_CONTAINER(item), align );
+ }
+
+ ink_comboboxentry_action->combobox = GTK_COMBO_BOX (comboBoxEntry);
+
+ //gtk_combo_box_set_active( GTK_COMBO_BOX( comboBoxEntry ), ink_comboboxentry_action->active );
+ gtk_combo_box_set_active( GTK_COMBO_BOX( comboBoxEntry ), 0 );
+
+ g_signal_connect( G_OBJECT(comboBoxEntry), "changed", G_CALLBACK(combo_box_changed_cb), action );
+
+ // Optionally add separator function...
+ if( ink_comboboxentry_action->separator_func != NULL ) {
+ gtk_combo_box_set_row_separator_func( ink_comboboxentry_action->combobox,
+ GtkTreeViewRowSeparatorFunc (ink_comboboxentry_action->separator_func),
+ NULL, NULL );
+ }
+
+ // FIXME: once gtk3 migration is done this can be removed
+ // https://bugzilla.gnome.org/show_bug.cgi?id=734915
+ gtk_widget_show_all (comboBoxEntry);
+
+ // Optionally add formatting...
+ if( ink_comboboxentry_action->cell_data_func != NULL ) {
+ GtkCellRenderer *cell = gtk_cell_renderer_text_new();
+ gtk_cell_layout_clear( GTK_CELL_LAYOUT( comboBoxEntry ) );
+ gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( comboBoxEntry ), cell, true );
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT( comboBoxEntry ), cell,
+ GtkCellLayoutDataFunc (ink_comboboxentry_action->cell_data_func),
+ NULL, NULL );
+ }
+
+ // Optionally widen the combobox width... which widens the drop-down list in list mode.
+ if( ink_comboboxentry_action->extra_width > 0 ) {
+ GtkRequisition req;
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_get_preferred_size(GTK_WIDGET(ink_comboboxentry_action->combobox), &req, NULL);
+#else
+ gtk_widget_size_request( GTK_WIDGET( ink_comboboxentry_action->combobox ), &req );
+#endif
+ gtk_widget_set_size_request( GTK_WIDGET( ink_comboboxentry_action->combobox ),
+ req.width + ink_comboboxentry_action->extra_width, -1 );
+ }
+
+ // Get reference to GtkEntry and fiddle a bit with it.
+ GtkWidget *child = gtk_bin_get_child( GTK_BIN(comboBoxEntry) );
+
+ // Name it so we can muck with it using an RC file
+ gtk_widget_set_name( child, entry_name );
+ g_free( entry_name );
+
+ if( child && GTK_IS_ENTRY( child ) ) {
+
+ ink_comboboxentry_action->entry = GTK_ENTRY(child);
+
+ // Change width
+ if( ink_comboboxentry_action->entry_width > 0 ) {
+ gtk_entry_set_width_chars (GTK_ENTRY (child), ink_comboboxentry_action->entry_width );
+ }
+
+ // Add pop-up entry completion if required
+ if( ink_comboboxentry_action->popup ) {
+ ink_comboboxentry_action_popup_enable( ink_comboboxentry_action );
+ }
+
+ // Add altx_name if required
+ if( ink_comboboxentry_action->altx_name ) {
+ g_object_set_data( G_OBJECT( child ), ink_comboboxentry_action->altx_name, ink_comboboxentry_action->entry );
+ }
+
+ // Add signal for GtkEntry to check if finished typing.
+ g_signal_connect( G_OBJECT(child), "activate", G_CALLBACK(entry_activate_cb), action );
+ g_signal_connect( G_OBJECT(child), "key-press-event", G_CALLBACK(keypress_cb), action );
+ }
+
+ gtk_activatable_set_related_action( GTK_ACTIVATABLE (item), GTK_ACTION( action ) );
+ gtk_widget_show_all( item );
+
+ } else {
+
+ item = GTK_ACTION_CLASS(ink_comboboxentry_action_parent_class)->create_tool_item( action );
+
+ }
+
+ return item;
+}
+
+// Create a drop-down menu.
+GtkWidget* create_menu_item( GtkAction* action )
+{
+ GtkWidget* item = 0;
+
+ item = GTK_ACTION_CLASS(ink_comboboxentry_action_parent_class)->create_menu_item( action );
+ g_warning( "ink_comboboxentry_action: create_menu_item not implemented" );
+ // One can easily modify ege-select-one-action routine to implement this.
+ return item;
+}
+
+// Setters/Getters ---------------------------------------------------
+
+GtkTreeModel *ink_comboboxentry_action_get_model( Ink_ComboBoxEntry_Action* action ) {
+
+ return action->model;
+}
+
+GtkComboBox *ink_comboboxentry_action_get_comboboxentry( Ink_ComboBoxEntry_Action* action ) {
+
+ return action->combobox;
+}
+
+gchar* ink_comboboxentry_action_get_active_text( Ink_ComboBoxEntry_Action* action ) {
+
+ gchar* text = g_strdup( action->text );
+ return text;
+}
+
+/*
+ * For the font-family list we need to handle two cases:
+ * Text is in list store:
+ * In this case we use row number as the font-family list can have duplicate
+ * entries, one in the document font part and one in the system font part. In
+ * order that scrolling through the list works properly we must distinguish
+ * between the two.
+ * Text is not in the list store (i.e. default font-family is not on system):
+ * In this case we have a row number of -1, and the text must be set by hand.
+ */
+gboolean ink_comboboxentry_action_set_active_text( Ink_ComboBoxEntry_Action* action, const gchar* text, int row ) {
+
+ if( strcmp( action->text, text ) != 0 ) {
+ g_free( action->text );
+ action->text = g_strdup( text );
+ }
+
+ // Get active row or -1 if none
+ if( row < 0 ) {
+ row = get_active_row_from_text( action, action->text );
+ }
+ action->active = row;
+
+ // Set active row, check that combobox has been created.
+ if( action->combobox ) {
+ gtk_combo_box_set_active( GTK_COMBO_BOX( action->combobox ), action->active );
+ }
+
+ // Fiddle with entry
+ if( action->entry ) {
+
+ // Explicitly set text in GtkEntry box (won't be set if text not in list).
+ gtk_entry_set_text( action->entry, text );
+
+ // Show or hide warning -- this might be better moved to text-toolbox.cpp
+ if( action->info_cb_id != 0 &&
+ !action->info_cb_blocked ) {
+ g_signal_handler_block (G_OBJECT(action->entry),
+ action->info_cb_id );
+ action->info_cb_blocked = true;
+ }
+ if( action->warning_cb_id != 0 &&
+ !action->warning_cb_blocked ) {
+ g_signal_handler_block (G_OBJECT(action->entry),
+ action->warning_cb_id );
+ action->warning_cb_blocked = true;
+ }
+
+ bool set = false;
+ if( action->warning != NULL ) {
+ Glib::ustring missing = check_comma_separated_text( action );
+ if( !missing.empty() ) {
+ gtk_entry_set_icon_from_icon_name( action->entry,
+ GTK_ENTRY_ICON_SECONDARY,
+ INKSCAPE_ICON("dialog-warning") );
+ // Can't add tooltip until icon set
+ Glib::ustring warning = action->warning;
+ warning += ": ";
+ warning += missing;
+ gtk_entry_set_icon_tooltip_text( action->entry,
+ GTK_ENTRY_ICON_SECONDARY,
+ warning.c_str() );
+
+ if( action->warning_cb ) {
+
+ // Add callback if we haven't already
+ if( action->warning_cb_id == 0 ) {
+ action->warning_cb_id =
+ g_signal_connect( G_OBJECT(action->entry),
+ "icon-press",
+ G_CALLBACK(action->warning_cb),
+ action);
+ }
+ // Unblock signal
+ if( action->warning_cb_blocked ) {
+ g_signal_handler_unblock (G_OBJECT(action->entry),
+ action->warning_cb_id );
+ action->warning_cb_blocked = false;
+ }
+ }
+ set = true;
+ }
+ }
+
+ if( !set && action->info != NULL ) {
+ gtk_entry_set_icon_from_icon_name( GTK_ENTRY(action->entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ INKSCAPE_ICON("edit-select-all") );
+ gtk_entry_set_icon_tooltip_text( action->entry,
+ GTK_ENTRY_ICON_SECONDARY,
+ action->info );
+
+ if( action->info_cb ) {
+ // Add callback if we haven't already
+ if( action->info_cb_id == 0 ) {
+ action->info_cb_id =
+ g_signal_connect( G_OBJECT(action->entry),
+ "icon-press",
+ G_CALLBACK(action->info_cb),
+ action);
+ }
+ // Unblock signal
+ if( action->info_cb_blocked ) {
+ g_signal_handler_unblock (G_OBJECT(action->entry),
+ action->info_cb_id );
+ action->info_cb_blocked = false;
+ }
+ }
+ set = true;
+ }
+
+ if( !set ) {
+ gtk_entry_set_icon_from_icon_name( GTK_ENTRY(action->entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ NULL );
+ }
+ }
+
+ // Return if active text in list
+ gboolean found = ( action->active != -1 );
+ return found;
+}
+
+void ink_comboboxentry_action_set_entry_width( Ink_ComboBoxEntry_Action* action, gint entry_width ) {
+
+ action->entry_width = entry_width;
+
+ // Widget may not have been created....
+ if( action->entry ) {
+ gtk_entry_set_width_chars( GTK_ENTRY(action->entry), entry_width );
+ }
+}
+
+void ink_comboboxentry_action_set_extra_width( Ink_ComboBoxEntry_Action* action, gint extra_width ) {
+
+ action->extra_width = extra_width;
+
+ // Widget may not have been created....
+ if( action->combobox ) {
+ GtkRequisition req;
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_get_preferred_size(GTK_WIDGET(action->combobox), &req, NULL);
+#else
+ gtk_widget_size_request( GTK_WIDGET( action->combobox ), &req );
+#endif
+ gtk_widget_set_size_request( GTK_WIDGET( action->combobox ), req.width + action->extra_width, -1 );
+ }
+}
+
+void ink_comboboxentry_action_popup_enable( Ink_ComboBoxEntry_Action* action ) {
+
+ action->popup = true;
+
+ // Widget may not have been created....
+ if( action->entry ) {
+
+ // Check we don't already have a GtkEntryCompletion
+ if( action->entry_completion ) return;
+
+ action->entry_completion = gtk_entry_completion_new();
+
+ gtk_entry_set_completion( action->entry, action->entry_completion );
+ gtk_entry_completion_set_model( action->entry_completion, action->model );
+ gtk_entry_completion_set_text_column( action->entry_completion, 0 );
+ gtk_entry_completion_set_popup_completion( action->entry_completion, true );
+ gtk_entry_completion_set_inline_completion( action->entry_completion, false );
+ gtk_entry_completion_set_inline_selection( action->entry_completion, true );
+
+ g_signal_connect (G_OBJECT (action->entry_completion), "match-selected", G_CALLBACK (match_selected_cb), action );
+
+
+ }
+}
+
+void ink_comboboxentry_action_popup_disable( Ink_ComboBoxEntry_Action* action ) {
+
+ action->popup = false;
+
+ if( action->entry_completion ) {
+ gtk_widget_destroy(GTK_WIDGET(action->entry_completion));
+ action->entry_completion = 0;
+ }
+}
+void ink_comboboxentry_action_set_tooltip( Ink_ComboBoxEntry_Action* action, const gchar* tooltip ) {
+
+ // Widget may not have been created....
+ if( action->entry ) {
+ gtk_widget_set_tooltip_text ( GTK_WIDGET(action->entry), tooltip);
+ }
+ if( action->combobox ) {
+ gtk_widget_set_tooltip_text ( GTK_WIDGET(action->combobox), tooltip);
+ }
+
+}
+
+void ink_comboboxentry_action_set_info( Ink_ComboBoxEntry_Action* action, const gchar* info ) {
+
+ g_free( action->info );
+ action->info = g_strdup( info );
+
+ // Widget may not have been created....
+ if( action->entry ) {
+ gtk_entry_set_icon_tooltip_text( GTK_ENTRY(action->entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ action->info );
+ }
+}
+
+void ink_comboboxentry_action_set_info_cb( Ink_ComboBoxEntry_Action* action, gpointer info_cb ) {
+
+ action->info_cb = info_cb;
+}
+
+void ink_comboboxentry_action_set_warning( Ink_ComboBoxEntry_Action* action, const gchar* warning ) {
+
+ g_free( action->warning );
+ action->warning = g_strdup( warning );
+
+ // Widget may not have been created....
+ if( action->entry ) {
+ gtk_entry_set_icon_tooltip_text( GTK_ENTRY(action->entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ action->warning );
+ }
+}
+
+void ink_comboboxentry_action_set_warning_cb( Ink_ComboBoxEntry_Action* action, gpointer warning_cb ) {
+
+ action->warning_cb = warning_cb;
+}
+
+void ink_comboboxentry_action_set_altx_name( Ink_ComboBoxEntry_Action* action, const gchar* altx_name ) {
+
+ g_free( action->altx_name );
+ action->altx_name = g_strdup( altx_name );
+
+ // Widget may not have been created....
+ if( action->entry ) {
+ g_object_set_data( G_OBJECT(action->entry), action->altx_name, action->entry );
+ }
+}
+
+// Internal ---------------------------------------------------
+
+// Return row of active text or -1 if not found. If exclude is true,
+// use 3d colunm if available to exclude row from checking (useful to
+// skip rows added for font-families included in doc and not on
+// system)
+gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text,
+ gboolean exclude, gboolean ignore_case ) {
+
+ // Check if text in list
+ gint row = 0;
+ gboolean found = false;
+ GtkTreeIter iter;
+ gboolean valid = gtk_tree_model_get_iter_first( action->model, &iter );
+ while ( valid ) {
+
+ // See if we should exclude a row
+ gboolean check = true; // If true, font-family is on system.
+ if( exclude && gtk_tree_model_get_n_columns( action->model ) > 2 ) {
+ gtk_tree_model_get( action->model, &iter, 2, &check, -1 );
+ }
+
+ if( check ) {
+ // Get text from list entry
+ gchar* text = 0;
+ gtk_tree_model_get( action->model, &iter, 0, &text, -1 ); // Column 0
+
+ if( !ignore_case ) {
+ // Case sensitive compare
+ if( strcmp( target_text, text ) == 0 ){
+ found = true;
+ break;
+ }
+ } else {
+ // Case insensitive compare
+ gchar* target_text_casefolded = g_utf8_casefold( target_text, -1 );
+ gchar* text_casefolded = g_utf8_casefold( text, -1 );
+ gboolean equal = (strcmp( target_text_casefolded, text_casefolded ) == 0 );
+ g_free( text_casefolded );
+ g_free( target_text_casefolded );
+ if( equal ) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ ++row;
+ valid = gtk_tree_model_iter_next( action->model, &iter );
+ }
+
+ if( !found ) row = -1;
+
+ return row;
+
+}
+
+// Checks if all comma separated text fragments are in the list and
+// returns a ustring with a list of missing fragments.
+// This is useful for checking if all fonts in a font-family fallback
+// list are available on the system.
+//
+// This routine could also create a Pango Markup string to show which
+// fragments are invalid in the entry box itself. See:
+// http://developer.gnome.org/pango/stable/PangoMarkupFormat.html
+// However... it appears that while one can retrieve the PangoLayout
+// for a GtkEntry box, it is only a copy and changing it has no effect.
+// PangoLayout * pl = gtk_entry_get_layout( entry );
+// pango_layout_set_markup( pl, "NEW STRING", -1 ); // DOESN'T WORK
+static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* action ) {
+
+ Glib::ustring missing;
+
+ // Parse fallback_list using a comma as deliminator
+ gchar** tokens = g_strsplit( action->text, ",", 0 );
+
+ gint i = 0;
+ while( tokens[i] != NULL ) {
+
+ // Remove any surrounding white space.
+ g_strstrip( tokens[i] );
+
+ if( get_active_row_from_text( action, tokens[i], true, true ) == -1 ) {
+ missing += tokens[i];
+ missing += ", ";
+ }
+ ++i;
+ }
+ g_strfreev( tokens );
+
+ // Remove extra comma and space from end.
+ if( missing.size() >= 2 ) {
+ missing.resize( missing.size()-2 );
+ }
+ return missing;
+}
+
+// Callbacks ---------------------------------------------------
+
+static void combo_box_changed_cb( GtkComboBox* widget, gpointer data ) {
+
+ // Two things can happen to get here:
+ // An item is selected in the drop-down menu.
+ // Text is typed.
+ // We only react here if an item is selected.
+
+ // Get action
+ Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION( data );
+
+ // Check if item selected:
+ gint newActive = gtk_combo_box_get_active(widget);
+ if( newActive >= 0 && newActive != action->active ) {
+
+ action->active = newActive;
+
+ GtkTreeIter iter;
+ if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX( action->combobox ), &iter ) ) {
+
+ gchar* text = 0;
+ gtk_tree_model_get( action->model, &iter, 0, &text, -1 );
+ gtk_entry_set_text( action->entry, text );
+
+ g_free( action->text );
+ action->text = text;
+ }
+
+ // Now let the world know
+ g_signal_emit( G_OBJECT(action), signals[CHANGED], 0 );
+ }
+}
+
+static void entry_activate_cb( GtkEntry* widget, gpointer data ) {
+
+ // Get text from entry box.. check if it matches a menu entry.
+
+ // Get action
+ Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION( data );
+
+ // Get text
+ g_free( action->text );
+ action->text = g_strdup( gtk_entry_get_text( widget ) );
+
+ // Get row
+ action->active =
+ get_active_row_from_text( action, action->text );
+
+ // Set active row
+ gtk_combo_box_set_active( GTK_COMBO_BOX( action->combobox), action->active );
+
+ // Now let the world know
+ g_signal_emit( G_OBJECT(action), signals[CHANGED], 0 );
+
+}
+
+static gboolean match_selected_cb( GtkEntryCompletion* /*widget*/, GtkTreeModel* model, GtkTreeIter* iter, gpointer data )
+{
+ // Get action
+ Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION( data );
+ GtkEntry *entry = action->entry;
+
+ if( entry) {
+ gchar *family = 0;
+ gtk_tree_model_get(model, iter, 0, &family, -1);
+
+ // Set text in GtkEntry
+ gtk_entry_set_text (GTK_ENTRY (entry), family );
+
+ // Set text in GtkAction
+ g_free( action->text );
+ action->text = family;
+
+ // Get row
+ action->active =
+ get_active_row_from_text( action, action->text );
+
+ // Set active row
+ gtk_combo_box_set_active( GTK_COMBO_BOX( action->combobox), action->active );
+
+ // Now let the world know
+ g_signal_emit( G_OBJECT(action), signals[CHANGED], 0 );
+
+ return true;
+ }
+ return false;
+}
+
+static void ink_comboboxentry_action_defocus( Ink_ComboBoxEntry_Action* action )
+{
+ if ( action->focusWidget ) {
+ gtk_widget_grab_focus( action->focusWidget );
+ }
+}
+
+gboolean keypress_cb( GtkWidget * /*widget*/, GdkEventKey *event, gpointer data )
+{
+ gboolean wasConsumed = FALSE; /* default to report event not consumed */
+ guint key = 0;
+ Ink_ComboBoxEntry_Action* action = INK_COMBOBOXENTRY_ACTION( data );
+ gdk_keymap_translate_keyboard_state( gdk_keymap_get_for_display( gdk_display_get_default() ),
+ event->hardware_keycode, (GdkModifierType)event->state,
+ 0, &key, 0, 0, 0 );
+
+ switch ( key ) {
+
+ // TODO Add bindings for Tab/LeftTab
+ case GDK_KEY_Escape:
+ {
+ //gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal );
+ ink_comboboxentry_action_defocus( action );
+ wasConsumed = TRUE;
+ }
+ break;
+
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ {
+ ink_comboboxentry_action_defocus( action );
+ //wasConsumed = TRUE;
+ }
+ break;
+
+
+ }
+
+ return wasConsumed;
+}
diff --git a/src/widgets/ink-comboboxentry-action.h b/src/widgets/ink-comboboxentry-action.h
new file mode 100644
index 000000000..04b66e8fe
--- /dev/null
+++ b/src/widgets/ink-comboboxentry-action.h
@@ -0,0 +1,106 @@
+/*
+ * A subclass of GtkAction that wraps a GtkComboBoxEntry.
+ * Features:
+ * Setting GtkEntryBox width in characters.
+ * Passing a function for formatting cells.
+ * Displaying a warning if text isn't in list.
+ * Setting names for GtkComboBoxEntry and GtkEntry (actionName_combobox, actionName_entry)
+ * to allow setting resources.
+ *
+ * Author(s):
+ * Tavmjong Bah
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Copyright (C) 2010 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INK_COMBOBOXENTRY_ACTION
+#define SEEN_INK_COMBOBOXENTRY_ACTION
+
+#include <gtk/gtk.h>
+
+#define INK_COMBOBOXENTRY_TYPE_ACTION (ink_comboboxentry_action_get_type())
+#define INK_COMBOBOXENTRY_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INK_COMBOBOXENTRY_TYPE_ACTION, Ink_ComboBoxEntry_Action))
+#define INK_COMBOBOXENTRY_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INK_COMBOBOXENTRY_TYPE_ACTION, Ink_ComboBoxEntry_ActionClass))
+#define INK_COMBOBOXENTRY_IS_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INK_COMBOBOXENTRY_TYPE_ACTION))
+#define INK_COMBOBOXENTRY_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INK_COMBOBOXENTRY_TYPE_ACTION, Ink_ComboBoxEntry_ActionClass))
+
+typedef struct _Ink_ComboBoxEntry_ActionClass Ink_ComboBoxEntry_ActionClass;
+typedef struct _Ink_ComboBoxEntry_Action Ink_ComboBoxEntry_Action;
+
+struct _Ink_ComboBoxEntry_ActionClass {
+ GtkActionClass parent_class;
+
+ void (*changed) (Ink_ComboBoxEntry_Action* action);
+ void (*activated) (Ink_ComboBoxEntry_Action* action);
+};
+
+struct _Ink_ComboBoxEntry_Action {
+ GtkAction parent_instance;
+
+ GtkTreeModel *model;
+ GtkComboBox *combobox;
+ GtkEntry *entry;
+ GtkEntryCompletion *entry_completion;
+ GtkWidget *indicator;
+
+ gpointer cell_data_func; // drop-down menu format
+ gpointer separator_func;
+
+ gint active; // Index of active menu item (-1 if not in list).
+ gchar *text; // Text of active menu item or entry box.
+ gint entry_width;// Width of GtkEntry in characters.
+ gint extra_width;// Extra Width of GtkComboBox.. to widen drop-down list in list mode.
+ gboolean popup; // Do we pop-up an entry-completion dialog?
+ gchar *info; // Text for tooltip info about entry.
+ gpointer info_cb; // Callback for clicking info icon.
+ gint info_cb_id;
+ gboolean info_cb_blocked;
+ gchar *warning; // Text for tooltip warning that entry isn't in list.
+ gpointer warning_cb; // Callback for clicking warning icon.
+ gint warning_cb_id;
+ gboolean warning_cb_blocked;
+ gchar *altx_name; // Target for Alt-X keyboard shortcut.
+ GtkWidget *focusWidget;
+};
+
+
+GType ink_comboboxentry_action_get_type (void);
+
+/**
+ * Creates a GtkAction subclass that wraps a GtkComboBoxEntry object.
+ */
+Ink_ComboBoxEntry_Action *ink_comboboxentry_action_new ( const gchar *name,
+ const gchar *label,
+ const gchar *tooltip,
+ const gchar *stock_id,
+ GtkTreeModel *model,
+ gint entry_width = -1,
+ gint extra_width = -1,
+ gpointer cell_data_func = NULL,
+ gpointer separator_func = NULL,
+ GtkWidget* focusWidget = NULL);
+
+GtkTreeModel *ink_comboboxentry_action_get_model( Ink_ComboBoxEntry_Action* action );
+GtkComboBox *ink_comboboxentry_action_get_comboboxentry( Ink_ComboBoxEntry_Action* action );
+
+gchar* ink_comboboxentry_action_get_active_text( Ink_ComboBoxEntry_Action* action );
+gboolean ink_comboboxentry_action_set_active_text( Ink_ComboBoxEntry_Action* action, const gchar* text, int row=-1 );
+
+void ink_comboboxentry_action_set_entry_width( Ink_ComboBoxEntry_Action* action, gint entry_width );
+void ink_comboboxentry_action_set_extra_width( Ink_ComboBoxEntry_Action* action, gint extra_width );
+
+void ink_comboboxentry_action_popup_enable( Ink_ComboBoxEntry_Action* action );
+void ink_comboboxentry_action_popup_disable( Ink_ComboBoxEntry_Action* action );
+
+void ink_comboboxentry_action_set_info( Ink_ComboBoxEntry_Action* action, const gchar* info );
+void ink_comboboxentry_action_set_info_cb( Ink_ComboBoxEntry_Action* action, gpointer info_cb );
+void ink_comboboxentry_action_set_warning( Ink_ComboBoxEntry_Action* action, const gchar* warning_cb );
+void ink_comboboxentry_action_set_warning_cb(Ink_ComboBoxEntry_Action* action, gpointer warning );
+void ink_comboboxentry_action_set_tooltip( Ink_ComboBoxEntry_Action* action, const gchar* tooltip );
+
+void ink_comboboxentry_action_set_altx_name( Ink_ComboBoxEntry_Action* action, const gchar* altx_name );
+
+#endif /* SEEN_INK_COMBOBOXENTRY_ACTION */
diff --git a/src/widgets/lpe-toolbar.cpp b/src/widgets/lpe-toolbar.cpp
index 7ad88b856..a85f3ae78 100644
--- a/src/widgets/lpe-toolbar.cpp
+++ b/src/widgets/lpe-toolbar.cpp
@@ -33,15 +33,15 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-select-one-action.h"
+#include "widgets/ege-select-one-action.h"
#include "helper/action-context.h"
#include "helper/action.h"
-#include "ink-action.h"
+#include "widgets/ink-action.h"
#include "live_effects/effect.h"
#include "preferences.h"
#include "selection.h"
#include "sp-namedview.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "ui/tools/lpe-tool.h"
#include "ui/widget/unit-tracker.h"
#include "util/units.h"
diff --git a/src/widgets/measure-toolbar.cpp b/src/widgets/measure-toolbar.cpp
index 46d3bd4e0..1a4678332 100644
--- a/src/widgets/measure-toolbar.cpp
+++ b/src/widgets/measure-toolbar.cpp
@@ -34,8 +34,8 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-output-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
#include "preferences.h"
#include "toolbox.h"
#include "ui/widget/unit-tracker.h"
diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp
index 73e450926..897d84278 100644
--- a/src/widgets/mesh-toolbar.cpp
+++ b/src/widgets/mesh-toolbar.cpp
@@ -50,11 +50,11 @@
#include "selection.h"
#include "ui/icon-names.h"
-#include "ege-adjustment-action.h"
-#include "ege-output-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
-#include "ink-comboboxentry-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
+#include "widgets/ink-comboboxentry-action.h"
#include "sp-stop.h"
#include "svg/css-ostringstream.h"
diff --git a/src/widgets/node-toolbar.cpp b/src/widgets/node-toolbar.cpp
index ace78f8f5..467325d08 100644
--- a/src/widgets/node-toolbar.cpp
+++ b/src/widgets/node-toolbar.cpp
@@ -34,8 +34,8 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ink-action.h"
#include "inkscape.h"
#include "preferences.h"
#include "selection-chemistry.h"
@@ -270,7 +270,7 @@ static void sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, Geom::D
}
// quit if run by the attr_changed listener
- if (g_object_get_data( tbl, "freeze" )) {
+ if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) {
return;
}
diff --git a/src/widgets/paintbucket-toolbar.cpp b/src/widgets/paintbucket-toolbar.cpp
index 8ddaccf64..d8edeb9f6 100644
--- a/src/widgets/paintbucket-toolbar.cpp
+++ b/src/widgets/paintbucket-toolbar.cpp
@@ -33,8 +33,8 @@
#include "paintbucket-toolbar.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-select-one-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-select-one-action.h"
#include "preferences.h"
#include "toolbox.h"
#include "ui/icon-names.h"
diff --git a/src/widgets/pencil-toolbar.cpp b/src/widgets/pencil-toolbar.cpp
index cf09a4d34..1214a378a 100644
--- a/src/widgets/pencil-toolbar.cpp
+++ b/src/widgets/pencil-toolbar.cpp
@@ -33,12 +33,12 @@
#include "pencil-toolbar.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
#include "preferences.h"
#include "toolbox.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "ui/icon-names.h"
#include "ui/tools/pen-tool.h"
#include "ui/uxmanager.h"
@@ -157,7 +157,7 @@ static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge)
static GList * freehand_shape_dropdown_items_list() {
GList *glist = NULL;
- glist = g_list_append (glist, _("None"));
+ glist = g_list_append (glist, const_cast<gchar *>(C_("Freehand shape", "None")));
glist = g_list_append (glist, _("Triangle in"));
glist = g_list_append (glist, _("Triangle out"));
glist = g_list_append (glist, _("Ellipse"));
diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp
index 48808fe70..e1ce01eaf 100644
--- a/src/widgets/rect-toolbar.cpp
+++ b/src/widgets/rect-toolbar.cpp
@@ -34,9 +34,9 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-output-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ink-action.h"
#include "inkscape.h"
#include "preferences.h"
#include "selection.h"
@@ -97,7 +97,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *
}
// quit if run by the attr_changed listener
- if (g_object_get_data( tbl, "freeze" )) {
+ if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) {
return;
}
diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp
index 18976b329..5f107c5a8 100644
--- a/src/widgets/select-toolbar.cpp
+++ b/src/widgets/select-toolbar.cpp
@@ -26,10 +26,10 @@
#include "display/sp-canvas.h"
#include "document-undo.h"
#include "document.h"
-#include "ege-adjustment-action.h"
+#include "widgets/ege-adjustment-action.h"
#include "helper/action-context.h"
#include "helper/action.h"
-#include "ink-action.h"
+#include "widgets/ink-action.h"
#include "inkscape.h"
#include "message-stack.h"
#include "preferences.h"
diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp
index 87cb7cae3..c7fa96efd 100644
--- a/src/widgets/sp-color-notebook.cpp
+++ b/src/widgets/sp-color-notebook.cpp
@@ -38,7 +38,7 @@
#include "../profile-manager.h"
#include "color-profile.h"
#include "cms-system.h"
-#include "tools-switch.h"
+#include "ui/tools-switch.h"
#include "ui/tools/tool-base.h"
using Inkscape::CMSSystem;
diff --git a/src/widgets/sp-widget.h b/src/widgets/sp-widget.h
index 9a1a93a45..a53062cf4 100644
--- a/src/widgets/sp-widget.h
+++ b/src/widgets/sp-widget.h
@@ -24,12 +24,10 @@
#define SP_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_WIDGET))
#define SP_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_WIDGET))
-
namespace Inkscape {
class Selection;
class SPWidgetImpl;
-
}
struct SPWidget {
diff --git a/src/widgets/spiral-toolbar.cpp b/src/widgets/spiral-toolbar.cpp
index 710be9440..e85b024ed 100644
--- a/src/widgets/spiral-toolbar.cpp
+++ b/src/widgets/spiral-toolbar.cpp
@@ -34,9 +34,9 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-output-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ink-action.h"
#include "preferences.h"
#include "selection.h"
#include "sp-spiral.h"
diff --git a/src/widgets/spray-toolbar.cpp b/src/widgets/spray-toolbar.cpp
index 788ce6475..183814b7e 100644
--- a/src/widgets/spray-toolbar.cpp
+++ b/src/widgets/spray-toolbar.cpp
@@ -33,9 +33,9 @@
#include "spray-toolbar.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
#include "preferences.h"
#include "toolbox.h"
#include "ui/icon-names.h"
diff --git a/src/widgets/star-toolbar.cpp b/src/widgets/star-toolbar.cpp
index 0f8c31be8..6213263fc 100644
--- a/src/widgets/star-toolbar.cpp
+++ b/src/widgets/star-toolbar.cpp
@@ -34,10 +34,10 @@
#include "desktop-handles.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-output-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
#include "selection.h"
#include "sp-star.h"
#include "toolbox.h"
diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp
index 9572f6426..24288299f 100644
--- a/src/widgets/stroke-marker-selector.cpp
+++ b/src/widgets/stroke-marker-selector.cpp
@@ -31,7 +31,7 @@
#include "preferences.h"
#include "path-prefix.h"
#include "io/sys.h"
-#include "marker.h"
+#include "sp-marker.h"
#include "sp-defs.h"
#include "sp-root.h"
#include "ui/cache/svg_preview_cache.h"
@@ -385,7 +385,7 @@ void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source, gbool
if (history) {
// add "None"
Gtk::TreeModel::Row row = *(marker_store->prepend());
- row[marker_columns.label] = _("None");
+ row[marker_columns.label] = C_("Marker", "None");
row[marker_columns.stock] = false;
row[marker_columns.marker] = g_strdup("None");
row[marker_columns.image] = NULL;
diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h
index 464e7d2d1..15e394097 100644
--- a/src/widgets/stroke-style.h
+++ b/src/widgets/stroke-style.h
@@ -44,7 +44,7 @@
#include "helper/stock-items.h"
#include "inkscape.h"
#include "io/sys.h"
-#include "marker.h"
+#include "sp-marker.h"
#include "preferences.h"
#include "path-prefix.h"
#include "selection.h"
diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp
index 88f698bc4..d62bb8027 100644
--- a/src/widgets/text-toolbar.cpp
+++ b/src/widgets/text-toolbar.cpp
@@ -36,10 +36,10 @@
#include "desktop.h"
#include "document-undo.h"
#include "document.h"
-#include "ege-adjustment-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
-#include "ink-comboboxentry-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
+#include "widgets/ink-comboboxentry-action.h"
#include "inkscape.h"
#include "preferences.h"
#include "selection-chemistry.h"
diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp
index 939546f78..9e55d1cf6 100644
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
@@ -43,20 +43,20 @@
#include "../desktop-handles.h"
#include "../desktop-style.h"
#include "document-undo.h"
-#include "../ege-adjustment-action.h"
-#include "../ege-output-action.h"
-#include "../ege-select-one-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ege-select-one-action.h"
#include "../graphlayout.h"
#include "../helper/action.h"
#include "../helper/action-context.h"
#include "icon.h"
-#include "../ink-action.h"
-#include "../ink-comboboxentry-action.h"
+#include "ink-action.h"
+#include "ink-comboboxentry-action.h"
#include "../inkscape.h"
-#include "../interface.h"
+#include "ui/interface.h"
#include "../shortcuts.h"
#include "../sp-namedview.h"
-#include "../tools-switch.h"
+#include "ui/tools-switch.h"
#include "../ui/icon-names.h"
#include "../ui/widget/style-swatch.h"
#include "../verbs.h"
diff --git a/src/widgets/tweak-toolbar.cpp b/src/widgets/tweak-toolbar.cpp
index 050d7fb5e..a5d90fc3d 100644
--- a/src/widgets/tweak-toolbar.cpp
+++ b/src/widgets/tweak-toolbar.cpp
@@ -33,10 +33,10 @@
#include "tweak-toolbar.h"
#include "desktop.h"
#include "document-undo.h"
-#include "ege-adjustment-action.h"
-#include "ege-output-action.h"
-#include "ege-select-one-action.h"
-#include "ink-action.h"
+#include "widgets/ege-adjustment-action.h"
+#include "widgets/ege-output-action.h"
+#include "widgets/ege-select-one-action.h"
+#include "widgets/ink-action.h"
#include "preferences.h"
#include "toolbox.h"
#include "ui/icon-names.h"