Code

Cmake: Improve Gtkmm dependency checking, add new files to CMakeLists.txts, remove...
[inkscape.git] / src / ege-adjustment-action.cpp
index d140ae12cceea295a4d70d87d37cb0636b9b4782..1983534df49797a5be255f22c04b245096315a11 100644 (file)
@@ -39,7 +39,7 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
-/* Note: this file should be kept compliable as both .cpp and .c */
+/* Note: this file should be kept compilable as both .cpp and .c */
 
 #include <string.h>
 
@@ -50,6 +50,7 @@
 #include <gtk/gtklabel.h>
 #include <gtk/gtkmisc.h>
 #include <gtk/gtktoolbar.h>
+#include <gtk/gtktooltips.h>
 #include <gtk/gtkradiomenuitem.h>
 
 #include "ege-adjustment-action.h"
@@ -57,6 +58,7 @@
 
 static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass );
 static void ege_adjustment_action_init( EgeAdjustmentAction* action );
+static void ege_adjustment_action_finalize( GObject* object );
 static void ege_adjustment_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec );
 static void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec );
 
@@ -71,6 +73,9 @@ static gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer dat
 
 static void ege_adjustment_action_defocus( EgeAdjustmentAction* action );
 
+static void egeAct_free_description( gpointer data, gpointer user_data );
+static void egeAct_free_all_descriptions( EgeAdjustmentAction* action );
+
 
 static GtkActionClass* gParentClass = 0;
 static GQuark gDataName = 0;
@@ -86,9 +91,12 @@ struct _EgeAdjustmentDescr
 struct _EgeAdjustmentActionPrivate
 {
     GtkAdjustment* adj;
+    GtkTooltips* toolTips;
     GtkWidget* focusWidget;
     gdouble climbRate;
     guint digits;
+    gdouble epsilon;
+    gchar* format;
     gchar* selfId;
     EgeWidgetFixup toolPost;
     gdouble lastVal;
@@ -116,7 +124,8 @@ enum {
     BUMP_NONE,
     BUMP_DOWN,
     BUMP_PAGE_DOWN,
-    BUMP_BOTTOM
+    BUMP_BOTTOM,
+    BUMP_CUSTOM = 100
 };
 
 GType ege_adjustment_action_get_type( void )
@@ -151,6 +160,8 @@ static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass )
 
         gDataName = g_quark_from_string("ege-adj-action");
 
+        objClass->finalize = ege_adjustment_action_finalize;
+
         objClass->get_property = ege_adjustment_action_get_property;
         objClass->set_property = ege_adjustment_action_set_property;
 
@@ -213,9 +224,12 @@ 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->toolTips = 0;
     action->private_data->focusWidget = 0;
     action->private_data->climbRate = 0.0;
     action->private_data->digits = 2;
+    action->private_data->epsilon = 0.009;
+    action->private_data->format = g_strdup_printf("%%0.%df%%s%%s", action->private_data->digits);
     action->private_data->selfId = 0;
     action->private_data->toolPost = 0;
     action->private_data->lastVal = 0.0;
@@ -225,6 +239,26 @@ static void ege_adjustment_action_init( EgeAdjustmentAction* action )
     action->private_data->descriptions = 0;
 }
 
+static void ege_adjustment_action_finalize( GObject* object )
+{
+    EgeAdjustmentAction* action = 0;
+    g_return_if_fail( object != NULL );
+    g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(object) );
+
+    action = EGE_ADJUSTMENT_ACTION( object );
+
+    if ( action->private_data->format ) {
+        g_free( action->private_data->format );
+        action->private_data->format = 0;
+    }
+
+    egeAct_free_all_descriptions( action );
+
+    if ( G_OBJECT_CLASS(gParentClass)->finalize ) {
+        (*G_OBJECT_CLASS(gParentClass)->finalize)(object);
+    }
+}
+
 EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment,
                                                 const gchar *name,
                                                 const gchar *label,
@@ -313,6 +347,17 @@ void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValu
         {
             /* TODO pass on */
             action->private_data->digits = g_value_get_uint( value );
+            switch ( action->private_data->digits ) {
+                case 0: action->private_data->epsilon = 0.9; break;
+                case 1: action->private_data->epsilon = 0.09; break;
+                case 2: action->private_data->epsilon = 0.009; break;
+                case 3: action->private_data->epsilon = 0.0009; break;
+                case 4: action->private_data->epsilon = 0.00009; break;
+            }
+            if ( action->private_data->format ) {
+                g_free( action->private_data->format );
+            }
+            action->private_data->format = g_strdup_printf("%%0.%df%%s%%s", action->private_data->digits);
         }
         break;
 
@@ -359,19 +404,28 @@ GtkWidget* ege_adjustment_action_get_focuswidget( EgeAdjustmentAction* action )
     return action->private_data->focusWidget;
 }
 
