Code

switch pref/repr utility methods to using long long ints; with
[inkscape.git] / src / ege-adjustment-action.cpp
3 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
4  *
5  */
6 /* ***** BEGIN LICENSE BLOCK *****
7  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
8  *
9  * The contents of this file are subject to the Mozilla Public License Version
10  * 1.1 (the "License"); you may not use this file except in compliance with
11  * the License. You may obtain a copy of the License at
12  * http://www.mozilla.org/MPL/
13  *
14  * Software distributed under the License is distributed on an "AS IS" basis,
15  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16  * for the specific language governing rights and limitations under the
17  * License.
18  *
19  * The Original Code is EGE Adjustment Action.
20  *
21  * The Initial Developer of the Original Code is
22  * Jon A. Cruz.
23  * Portions created by the Initial Developer are Copyright (C) 2006
24  * the Initial Developer. All Rights Reserved.
25  *
26  * Contributor(s):
27  *
28  * Alternatively, the contents of this file may be used under the terms of
29  * either the GNU General Public License Version 2 or later (the "GPL"), or
30  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31  * in which case the provisions of the GPL or the LGPL are applicable instead
32  * of those above. If you wish to allow use of your version of this file only
33  * under the terms of either the GPL or the LGPL, and not to allow others to
34  * use your version of this file under the terms of the MPL, indicate your
35  * decision by deleting the provisions above and replace them with the notice
36  * and other provisions required by the GPL or the LGPL. If you do not delete
37  * the provisions above, a recipient may use your version of this file under
38  * the terms of any one of the MPL, the GPL or the LGPL.
39  *
40  * ***** END LICENSE BLOCK ***** */
42 /* Note: this file should be kept compliable as both .cpp and .c */
44 #include <string.h>
46 #include <gdk/gdkkeysyms.h>
47 #include <gtk/gtktoolitem.h>
48 #include <gtk/gtkspinbutton.h>
49 #include <gtk/gtkhbox.h>
50 #include <gtk/gtklabel.h>
51 #include <gtk/gtkmisc.h>
52 #include <gtk/gtktoolbar.h>
53 #include <gtk/gtkradiomenuitem.h>
55 #include "ege-adjustment-action.h"
58 static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass );
59 static void ege_adjustment_action_init( EgeAdjustmentAction* action );
60 static void ege_adjustment_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
61 static void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
63 static GtkWidget* create_menu_item( GtkAction* action );
64 static GtkWidget* create_tool_item( GtkAction* action );
65 static void connect_proxy( GtkAction *action, GtkWidget *proxy );
66 static void disconnect_proxy( GtkAction *action, GtkWidget *proxy );
68 static gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
69 static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
70 static gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
72 static void ege_adjustment_action_defocus( EgeAdjustmentAction* action );
75 static GtkActionClass* gParentClass = 0;
76 static GQuark gDataName = 0;
78 struct _EgeAdjustmentActionPrivate
79 {
80     GtkAdjustment* adj;
81     GtkWidget* focusWidget;
82     gdouble climbRate;
83     guint digits;
84     gchar* selfId;
85     EgeWidgetFixup toolPost;
86     gdouble lastVal;
87     gdouble step;
88     gdouble page;
89     gboolean transferFocus;
90 };
92 #define EGE_ADJUSTMENT_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionPrivate ) )
94 enum {
95     PROP_ADJUSTMENT = 1,
96     PROP_FOCUS_WIDGET,
97     PROP_CLIMB_RATE,
98     PROP_DIGITS,
99     PROP_SELFID,
100     PROP_TOOL_POST
101 };
103 enum {
104     BUMP_TOP = 0,
105     BUMP_PAGE_UP,
106     BUMP_UP,
107     BUMP_NONE,
108     BUMP_DOWN,
109     BUMP_PAGE_DOWN,
110     BUMP_BOTTOM
111 };
113 GType ege_adjustment_action_get_type( void )
115     static GType myType = 0;
116     if ( !myType ) {
117         static const GTypeInfo myInfo = {
118             sizeof( EgeAdjustmentActionClass ),
119             NULL, /* base_init */
120             NULL, /* base_finalize */
121             (GClassInitFunc)ege_adjustment_action_class_init,
122             NULL, /* class_finalize */
123             NULL, /* class_data */
124             sizeof( EgeAdjustmentAction ),
125             0, /* n_preallocs */
126             (GInstanceInitFunc)ege_adjustment_action_init,
127             NULL
128         };
130         myType = g_type_register_static( GTK_TYPE_ACTION, "EgeAdjustmentAction", &myInfo, (GTypeFlags)0 );
131     }
133     return myType;
137 static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass )
139     if ( klass ) {
140         gParentClass = GTK_ACTION_CLASS( g_type_class_peek_parent( klass ) );
141         GObjectClass * objClass = G_OBJECT_CLASS( klass );
143         gDataName = g_quark_from_string("ege-adj-action");
145         objClass->get_property = ege_adjustment_action_get_property;
146         objClass->set_property = ege_adjustment_action_set_property;
148         klass->parent_class.create_menu_item = create_menu_item;
149         klass->parent_class.create_tool_item = create_tool_item;
150         klass->parent_class.connect_proxy = connect_proxy;
151         klass->parent_class.disconnect_proxy = disconnect_proxy;
153         g_object_class_install_property( objClass,
154                                          PROP_ADJUSTMENT,
155                                          g_param_spec_object( "adjustment",
156                                                               "Adjustment",
157                                                               "The adjustment to change",
158                                                               GTK_TYPE_ADJUSTMENT,
159                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
161         g_object_class_install_property( objClass,
162                                          PROP_FOCUS_WIDGET,
163                                          g_param_spec_pointer( "focus-widget",
164                                                                "Focus Widget",
165                                                                "The widget to return focus to",
166                                                                (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
168         g_object_class_install_property( objClass,
169                                          PROP_CLIMB_RATE,
170                                          g_param_spec_double( "climb-rate",
171                                                               "Climb Rate",
172                                                               "The acelleraton rate",
173                                                               0.0, G_MAXDOUBLE, 0.0,
174                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
176         g_object_class_install_property( objClass,
177                                          PROP_DIGITS,
178                                          g_param_spec_uint( "digits",
179                                                             "Digits",
180                                                             "The number of digits to show",
181                                                             0, 20, 0,
182                                                             (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
184         g_object_class_install_property( objClass,
185                                          PROP_SELFID,
186                                          g_param_spec_string( "self-id",
187                                                               "Self ID",
188                                                               "Marker for self pointer",
189                                                               0,
190                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
192         g_object_class_install_property( objClass,
193                                          PROP_TOOL_POST,
194                                          g_param_spec_pointer( "tool-post",
195                                                                "Tool Widget post process",
196                                                                "Function for final adjustments",
197                                                                (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
199         g_type_class_add_private( klass, sizeof(EgeAdjustmentActionClass) );
200     }
203 static void ege_adjustment_action_init( EgeAdjustmentAction* action )
205     action->private_data = EGE_ADJUSTMENT_ACTION_GET_PRIVATE( action );
206     action->private_data->adj = 0;
207     action->private_data->focusWidget = 0;
208     action->private_data->climbRate = 0.0;
209     action->private_data->digits = 2;
210     action->private_data->selfId = 0;
211     action->private_data->toolPost = 0;
212     action->private_data->lastVal = 0.0;
213     action->private_data->step = 0.0;
214     action->private_data->page = 0.0;
215     action->private_data->transferFocus = FALSE;
218 EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment,
219                                                 const gchar *name,
220                                                 const gchar *label,
221                                                 const gchar *tooltip,
222                                                 const gchar *stock_id,
223                                                 gdouble climb_rate,
224                                                 guint digits )
226     GObject* obj = (GObject*)g_object_new( EGE_ADJUSTMENT_ACTION_TYPE,
227                                            "name", name,
228                                            "label", label,
229                                            "tooltip", tooltip,
230                                            "stock_id", stock_id,
231                                            "adjustment", adjustment,
232                                            "climb-rate", climb_rate,
233                                            "digits", digits,
234                                            NULL );
236     EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
238     return action;
241 static void ege_adjustment_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
243     EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
244     switch ( propId ) {
245         case PROP_ADJUSTMENT:
246             g_value_set_object( value, action->private_data->adj );
247             break;
249         case PROP_FOCUS_WIDGET:
250             g_value_set_pointer( value, action->private_data->focusWidget );
251             break;
253         case PROP_CLIMB_RATE:
254             g_value_set_double( value, action->private_data->climbRate );
255             break;
257         case PROP_DIGITS:
258             g_value_set_uint( value, action->private_data->digits );
259             break;
261         case PROP_SELFID:
262             g_value_set_string( value, action->private_data->selfId );
263             break;
265         case PROP_TOOL_POST:
266             g_value_set_pointer( value, (void*)action->private_data->toolPost );
267             break;
269         default:
270             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
271     }
274 void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec )
276     EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
277     switch ( propId ) {
278         case PROP_ADJUSTMENT:
279         {
280             action->private_data->adj = GTK_ADJUSTMENT( g_value_get_object( value ) );
281             g_object_get( G_OBJECT(action->private_data->adj),
282                           "step-increment", &action->private_data->step,
283                           "page-increment", &action->private_data->page,
284                           NULL );
285         }
286         break;
288         case PROP_FOCUS_WIDGET:
289         {
290             /* TODO unhook prior */
291             action->private_data->focusWidget = (GtkWidget*)g_value_get_pointer( value );
292         }
293         break;
295         case PROP_CLIMB_RATE:
296         {
297             /* TODO pass on */
298             action->private_data->climbRate = g_value_get_double( value );
299         }
300         break;
302         case PROP_DIGITS:
303         {
304             /* TODO pass on */
305             action->private_data->digits = g_value_get_uint( value );
306         }
307         break;
309         case PROP_SELFID:
310         {
311             /* TODO pass on */
312             gchar* prior = action->private_data->selfId;
313             action->private_data->selfId = g_value_dup_string( value );
314             g_free( prior );
315         }
316         break;
318         case PROP_TOOL_POST:
319         {
320             action->private_data->toolPost = (EgeWidgetFixup)g_value_get_pointer( value );
321         }
322         break;
324         default:
325             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
326     }
329 GtkAdjustment* ege_adjustment_action_get_adjustment( EgeAdjustmentAction* action )
331     g_return_val_if_fail( IS_EGE_ADJUSTMENT_ACTION(action), NULL );
333     return action->private_data->adj;
336 void ege_adjustment_action_set_focuswidget( EgeAdjustmentAction* action, GtkWidget* widget )
338     g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(action) );
340     /* TODO unhook prior */
342     action->private_data->focusWidget = widget;
345 GtkWidget* ege_adjustment_action_get_focuswidget( EgeAdjustmentAction* action )
347     g_return_val_if_fail( IS_EGE_ADJUSTMENT_ACTION(action), NULL );
349     return action->private_data->focusWidget;
352 static void process_menu_action( GtkWidget* obj, gpointer data )
354     GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(obj);
355     if ( item->active ) {
356         EgeAdjustmentAction* act = (EgeAdjustmentAction*)g_object_get_qdata( G_OBJECT(obj), gDataName );
357         gint what = GPOINTER_TO_INT(data);
360         gdouble base = gtk_adjustment_get_value( act->private_data->adj );
361         gdouble lower = 0.0;
362         gdouble upper = 0.0;
363         gdouble step = 0.0;
364         gdouble page = 0.0;
365         g_object_get( G_OBJECT(act->private_data->adj),
366                       "lower", &lower,
367                       "upper", &upper,
368                       "step-increment", &step,
369                       "page-increment", &page,
370                       NULL );
372         switch ( what ) {
373             case BUMP_TOP:
374                 gtk_adjustment_set_value( act->private_data->adj, upper );
375                 break;
377             case BUMP_PAGE_UP:
378                 gtk_adjustment_set_value( act->private_data->adj, base + page );
379                 break;
381             case BUMP_UP:
382                 gtk_adjustment_set_value( act->private_data->adj, base + step );
383                 break;
385             case BUMP_DOWN:
386                 gtk_adjustment_set_value( act->private_data->adj, base - step );
387                 break;
389             case BUMP_PAGE_DOWN:
390                 gtk_adjustment_set_value( act->private_data->adj, base - page );
391                 break;
393             case BUMP_BOTTOM:
394                 gtk_adjustment_set_value( act->private_data->adj, lower );
395                 break;
396         }
397     }
400 static void create_single_menu( GCallback toggleCb, int val, GtkWidget* menu, EgeAdjustmentAction* act, GtkWidget** dst, GSList** group, gdouble num, gboolean active )
402     char* fmt = g_strdup_printf("%%0.%df", act->private_data->digits);
403     char *str = g_strdup_printf ( fmt, num );
405     *dst = gtk_radio_menu_item_new_with_label( *group, str );
406     if ( !*group) {
407         *group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(*dst) );
408     }
409     if ( active ) {
410         gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(*dst), TRUE );
411     }
412     gtk_menu_shell_append( GTK_MENU_SHELL(menu), *dst );
413     g_object_set_qdata( G_OBJECT(*dst), gDataName, act );
415     g_signal_connect( G_OBJECT(*dst), "toggled", toggleCb, GINT_TO_POINTER(val) );
417     g_free(str);
418     g_free(fmt);
421 static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act )
423     GtkWidget* menu = gtk_menu_new();
425     GSList* group = 0;
426     GtkWidget* single = 0;
428     gdouble base = gtk_adjustment_get_value( act->private_data->adj );
429     gdouble lower = 0.0;
430     gdouble upper = 0.0;
431     gdouble step = 0.0;
432     gdouble page = 0.0;
433     g_object_get( G_OBJECT(act->private_data->adj),
434                   "lower", &lower,
435                   "upper", &upper,
436                   "step-increment", &step,
437                   "page-increment", &page,
438                   NULL );
440     if ( base < upper ) {
441         create_single_menu( G_CALLBACK(process_menu_action), BUMP_TOP, menu, act, &single, &group, upper, FALSE );
442         if ( (base + page) < upper ) {
443             create_single_menu( G_CALLBACK(process_menu_action), BUMP_PAGE_UP, menu, act, &single, &group, base + page, FALSE );
444         }
445         if ( (base + step) < upper ) {
446             create_single_menu( G_CALLBACK(process_menu_action), BUMP_UP, menu, act, &single, &group, base + step, FALSE );
447         }
448     }
450     create_single_menu( G_CALLBACK(process_menu_action), BUMP_NONE, menu, act, &single, &group, base, TRUE );
451     if ( base > lower ) {
452         if ( (base - step) > lower ) {
453             create_single_menu( G_CALLBACK(process_menu_action), BUMP_DOWN, menu, act, &single, &group, base - step, FALSE );
454         }
455         if ( (base - page) > lower ) {
456             create_single_menu( G_CALLBACK(process_menu_action), BUMP_PAGE_DOWN, menu, act, &single, &group, base - page, FALSE );
457         }
458         create_single_menu( G_CALLBACK(process_menu_action), BUMP_BOTTOM, menu, act, &single, &group, lower, FALSE );
459     }
461     return menu;
464 static GtkWidget* create_menu_item( GtkAction* action )
466     GtkWidget* item = 0;
468     if ( IS_EGE_ADJUSTMENT_ACTION(action) ) {
469         EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action );
470         GValue value;
471         const gchar*  sss = 0;
472         GtkWidget*  subby = 0;
474         memset( &value, 0, sizeof(value) );
475         g_value_init( &value, G_TYPE_STRING );
476         g_object_get_property( G_OBJECT(action), "label", &value );
478         sss = g_value_get_string( &value );
480         item = gtk_menu_item_new_with_label( sss );
482         subby = create_popup_number_menu( act );
483         gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby );
484         gtk_widget_show_all( subby );
485     } else {
486         item = gParentClass->create_menu_item( action );
487     }
489     return item;
492 void value_changed_cb( GtkSpinButton* spin, EgeAdjustmentAction* act )
494     if ( GTK_WIDGET_HAS_FOCUS( GTK_WIDGET(spin) ) ) {
495         ege_adjustment_action_defocus( act );
496     }
499 static gboolean event_cb( EgeAdjustmentAction* act, GdkEvent* evt )
501     gboolean handled = FALSE;
502     if ( evt->type == GDK_BUTTON_PRESS ) {
503         if ( evt->button.button == 3 ) {
504             if ( IS_EGE_ADJUSTMENT_ACTION(act) ) {
505                 GdkEventButton* btnevt = (GdkEventButton*)evt;
506                 GtkWidget* menu = create_popup_number_menu(act);
507                 gtk_widget_show_all( menu );
508                 gtk_menu_popup( GTK_MENU(menu), NULL, NULL, NULL, NULL, btnevt->button, btnevt->time );
509             }
510             handled = TRUE;
511         }
512     }
514     return handled;
517 static GtkWidget* create_tool_item( GtkAction* action )
519     GtkWidget* item = 0;
521     if ( IS_EGE_ADJUSTMENT_ACTION(action) ) {
522         EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action );
523         GtkWidget* spinbutton = gtk_spin_button_new( act->private_data->adj, act->private_data->climbRate, act->private_data->digits );
524         GtkWidget* hb = gtk_hbox_new( FALSE, 5 );
525         GValue value;
527         item = GTK_WIDGET( gtk_tool_item_new() );
529         memset( &value, 0, sizeof(value) );
530         g_value_init( &value, G_TYPE_STRING );
531         g_object_get_property( G_OBJECT(action), "label", &value );
532         const gchar* sss = g_value_get_string( &value );
533         GtkWidget* lbl = gtk_label_new( sss ? sss : "wwww" );
535         gtk_misc_set_alignment( GTK_MISC(lbl), 1.0, 0.5 );
537         gtk_box_pack_start( GTK_BOX(hb), lbl, FALSE, FALSE, 0 );
538         gtk_box_pack_end( GTK_BOX(hb), spinbutton, FALSE, FALSE, 0 );
539         gtk_container_add( GTK_CONTAINER(item), hb );
541         if ( act->private_data->selfId ) {
542             g_object_set_data( G_OBJECT(spinbutton), act->private_data->selfId, spinbutton );
543         }
545         g_signal_connect( G_OBJECT(spinbutton), "focus-in-event", G_CALLBACK(focus_in_cb), action );
546         g_signal_connect( G_OBJECT(spinbutton), "focus-out-event", G_CALLBACK(focus_out_cb), action );
547         g_signal_connect( G_OBJECT(spinbutton), "key-press-event", G_CALLBACK(keypress_cb), action );
549         g_signal_connect( G_OBJECT(spinbutton), "value-changed", G_CALLBACK(value_changed_cb), action );
551         g_signal_connect_swapped( G_OBJECT(spinbutton), "event", G_CALLBACK(event_cb), action );
553         gtk_widget_show_all( item );
555         /* Shrink or whatnot after shown */
556         if ( act->private_data->toolPost ) {
557             act->private_data->toolPost( item );
558         }
559     } else {
560         item = gParentClass->create_tool_item( action );
561     }
563     return item;
566 static void connect_proxy( GtkAction *action, GtkWidget *proxy )
568     gParentClass->connect_proxy( action, proxy );
571 static void disconnect_proxy( GtkAction *action, GtkWidget *proxy )
573     gParentClass->disconnect_proxy( action, proxy );
576 void ege_adjustment_action_defocus( EgeAdjustmentAction* action )
578     if ( action->private_data->transferFocus ) {
579         if ( action->private_data->focusWidget ) {
580             gtk_widget_grab_focus( action->private_data->focusWidget );
581         }
582     }
585 gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
587     (void)event;
588     if ( IS_EGE_ADJUSTMENT_ACTION(data) ) {
589         EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data );
590         action->private_data->lastVal = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
591         action->private_data->transferFocus = TRUE;
592     }
594     return FALSE; /* report event not consumed */
597 static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
599     (void)widget;
600     (void)event;
601     if ( IS_EGE_ADJUSTMENT_ACTION(data) ) {
602         EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data );
603         action->private_data->transferFocus = FALSE;
604     }
606     return FALSE; /* report event not consumed */
610 static gboolean process_tab( GtkWidget* widget, int direction )
612     gboolean handled = FALSE;
613     GtkWidget* parent = gtk_widget_get_parent(widget);
614     GtkWidget* gp = parent ? gtk_widget_get_parent(parent) : 0;
615     GtkWidget* ggp = gp ? gtk_widget_get_parent(gp) : 0;
617     if ( ggp && GTK_IS_TOOLBAR(ggp) ) {
618         GList* kids = gtk_container_get_children( GTK_CONTAINER(ggp) );
619         if ( kids ) {
620             GtkWidget* curr = widget;
621             while ( curr && (gtk_widget_get_parent(curr) != ggp) ) {
622                 curr = gtk_widget_get_parent( curr );
623             }
624             if ( curr ) {
625                 GList* mid = g_list_find( kids, curr );
626                 while ( mid ) {
627                     mid = ( direction < 0 ) ? g_list_previous(mid) : g_list_next(mid);
628                     if ( mid && GTK_IS_TOOL_ITEM(mid->data) ) {
629                         /* potential target */
630                         GtkWidget* child = gtk_bin_get_child( GTK_BIN(mid->data) );
631                         if ( child && GTK_IS_HBOX(child) ) { /* could be ours */
632                             GList* subChildren = gtk_container_get_children( GTK_CONTAINER(child) );
633                             if ( subChildren ) {
634                                 GList* last = g_list_last(subChildren);
635                                 if ( last && GTK_IS_SPIN_BUTTON(last->data) && GTK_WIDGET_IS_SENSITIVE( GTK_WIDGET(last->data) ) ) {
636                                     gtk_widget_grab_focus( GTK_WIDGET(last->data) );
637                                     handled = TRUE;
638                                     mid = 0; /* to stop loop */
639                                 }
641                                 g_list_free(subChildren);
642                             }
643                         }
644                     }
645                 }
646             }
647             g_list_free( kids );
648         }
649     }
651     return handled;
654 gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
656     gboolean wasConsumed = FALSE; /* default to report event not consumed */
657     EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION(data);
658     guint key = 0;
659     gdk_keymap_translate_keyboard_state( gdk_keymap_get_for_display( gdk_display_get_default() ),
660                                          event->hardware_keycode, (GdkModifierType)event->state,
661                                          0, &key, 0, 0, 0 );
663     switch ( key ) {
664         case GDK_Escape:
665         {
666             action->private_data->transferFocus = TRUE;
667             gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal );
668             ege_adjustment_action_defocus( action );
669             wasConsumed = TRUE;
670         }
671         break;
673         case GDK_Return:
674         case GDK_KP_Enter:
675         {
676             action->private_data->transferFocus = TRUE;
677             ege_adjustment_action_defocus( action );
678             wasConsumed = TRUE;
679         }
680         break;
682         case GDK_Tab:
683         {
684             action->private_data->transferFocus = FALSE;
685             wasConsumed = process_tab( widget, 1 );
686         }
687         break;
689         case GDK_ISO_Left_Tab:
690         {
691             action->private_data->transferFocus = FALSE;
692             wasConsumed = process_tab( widget, -1 );
693         }
694         break;
696         case GDK_Up:
697         case GDK_KP_Up:
698         {
699             action->private_data->transferFocus = FALSE;
700             gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
701             gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + action->private_data->step );
702             wasConsumed = TRUE;
703         }
704         break;
706         case GDK_Down:
707         case GDK_KP_Down:
708         {
709             action->private_data->transferFocus = FALSE;
710             gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
711             gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - action->private_data->step );
712             wasConsumed = TRUE;
713         }
714         break;
716         case GDK_Page_Up:
717         case GDK_KP_Page_Up:
718         {
719             action->private_data->transferFocus = FALSE;
720             gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
721             gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + action->private_data->page );
722             wasConsumed = TRUE;
723         }
724         break;
726         case GDK_Page_Down:
727         case GDK_KP_Page_Down:
728         {
729             action->private_data->transferFocus = FALSE;
730             gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
731             gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - action->private_data->page );
732             wasConsumed = TRUE;
733         }
734         break;
736         case GDK_z:
737         case GDK_Z:
738         {
739             action->private_data->transferFocus = FALSE;
740             gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal );
741             wasConsumed = TRUE;
742         }
743         break;
745     }
747     return wasConsumed;