834b06b3b035b4f876e1fa0f6f0cd9faccb7f5fb
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 )
118 {
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;
138 }
140 GtkTreeModel *ege_select_one_action_get_model(EgeSelectOneAction* action ){
141 return GTK_TREE_MODEL(action->private_data->model);
142 }
143 void ege_select_one_action_class_init( EgeSelectOneActionClass* klass )
144 {
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 }
233 }
236 void ege_select_one_action_init( EgeSelectOneAction* action )
237 {
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 ); */
251 }
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 )
258 {
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;
272 }
275 gint ege_select_one_action_get_active( EgeSelectOneAction* action )
276 {
277 g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
278 return action->private_data->active;
279 }
281 gchar *ege_select_one_action_get_active_text( EgeSelectOneAction* action )
282 {
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;
294 }
296 void ege_select_one_action_set_active( EgeSelectOneAction* action, gint val )
297 {
298 g_object_set( G_OBJECT(action), "active", val, NULL );
299 }
301 gint ege_select_one_action_get_label_column( EgeSelectOneAction* action )
302 {
303 g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
304 return action->private_data->labelColumn;
305 }
307 void ege_select_one_action_set_label_column( EgeSelectOneAction* action, gint col )
308 {
309 g_object_set( G_OBJECT(action), "label-column", col, NULL );
310 }
312 gint ege_select_one_action_get_icon_column( EgeSelectOneAction* action )
313 {
314 g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
315 return action->private_data->iconColumn;
316 }
318 void ege_select_one_action_set_icon_column( EgeSelectOneAction* action, gint col )
319 {
320 g_object_set( G_OBJECT(action), "icon-column", col, NULL );
321 }
323 gint ege_select_one_action_get_icon_size( EgeSelectOneAction* action )
324 {
325 g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
326 return action->private_data->iconSize;
327 }
329 void ege_select_one_action_set_icon_size( EgeSelectOneAction* action, gint size )
330 {
331 g_object_set( G_OBJECT(action), "icon-size", size, NULL );
332 }
334 gint ege_select_one_action_get_tooltip_column( EgeSelectOneAction* action )
335 {
336 g_return_val_if_fail( IS_EGE_SELECT_ONE_ACTION(action), 0 );
337 return action->private_data->tooltipColumn;
338 }
340 void ege_select_one_action_set_tooltip_column( EgeSelectOneAction* action, gint col )
341 {
342 g_object_set( G_OBJECT(action), "tooltip-column", col, NULL );
343 }
345 void ege_select_one_action_set_appearance( EgeSelectOneAction* action, gchar const* val )
346 {
347 g_object_set( G_OBJECT(action), "appearance", val, NULL );
348 }
350 void ege_select_one_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
351 {
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 }
389 }
391 void ege_select_one_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
392 {
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 }
464 }
466 GtkWidget* create_menu_item( GtkAction* action )
467 {
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;
514 }
517 void ege_select_one_action_set_radio_action_type( EgeSelectOneAction* action, GType radioActionType )
518 {
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 }
526 }
528 GtkWidget* create_tool_item( GtkAction* action )
529 {
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;
676 }
679 void connect_proxy( GtkAction *action, GtkWidget *proxy )
680 {
681 gParentClass->connect_proxy( action, proxy );
682 }
684 void disconnect_proxy( GtkAction *action, GtkWidget *proxy )
685 {
686 gParentClass->disconnect_proxy( action, proxy );
687 }
690 void resync_active( EgeSelectOneAction* act, gint active )
691 {
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 }
744 }
746 void combo_changed_cb( GtkComboBox* widget, gpointer user_data )
747 {
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 }
753 }
755 void menu_toggled_cb( GtkWidget* obj, gpointer data )
756 {
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 }
763 }
765 void proxy_action_chagned_cb( GtkRadioAction* action, GtkRadioAction* current, gpointer user_data )
766 {
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 }
775 }