-static void i_free_description( gpointer data, gpointer user_data ) {
+static void egeAct_free_description( gpointer data, gpointer user_data ) {
     (void)user_data;
     if ( data ) {
         EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)data;
-       if ( descr->descr ) {
-           g_free( descr->descr );
-           descr->descr = 0;
-       }
-       g_free( descr );
+        if ( descr->descr ) {
+            g_free( descr->descr );
+            descr->descr = 0;
+        }
+        g_free( descr );
     }
 }
 
-static gint i_compare_descriptions( gconstpointer a, gconstpointer b )
+static void egeAct_free_all_descriptions( EgeAdjustmentAction* action )
+{
+    if ( action->private_data->descriptions ) {
+        g_list_foreach( action->private_data->descriptions, egeAct_free_description, 0 );
+        g_list_free( action->private_data->descriptions );
+        action->private_data->descriptions = 0;
+    }
+}
+
+static gint egeAct_compare_descriptions( gconstpointer a, gconstpointer b )
 {
     gint val = 0;
 
@@ -380,10 +434,10 @@ static gint i_compare_descriptions( gconstpointer a, gconstpointer b )
 
     if ( aa && bb ) {
         if ( aa->value < bb->value ) {
-           val = -1;
-       } else if ( aa->value > bb->value ) {
-           val = 1;
-       }
+            val = -1;
+        } else if ( aa->value > bb->value ) {
+            val = 1;
+        }
     }
 
     return val;
@@ -393,22 +447,16 @@ void ege_adjustment_action_set_descriptions( EgeAdjustmentAction* action, gchar
 {
     g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(action) );
 
-    if ( action->private_data->descriptions ) {
-        g_list_foreach( action->private_data->descriptions, i_free_description, 0 );
-       g_list_free( action->private_data->descriptions );
-       action->private_data->descriptions = 0;
-    }
+    egeAct_free_all_descriptions( action );
 
     if ( count && descriptions && values ) {
         guint i = 0;
         for ( i = 0; i < count; i++ ) {
-           EgeAdjustmentDescr* descr = g_new0( EgeAdjustmentDescr, 1 );
-           if ( descriptions[i] ) {
-               descr->descr = g_strdup( descriptions[i] );
-               descr->value = values[i];
-           }
-           action->private_data->descriptions = g_list_insert_sorted( action->private_data->descriptions, (gpointer)descr, i_compare_descriptions );
-       }
+            EgeAdjustmentDescr* descr = g_new0( EgeAdjustmentDescr, 1 );
+            descr->descr = descriptions[i] ? g_strdup( descriptions[i] ) : 0;
+            descr->value = values[i];
+            action->private_data->descriptions = g_list_insert_sorted( action->private_data->descriptions, (gpointer)descr, egeAct_compare_descriptions );
+        }
     }
 }
 
@@ -456,41 +504,43 @@ static void process_menu_action( GtkWidget* obj, gpointer data )
             case BUMP_BOTTOM:
                 gtk_adjustment_set_value( act->private_data->adj, lower );
                 break;
+
+            default:
+                if ( what >= BUMP_CUSTOM ) {
+                    guint index = what - BUMP_CUSTOM;
+                    if ( index < g_list_length( act->private_data->descriptions ) ) {
+                        EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)g_list_nth_data( act->private_data->descriptions, index );
+                        if ( descr ) {
+                            gtk_adjustment_set_value( act->private_data->adj, descr->value );
+                        }
+                    }
+                }
         }
     }
 }
 
 static void create_single_menu_item( GCallback toggleCb, int val, GtkWidget* menu, EgeAdjustmentAction* act, GtkWidget** dst, GSList** group, gdouble num, gboolean active )
 {
-    gdouble epsilon = 0.1;
-    char* fmt = 0;
     char* str = 0;
     EgeAdjustmentDescr* marker = 0;
     GList* cur = act->private_data->descriptions;
 
-    switch ( act->private_data->digits ) {
-        case 0: epsilon = 1.0; break;
-        case 1: epsilon = 0.1; break;
-        case 2: epsilon = 0.01; break;
-        case 3: epsilon = 0.001; break;
-        case 4: epsilon = 0.0001; break;
-    }
-
     while ( cur ) {
         EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)cur->data;
-       gdouble delta = num - descr->value;
-       if ( delta < 0.0 ) {
-           delta = -delta;
-       }
-       if ( delta < epsilon ) {
-           marker = descr;
-           break;
-       }
-       cur = g_list_next( cur );
+        gdouble delta = num - descr->value;
+        if ( delta < 0.0 ) {
+            delta = -delta;
+        }
+        if ( delta < act->private_data->epsilon ) {
+            marker = descr;
+            break;
+        }
+        cur = g_list_next( cur );
     }
 
