From 59c5c3e7575768faa00dd7d9fde9eca6d8815aab Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sun, 5 Oct 2014 14:14:01 -0400 Subject: Move GtkAction subclasses to widgets/ (bzr r13341.1.249) --- src/Makefile_insert | 7 - src/ege-adjustment-action.cpp | 1113 ---------------------------- src/ege-adjustment-action.h | 192 ----- src/ege-output-action.cpp | 245 ------- src/ege-output-action.h | 120 ---- src/ege-select-one-action.cpp | 1153 ------------------------------ src/ege-select-one-action.h | 245 ------- src/ink-action.cpp | 638 ----------------- src/ink-action.h | 159 ---- src/ink-comboboxentry-action.cpp | 958 ------------------------- src/ink-comboboxentry-action.h | 106 --- src/ui/widget/unit-tracker.cpp | 2 +- src/widgets/Makefile_insert | 10 + src/widgets/arc-toolbar.cpp | 8 +- src/widgets/box3d-toolbar.cpp | 4 +- src/widgets/calligraphy-toolbar.cpp | 6 +- src/widgets/connector-toolbar.cpp | 4 +- src/widgets/desktop-widget.cpp | 2 +- src/widgets/dropper-toolbar.cpp | 4 +- src/widgets/ege-adjustment-action.cpp | 1113 ++++++++++++++++++++++++++++ src/widgets/ege-adjustment-action.h | 192 +++++ src/widgets/ege-output-action.cpp | 245 +++++++ src/widgets/ege-output-action.h | 120 ++++ src/widgets/ege-select-one-action.cpp | 1153 ++++++++++++++++++++++++++++++ src/widgets/ege-select-one-action.h | 245 +++++++ src/widgets/eraser-toolbar.cpp | 6 +- src/widgets/gradient-toolbar.cpp | 6 +- src/widgets/ink-action.cpp | 638 +++++++++++++++++ src/widgets/ink-action.h | 159 ++++ src/widgets/ink-comboboxentry-action.cpp | 958 +++++++++++++++++++++++++ src/widgets/ink-comboboxentry-action.h | 106 +++ src/widgets/lpe-toolbar.cpp | 4 +- src/widgets/measure-toolbar.cpp | 4 +- src/widgets/mesh-toolbar.cpp | 10 +- src/widgets/node-toolbar.cpp | 4 +- src/widgets/paintbucket-toolbar.cpp | 4 +- src/widgets/pencil-toolbar.cpp | 6 +- src/widgets/rect-toolbar.cpp | 6 +- src/widgets/select-toolbar.cpp | 4 +- src/widgets/spiral-toolbar.cpp | 6 +- src/widgets/spray-toolbar.cpp | 6 +- src/widgets/star-toolbar.cpp | 8 +- src/widgets/text-toolbar.cpp | 8 +- src/widgets/toolbox.cpp | 10 +- src/widgets/tweak-toolbar.cpp | 8 +- 45 files changed, 5004 insertions(+), 5001 deletions(-) delete mode 100644 src/ege-adjustment-action.cpp delete mode 100644 src/ege-adjustment-action.h delete mode 100644 src/ege-output-action.cpp delete mode 100644 src/ege-output-action.h delete mode 100644 src/ege-select-one-action.cpp delete mode 100644 src/ege-select-one-action.h delete mode 100644 src/ink-action.cpp delete mode 100644 src/ink-action.h delete mode 100644 src/ink-comboboxentry-action.cpp delete mode 100644 src/ink-comboboxentry-action.h create mode 100644 src/widgets/ege-adjustment-action.cpp create mode 100644 src/widgets/ege-adjustment-action.h create mode 100644 src/widgets/ege-output-action.cpp create mode 100644 src/widgets/ege-output-action.h create mode 100644 src/widgets/ege-select-one-action.cpp create mode 100644 src/widgets/ege-select-one-action.h create mode 100644 src/widgets/ink-action.cpp create mode 100644 src/widgets/ink-action.h create mode 100644 src/widgets/ink-comboboxentry-action.cpp create mode 100644 src/widgets/ink-comboboxentry-action.h (limited to 'src') diff --git a/src/Makefile_insert b/src/Makefile_insert index f8f0ac122..762535cb5 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -38,10 +38,7 @@ ink_common_sources += \ document-undo.cpp document-undo.h \ doxygen-main.cpp \ draw-anchor.cpp draw-anchor.h \ - ege-adjustment-action.cpp ege-adjustment-action.h \ ege-color-prof-tracker.cpp ege-color-prof-tracker.h \ - ege-output-action.cpp ege-output-action.h \ - ege-select-one-action.cpp ege-select-one-action.h \ enums.h \ event-log.cpp event-log.h event.h \ extract-uri.cpp extract-uri.h \ @@ -67,10 +64,6 @@ ink_common_sources += \ helper/pixbuf-ops.h \ icon-size.h \ id-clash.cpp id-clash.h \ - ink-action.cpp \ - ink-action.h \ - ink-comboboxentry-action.cpp \ - ink-comboboxentry-action.h \ inkscape.cpp inkscape.h inkscape-private.h \ isinf.h \ knot.cpp knot.h \ diff --git a/src/ege-adjustment-action.cpp b/src/ege-adjustment-action.cpp deleted file mode 100644 index 9491468dc..000000000 --- a/src/ege-adjustment-action.cpp +++ /dev/null @@ -1,1113 +0,0 @@ -/* -*- 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 -#include - -#include "widgets/icon.h" -#include - -#include "icon-size.h" -#include "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/ege-adjustment-action.h b/src/ege-adjustment-action.h deleted file mode 100644 index 8cfaa3e52..000000000 --- a/src/ege-adjustment-action.h +++ /dev/null @@ -1,192 +0,0 @@ -#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 - -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/ege-output-action.cpp b/src/ege-output-action.cpp deleted file mode 100644 index 9a7d7e318..000000000 --- a/src/ege-output-action.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* -*- 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 - -#include - -#include "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/ege-output-action.h b/src/ege-output-action.h deleted file mode 100644 index 0f4e21805..000000000 --- a/src/ege-output-action.h +++ /dev/null @@ -1,120 +0,0 @@ -#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 - -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/ege-select-one-action.cpp b/src/ege-select-one-action.cpp deleted file mode 100644 index 3facf7242..000000000 --- a/src/ege-select-one-action.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -/* -*- 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 - -#include - -#include "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/ege-select-one-action.h b/src/ege-select-one-action.h deleted file mode 100644 index 0c5cecaa3..000000000 --- a/src/ege-select-one-action.h +++ /dev/null @@ -1,245 +0,0 @@ -#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 - -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/ink-action.cpp b/src/ink-action.cpp deleted file mode 100644 index dd1fe5484..000000000 --- a/src/ink-action.cpp +++ /dev/null @@ -1,638 +0,0 @@ -#include "widgets/icon.h" -#include "icon-size.h" -#include -#include - -#include "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/ink-action.h b/src/ink-action.h deleted file mode 100644 index ac5cb9873..000000000 --- a/src/ink-action.h +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef SEEN_INK_ACTION -#define SEEN_INK_ACTION - - -#include -#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/ink-comboboxentry-action.cpp b/src/ink-comboboxentry-action.cpp deleted file mode 100644 index 6ae2a8485..000000000 --- a/src/ink-comboboxentry-action.cpp +++ /dev/null @@ -1,958 +0,0 @@ -/* - * 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 - * - * 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 -#include -#include - -#include -#include - -#include "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/ink-comboboxentry-action.h b/src/ink-comboboxentry-action.h deleted file mode 100644 index 04b66e8fe..000000000 --- a/src/ink-comboboxentry-action.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 - * - * 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 - -#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/ui/widget/unit-tracker.cpp b/src/ui/widget/unit-tracker.cpp index 67eb1f48d..c6318db25 100644 --- a/src/ui/widget/unit-tracker.cpp +++ b/src/ui/widget/unit-tracker.cpp @@ -13,7 +13,7 @@ */ #include "unit-tracker.h" -#include "ege-select-one-action.h" +#include "widgets/ege-select-one-action.h" #define COLUMN_STRING 0 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 7629e8c24..41f440ccc 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/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 388d22e29..9c8dac7dc 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 #include "file.h" #include "helper/action.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 +#include + +#include "widgets/icon.h" +#include + +#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 + +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 + +#include + +#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 + +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 + +#include + +#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 + +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..3e358e522 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" 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 +#include + +#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 +#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 + * + * 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 +#include +#include + +#include +#include + +#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 + * + * 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 + +#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..485a4289d 100644 --- a/src/widgets/lpe-toolbar.cpp +++ b/src/widgets/lpe-toolbar.cpp @@ -33,10 +33,10 @@ #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" 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..49f9732e5 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" 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..c387d9f78 100644 --- a/src/widgets/pencil-toolbar.cpp +++ b/src/widgets/pencil-toolbar.cpp @@ -33,9 +33,9 @@ #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" diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 48808fe70..64090b7cf 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" diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp index d45fb7e4d..08a46354e 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/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/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 ba70c081e..45aa01dd1 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -43,15 +43,15 @@ #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 "ui/interface.h" #include "../shortcuts.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" -- cgit v1.2.3