Code

Connector tool: make connectors avoid the convex hull of shapes.
[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 void ege_select_one_action_set_active( EgeSelectOneAction* action, gint val )
283     g_object_set( G_OBJECT(action), "active", val, NULL );
286 gint ege_select_one_action_get_label_column( EgeSelectOneAction* action )
288     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
289     return action->private_data->labelColumn;
292 void ege_select_one_action_set_label_column( EgeSelectOneAction* action, gint col )
294     g_object_set( G_OBJECT(action), "label-column", col, NULL );
297 gint ege_select_one_action_get_icon_column( EgeSelectOneAction* action )
299     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
300     return action->private_data->iconColumn;
303 void ege_select_one_action_set_icon_column( EgeSelectOneAction* action, gint col )
305     g_object_set( G_OBJECT(action), "icon-column", col, NULL );
308 gint ege_select_one_action_get_icon_size( EgeSelectOneAction* action )
310     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
311     return action->private_data->iconSize;
314 void ege_select_one_action_set_icon_size( EgeSelectOneAction* action, gint size )
316     g_object_set( G_OBJECT(action), "icon-size", size, NULL );
319 gint ege_select_one_action_get_tooltip_column( EgeSelectOneAction* action )
321     g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
322     return action->private_data->tooltipColumn;
325 void ege_select_one_action_set_tooltip_column( EgeSelectOneAction* action, gint col )
327     g_object_set( G_OBJECT(action), "tooltip-column", col, NULL );
330 void ege_select_one_action_set_appearance( EgeSelectOneAction* action, gchar const* val )
332     g_object_set( G_OBJECT(action), "appearance", val, NULL );
335 void ege_select_one_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
337     EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
338     switch ( propId ) {
339         case PROP_MODEL:
340             g_value_set_object( value, action->private_data->model );
341             break;
343         case PROP_ACTIVE:
344             g_value_set_int( value, action->private_data->active );
345             break;
347         case PROP_LABEL_COLUMN:
348             g_value_set_int( value, action->private_data->labelColumn );
349             break;
351         case PROP_ICON_COLUMN:
352             g_value_set_int( value, action->private_data->iconColumn );
353             break;
355         case PROP_TOOLTIP_COLUMN:
356             g_value_set_int( value, action->private_data->tooltipColumn );
357             break;
359         case PROP_ICON_PROP:
360             g_value_set_string( value, action->private_data->iconProperty );
361             break;
363         case PROP_ICON_SIZE:
364             g_value_set_int( value, action->private_data->iconSize );
365             break;
367         case PROP_APPEARANCE:
368             g_value_set_string( value, action->private_data->appearance );
369             break;
371         default:
372             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
373     }
376 void ege_select_one_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
378     EgeSelectOneAction* action = EGE_SELECT_ONE_ACTION( obj );
379     switch ( propId ) {
380         case PROP_MODEL:
381         {
382             action->private_data->model = GTK_TREE_MODEL( g_value_get_object( value ) );
383         }
384         break;
386         case PROP_ACTIVE:
387         {
388             resync_active( action, g_value_get_int( value ) );
389         }
390         break;
392         case PROP_LABEL_COLUMN:
393         {
394             action->private_data->labelColumn = g_value_get_int( value );
395         }
396         break;
398         case PROP_ICON_COLUMN:
399         {
400             action->private_data->iconColumn = g_value_get_int( value );
401         }
402         break;
404         case PROP_TOOLTIP_COLUMN:
405         {
406             action->private_data->tooltipColumn = g_value_get_int( value );
407         }
408         break;
410         case PROP_ICON_PROP:
411         {
412             gchar* tmp = action->private_data->iconProperty;
413             gchar* newVal = g_value_dup_string( value );
414             action->private_data->iconProperty = newVal;
415             g_free( tmp );
416         }
417         break;
419         case PROP_ICON_SIZE:
420         {
421             action->private_data->iconSize = g_value_get_int( value );
422         }
423         break;
425         case PROP_APPEARANCE:
426         {
427             gchar* tmp = action->private_data->appearance;
428             gchar* newVal = g_value_dup_string( value );
429             action->private_data->appearance = newVal;
430             g_free( tmp );
432             if ( !action->private_data->appearance || (strcmp("", newVal) == 0) ) {
433                 action->private_data->appearanceMode = APPEARANCE_NONE;
434             } else if ( strcmp("full", newVal) == 0 ) {
435                 action->private_data->appearanceMode = APPEARANCE_FULL;
436             } else if ( strcmp("compact", newVal) == 0 ) {
437                 action->private_data->appearanceMode = APPEARANCE_COMPACT;
438             } else if ( strcmp("minimal", newVal) == 0 ) {
439                 action->private_data->appearanceMode = APPEARANCE_MINIMAL;
440             } else {
441                 action->private_data->appearanceMode = APPEARANCE_UNKNOWN;
442             }
443         }
444         break;
446         default:
447             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
448     }
451 GtkWidget* create_menu_item( GtkAction* action )
453     GtkWidget* item = 0;
455     if ( IS_EGE_SELECT_ONE_ACTION(action) ) {
456         EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION( action );
457         gchar*  sss = 0;
458         gboolean valid = FALSE;
459         gint index = 0;
460         GtkTreeIter iter;
461         GSList* group = 0;
462         GtkWidget* subby = gtk_menu_new();
464         g_object_get( G_OBJECT(action), "label", &sss, NULL );
466         item = gtk_menu_item_new_with_label( sss );
468         valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
469         while ( valid ) {
470             gchar* str = 0;
471             gtk_tree_model_get( act->private_data->model, &iter,
472                                 act->private_data->labelColumn, &str,
473                                 -1 );
475             GtkWidget *item = gtk_radio_menu_item_new_with_label( group, str );
476             group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(item) );
477             gtk_menu_shell_append( GTK_MENU_SHELL(subby), item );
478             g_object_set_qdata( G_OBJECT(item), gDataName, act );
480             gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), index == act->private_data->active );
482             g_free(str);
484             g_signal_connect( G_OBJECT(item), "toggled", G_CALLBACK(menu_toggled_cb), GINT_TO_POINTER(index) );
486             index++;
487             valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
488         }
490         gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby );
491         gtk_widget_show_all( subby );
493         g_free(sss);
494     } else {
495         item = gParentClass->create_menu_item( action );
496     }
498     return item;
502 void ege_select_one_action_set_radio_action_type( EgeSelectOneAction* action, GType radioActionType )
504     (void)action;
506     if ( g_type_is_a( radioActionType, GTK_TYPE_RADIO_ACTION ) ) {
507         action->private_data->radioActionType = radioActionType;
508     } else {
509         g_warning("Passed in type '%s' is not derived from '%s'", g_type_name(radioActionType), g_type_name(GTK_TYPE_RADIO_ACTION) );
510     }
513 GtkWidget* create_tool_item( GtkAction* action )
515     GtkWidget* item = 0;
517     if ( IS_EGE_SELECT_ONE_ACTION(action) && EGE_SELECT_ONE_ACTION(action)->private_data->model )
518     {
519         EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(action);
520         item = GTK_WIDGET( gtk_tool_item_new() );
522         if ( act->private_data->appearanceMode == APPEARANCE_FULL ) {
523             GtkWidget* holder = gtk_hbox_new( FALSE, 0 );
525             GtkRadioAction* ract = 0;
526             GtkWidget* sub = 0;
527             GSList* group = 0;
528             GtkTreeIter iter;
529             gboolean valid = FALSE;
530             gint index = 0;
531             GtkTooltips* tooltips = gtk_tooltips_new();
533             gchar*  sss = 0;
534             g_object_get( G_OBJECT(action), "short_label", &sss, NULL );
535             if (sss) {
536                 GtkWidget* lbl;
537                 lbl = gtk_label_new(sss);
538                 gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 );
539             }
541             valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter );
542             while ( valid ) {
543                 gchar* str = 0;
544                 gchar* tip = 0;
545                 gchar* iconId = 0;
546                 /*
547                 gint size = 0;
548                 */
549                 gtk_tree_model_get( act->private_data->model, &iter,
550                                     act->private_data->labelColumn, &str,
551                                     -1 );
552                 if ( act->private_data->iconColumn >= 0 ) {
553                     gtk_tree_model_get( act->private_data->model, &iter,
554                                         act->private_data->iconColumn, &iconId,
555                                         -1 );
556                 }
557                 if ( act->private_data->tooltipColumn >= 0 ) {
558                     gtk_tree_model_get( act->private_data->model, &iter,
559                                         act->private_data->tooltipColumn, &tip,
560                                         -1 );
561                 }
563                 if ( act->private_data->radioActionType ) {
564                     void* obj = g_object_new( act->private_data->radioActionType,
565                                               "name", "Name 1",
566                                               "label", str,
567                                               "tooltip", tip,
568                                               "value", index,
569                                               /*
570                                               "iconId", iconId,
571                                               "iconSize", size,
572                                               */
573                                               NULL );
574                     if ( iconId ) {
575                         g_object_set( G_OBJECT(obj), act->private_data->iconProperty, iconId, NULL );
576                     }
578                     if ( act->private_data->iconProperty >= 0 ) {
579                         /* TODO get this string to be set instead of hardcoded */
580                         if ( act->private_data->iconSize >= 0 ) {
581                             g_object_set( G_OBJECT(obj), "iconSize", act->private_data->iconSize, NULL );
582                         }
583                     }
585                     ract = GTK_RADIO_ACTION(obj);
586                 } else {
587                     ract = gtk_radio_action_new( "Name 1", str, tip, iconId, index );
588                 }
590                 gtk_radio_action_set_group( ract, group );
591                 group = gtk_radio_action_get_group( ract );
593                 if ( index == act->private_data->active ) {
594                     gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(ract), TRUE );
595                 }
596                 g_signal_connect( G_OBJECT(ract), "changed", G_CALLBACK( proxy_action_chagned_cb ), act );
598                 sub = gtk_action_create_tool_item( GTK_ACTION(ract) );
599                 gtk_action_connect_proxy( GTK_ACTION(ract), sub );
600                 gtk_tool_item_set_tooltip( GTK_TOOL_ITEM(sub), tooltips, tip, NULL );
602                 gtk_box_pack_start( GTK_BOX(holder), sub, FALSE, FALSE, 0 );
604                 g_free( str );
605                 g_free( tip );
606                 g_free( iconId );
608                 index++;
609                 valid = gtk_tree_model_iter_next( act->private_data->model, &iter );
610             }
612             g_object_set_data( G_OBJECT(holder), "ege-proxy_action-group", group );
613             g_object_set_data( G_OBJECT(holder), "ege-tooltips", tooltips );
615             gtk_container_add( GTK_CONTAINER(item), holder );
616         } else {
617             GtkWidget* holder = gtk_hbox_new( FALSE, 4 );
618             GtkWidget* normal = gtk_combo_box_new_with_model( act->private_data->model );
620             GtkCellRenderer * renderer = 0;
622             if ( act->private_data->iconColumn >= 0 ) {
623                 renderer = gtk_cell_renderer_pixbuf_new();
624                 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(normal), renderer, TRUE );
626                 // "icon-name"
627                 gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(normal), renderer, "stock-id", act->private_data->iconColumn );
628             }
630             renderer = gtk_cell_renderer_text_new();
631             gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(normal), renderer, TRUE );
632             gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(normal), renderer, "text", act->private_data->labelColumn );
634             gtk_combo_box_set_active( GTK_COMBO_BOX(normal), act->private_data->active );
636             g_signal_connect( G_OBJECT(normal), "changed", G_CALLBACK(combo_changed_cb), action );
638             g_object_set_data( G_OBJECT(holder), "ege-combo-box", normal );
640             if (act->private_data->appearanceMode == APPEARANCE_COMPACT) {
641                 gchar*  sss = 0;
642                 g_object_get( G_OBJECT(action), "short_label", &sss, NULL );
643                 if (sss) {
644                     GtkWidget* lbl;
645                     lbl = gtk_label_new(sss);
646                     gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 );
647                 }
648             }
650             gtk_box_pack_start( GTK_BOX(holder), normal, FALSE, FALSE, 0 );
652             gtk_container_add( GTK_CONTAINER(item), holder );
653         }
655         gtk_widget_show_all( item );
656     } else {
657         item = gParentClass->create_tool_item( action );
658     }
660     return item;
664 void connect_proxy( GtkAction *action, GtkWidget *proxy )
666     gParentClass->connect_proxy( action, proxy );
669 void disconnect_proxy( GtkAction *action, GtkWidget *proxy )
671     gParentClass->disconnect_proxy( action, proxy );
675 void resync_active( EgeSelectOneAction* act, gint active )
677     if ( act->private_data->active != active ) {
678         act->private_data->active = active;
679         GSList* proxies = gtk_action_get_proxies( GTK_ACTION(act) );
680         while ( proxies ) {
681             if ( GTK_IS_TOOL_ITEM(proxies->data) ) {
682                 /* Search for the things we built up in create_tool_item() */
683                 GList* children = gtk_container_get_children( GTK_CONTAINER(proxies->data) );
684                 if ( children && children->data ) {
685                     gpointer combodata = g_object_get_data( G_OBJECT(children->data), "ege-combo-box" );
686                     if ( GTK_IS_COMBO_BOX(combodata) ) {
687                         GtkComboBox* combo = GTK_COMBO_BOX(combodata);
688                         if ( gtk_combo_box_get_active(combo) != active ) {
689                             gtk_combo_box_set_active( combo, active );
690                         }
691                     } else if ( GTK_IS_HBOX(children->data) ) {
692                         gpointer data = g_object_get_data( G_OBJECT(children->data), "ege-proxy_action-group" );
693                         if ( data ) {
694                             GSList* group = (GSList*)data;
695                             GtkRadioAction* oneAction = GTK_RADIO_ACTION(group->data);
696                             gint hot = gtk_radio_action_get_current_value( oneAction );
697                             if ( hot != active ) {
698                                 /*gtk_radio_action_set_current_value( oneAction, active );*/
699                                 gint value = 0;
700                                 while ( group ) {
701                                     GtkRadioAction* possible = GTK_RADIO_ACTION(group->data);
702                                     g_object_get( G_OBJECT(possible), "value", &value, NULL );
703                                     if ( value == active ) {
704                                         /* Found the group member to set active */
705                                         gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(possible), TRUE );
706                                         break;
707                                     }
709                                     group = g_slist_next(group);
710                                 }
711                             }
712                         }
713                     }
714                 }
715             } else if ( GTK_IS_MENU_ITEM(proxies->data) ) {
716                 GtkWidget* subMenu = gtk_menu_item_get_submenu( GTK_MENU_ITEM(proxies->data) );
717                 GList* children = gtk_container_get_children( GTK_CONTAINER(subMenu) );
718                 if ( children && (g_list_length(children) > (guint)active) ) {
719                     gpointer data = g_list_nth_data( children, active );
720                     gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(data), TRUE );
721                 }
722             }
724             proxies = g_slist_next( proxies );
725         }
727         g_signal_emit( G_OBJECT(act), signals[CHANGED], 0);
728     }
731 void combo_changed_cb( GtkComboBox* widget, gpointer user_data )
733     EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(user_data);
734     gint newActive = gtk_combo_box_get_active(widget);
735     if (newActive != act->private_data->active && newActive != -1) {
736         g_object_set( G_OBJECT(act), "active", newActive, NULL );
737     }
740 void menu_toggled_cb( GtkWidget* obj, gpointer data )
742     GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(obj);
743     EgeSelectOneAction* act = (EgeSelectOneAction*)g_object_get_qdata( G_OBJECT(obj), gDataName );
744     gint newActive = GPOINTER_TO_INT(data);
745     if ( gtk_check_menu_item_get_active(item) && (newActive != act->private_data->active) ) {
746         g_object_set( G_OBJECT(act), "active", newActive, NULL );
747     }
750 void proxy_action_chagned_cb( GtkRadioAction* action, GtkRadioAction* current, gpointer user_data )
752     (void)current;
753     if ( gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(action) ) ) {
754         EgeSelectOneAction* act = EGE_SELECT_ONE_ACTION(user_data);
755         gint newActive = gtk_radio_action_get_current_value( action );
756         if ( newActive != act->private_data->active ) {
757             g_object_set( G_OBJECT(act), "active", newActive, NULL );
758         }
759     }