-    fmt = g_strdup_printf("%%0.%df%%s%%s", act->private_data->digits);
-    str = g_strdup_printf ( fmt, num, (marker?" ":""), (marker?marker->descr:"") );
+    str = g_strdup_printf( act->private_data->format, num, 
+                           ((marker && marker->descr) ? ": " : ""),
+                           ((marker && marker->descr) ? marker->descr : ""));
 
     *dst = gtk_radio_menu_item_new_with_label( *group, str );
     if ( !*group) {
@@ -505,7 +555,36 @@ static void create_single_menu_item( GCallback toggleCb, int val, GtkWidget* men
     g_signal_connect( G_OBJECT(*dst), "toggled", toggleCb, GINT_TO_POINTER(val) );
 
     g_free(str);
-    g_free(fmt);
+}
+
+static GList* flush_explicit_items( GList* descriptions,
+                                    GCallback toggleCb,
+                                    int val,
+                                    GtkWidget* menu,
+                                    EgeAdjustmentAction* act,
+                                    GtkWidget** dst,
+                                    GSList** group,
+                                    gdouble num )
+{
+    GList* cur = descriptions;
+
+    if ( cur ) {
+        gdouble valUpper = num + act->private_data->epsilon;
+        gdouble valLower = num - act->private_data->epsilon;
+
+        EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)cur->data;
+
+        while ( cur && descr && (descr->value >= valLower) ) {
+            if ( descr->value > valUpper ) {
+                create_single_menu_item( toggleCb, val + g_list_position(act->private_data->descriptions, cur), menu, act, dst, group, descr->value, FALSE );
+            }
+
+            cur = g_list_previous( cur );
+            descr = cur ? (EgeAdjustmentDescr*)cur->data : 0;
+        }
+    }
+
+    return cur;
 }
 
 static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act )
@@ -515,6 +594,8 @@ static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act )
     GSList* group = 0;
     GtkWidget* single = 0;
 
+    GList* addOns = g_list_last( act->private_data->descriptions );
+
     gdouble base = gtk_adjustment_get_value( act->private_data->adj );
     gdouble lower = 0.0;
     gdouble upper = 0.0;
@@ -527,28 +608,41 @@ static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act )
                   "page-increment", &page,
                   NULL );
 
+
     if ( base < upper ) {
+        addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, upper );
         create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_TOP, menu, act, &single, &group, upper, FALSE );
         if ( (base + page) < upper ) {
+            addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base + page );
             create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_PAGE_UP, menu, act, &single, &group, base + page, FALSE );
         }
         if ( (base + step) < upper ) {
+            addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base + step );
             create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_UP, menu, act, &single, &group, base + step, FALSE );
         }
     }
 
+    addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base );
     create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_NONE, menu, act, &single, &group, base, TRUE );
 
     if ( base > lower ) {
         if ( (base - step) > lower ) {
+            addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base - step );
             create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_DOWN, menu, act, &single, &group, base - step, FALSE );
         }
         if ( (base - page) > lower ) {
+            addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base - page );
             create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_PAGE_DOWN, menu, act, &single, &group, base - page, FALSE );
         }
+        addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, lower );
         create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_BOTTOM, menu, act, &single, &group, lower, FALSE );
     }
 
+    if ( act->private_data->descriptions ) {
+        gdouble value = ((EgeAdjustmentDescr*)act->private_data->descriptions->data)->value;
+        addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, value );
+    }
+
     return menu;
 }
 
@@ -619,14 +713,32 @@ static GtkWidget* create_tool_item( GtkAction* action )
 
         memset( &value, 0, sizeof(value) );
         g_value_init( &value, G_TYPE_STRING );
-        g_object_get_property( G_OBJECT(action), "label", &value );
+        g_object_get_property( G_OBJECT(action), "short_label", &value );
         const gchar* sss = g_value_get_string( &value );
+
         GtkWidget* lbl = gtk_label_new( sss ? sss : "wwww" );
+        GtkWidget* filler1 = gtk_label_new(" ");
+
+        {
+            GValue tooltip;
+            memset( &tooltip, 0, sizeof(tooltip) );
+            g_value_init( &tooltip, G_TYPE_STRING );
+            g_object_get_property( G_OBJECT(action), "tooltip", &tooltip );
+            const gchar* tipstr = g_value_get_string( &tooltip );
+            if ( tipstr && *tipstr ) {
+                if ( !act->private_data->toolTips ) {
+                    act->private_data->toolTips = gtk_tooltips_new();
+                }
+                gtk_tooltips_set_tip( act->private_data->toolTips, spinbutton, tipstr, 0 );
+            }
+        }
 
         gtk_misc_set_alignment( GTK_MISC(lbl), 1.0, 0.5 );
 
+        gtk_box_pack_start( GTK_BOX(hb), filler1, FALSE, FALSE, 0 );
         gtk_box_pack_start( GTK_BOX(hb), lbl, FALSE, FALSE, 0 );
-        gtk_box_pack_end( GTK_BOX(hb), spinbutton, FALSE, FALSE, 0 );
+        gtk_box_pack_start( GTK_BOX(hb), spinbutton, FALSE, FALSE, 0 );
+
         gtk_container_add( GTK_CONTAINER(item), hb );
 
         if ( act->private_data->selfId ) {
@@ -640,6 +752,7 @@ static GtkWidget* create_tool_item( GtkAction* 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_entry_set_width_chars( GTK_ENTRY(spinbutton), act->private_data->digits + 3 );
 
         gtk_widget_show_all( item );