Code

Cleanup public/private, doxygen comments
[inkscape.git] / src / ege-adjustment-action.cpp
index 52037f1e9751431c580dca116c3402f1f63a5586..179f1f24877fce91f415b2ab05b6f457f553b216 100644 (file)
 
 #include <string.h>
 
+#include <gdk/gdkkeysyms.h>
 #include <gtk/gtktoolitem.h>
 #include <gtk/gtkspinbutton.h>
 #include <gtk/gtkhbox.h>
 #include <gtk/gtklabel.h>
 #include <gtk/gtkmisc.h>
+#include <gtk/gtktoolbar.h>
+#include <gtk/gtkradiomenuitem.h>
 
 #include "ege-adjustment-action.h"
 
@@ -63,24 +66,48 @@ static void connect_proxy( GtkAction *action, GtkWidget *proxy );
 static void disconnect_proxy( GtkAction *action, GtkWidget *proxy );
 
 static gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
+static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
 static gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data );
 
-static GtkActionClass* gParentClass = 0;
+static void ege_adjustment_action_defocus( EgeAdjustmentAction* action );
+
 
+static GtkActionClass* gParentClass = 0;
+static GQuark gDataName = 0;
 
 struct _EgeAdjustmentActionPrivate
 {
     GtkAdjustment* adj;
     GtkWidget* focusWidget;
+    gdouble climbRate;
+    guint digits;
+    gchar* selfId;
+    EgeWidgetFixup toolPost;
     gdouble lastVal;
-    gboolean keepFocus;
+    gdouble step;
+    gdouble page;
+    gboolean transferFocus;
 };
 
 #define EGE_ADJUSTMENT_ACTION_GET_PRIVATE( o ) ( G_TYPE_INSTANCE_GET_PRIVATE( (o), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionPrivate ) )
 
 enum {
     PROP_ADJUSTMENT = 1,
-    PROP_FOCUS_WIDGET
+    PROP_FOCUS_WIDGET,
+    PROP_CLIMB_RATE,
+    PROP_DIGITS,
+    PROP_SELFID,
+    PROP_TOOL_POST
+};
+
+enum {
+    BUMP_TOP = 0,
+    BUMP_PAGE_UP,
+    BUMP_UP,
+    BUMP_NONE,
+    BUMP_DOWN,
+    BUMP_PAGE_DOWN,
+    BUMP_BOTTOM
 };
 
 GType ege_adjustment_action_get_type( void )
@@ -113,6 +140,8 @@ static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass )
         gParentClass = GTK_ACTION_CLASS( g_type_class_peek_parent( klass ) );
         GObjectClass * objClass = G_OBJECT_CLASS( klass );
 
+        gDataName = g_quark_from_string("ege-adj-action");
+
         objClass->get_property = ege_adjustment_action_get_property;
         objClass->set_property = ege_adjustment_action_set_property;
 
