Code

834b06b3b035b4f876e1fa0f6f0cd9faccb7f5fb
[inkscape.git] / src / ege-select-one-action.cpp
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  */
4 /* ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is EGE Select One Action.
18  *
19  * The Initial Developer of the Original Code is
20  * Jon A. Cruz.
21  * Portions created by the Initial Developer are Copyright (C) 2007
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either the GNU General Public License Version 2 or later (the "GPL"), or
28  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
40 /* Note: this file should be kept compilable as both .cpp and .c */
42 #include <string.h>
44 #include <gtk/gtkhbox.h>
45 #include <gtk/gtklabel.h>
46 #include <gtk/gtktoolitem.h>
47 #include <gtk/gtk.h>
48 #include <gtk/gtkcellrenderertext.h>
49 #include <gtk/gtkcellrendererpixbuf.h>
50 #include <gtk/gtkcelllayout.h>
51 #include <gtk/gtkradioaction.h>
52 #include <gtk/gtkradiomenuitem.h>
53 #include <gtk/gtktable.h>
55 #include "ege-select-one-action.h"
57 enum {
58     CHANGED = 0,
59     LAST_SIGNAL};
62 static void ege_select_one_action_class_init( EgeSelectOneActionClass* klass );
63 static void ege_select_one_action_init( EgeSelectOneAction* action );
64 static void ege_select_one_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
65 static void ege_select_one_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
67 static void resync_active( EgeSelectOneAction* act, gint active );
68 static void combo_changed_cb( GtkComboBox* widget, gpointer user_data );
69 static void menu_toggled_cb( GtkWidget* obj, gpointer data );
70 static void proxy_action_chagned_cb( GtkRadioAction* action, GtkRadioAction* current, gpointer user_data );
72 static GtkWidget* create_menu_item( GtkAction* action );
73 static GtkWidget* create_tool_item( GtkAction* action );
74 static void connect_proxy( GtkAction *action, GtkWidget *proxy );
75 static void disconnect_proxy( GtkAction *action, GtkWidget *proxy );
77 static GtkActionClass* gParentClass = 0;
78 static guint signals[LAST_SIGNAL] = {0};
79 static GQuark gDataName = 0;
82 enum {
83     APPEARANCE_UNKNOWN = -1,
84     APPEARANCE_NONE = 0,
85     APPEARANCE_FULL,    // label, then all choices represented by separate buttons
86     APPEARANCE_COMPACT, // label, then choices in a drop-down menu
87     APPEARANCE_MINIMAL, // no label, just choices in a drop-down menu
88 };
90 struct _EgeSelectOneActionPrivate
91 {
92     gint active;
93     gint labelColumn;
94     gint iconColumn;
95     gint tooltipColumn;
96     gint appearanceMode;
97     gint iconSize;
98     GType radioActionType;
99     GtkTreeModel* model;
100     gchar* iconProperty;
101     gchar* appearance;
102 };
104 #define EGE_SELECT_ONE_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_SELECT_ONE_ACTION_TYPE, EgeSelectOneActionPrivate ) )
106 enum {
107     PROP_MODEL = 1,
108     PROP_ACTIVE,
109     PROP_LABEL_COLUMN,
110     PROP_ICON_COLUMN,
111     PROP_TOOLTIP_COLUMN,
112     PROP_ICON_PROP,
113     PROP_ICON_SIZE,
114     PROP_APPEARANCE
115 };
117 GType ege_select_one_action_get_type( void )
119     static GType myType = 0;
120     if ( !myType ) {
121         static const GTypeInfo myInfo = {
122             sizeof( EgeSelectOneActionClass ),
123             NULL, /* base_init */
124             NULL, /* base_finalize */
125             (GClassInitFunc)ege_select_one_action_class_init,
126             NULL, /* class_finalize */
127             NULL, /* class_data */
128             sizeof( EgeSelectOneAction ),
129             0, /* n_preallocs */
130             (GInstanceInitFunc)ege_select_one_action_init,
131             NULL
132         };
134         myType = g_type_register_static( GTK_TYPE_ACTION, "EgeSelectOneAction", &myInfo, (GTypeFlags)0 );
135     }
137     return myType;
140 GtkTreeModel *ege_select_one_action_get_model(EgeSelectOneAction* action ){
141     return GTK_TREE_MODEL(action->private_data->model);
143 void ege_select_one_action_class_init( EgeSelectOneActionClass* klass )
145     if ( klass ) {
146         gParentClass = GTK_ACTION_CLASS( g_type_class_peek_parent( klass ) );
147         GObjectClass* objClass = G_OBJECT_CLASS( klass );
149         gDataName = g_quark_from_string("ege-select1-action");
151         objClass->get_property = ege_select_one_action_get_property;
152         objClass->set_property = ege_select_one_action_set_property;
154         klass->parent_class.create_menu_item = create_menu_item;
155         klass->parent_class.create_tool_item = create_tool_item;
156         klass->parent_class.connect_proxy = connect_proxy;
157         klass->parent_class.disconnect_proxy = disconnect_proxy;
159         g_object_class_install_property( objClass,
160                                          PROP_MODEL,
161                                          g_param_spec_object( "model",
162                                                               "Tree Model",
163                                                               "Tree model of possible items",
164                                                               GTK_TYPE_TREE_MODEL,
165                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
167         g_object_class_install_property( objClass,
168                                          PROP_ACTIVE,
169                                          g_param_spec_int( "active",
170                                                            "Active Selection",
171                                                            "The index of the selected item",
172                                                            0, 20, 0,
173                                                            (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
175         g_object_class_install_property( objClass,
176                                          PROP_LABEL_COLUMN,
177                                          g_param_spec_int( "label-column",
178                                                            "Display Column",
179                                                            "The column of the model that holds display strings",
180                                                            0, 20, 0,
181                                                            (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
183         g_object_class_install_property( objClass,
184                                          PROP_ICON_COLUMN,
185                                          g_param_spec_int( "icon-column",
186                                                            "Icon Column",
187                                                            "The column of the model that holds display icon name",
188                                                            -1, 20, -1,
189                                                            (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
191         g_object_class_install_property( objClass,
192                                          PROP_TOOLTIP_COLUMN,
193                                          g_param_spec_int( "tooltip-column",
194                                                            "Tooltip Column",
195                                                           "The column of the model that holds tooltip strings",
196                                                            -1, 20, -1,
197                                                            (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
199         g_object_class_install_property( objClass,
200                                          PROP_ICON_PROP,
201                                          g_param_spec_string( "icon-property",
202                                                               "Icon Property",
203                                                               "Target icon property",
204                                                               "",
205                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
207         g_object_class_install_property( objClass,
208                                          PROP_ICON_SIZE,
209                                          g_param_spec_int( "icon-size",
210                                                            "Icon Size",
211                                                           "Target icon size",
212                                                            -1, 20, -1,
213                                                            (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
215         g_object_class_install_property( objClass,
216                                          PROP_APPEARANCE,
217                                          g_param_spec_string( "appearance",
218                                                               "Appearance hint",
219                                                               "A hint for how to display",
220                                                               "",
221                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
223         signals[CHANGED] = g_signal_new( "changed",
224                                          G_TYPE_FROM_CLASS(klass),
225                                          G_SIGNAL_RUN_FIRST,
226                                          G_STRUCT_OFFSET(EgeSelectOneActionClass, changed),
227                                          NULL, NULL,
228                                          g_cclosure_marshal_VOID__VOID,
229                                          G_TYPE_NONE, 0);
231         g_type_class_add_private( klass, sizeof(EgeSelectOneActionClass) );
232     }
236 void ege_select_one_action_init( EgeSelectOneAction* action )
238     action->private_data = EGE_SELECT_ONE_ACTION_GET_PRIVATE( action );
239     action->private_data->active = 0;
240     action->private_data->labelColumn = 0;
241     action->private_data->iconColumn = -1;
242     action->private_data->tooltipColumn = -1;
243     action->private_data->appearanceMode = APPEARANCE_NONE;
244     action->private_data->radioActionType = 0;
245     action->private_data->model = 0;
246     action->private_data->iconProperty = g_strdup("stock-id");
247     action->private_data->iconSize = -1;
248     action->private_data->appearance = 0;
250 /*     g_signal_connect( action, "notify", G_CALLBACK( fixup_labels ), NULL ); */
253 EgeSelectOneAction* ege_select_one_action_new( const gchar *name,
254                                                const gchar *label,
255                                                const gchar *tooltip,
256                                                const gchar *stock_id,
257                                                GtkTreeModel* model )
259     GObject* obj = (GObject*)g_object_new( EGE_SELECT_ONE_ACTION_TYPE,
260                                            "name", name,
261                                            "label", label,
262                                            "tooltip", tooltip,
263                                            "stock_id", stock_id,
264                                            "model", model,
265                                            "active", 0,
266                                            "icon-property", "stock-id",
267                                            NULL );
269     EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
271     return action;
275 gint ege_select_one_action_get_active( EgeSelectOneAction* action )
277     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
278     return action->private_data->active;
281 gchar *ege_select_one_action_get_active_text( EgeSelectOneAction* action )
283     GtkTreeIter iter;
284     gchar *str = 0;
285     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
287     if ( gtk_tree_model_iter_nth_child( action->private_data->model, &iter, NULL, action->private_data->active ) ) {
288         gtk_tree_model_get( action->private_data->model, &iter,
289                             action->private_data->labelColumn, &str,
290                             -1 );
291     }
293     return str;
296 void ege_select_one_action_set_active( EgeSelectOneAction* action, gint val )
298     g_object_set( G_OBJECT(action), "active", val, NULL );
301 gint ege_select_one_action_get_label_column( EgeSelectOneAction* action )
303     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
304     return action->private_data->labelColumn;
307 void ege_select_one_action_set_label_column( EgeSelectOneAction* action, gint col )
309     g_object_set( G_OBJECT(action), "label-column", col, NULL );
312 gint ege_select_one_action_get_icon_column( EgeSelectOneAction* action )
314     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
315     return action->private_data->iconColumn;
318 void ege_select_one_action_set_icon_column( EgeSelectOneAction* action, gint col )
320     g_object_set( G_OBJECT(action), "icon-column", col, NULL );
323 gint ege_select_one_action_get_icon_size( EgeSelectOneAction* action )
325     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
326     return action->private_data->iconSize;
329 void ege_select_one_action_set_icon_size( EgeSelectOneAction* action, gint size )
331     g_object_set( G_OBJECT(action), "icon-size", size, NULL );
334 gint ege_select_one_action_get_tooltip_column( EgeSelectOneAction* action )
336     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
337     return action->private_data->tooltipColumn;
340 void ege_select_one_action_set_tooltip_column( EgeSelectOneAction* action, gint col )
342     g_object_set( G_OBJECT(action), "tooltip-column", col, NULL );
345 void ege_select_one_action_set_appearance( EgeSelectOneAction* action, gchar const* val )
347     g_object_set( G_OBJECT(action), "appearance", val, NULL );
350 void ege_select_one_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
352     EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
353     switch ( propId ) {
354         case PROP_MODEL:
355             g_value_set_object( value, action->private_data->model );
356             break;
358         case PROP_ACTIVE:
359             g_value_set_int( value, action->private_data->active );
360             break;
362         case PROP_LABEL_COLUMN:
363             g_value_set_int( value, action->private_data->labelColumn );
364             break;
366         case PROP_ICON_COLUMN:
367             g_value_set_int( value, action->private_data->iconColumn );
368             break;
370         case PROP_TOOLTIP_COLUMN:
371             g_value_set_int( value, action->private_data->tooltipColumn );
372             break;
374         case PROP_ICON_PROP:
375             g_value_set_string( value, action->private_data->iconProperty );
376             break;
378         case PROP_ICON_SIZE:
379             g_value_set_int( value, action->private_data->iconSize );
380             break;
382         case PROP_APPEARANCE:
383             g_value_set_string( value, action->private_data->appearance );
384             break;
386         default:
387             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
388     }
391 void ege_select_one_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
393     EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
394     switch ( propId ) {
395         case PROP_MODEL:
396         {
397             action->private_data->model = GTK_TREE_MODEL( g_value_get_object( value ) );
398         }
399         break;
401         case PROP_ACTIVE:
402         {
403             resync_active( action, g_value_get_int( value ) );
404         }
405         break;
407         case PROP_LABEL_COLUMN:
408         {
409             action->private_data->labelColumn = g_value_get_int( value );
410         }
411         break;
413         case PROP_ICON_COLUMN:
414         {
415             action->private_data->iconColumn = g_value_get_int( value );
416         }
417         break;
419         case PROP_TOOLTIP_COLUMN:
420         {
421             action->private_data->tooltipColumn = g_value_get_int( value );
422         }
423         break;
425         case PROP_ICON_PROP:
426         {
427             gchar* tmp = action->private_data->iconProperty;
428             gchar* newVal = g_value_dup_string( value );
429             action->private_data->iconProperty = newVal;
430             g_free( tmp );
431         }
432         break;
434         case PROP_ICON_SIZE:
435         {
436             action->private_data->iconSize = g_value_get_int( value );
437         }
438         break;
440         case PROP_APPEARANCE:
441         {
442             gchar* tmp = action->private_data->appearance;
443             gchar* newVal = g_value_dup_string( value );
444             action->private_data->appearance = newVal;
445             g_free( tmp );
447             if ( !action->private_data->appearance || (strcmp("", newVal) == 0) ) {
448                 action->private_data->appearanceMode = APPEARANCE_NONE;
449             } else if ( strcmp("full", newVal) == 0 ) {
450                 action->private_data->appearanceMode = APPEARANCE_FULL;
451             } else if ( strcmp("compact", newVal) == 0 ) {
452                 action->private_data->appearanceMode = APPEARANCE_COMPACT;
453             } else if ( strcmp("minimal", newVal) == 0 ) {
454                 action->private_data->appearanceMode = APPEARANCE_MINIMAL;
455             } else {
456                 action->private_data->appearanceMode = APPEARANCE_UNKNOWN;
457             }
458         }
459         break;
461         default:
462             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
463     }
466 GtkWidget* create_menu_item( GtkAction* action )
468     GtkWidget* item = 0;
470     if ( IS_EGE_SELECT_ONE_ACTION(action) ) {
471         EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION( action );
472         gchar*  sss = 0;
473         gboolean valid = FALSE;
474         gint index = 0;
475         GtkTreeIter iter;
476         GSList* group = 0;
477         GtkWidget* subby = gtk_menu_new();
479         g_object_get( G_OBJECT(action), "label", &sss, NULL );
481         item = gtk_menu_item_new_with_label( sss );
483         valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
484         while ( valid ) {
485             gchar* str = 0;
486             gtk_tree_model_get( act->private_data->model, &iter,
487                                 act->private_data->labelColumn, &str,
488                                 -1 );
490             GtkWidget *item = gtk_radio_menu_item_new_with_label( group, str );
491             group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item) );
492             gtk_menu_shell_append( GTK_MENU_SHELL(subby), item );
493             g_object_set_qdata( G_OBJECT(item), gDataName, act );
495             gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), index == act->private_data->active );
497             g_free(str);
499             g_signal_connect( G_OBJECT(item), "toggled", G_CALLBACK(menu_toggled_cb), GINT_TO_POINTER(index) );
501             index++;
502             valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
503         }
505         gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby );
506         gtk_widget_show_all( subby );
508         g_free(sss);
509     } else {
510         item = gParentClass->create_menu_item( action );
511     }
513     return item;
517 void ege_select_one_action_set_radio_action_type( EgeSelectOneAction* action, GType radioActionType )
519     (void)action;
521     if ( g_type_is_a( radioActionType, GTK_TYPE_RADIO_ACTION ) ) {
522         action->private_data->radioActionType = radioActionType;
523     } else {
524         g_warning("Passed in type '%s' is not derived from '%s'", g_type_name(radioActionType), g_type_name(GTK_TYPE_RADIO_ACTION) );
525     }
528 GtkWidget* create_tool_item( GtkAction* action )
530     GtkWidget* item = 0;
532     if ( IS_EGE_SELECT_ONE_ACTION(action) && EGE_SELECT_ONE_ACTION(action)->private_data->model )
533     {
534         EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(action);
535         item = GTK_WIDGET( gtk_tool_item_new() );
537         if ( act->private_data->appearanceMode == APPEARANCE_FULL ) {
538             GtkWidget* holder = gtk_hbox_new( FALSE, 0 );
540             GtkRadioAction* ract = 0;
541             GtkWidget* sub = 0;
542             GSList* group = 0;
543             GtkTreeIter iter;
544             gboolean valid = FALSE;
545             gint index = 0;
546             GtkTooltips* tooltips = gtk_tooltips_new();
548             gchar*  sss = 0;
549             g_object_get( G_OBJECT(action), "short_label", &sss, NULL );
550             if (sss) {
551                 GtkWidget* lbl;
552                 lbl = gtk_label_new(sss);
553                 gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 );
554             }
556             valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
557             while ( valid ) {
558                 gchar* str = 0;
559                 gchar* tip = 0;
560                 gchar* iconId = 0;
561                 /*
562                 gint size = 0;
563                 */
564                 gtk_tree_model_get( act->private_data->model, &iter,
565                                     act->private_data->labelColumn, &str,
566                                     -1 );
567                 if ( act->private_data->iconColumn >= 0 ) {
568                     gtk_tree_model_get( act->private_data->model, &iter,
569                                         act->private_data->iconColumn, &iconId,
570                                         -1 );
571                 }
572                 if ( act->private_data->tooltipColumn >= 0 ) {
573                     gtk_tree_model_get( act->private_data->model, &iter,
574                                         act->private_data->tooltipColumn, &tip,
575                                         -1 );
576                 }
578                 if ( act->private_data->radioActionType ) {
579                     void* obj = g_object_new( act->private_data->radioActionType,
580                                               "name", "Name 1",
581                                               "label", str,
582                                               "tooltip", tip,
583                                               "value", index,
584                                               /*
585                                               "iconId", iconId,
586                                               "iconSize", size,
587                                               */
588                                               NULL );
589                     if ( iconId ) {
590                         g_object_set( G_OBJECT(obj), act->private_data->iconProperty, iconId, NULL );
591                     }
593                     if ( act->private_data->iconProperty ) {
594                         /* TODO get this string to be set instead of hardcoded */
595                         if ( act->private_data->iconSize >= 0 ) {
596                             g_object_set( G_OBJECT(obj), "iconSize", act->private_data->iconSize, NULL );
597                         }
598                     }
600                     ract = GTK_RADIO_ACTION(obj);
601                 } else {
602                     ract = gtk_radio_action_new( "Name 1", str, tip, iconId, index );
603                 }
605                 gtk_radio_action_set_group( ract, group );
606                 group = gtk_radio_action_get_group( ract );
608                 if ( index == act->private_data->active ) {
609                     gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(ract), TRUE );
610                 }
611                 g_signal_connect( G_OBJECT(ract), "changed", G_CALLBACK( proxy_action_chagned_cb ), act );
613                 sub = gtk_action_create_tool_item( GTK_ACTION(ract) );
614                 gtk_action_connect_proxy( GTK_ACTION(ract), sub );
615                 gtk_tool_item_set_tooltip( GTK_TOOL_ITEM(sub), tooltips, tip, NULL );
617                 gtk_box_pack_start( GTK_BOX(holder), sub, FALSE, FALSE, 0 );
619                 g_free( str );
620                 g_free( tip );
621                 g_free( iconId );
623                 index++;
624                 valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
625             }
627             g_object_set_data( G_OBJECT(holder), "ege-proxy_action-group", group );
628             g_object_set_data( G_OBJECT(holder), "ege-tooltips", tooltips );
630             gtk_container_add( GTK_CONTAINER(item), holder );
631         } else {
632             GtkWidget* holder = gtk_hbox_new( FALSE, 4 );
633             GtkWidget* normal = gtk_combo_box_new_with_model( act->private_data->model );
635             GtkCellRenderer * renderer = 0;
637             if ( act->private_data->iconColumn >= 0 ) {
638                 renderer = gtk_cell_renderer_pixbuf_new();
639                 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(normal), renderer, TRUE );
641                 // "icon-name"
642                 gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(normal), renderer, "stock-id", act->private_data->iconColumn );
643             }
645             renderer = gtk_cell_renderer_text_new();
646             gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(normal), renderer, TRUE );
647             gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(normal), renderer, "text", act->private_data->labelColumn );
649             gtk_combo_box_set_active( GTK_COMBO_BOX(normal), act->private_data->active );
651             g_signal_connect( G_OBJECT(normal), "changed", G_CALLBACK(combo_changed_cb), action );
653             g_object_set_data( G_OBJECT(holder), "ege-combo-box", normal );
655             if (act->private_data->appearanceMode == APPEARANCE_COMPACT) {
656                 gchar*  sss = 0;
657                 g_object_get( G_OBJECT(action), "short_label", &sss, NULL );
658                 if (sss) {
659                     GtkWidget* lbl;
660                     lbl = gtk_label_new(sss);
661                     gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 );
662                 }
663             }
665             gtk_box_pack_start( GTK_BOX(holder), normal, FALSE, FALSE, 0 );
667             gtk_container_add( GTK_CONTAINER(item), holder );
668         }
670         gtk_widget_show_all( item );
671     } else {
672         item = gParentClass->create_tool_item( action );
673     }
675     return item;
679 void connect_proxy( GtkAction *action, GtkWidget *proxy )
681     gParentClass->connect_proxy( action, proxy );
684 void disconnect_proxy( GtkAction *action, GtkWidget *proxy )
686     gParentClass->disconnect_proxy( action, proxy );
690 void resync_active( EgeSelectOneAction* act, gint active )
692     if ( act->private_data->active != active ) {
693         act->private_data->active = active;
694         GSList* proxies = gtk_action_get_proxies( GTK_ACTION(act) );
695         while ( proxies ) {
696             if ( GTK_IS_TOOL_ITEM(proxies->data) ) {
697                 /* Search for the things we built up in create_tool_item() */
698                 GList* children = gtk_container_get_children( GTK_CONTAINER(proxies->data) );
699                 if ( children && children->data ) {
700                     gpointer combodata = g_object_get_data( G_OBJECT(children->data), "ege-combo-box" );
701                     if ( GTK_IS_COMBO_BOX(combodata) ) {
702                         GtkComboBox* combo = GTK_COMBO_BOX(combodata);
703                         if ( gtk_combo_box_get_active(combo) != active ) {
704                             gtk_combo_box_set_active( combo, active );
705                         }
706                     } else if ( GTK_IS_HBOX(children->data) ) {
707                         gpointer data = g_object_get_data( G_OBJECT(children->data), "ege-proxy_action-group" );
708                         if ( data ) {
709                             GSList* group = (GSList*)data;
710                             GtkRadioAction* oneAction = GTK_RADIO_ACTION(group->data);
711                             gint hot = gtk_radio_action_get_current_value( oneAction );
712                             if ( hot != active ) {
713                                 /*gtk_radio_action_set_current_value( oneAction, active );*/
714                                 gint value = 0;
715                                 while ( group ) {
716                                     GtkRadioAction* possible = GTK_RADIO_ACTION(group->data);
717                                     g_object_get( G_OBJECT(possible), "value", &value, NULL );
718                                     if ( value == active ) {
719                                         /* Found the group member to set active */
720                                         gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(possible), TRUE );
721                                         break;
722                                     }
724                                     group = g_slist_next(group);
725                                 }
726                             }
727                         }
728                     }
729                 }
730             } else if ( GTK_IS_MENU_ITEM(proxies->data) ) {
731                 GtkWidget* subMenu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(proxies->data) );
732                 GList* children = gtk_container_get_children( GTK_CONTAINER(subMenu) );
733                 if ( children && (g_list_length(children) > (guint)active) ) {
734                     gpointer data = g_list_nth_data( children, active );
735                     gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(data), TRUE );
736                 }
737             }
739             proxies = g_slist_next( proxies );
740         }
742         g_signal_emit( G_OBJECT(act), signals[CHANGED], 0);
743     }
746 void combo_changed_cb( GtkComboBox* widget, gpointer user_data )
748     EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(user_data);
749     gint newActive = gtk_combo_box_get_active(widget);
750     if (newActive != act->private_data->active && newActive != -1) {
751         g_object_set( G_OBJECT(act), "active", newActive, NULL );
752     }
755 void menu_toggled_cb( GtkWidget* obj, gpointer data )
757     GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(obj);
758     EgeSelectOneAction* act = (EgeSelectOneAction*)g_object_get_qdata( G_OBJECT(obj), gDataName );
759     gint newActive = GPOINTER_TO_INT(data);
760     if ( gtk_check_menu_item_get_active(item) && (newActive != act->private_data->active) ) {
761         g_object_set( G_OBJECT(act), "active", newActive, NULL );
762     }
765 void proxy_action_chagned_cb( GtkRadioAction* action, GtkRadioAction* current, gpointer user_data )
767     (void)current;
768     if ( gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(action) ) ) {
769         EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(user_data);
770         gint newActive = gtk_radio_action_get_current_value( action );
771         if ( newActive != act->private_data->active ) {
772             g_object_set( G_OBJECT(act), "active", newActive, NULL );
773         }
774     }