@@ -123,10 +152,11 @@ static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass )
 
         g_object_class_install_property( objClass,
                                          PROP_ADJUSTMENT,
-                                         g_param_spec_pointer( "adjustment",
-                                                               "Adjustment",
-                                                               "The adjustment to change",
-                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+                                         g_param_spec_object( "adjustment",
+                                                              "Adjustment",
+                                                              "The adjustment to change",
+                                                              GTK_TYPE_ADJUSTMENT,
+                                                              (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
 
         g_object_class_install_property( objClass,
                                          PROP_FOCUS_WIDGET,
@@ -135,6 +165,37 @@ static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass )
                                                                "The widget to return focus to",
                                                                (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
 
+        g_object_class_install_property( objClass,
+                                         PROP_CLIMB_RATE,
+                                         g_param_spec_double( "climb-rate",
+                                                              "Climb Rate",
+                                                              "The acelleraton rate",
+                                                              0.0, G_MAXDOUBLE, 0.0,
+                                                              (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+        g_object_class_install_property( objClass,
+                                         PROP_DIGITS,
+                                         g_param_spec_uint( "digits",
+                                                            "Digits",
+                                                            "The number of digits to show",
+                                                            0, 20, 0,
+                                                            (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+        g_object_class_install_property( objClass,
+                                         PROP_SELFID,
+                                         g_param_spec_string( "self-id",
+                                                              "Self ID",
+                                                              "Marker for self pointer",
+                                                              0,
+                                                              (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
+        g_object_class_install_property( objClass,
+                                         PROP_TOOL_POST,
+                                         g_param_spec_pointer( "tool-post",
+                                                               "Tool Widget post process",
+                                                               "Function for final adjustments",
+                                                               (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) );
+
         g_type_class_add_private( klass, sizeof(EgeAdjustmentActionClass) );
     }
 }
@@ -144,15 +205,23 @@ static void ege_adjustment_action_init( EgeAdjustmentAction* action )
     action->private_data = EGE_ADJUSTMENT_ACTION_GET_PRIVATE( action );
     action->private_data->adj = 0;
     action->private_data->focusWidget = 0;
+    action->private_data->climbRate = 0.0;
+    action->private_data->digits = 2;
+    action->private_data->selfId = 0;
+    action->private_data->toolPost = 0;
     action->private_data->lastVal = 0.0;
-    action->private_data->keepFocus = FALSE;
+    action->private_data->step = 0.0;
+    action->private_data->page = 0.0;
+    action->private_data->transferFocus = FALSE;
 }
 
 EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment,
                                                 const gchar *name,
                                                 const gchar *label,
                                                 const gchar *tooltip,
-                                                const gchar *stock_id )
+                                                const gchar *stock_id,
+                                                gdouble climb_rate,
+                                                guint digits )
 {
     GObject* obj = (GObject*)g_object_new( EGE_ADJUSTMENT_ACTION_TYPE,
                                            "name", name,
@@ -160,6 +229,8 @@ EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment,
                                            "tooltip", tooltip,
                                            "stock_id", stock_id,
                                            "adjustment", adjustment,
+                                           "climb-rate", climb_rate,
+                                           "digits", digits,
                                            NULL );
 
     EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
@@ -172,16 +243,28 @@ static void ege_adjustment_action_get_property( GObject* obj, guint propId, GVal
     EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj );
     switch ( propId ) {
         case PROP_ADJUSTMENT:
-        {
-            g_value_set_pointer( value, action->private_data->adj );
-        }
-        break;
+            g_value_set_object( value, action->private_data->adj );
+            break;
 
         case PROP_FOCUS_WIDGET:
-        {
             g_value_set_pointer( value, action->private_data->focusWidget );
-        }
-        break;
+            break;
+
+        case PROP_CLIMB_RATE:
+            g_value_set_double( value, action->private_data->climbRate );
+            break;
+
+        case PROP_DIGITS:
+            g_value_set_uint( value, action->private_data->digits );
+            break;
+
+        case PROP_SELFID:
+            g_value_set_string( value, action->private_data->selfId );
+            break;
+
+        case PROP_TOOL_POST:
+            g_value_set_pointer( value, (void*)action->private_data->toolPost );
+            break;
 
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
@@ -194,7 +277,11 @@ void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValu
     switch ( propId ) {
         case PROP_ADJUSTMENT:
         {
-            action->private_data->adj = (GtkAdjustment*)g_value_get_pointer( value );
+            action->private_data->adj = GTK_ADJUSTMENT( g_value_get_object( value ) );
+            g_object_get( G_OBJECT(action->private_data->adj),
+                          "step-increment", &action->private_data->step,
+                          "page-increment", &action->private_data->page,
+                          NULL );
         }
         break;
 
@@ -205,6 +292,35 @@ void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValu
         }
         break;
 
+        case PROP_CLIMB_RATE:
+        {
+            /* TODO pass on */
+            action->private_data->climbRate = g_value_get_double( value );
+        }
+        break;
+
+        case PROP_DIGITS:
+        {
+            /* TODO pass on */
+            action->private_data->digits = g_value_get_uint( value );
+        }
+        break;
+
+        case PROP_SELFID:
+        {
+            /* TODO pass on */
+            gchar* prior = action->private_data->selfId;
+            action->private_data->selfId = g_value_dup_string( value );
+            g_free( prior );
+        }
+        break;
+
+        case PROP_TOOL_POST:
+        {
+            action->private_data->toolPost = (EgeWidgetFixup)g_value_get_pointer( value );
+        }
+        break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec );
     }
@@ -233,31 +349,178 @@ GtkWidget* ege_adjustment_action_get_focuswidget( EgeAdjustmentAction* action )
     return action->private_data->focusWidget;
 }
 
+static void process_menu_action( GtkWidget* obj, gpointer data )
+{
+    GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(obj);
+    if ( item->active ) {
+        EgeAdjustmentAction* act = (EgeAdjustmentAction*)g_object_get_qdata( G_OBJECT(obj), gDataName );
+        gint what = GPOINTER_TO_INT(data);
+
+
+        gdouble base = gtk_adjustment_get_value( act->private_data->adj );
+        gdouble lower = 0.0;
+        gdouble upper = 0.0;
+        gdouble step = 0.0;
+        gdouble page = 0.0;
+        g_object_get( G_OBJECT(act->private_data->adj),
+                      "lower", &lower,
+                      "upper", &upper,
+                      "step-increment", &step,
+                      "page-increment", &page,
+                      NULL );
+
+        switch ( what ) {
+            case BUMP_TOP:
+                gtk_adjustment_set_value( act->private_data->adj, upper );
+                break;
+
+            case BUMP_PAGE_UP:
+                gtk_adjustment_set_value( act->private_data->adj, base + page );
+                break;
+
+            case BUMP_UP:
+                gtk_adjustment_set_value( act->private_data->adj, base + step );
+                break;
+
+            case BUMP_DOWN:
+                gtk_adjustment_set_value( act->private_data->adj, base - step );
+                break;
+
+            case BUMP_PAGE_DOWN:
+                gtk_adjustment_set_value( act->private_data->adj, base - page );
+                break;
+
+            case BUMP_BOTTOM:
+                gtk_adjustment_set_value( act->private_data->adj, lower );
+                break;
+        }
+    }
+}
+
+static void create_single_menu( GCallback toggleCb, int val, GtkWidget* menu, EgeAdjustmentAction* act, GtkWidget** dst, GSList** group, gdouble num, gboolean active )
+{
+    char* fmt = g_strdup_printf("%%0.%df", act->private_data->digits);
+    char *str = g_strdup_printf ( fmt, num );
+
+    *dst = gtk_radio_menu_item_new_with_label( *group, str );
+    if ( !*group) {
+        *group = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(*dst) );
+    }
+    if ( active ) {
+        gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(*dst), TRUE );
+    }
+    gtk_menu_shell_append( GTK_MENU_SHELL(menu), *dst );
+    g_object_set_qdata( G_OBJECT(*dst), gDataName, act );
+
+    g_signal_connect( G_OBJECT(*dst), "toggled", toggleCb, GINT_TO_POINTER(val) );
+
+    g_free(str);
+    g_free(fmt);
+}
+
+static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act )
+{
+    GtkWidget* menu = gtk_menu_new();
+
+    GSList* group = 0;
+    GtkWidget* single = 0;
+
+    gdouble base = gtk_adjustment_get_value( act->private_data->adj );
+    gdouble lower = 0.0;
+    gdouble upper = 0.0;
+    gdouble step = 0.0;
+    gdouble page = 0.0;
+    g_object_get( G_OBJECT(act->private_data->adj),
+                  "lower", &lower,
+                  "upper", &upper,
+                  "step-increment", &step,
+                  "page-increment", &page,
+                  NULL );
+
+    if ( base < upper ) {
+        create_single_menu( G_CALLBACK(process_menu_action), BUMP_TOP, menu, act, &single, &group, upper, FALSE );
+        if ( (base + page) < upper ) {
+            create_single_menu( G_CALLBACK(process_menu_action), BUMP_PAGE_UP, menu, act, &single, &group, base + page, FALSE );
+        }
+        if ( (base + step) < upper ) {
+            create_single_menu( G_CALLBACK(process_menu_action), BUMP_UP, menu, act, &single, &group, base + step, FALSE );
+        }
+    }
+
+    create_single_menu( G_CALLBACK(process_menu_action), BUMP_NONE, menu, act, &single, &group, base, TRUE );
+    if ( base > lower ) {
+        if ( (base - step) > lower ) {
+            create_single_menu( G_CALLBACK(process_menu_action), BUMP_DOWN, menu, act, &single, &group, base - step, FALSE );
+        }
+        if ( (base - page) > lower ) {
+            create_single_menu( G_CALLBACK(process_menu_action), BUMP_PAGE_DOWN, menu, act, &single, &group, base - page, FALSE );
+        }
+        create_single_menu( G_CALLBACK(process_menu_action), BUMP_BOTTOM, menu, act, &single, &group, lower, FALSE );
+    }
+
+    return menu;
+}
+
 static GtkWidget* create_menu_item( GtkAction* action )
 {
     GtkWidget* item = 0;
 
-    item = gParentClass->create_menu_item( action );
+    if ( IS_EGE_ADJUSTMENT_ACTION(action) ) {
+        EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action );
+        GValue value;
+        const gchar*  sss = 0;
+        GtkWidget*  subby = 0;
+
+        memset( &value, 0, sizeof(value) );
+        g_value_init( &value, G_TYPE_STRING );
+        g_object_get_property( G_OBJECT(action), "label", &value );
+
+        sss = g_value_get_string( &value );
+
+        item = gtk_menu_item_new_with_label( sss );
+
+        subby = create_popup_number_menu( act );
+        gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby );
+        gtk_widget_show_all( subby );
+    } else {
+        item = gParentClass->create_menu_item( action );
+    }
 
     return item;
 }
 
-/* void flippy(GtkAdjustment *adj, GtkWidget *) */
-/* { */
-/*     g_message("flippy  on %p to %f", adj, gtk_adjustment_get_value(adj) ); */
-/* } */
+void value_changed_cb( GtkSpinButton* spin, EgeAdjustmentAction* act )
+{
+    if ( GTK_WIDGET_HAS_FOCUS( GTK_WIDGET(spin) ) ) {
+        ege_adjustment_action_defocus( act );
+    }
+}
+
+static gboolean event_cb( EgeAdjustmentAction* act, GdkEvent* evt )
+{
+    gboolean handled = FALSE;
+    if ( evt->type == GDK_BUTTON_PRESS ) {
+        if ( evt->button.button == 3 ) {
+            if ( IS_EGE_ADJUSTMENT_ACTION(act) ) {
+                GdkEventButton* btnevt = (GdkEventButton*)evt;
+                GtkWidget* menu = create_popup_number_menu(act);
+                gtk_widget_show_all( menu );
+                gtk_menu_popup( GTK_MENU(menu), NULL, NULL, NULL, NULL, btnevt->button, btnevt->time );
+            }
+            handled = TRUE;
+        }
+    }
 
-/* void floppy(GtkSpinButton *spin, GtkWidget *) */
-/* { */
-/*     g_message("f__ppy  on %p to %f", spin, gtk_spin_button_get_value(spin) ); */
-/* } */
+    return handled;
+}
 
 static GtkWidget* create_tool_item( GtkAction* action )
 {
     GtkWidget* item = 0;
 
     if ( IS_EGE_ADJUSTMENT_ACTION(action) ) {
-        GtkWidget* spinbutton = gtk_spin_button_new( EGE_ADJUSTMENT_ACTION(action)->private_data->adj, 0.1, 2 );
+        EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action );
+        GtkWidget* spinbutton = gtk_spin_button_new( act->private_data->adj, act->private_data->climbRate, act->private_data->digits );
         GtkWidget* hb = gtk_hbox_new( FALSE, 5 );
         GValue value;
 
@@ -275,14 +538,24 @@ static GtkWidget* create_tool_item( GtkAction* action )
         gtk_box_pack_end( GTK_BOX(hb), spinbutton, FALSE, FALSE, 0 );
         gtk_container_add( GTK_CONTAINER(item), hb );
 
+        if ( act->private_data->selfId ) {
+            g_object_set_data( G_OBJECT(spinbutton), act->private_data->selfId, spinbutton );
+        }
+
         g_signal_connect( G_OBJECT(spinbutton), "focus-in-event", G_CALLBACK(focus_in_cb), action );
+        g_signal_connect( G_OBJECT(spinbutton), "focus-out-event", G_CALLBACK(focus_out_cb), action );
         g_signal_connect( G_OBJECT(spinbutton), "key-press-event", G_CALLBACK(keypress_cb), action );
 
-/*      g_signal_connect( G_OBJECT(spinbutton), "value-changed", G_CALLBACK(floppy), action ); */
-/*      g_signal_connect( G_OBJECT(EGE_ADJUSTMENT_ACTION(action)->private_data->adj), "value-changed", G_CALLBACK(flippy), action ); */
+        g_signal_connect( G_OBJECT(spinbutton), "value-changed", G_CALLBACK(value_changed_cb), action );
 
+        g_signal_connect_swapped( G_OBJECT(spinbutton), "event", G_CALLBACK(event_cb), action );
 
         gtk_widget_show_all( item );
+
+        /* Shrink or whatnot after shown */
+        if ( act->private_data->toolPost ) {
+            act->private_data->toolPost( item );
+        }
     } else {
         item = gParentClass->create_tool_item( action );
     }
@@ -302,9 +575,7 @@ static void disconnect_proxy( GtkAction *action, GtkWidget *proxy )
 
 void ege_adjustment_action_defocus( EgeAdjustmentAction* action )
 {
-    if ( action->private_data->keepFocus ) {
-        action->private_data->keepFocus = FALSE;
-    } else {
+    if ( action->private_data->transferFocus ) {
         if ( action->private_data->focusWidget ) {
             gtk_widget_grab_focus( action->private_data->focusWidget );
         }
@@ -313,16 +584,165 @@ void ege_adjustment_action_defocus( EgeAdjustmentAction* action )
 
 gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
 {
+    (void)event;
     if ( IS_EGE_ADJUSTMENT_ACTION(data) ) {
         EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data );
         action->private_data->lastVal = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+        action->private_data->transferFocus = TRUE;
     }
 
     return FALSE; /* report event not consumed */
 }
 
-gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
+static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
 {
+    (void)widget;
+    (void)event;
+    if ( IS_EGE_ADJUSTMENT_ACTION(data) ) {
+        EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data );
+        action->private_data->transferFocus = FALSE;
+    }
 
     return FALSE; /* report event not consumed */
 }
+
+
+static gboolean process_tab( GtkWidget* widget, int direction )
+{
+    gboolean handled = FALSE;
+    GtkWidget* parent = gtk_widget_get_parent(widget);
+    GtkWidget* gp = parent ? gtk_widget_get_parent(parent) : 0;
+    GtkWidget* ggp = gp ? gtk_widget_get_parent(gp) : 0;
+
+    if ( ggp && GTK_IS_TOOLBAR(ggp) ) {
+        GList* kids = gtk_container_get_children( GTK_CONTAINER(ggp) );
+        if ( kids ) {
+            GtkWidget* curr = widget;
+            while ( curr && (gtk_widget_get_parent(curr) != ggp) ) {
+                curr = gtk_widget_get_parent( curr );
+            }
+            if ( curr ) {
+                GList* mid = g_list_find( kids, curr );
+                while ( mid ) {
+                    mid = ( direction < 0 ) ? g_list_previous(mid) : g_list_next(mid);
+                    if ( mid && GTK_IS_TOOL_ITEM(mid->data) ) {
+                        /* potential target */
+                        GtkWidget* child = gtk_bin_get_child( GTK_BIN(mid->data) );
+                        if ( child && GTK_IS_HBOX(child) ) { /* could be ours */
+                            GList* subChildren = gtk_container_get_children( GTK_CONTAINER(child) );
+                            if ( subChildren ) {
+                                GList* last = g_list_last(subChildren);
+                                if ( last && GTK_IS_SPIN_BUTTON(last->data) && GTK_WIDGET_IS_SENSITIVE( GTK_WIDGET(last->data) ) ) {
+                                    gtk_widget_grab_focus( GTK_WIDGET(last->data) );
+                                    handled = TRUE;
+                                    mid = 0; /* to stop loop */
+                                }
+
+                                g_list_free(subChildren);
+                            }
+                        }
+                    }
+                }
+            }
+            g_list_free( kids );
+        }
+    }
+
+    return handled;
+}
+
+gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data )
+{
+    gboolean wasConsumed = FALSE; /* default to report event not consumed */
+    EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION(data);
+    guint key = 0;
+    gdk_keymap_translate_keyboard_state( gdk_keymap_get_for_display( gdk_display_get_default() ),
+                                         event->hardware_keycode, (GdkModifierType)event->state,
+                                         0, &key, 0, 0, 0 );
+
+    switch ( key ) {
+        case GDK_Escape:
+        {
+            action->private_data->transferFocus = TRUE;
+            gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal );
+            ege_adjustment_action_defocus( action );
+            wasConsumed = TRUE;
+        }
+        break;
+
+        case GDK_Return:
+        case GDK_KP_Enter:
+        {
+            action->private_data->transferFocus = TRUE;
+            ege_adjustment_action_defocus( action );
+            wasConsumed = TRUE;
+        }
+        break;
+
+        case GDK_Tab:
+        {
+            action->private_data->transferFocus = FALSE;
+            wasConsumed = process_tab( widget, 1 );
+        }
+        break;
+
+        case GDK_ISO_Left_Tab:
+        {
+            action->private_data->transferFocus = FALSE;
+            wasConsumed = process_tab( widget, -1 );
+        }
+        break;
+
+        case GDK_Up:
+        case GDK_KP_Up:
+        {
+            action->private_data->transferFocus = FALSE;
+            gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+            gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + action->private_data->step );
+            wasConsumed = TRUE;
+        }
+        break;
+
+        case GDK_Down:
+        case GDK_KP_Down:
+        {
+            action->private_data->transferFocus = FALSE;
+            gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+            gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - action->private_data->step );
+            wasConsumed = TRUE;
+        }
+        break;
+
+        case GDK_Page_Up:
+        case GDK_KP_Page_Up:
+        {
+            action->private_data->transferFocus = FALSE;
+            gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+            gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + action->private_data->page );
+            wasConsumed = TRUE;
+        }
+        break;
+
+        case GDK_Page_Down:
+        case GDK_KP_Page_Down:
+        {
+            action->private_data->transferFocus = FALSE;
+            gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) );
+            gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - action->private_data->page );
+            wasConsumed = TRUE;
+        }
+        break;
+
+        case GDK_z:
+        case GDK_Z:
+        {
+            action->private_data->transferFocus = FALSE;
+            gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal );
+            wasConsumed = TRUE;
+        }
+        break;
+
+    }
+
+    return wasConsumed;
+}