summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Smith <john.smith7545@yahoo.com>2012-09-22 01:43:42 +0000
committerJohn Smith <john.smith7545@yahoo.com>2012-09-22 01:43:42 +0000
commit5ab9fc74c53a9e59dd4f46a1f8ff027f878e7836 (patch)
tree0f09c4e06b1cc8b33da603f8e114b9c7bd54867b /src
parentFix for bug #1053024: set current layer from template in new blank document a... (diff)
downloadinkscape-5ab9fc74c53a9e59dd4f46a1f8ff027f878e7836.tar.gz
inkscape-5ab9fc74c53a9e59dd4f46a1f8ff027f878e7836.zip
Fix for 1014988 : Add gimp spin scale widget
(bzr r11690)
Diffstat (limited to 'src')
-rw-r--r--src/ui/widget/Makefile_insert4
-rw-r--r--src/ui/widget/gimpspinscale.c1089
-rw-r--r--src/ui/widget/gimpspinscale.h76
-rw-r--r--src/ui/widget/spin-scale.cpp248
-rw-r--r--src/ui/widget/spin-scale.h117
5 files changed, 1534 insertions, 0 deletions
diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert
index 8589f16b0..bbda64648 100644
--- a/src/ui/widget/Makefile_insert
+++ b/src/ui/widget/Makefile_insert
@@ -19,6 +19,8 @@ ink_common_sources += \
ui/widget/entry.h \
ui/widget/filter-effect-chooser.h \
ui/widget/filter-effect-chooser.cpp \
+ ui/widget/gimpspinscale.c \
+ ui/widget/gimpspinscale.h \
ui/widget/frame.cpp \
ui/widget/frame.h \
ui/widget/imageicon.cpp \
@@ -62,6 +64,8 @@ ink_common_sources += \
ui/widget/selected-style.cpp \
ui/widget/spinbutton.h \
ui/widget/spinbutton.cpp \
+ ui/widget/spin-scale.h \
+ ui/widget/spin-scale.cpp \
ui/widget/spin-slider.h \
ui/widget/spin-slider.cpp \
ui/widget/style-subject.h \
diff --git a/src/ui/widget/gimpspinscale.c b/src/ui/widget/gimpspinscale.c
new file mode 100644
index 000000000..1b7ac7bfe
--- /dev/null
+++ b/src/ui/widget/gimpspinscale.c
@@ -0,0 +1,1089 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpspinscale.c
+ * Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
+ * 2012 Øyvind Kolås <pippin@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gimpspinscale.h"
+
+
+enum
+{
+ PROP_0,
+ PROP_LABEL,
+ PROP_FOCUS_WIDGET
+};
+
+typedef enum
+{
+ TARGET_NUMBER,
+ TARGET_UPPER,
+ TARGET_LOWER
+#if WITH_GTKMM_3_0
+ ,TARGET_NONE
+#endif
+} SpinScaleTarget;
+
+typedef enum
+{
+ APPEARANCE_FULL = 1, /* Full size suitable for tablets */
+ APPEARANCE_COMPACT, /* Compact, suitable for desktops with mouse control */
+} SpinScaleAppearance;
+
+typedef struct _GimpSpinScalePrivate GimpSpinScalePrivate;
+
+struct _GimpSpinScalePrivate
+{
+ gchar *label;
+
+ gboolean scale_limits_set;
+ gdouble scale_lower;
+ gdouble scale_upper;
+ gdouble gamma;
+
+ PangoLayout *layout;
+ gboolean changing_value;
+ gboolean relative_change;
+ gdouble start_x;
+ gdouble start_value;
+
+ GtkWidget* focusWidget;
+ gboolean transferFocus;
+ SpinScaleAppearance appearanceMode;
+};
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+ GIMP_TYPE_SPIN_SCALE, \
+ GimpSpinScalePrivate))
+
+
+static void gimp_spin_scale_dispose (GObject *object);
+static void gimp_spin_scale_finalize (GObject *object);
+static void gimp_spin_scale_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_spin_scale_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_spin_scale_style_set (GtkWidget *widget,
+ GtkStyle *prev_style);
+
+#if WITH_GTKMM_3_0
+static void gimp_spin_scale_get_preferred_width (GtkWidget *widget,
+ gint *minimum_width,
+ gint *natural_width);
+static void gimp_spin_scale_get_preferred_height (GtkWidget *widget,
+ gint *minimum_width,
+ gint *natural_width);
+static gboolean gimp_spin_scale_draw (GtkWidget *widget,
+ cairo_t *cr);
+#else
+static void gimp_spin_scale_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+
+static gboolean gimp_spin_scale_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+#endif
+
+static gboolean gimp_spin_scale_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean gimp_spin_scale_button_release (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean gimp_spin_scale_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event);
+static gboolean gimp_spin_scale_leave_notify (GtkWidget *widget,
+ GdkEventCrossing *event);
+static gboolean gimp_spin_scale_keypress( GtkWidget *widget,
+ GdkEventKey *event);
+
+static void gimp_spin_scale_defocus( GtkSpinButton *spin_button );
+
+static void gimp_spin_scale_value_changed (GtkSpinButton *spin_button);
+
+
+G_DEFINE_TYPE (GimpSpinScale, gimp_spin_scale, GTK_TYPE_SPIN_BUTTON);
+
+#define parent_class gimp_spin_scale_parent_class
+
+
+static void
+gimp_spin_scale_class_init (GimpSpinScaleClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkSpinButtonClass *spin_button_class = GTK_SPIN_BUTTON_CLASS (klass);
+
+ object_class->dispose = gimp_spin_scale_dispose;
+ object_class->finalize = gimp_spin_scale_finalize;
+ object_class->set_property = gimp_spin_scale_set_property;
+ object_class->get_property = gimp_spin_scale_get_property;
+
+ widget_class->style_set = gimp_spin_scale_style_set;
+#if WITH_GTKMM_3_0
+ widget_class->get_preferred_width = gimp_spin_scale_get_preferred_width;
+ widget_class->get_preferred_height = gimp_spin_scale_get_preferred_height;
+ widget_class->draw = gimp_spin_scale_draw;
+#else
+ widget_class->size_request = gimp_spin_scale_size_request;
+ widget_class->expose_event = gimp_spin_scale_expose;
+#endif
+ widget_class->button_press_event = gimp_spin_scale_button_press;
+ widget_class->button_release_event = gimp_spin_scale_button_release;
+ widget_class->motion_notify_event = gimp_spin_scale_motion_notify;
+ widget_class->leave_notify_event = gimp_spin_scale_leave_notify;
+ widget_class->key_press_event = gimp_spin_scale_keypress;
+
+ spin_button_class->value_changed = gimp_spin_scale_value_changed;
+
+ g_object_class_install_property (object_class, PROP_LABEL,
+ g_param_spec_string ("label", NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (klass, sizeof (GimpSpinScalePrivate));
+}
+
+static void
+gimp_spin_scale_init (GimpSpinScale *scale)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (scale);
+
+ gtk_entry_set_alignment (GTK_ENTRY (scale), 1.0);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (scale), TRUE);
+
+ private->gamma = 1.0;
+ private->focusWidget = NULL;
+ private->transferFocus = FALSE;
+ private->appearanceMode = APPEARANCE_COMPACT;
+}
+
+static void
+gimp_spin_scale_dispose (GObject *object)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (object);
+
+ if (private->layout)
+ {
+ g_object_unref (private->layout);
+ private->layout = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gimp_spin_scale_finalize (GObject *object)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (object);
+
+ if (private->label)
+ {
+ g_free (private->label);
+ private->label = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_spin_scale_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (object);
+
+ switch (property_id)
+ {
+ case PROP_LABEL:
+ g_free (private->label);
+ private->label = g_value_dup_string (value);
+ if (private->layout)
+ {
+ g_object_unref (private->layout);
+ private->layout = NULL;
+ }
+ gtk_widget_queue_resize (GTK_WIDGET (object));
+ break;
+
+ case PROP_FOCUS_WIDGET:
+ {
+ /* TODO unhook prior */
+ private->focusWidget = (GtkWidget*)g_value_get_pointer( value );
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_spin_scale_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (object);
+
+ switch (property_id)
+ {
+ case PROP_LABEL:
+ g_value_set_string (value, private->label);
+ break;
+
+ case PROP_FOCUS_WIDGET:
+ g_value_set_pointer( value, private->focusWidget );
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+void
+gimp_spin_scale_set_focuswidget( GtkWidget *scale, GtkWidget* widget )
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (scale);
+
+ /* TODO unhook prior */
+
+ private->focusWidget = widget;
+}
+
+void
+gimp_spin_scale_set_appearance( GtkWidget *widget, const gchar *appearance)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+
+ if ( strcmp("full", appearance) == 0 ) {
+ private->appearanceMode = APPEARANCE_FULL;
+ } else if ( strcmp("compact", appearance) == 0 ) {
+ private->appearanceMode = APPEARANCE_COMPACT;
+ }
+}
+
+static void
+#if WITH_GTKMM_3_0
+gimp_spin_scale_get_preferred_width (GtkWidget *widget,
+ gint *minimum_width,
+ gint *natural_width)
+#else
+gimp_spin_scale_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+#endif
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+ GtkStyle *style = gtk_widget_get_style (widget);
+ PangoContext *context = gtk_widget_get_pango_context (widget);
+ PangoFontMetrics *metrics;
+
+#if WITH_GTKMM_3_0
+ GTK_WIDGET_CLASS (parent_class)->get_preferred_width (widget,
+ minimum_width,
+ natural_width);
+#else
+ gint height;
+ GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
+#endif
+
+ metrics = pango_context_get_metrics (context, style->font_desc,
+ pango_context_get_language (context));
+
+#if WITH_GTKMM_3_0
+#else
+ height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
+ pango_font_metrics_get_descent (metrics));
+
+ if (private->appearanceMode == APPEARANCE_COMPACT) {
+ requisition->height += 1;
+ } else {
+ requisition->height += height;
+ }
+
+#endif
+
+
+ if (private->label)
+ {
+ gint char_width;
+ gint digit_width;
+ gint char_pixels;
+
+ char_width = pango_font_metrics_get_approximate_char_width (metrics);
+ digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
+ char_pixels = PANGO_PIXELS (MAX (char_width, digit_width));
+
+#if WITH_GTKMM_3_0
+ *minimum_width += char_pixels * 3;
+ *natural_width += char_pixels * 3;
+#else
+ /* ~3 chars for the ellipses */
+ requisition->width += char_pixels * 3;
+#endif
+
+ }
+
+ pango_font_metrics_unref (metrics);
+}
+
+#if WITH_GTKMM_3_0
+static void
+gimp_spin_scale_get_preferred_height (GtkWidget *widget,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ GtkStyle *style = gtk_widget_get_style (widget);
+ PangoContext *context = gtk_widget_get_pango_context (widget);
+ PangoFontMetrics *metrics;
+ //gint height;
+
+ GTK_WIDGET_CLASS (parent_class)->get_preferred_height (widget,
+ minimum_height,
+ natural_height);
+
+ metrics = pango_context_get_metrics (context, style->font_desc,
+ pango_context_get_language (context));
+
+ //height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
+ // pango_font_metrics_get_descent (metrics));
+
+ *minimum_height += 1;
+ *natural_height += 1;
+
+ pango_font_metrics_unref (metrics);
+}
+#endif
+
+static void
+gimp_spin_scale_style_set (GtkWidget *widget,
+ GtkStyle *prev_style)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
+
+ if (private->layout)
+ {
+ g_object_unref (private->layout);
+ private->layout = NULL;
+ }
+}
+
+
+static gboolean
+
+#if WITH_GTKMM_3_0
+ gimp_spin_scale_draw (GtkWidget *widget, cairo_t *cr)
+#else
+ gimp_spin_scale_expose (GtkWidget *widget, GdkEventExpose *event)
+#endif
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+ GtkStyle *style = gtk_widget_get_style (widget);
+
+
+#if WITH_GTKMM_3_0
+ GtkAllocation allocation;
+
+ cairo_save (cr);
+ GTK_WIDGET_CLASS (parent_class)->draw (widget, cr);
+ cairo_restore (cr);
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+
+#else
+ cairo_t *cr;
+ gint w;
+
+ GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
+
+ cr = gdk_cairo_create (event->window);
+ gdk_cairo_region (cr, event->region);
+ cairo_clip (cr);
+
+ w = gdk_window_get_width (event->window);
+
+#endif
+
+ cairo_set_line_width (cr, 1.0);
+
+
+#if WITH_GTKMM_3_0
+ if (private->label)
+ {
+ GdkRectangle text_area;
+ gint minimum_width;
+ gint natural_width;
+#else
+ if (private->label &&
+ gtk_widget_is_drawable (widget) &&
+ event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)))
+ {
+ GtkRequisition requisition;
+ GtkAllocation allocation;
+#endif
+
+ PangoRectangle logical;
+ gint layout_offset_x;
+ gint layout_offset_y;
+
+#if WITH_GTKMM_3_0
+ gtk_entry_get_text_area (GTK_ENTRY (widget), &text_area);
+
+ GTK_WIDGET_CLASS (parent_class)->get_preferred_width (widget,
+ &minimum_width,
+ &natural_width);
+#else
+ GTK_WIDGET_CLASS (parent_class)->size_request (widget, &requisition);
+ gtk_widget_get_allocation (widget, &allocation);
+#endif
+
+ if (! private->layout)
+ {
+ private->layout = gtk_widget_create_pango_layout (widget,
+ private->label);
+ pango_layout_set_ellipsize (private->layout, PANGO_ELLIPSIZE_END);
+ }
+
+ pango_layout_set_width (private->layout,
+ PANGO_SCALE *
+#if WITH_GTKMM_3_0
+ (allocation.width - minimum_width + 10));
+#else
+ (allocation.width - requisition.width + 10));
+#endif
+ pango_layout_get_pixel_extents (private->layout, NULL, &logical);
+
+ gtk_entry_get_layout_offsets (GTK_ENTRY (widget), NULL, &layout_offset_y);
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+#if WITH_GTKMM_3_0
+ layout_offset_x = text_area.x + text_area.width - logical.width - 4;
+#else
+ layout_offset_x = w - logical.width - 4;
+#endif
+ else
+ layout_offset_x = 4;
+
+ layout_offset_x -= logical.x;
+
+#if WITH_GTKMM_3_0
+ cairo_move_to (cr, layout_offset_x, text_area.y + layout_offset_y-3);
+#else
+ cairo_move_to (cr, layout_offset_x, layout_offset_y-3);
+#endif
+
+ gdk_cairo_set_source_color (cr,
+ &style->text[gtk_widget_get_state (widget)]);
+
+ pango_cairo_show_layout (cr, private->layout);
+ }
+
+#if WITH_GTKMM_3_0
+#else
+ cairo_destroy (cr);
+#endif
+
+ return FALSE;
+}
+
+#if WITH_GTKMM_3_0
+/* Returns TRUE if a translation should be done */
+static gboolean
+gtk_widget_get_translation_to_window (GtkWidget *widget,
+ GdkWindow *window,
+ int *x,
+ int *y)
+{
+ GdkWindow *w, *widget_window;
+
+ if (!gtk_widget_get_has_window (widget))
+ {
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ *x = -allocation.x;
+ *y = -allocation.y;
+ }
+ else
+ {
+ *x = 0;
+ *y = 0;
+ }
+
+ widget_window = gtk_widget_get_window (widget);
+
+ for (w = window; w && w != widget_window; w = gdk_window_get_parent (w))
+ {
+ int wx, wy;
+ gdk_window_get_position (w, &wx, &wy);
+ *x += wx;
+ *y += wy;
+ }
+
+ if (w == NULL)
+ {
+ *x = 0;
+ *y = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gimp_spin_scale_event_to_widget_coords (GtkWidget *widget,
+ GdkWindow *window,
+ gdouble event_x,
+ gdouble event_y,
+ gint *widget_x,
+ gint *widget_y)
+{
+ gint tx, ty;
+
+ if (gtk_widget_get_translation_to_window (widget, window, &tx, &ty))
+ {
+ event_x += tx;
+ event_y += ty;
+ }
+
+ *widget_x = event_x;
+ *widget_y = event_y;
+}
+#endif
+
+static SpinScaleTarget
+gimp_spin_scale_get_target (GtkWidget *widget,
+ gdouble x,
+ gdouble y)
+{
+ GtkAllocation allocation;
+ PangoRectangle logical;
+ gint layout_x;
+ gint layout_y;
+
+ gtk_widget_get_allocation (widget, &allocation);
+ gtk_entry_get_layout_offsets (GTK_ENTRY (widget), &layout_x, &layout_y);
+ pango_layout_get_pixel_extents (gtk_entry_get_layout (GTK_ENTRY (widget)),
+ NULL, &logical);
+
+#if WITH_GTKMM_3_0
+ GdkRectangle text_area;
+ gtk_entry_get_text_area (GTK_ENTRY (widget), &text_area);
+
+ if (x >= text_area.x && x < text_area.width &&
+ y >= text_area.y && y < text_area.height)
+ {
+ x -= text_area.x;
+ y -= text_area.y;
+
+ if (x > layout_x && x < layout_x + logical.width &&
+ y > layout_y && y < layout_y + logical.height)
+ {
+ return TARGET_NUMBER;
+ }
+ else if (y > text_area.height / 2)
+ {
+ return TARGET_LOWER;
+ }
+
+ return TARGET_UPPER;
+ }
+
+ return TARGET_NONE;
+#else
+ if (x > layout_x && x < layout_x + logical.width &&
+ y > layout_y && y < layout_y + logical.height)
+ {
+ return TARGET_NUMBER;
+ }
+
+ else if (y > allocation.height / 2)
+ {
+ return TARGET_LOWER;
+ }
+ return TARGET_UPPER;
+#endif
+}
+
+static void
+gimp_spin_scale_get_limits (GimpSpinScale *scale,
+ gdouble *lower,
+ gdouble *upper)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (scale);
+
+ if (private->scale_limits_set)
+ {
+ *lower = private->scale_lower;
+ *upper = private->scale_upper;
+ }
+ else
+ {
+ GtkSpinButton *spin_button = GTK_SPIN_BUTTON (scale);
+ GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
+
+ *lower = gtk_adjustment_get_lower (adjustment);
+ *upper = gtk_adjustment_get_upper (adjustment);
+ }
+}
+
+static void
+gimp_spin_scale_change_value (GtkWidget *widget,
+ gdouble x)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+ GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget);
+ GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
+ gdouble lower;
+ gdouble upper;
+ gdouble value;
+#if WITH_GTKMM_3_0
+#else
+#endif
+#if WITH_GTKMM_3_0
+ GdkRectangle text_area;
+ gtk_entry_get_text_area (GTK_ENTRY (widget), &text_area);
+ gimp_spin_scale_get_limits (GIMP_SPIN_SCALE (widget), &lower, &upper);
+#else
+ GdkWindow *text_window = gtk_entry_get_text_window (GTK_ENTRY (widget));
+ gint width;
+
+ gimp_spin_scale_get_limits (GIMP_SPIN_SCALE (widget), &lower, &upper);
+ width = gdk_window_get_width (text_window);
+
+#endif
+
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+#if WITH_GTKMM_3_0
+ x = text_area.width - x;
+#else
+ x = width - x;
+#endif
+
+
+ if (private->relative_change)
+ {
+ gdouble diff;
+ gdouble step;
+
+
+#if WITH_GTKMM_3_0
+ step = (upper - lower) / text_area.width / 10.0;
+#else
+ step = (upper - lower) / width / 10.0;
+#endif
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+
+#if WITH_GTKMM_3_0
+ diff = x - (text_area.width - private->start_x);
+#else
+ diff = x - (width - private->start_x);
+#endif
+ else
+ diff = x - private->start_x;
+
+ value = (private->start_value + diff * step);
+ }
+ else
+ {
+ gdouble fraction;
+
+
+#if WITH_GTKMM_3_0
+ fraction = x / (gdouble) text_area.width;
+#else
+ fraction = x / (gdouble) width;
+#endif
+ if (fraction > 0.0)
+ fraction = pow (fraction, private->gamma);
+
+ value = fraction * (upper - lower) + lower;
+ }
+
+ gtk_adjustment_set_value (adjustment, value);
+}
+
+static gboolean
+gimp_spin_scale_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+
+ private->changing_value = FALSE;
+ private->relative_change = FALSE;
+
+#if WITH_GTKMM_3_0
+ gint x, y;
+ gimp_spin_scale_event_to_widget_coords (widget, event->window,
+ event->x, event->y,
+ &x, &y);
+ switch (gimp_spin_scale_get_target (widget, x, y))
+ {
+ case TARGET_UPPER:
+ private->changing_value = TRUE;
+
+ gtk_widget_grab_focus (widget);
+
+ gimp_spin_scale_change_value (widget, x);
+
+ return TRUE;
+
+ case TARGET_LOWER:
+ private->changing_value = TRUE;
+
+ gtk_widget_grab_focus (widget);
+
+ private->relative_change = TRUE;
+ private->start_x = x;
+ private->start_value = gtk_adjustment_get_value (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget)));
+
+ return TRUE;
+
+ default:
+ break;
+ }
+#else
+ if (event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)))
+ {
+ switch (gimp_spin_scale_get_target (widget, event->x, event->y))
+ {
+ case TARGET_UPPER:
+ private->changing_value = TRUE;
+
+ gtk_widget_grab_focus (widget);
+
+ gimp_spin_scale_change_value (widget, event->x);
+
+ return TRUE;
+
+ case TARGET_LOWER:
+ private->changing_value = TRUE;
+
+ gtk_widget_grab_focus (widget);
+
+ private->relative_change = TRUE;
+ private->start_x = event->x;
+ private->start_value = gtk_adjustment_get_value (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget)));
+
+ return TRUE;
+
+ default:
+ break;
+ }
+ }
+#endif
+
+ return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
+}
+
+static gboolean
+gimp_spin_scale_button_release (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+#if WITH_GTKMM_3_0
+ gint x, y;
+
+ gimp_spin_scale_event_to_widget_coords (widget, event->window,
+ event->x, event->y,
+ &x, &y);
+#endif
+
+ if (private->changing_value)
+ {
+ private->changing_value = FALSE;
+#if WITH_GTKMM_3_0
+ gimp_spin_scale_change_value (widget, x);
+#else
+ gimp_spin_scale_change_value (widget, event->x);
+#endif
+ return TRUE;
+ }
+
+ return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
+}
+
+static gboolean
+gimp_spin_scale_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+#if WITH_GTKMM_3_0
+ gint x, y;
+
+ gimp_spin_scale_event_to_widget_coords (widget, event->window,
+ event->x, event->y,
+ &x, &y);
+#endif
+
+ if (private->changing_value)
+ {
+#if WITH_GTKMM_3_0
+ gimp_spin_scale_change_value (widget, x);
+#else
+ gimp_spin_scale_change_value (widget, event->x);
+#endif
+
+ return TRUE;
+ }
+
+ GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
+
+ if (! (event->state &
+ (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))
+#if WITH_GTKMM_3_0
+#else
+ && event->window == gtk_entry_get_text_window (GTK_ENTRY (widget))
+#endif
+ )
+ {
+ GdkDisplay *display = gtk_widget_get_display (widget);
+ GdkCursor *cursor = NULL;
+
+#if WITH_GTKMM_3_0
+ switch (gimp_spin_scale_get_target (widget, x, y))
+#else
+ switch (gimp_spin_scale_get_target (widget, event->x, event->y))
+#endif
+ {
+ case TARGET_NUMBER:
+ cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
+ break;
+
+ case TARGET_UPPER:
+ cursor = gdk_cursor_new_for_display (display, GDK_SB_UP_ARROW);
+ break;
+
+ case TARGET_LOWER:
+ cursor = gdk_cursor_new_for_display (display, GDK_SB_H_DOUBLE_ARROW);
+ break;
+
+ default:
+ break;
+ }
+
+
+#if WITH_GTKMM_3_0
+ if (cursor)
+ {
+ gdk_window_set_cursor (event->window, cursor);
+ g_object_unref (cursor);
+ }
+#else
+ gdk_window_set_cursor (event->window, cursor);
+ gdk_cursor_unref (cursor);
+#endif
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gimp_spin_scale_leave_notify (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ gdk_window_set_cursor (event->window, NULL);
+
+ return GTK_WIDGET_CLASS (parent_class)->leave_notify_event (widget, event);
+}
+
+gboolean gimp_spin_scale_keypress( GtkWidget *widget, GdkEventKey *event)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (widget);
+ 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_KEY_Escape:
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ {
+ private->transferFocus = TRUE;
+ gimp_spin_scale_defocus( GTK_SPIN_BUTTON(widget) );
+ }
+ break;
+
+ }
+
+ return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+}
+
+static void
+gimp_spin_scale_defocus( GtkSpinButton *spin_button )
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (spin_button);
+
+ if ( private->transferFocus ) {
+ if ( private->focusWidget ) {
+ gtk_widget_grab_focus( private->focusWidget );
+ }
+ }
+}
+
+static void
+gimp_spin_scale_value_changed (GtkSpinButton *spin_button)
+{
+ GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
+ GimpSpinScalePrivate *private = GET_PRIVATE (spin_button);
+ gdouble lower;
+ gdouble upper;
+ gdouble value;
+
+ gimp_spin_scale_get_limits (GIMP_SPIN_SCALE (spin_button), &lower, &upper);
+
+ value = CLAMP (gtk_adjustment_get_value (adjustment), lower, upper);
+
+
+ gtk_entry_set_progress_fraction (GTK_ENTRY (spin_button),
+ pow ((value - lower) / (upper - lower),
+ 1.0 / private->gamma));
+
+ // TODO - Allow scrollwheel to change value then return focus,
+ // but clicks/keypress should keep focus in the control
+ //if ( gtk_widget_has_focus( GTK_WIDGET(spin_button) ) ) {
+ // gimp_spin_scale_defocus( spin_button );
+ //}
+}
+
+
+/* public functions */
+
+GtkWidget *
+gimp_spin_scale_new (GtkAdjustment *adjustment,
+ const gchar *label,
+ gint digits)
+{
+ g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
+
+ return g_object_new (GIMP_TYPE_SPIN_SCALE,
+ "adjustment", adjustment,
+ "label", label,
+ "digits", digits,
+ NULL);
+}
+
+void
+gimp_spin_scale_set_scale_limits (GimpSpinScale *scale,
+ gdouble lower,
+ gdouble upper)
+{
+ GimpSpinScalePrivate *private;
+ GtkSpinButton *spin_button;
+ GtkAdjustment *adjustment;
+
+ g_return_if_fail (GIMP_IS_SPIN_SCALE (scale));
+
+ private = GET_PRIVATE (scale);
+ spin_button = GTK_SPIN_BUTTON (scale);
+ adjustment = gtk_spin_button_get_adjustment (spin_button);
+
+ g_return_if_fail (lower >= gtk_adjustment_get_lower (adjustment));
+ g_return_if_fail (upper <= gtk_adjustment_get_upper (adjustment));
+
+ private->scale_limits_set = TRUE;
+ private->scale_lower = lower;
+ private->scale_upper = upper;
+ private->gamma = 1.0;
+
+ gimp_spin_scale_value_changed (spin_button);
+}
+
+void
+gimp_spin_scale_set_gamma (GimpSpinScale *scale,
+ gdouble gamma)
+{
+ GimpSpinScalePrivate *private;
+
+ g_return_if_fail (GIMP_IS_SPIN_SCALE (scale));
+
+ private = GET_PRIVATE (scale);
+
+ private->gamma = gamma;
+
+ gimp_spin_scale_value_changed (GTK_SPIN_BUTTON (scale));
+}
+
+gdouble
+gimp_spin_scale_get_gamma (GimpSpinScale *scale)
+{
+ GimpSpinScalePrivate *private;
+
+ g_return_val_if_fail (GIMP_IS_SPIN_SCALE (scale), 1.0);
+
+ private = GET_PRIVATE (scale);
+
+ return private->gamma;
+}
+
+void
+gimp_spin_scale_unset_scale_limits (GimpSpinScale *scale)
+{
+ GimpSpinScalePrivate *private;
+
+ g_return_if_fail (GIMP_IS_SPIN_SCALE (scale));
+
+ private = GET_PRIVATE (scale);
+
+ private->scale_limits_set = FALSE;
+ private->scale_lower = 0.0;
+ private->scale_upper = 0.0;
+
+ gimp_spin_scale_value_changed (GTK_SPIN_BUTTON (scale));
+}
+
+gboolean
+gimp_spin_scale_get_scale_limits (GimpSpinScale *scale,
+ gdouble *lower,
+ gdouble *upper)
+{
+ GimpSpinScalePrivate *private;
+
+ g_return_val_if_fail (GIMP_IS_SPIN_SCALE (scale), FALSE);
+
+ private = GET_PRIVATE (scale);
+
+ if (lower)
+ *lower = private->scale_lower;
+
+ if (upper)
+ *upper = private->scale_upper;
+
+ return private->scale_limits_set;
+}
diff --git a/src/ui/widget/gimpspinscale.h b/src/ui/widget/gimpspinscale.h
new file mode 100644
index 000000000..ad63625ac
--- /dev/null
+++ b/src/ui/widget/gimpspinscale.h
@@ -0,0 +1,76 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpspinscale.h
+ * Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_SPIN_SCALE_H__
+#define __GIMP_SPIN_SCALE_H__
+
+#ifndef WITH_GIMP
+#include <gtk/gtk.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GIMP_TYPE_SPIN_SCALE (gimp_spin_scale_get_type ())
+#define GIMP_SPIN_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SPIN_SCALE, GimpSpinScale))
+#define GIMP_SPIN_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SPIN_SCALE, GimpSpinScaleClass))
+#define GIMP_IS_SPIN_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_SPIN_SCALE))
+#define GIMP_IS_SPIN_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SPIN_SCALE))
+#define GIMP_SPIN_SCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SPIN_SCALE, GimpSpinScaleClass))
+
+
+typedef struct _GimpSpinScale GimpSpinScale;
+typedef struct _GimpSpinScaleClass GimpSpinScaleClass;
+
+struct _GimpSpinScale
+{
+ GtkSpinButton parent_instance;
+};
+
+struct _GimpSpinScaleClass
+{
+ GtkSpinButtonClass parent_class;
+};
+
+
+GType gimp_spin_scale_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gimp_spin_scale_new (GtkAdjustment *adjustment,
+ const gchar *label,
+ gint digits);
+
+void gimp_spin_scale_set_scale_limits (GimpSpinScale *scale,
+ gdouble lower,
+ gdouble upper);
+void gimp_spin_scale_unset_scale_limits (GimpSpinScale *scale);
+gboolean gimp_spin_scale_get_scale_limits (GimpSpinScale *scale,
+ gdouble *lower,
+ gdouble *upper);
+
+void gimp_spin_scale_set_gamma (GimpSpinScale *scale,
+ gdouble gamma);
+gdouble gimp_spin_scale_get_gamma (GimpSpinScale *scale);
+
+void gimp_spin_scale_set_focuswidget( GtkWidget *scale, GtkWidget* widget );
+
+void gimp_spin_scale_set_appearance( GtkWidget *scale, const gchar *appearance);
+
+G_END_DECLS
+
+#endif /* __GIMP_SPIN_SCALE_H__ */
diff --git a/src/ui/widget/spin-scale.cpp b/src/ui/widget/spin-scale.cpp
new file mode 100644
index 000000000..00c575568
--- /dev/null
+++ b/src/ui/widget/spin-scale.cpp
@@ -0,0 +1,248 @@
+/*
+ * Author:
+ *
+ * Copyright (C) 2012 Author
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#include <glib.h>
+#include <glibmm/i18n.h>
+#include <glibmm/stringutils.h>
+#include <gtkmm/adjustment.h>
+
+#include "spin-scale.h"
+#include "ui/widget/gimpspinscale.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+SpinScale::SpinScale(const char* label, double value, double lower, double upper, double step_inc,
+ double climb_rate, int digits, const SPAttributeEnum a, const char* tip_text)
+ : AttrWidget(a, value)
+{
+
+#if WITH_GTKMM_3_0
+ _adjustment = Gtk::Adjustment::create(value, lower, upper, step_inc);
+ _spinscale = gimp_spin_scale_new (_adjustment->gobj(), label, digits);
+#else
+ _adjustment = new Gtk::Adjustment(value, lower, upper, step_inc);
+ _spinscale = gimp_spin_scale_new (_adjustment->gobj(), label, digits);
+#endif
+
+ signal_value_changed().connect(signal_attr_changed().make_slot());
+
+ pack_start(*Gtk::manage(Glib::wrap(_spinscale)));
+
+ if (tip_text){
+ gtk_widget_set_tooltip_text( _spinscale, tip_text );
+ }
+
+ show_all_children();
+}
+
+SpinScale::SpinScale(const char* label,
+#if WITH_GTKMM_3_0
+ Glib::RefPtr<Gtk::Adjustment> adj,
+#else
+ Gtk::Adjustment *adj,
+#endif
+ int digits, const SPAttributeEnum a, const char* tip_text)
+ : AttrWidget(a, 0.0),
+ _adjustment(adj)
+
+{
+
+ _spinscale = gimp_spin_scale_new (_adjustment->gobj(), label, digits);
+
+ signal_value_changed().connect(signal_attr_changed().make_slot());
+
+ pack_start(*Gtk::manage(Glib::wrap(_spinscale)));
+
+ if (tip_text){
+ gtk_widget_set_tooltip_text( _spinscale, tip_text );
+ }
+
+ show_all_children();
+}
+
+Glib::ustring SpinScale::get_as_attribute() const
+{
+ const double val = _adjustment->get_value();
+
+ //if(_spin.get_digits() == 0)
+ // return Glib::Ascii::dtostr((int)val);
+ //else
+ return Glib::Ascii::dtostr(val);
+}
+
+void SpinScale::set_from_attribute(SPObject* o)
+{
+ const gchar* val = attribute_value(o);
+ if(val)
+ _adjustment->set_value(Glib::Ascii::strtod(val));
+ else
+ _adjustment->set_value(get_default()->as_double());
+}
+
+Glib::SignalProxy0<void> SpinScale::signal_value_changed()
+{
+ return _adjustment->signal_value_changed();
+}
+
+double SpinScale::get_value() const
+{
+ return _adjustment->get_value();
+}
+
+void SpinScale::set_value(const double val)
+{
+ _adjustment->set_value(val);
+}
+
+void SpinScale::set_focuswidget(GtkWidget *widget)
+{
+ gimp_spin_scale_set_focuswidget(_spinscale, widget);
+}
+
+
+void SpinScale::set_appearance(const gchar* appearance)
+{
+ gimp_spin_scale_set_appearance(_spinscale, appearance);
+}
+
+#if WITH_GTKMM_3_0
+const Glib::RefPtr<Gtk::Adjustment> SpinScale::get_adjustment() const
+#else
+const Gtk::Adjustment *SpinScale::get_adjustment() const
+#endif
+{
+ return _adjustment;
+}
+#if WITH_GTKMM_3_0
+Glib::RefPtr<Gtk::Adjustment> SpinScale::get_adjustment()
+#else
+Gtk::Adjustment *SpinScale::get_adjustment()
+#endif
+{
+ return _adjustment;
+}
+
+
+DualSpinScale::DualSpinScale(const char* label1, const char* label2, double value, double lower, double upper, double step_inc,
+ double climb_rate, int digits, const SPAttributeEnum a, char* tip_text1, char* tip_text2)
+ : AttrWidget(a),
+ _s1(label1, value, lower, upper, step_inc, climb_rate, digits, SP_ATTR_INVALID, tip_text1),
+ _s2(label2, value, lower, upper, step_inc, climb_rate, digits, SP_ATTR_INVALID, tip_text2),
+ //TRANSLATORS: "Link" means to _link_ two sliders together
+ _link(C_("Sliders", "Link"))
+{
+ signal_value_changed().connect(signal_attr_changed().make_slot());
+
+ _s1.get_adjustment()->signal_value_changed().connect(_signal_value_changed.make_slot());
+ _s2.get_adjustment()->signal_value_changed().connect(_signal_value_changed.make_slot());
+ _s1.get_adjustment()->signal_value_changed().connect(sigc::mem_fun(*this, &DualSpinScale::update_linked));
+
+ _link.signal_toggled().connect(sigc::mem_fun(*this, &DualSpinScale::link_toggled));
+
+ Gtk::VBox* vb = Gtk::manage(new Gtk::VBox);
+ vb->add(_s1);
+ vb->add(_s2);
+ pack_start(*vb);
+ pack_start(_link, false, false);
+ _link.set_active(true);
+
+ show_all();
+}
+
+Glib::ustring DualSpinScale::get_as_attribute() const
+{
+ if(_link.get_active())
+ return _s1.get_as_attribute();
+ else
+ return _s1.get_as_attribute() + " " + _s2.get_as_attribute();
+}
+
+void DualSpinScale::set_from_attribute(SPObject* o)
+{
+ const gchar* val = attribute_value(o);
+ if(val) {
+ // Split val into parts
+ gchar** toks = g_strsplit(val, " ", 2);
+
+ if(toks) {
+ double v1 = 0.0, v2 = 0.0;
+ if(toks[0])
+ v1 = v2 = Glib::Ascii::strtod(toks[0]);
+ if(toks[1])
+ v2 = Glib::Ascii::strtod(toks[1]);
+
+ _link.set_active(toks[1] == 0);
+
+ _s1.get_adjustment()->set_value(v1);
+ _s2.get_adjustment()->set_value(v2);
+
+ g_strfreev(toks);
+ }
+ }
+}
+
+sigc::signal<void>& DualSpinScale::signal_value_changed()
+{
+ return _signal_value_changed;
+}
+
+const SpinScale& DualSpinScale::get_SpinScale1() const
+{
+ return _s1;
+}
+
+SpinScale& DualSpinScale::get_SpinScale1()
+{
+ return _s1;
+}
+
+const SpinScale& DualSpinScale::get_SpinScale2() const
+{
+ return _s2;
+}
+
+SpinScale& DualSpinScale::get_SpinScale2()
+{
+ return _s2;
+}
+
+/*void DualSpinScale::remove_scale()
+{
+ _s1.remove_scale();
+ _s2.remove_scale();
+}*/
+
+void DualSpinScale::link_toggled()
+{
+ _s2.set_sensitive(!_link.get_active());
+ update_linked();
+}
+
+void DualSpinScale::update_linked()
+{
+ if(_link.get_active())
+ _s2.set_value(_s1.get_value());
+}
+
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/ui/widget/spin-scale.h b/src/ui/widget/spin-scale.h
new file mode 100644
index 000000000..a8403307f
--- /dev/null
+++ b/src/ui/widget/spin-scale.h
@@ -0,0 +1,117 @@
+/*
+ * Author:
+ *
+ * Copyright (C) 2012 Author
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information.
+ */
+
+#ifndef INKSCAPE_UI_WIDGET_SPIN_SCALE_H
+#define INKSCAPE_UI_WIDGET_SPIN_SCALE_H
+
+#include <gtkmm/adjustment.h>
+#include <gtkmm/box.h>
+#include <gtkmm/scale.h>
+#include <gtkmm/togglebutton.h>
+#include "spinbutton.h"
+#include "attr-widget.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+/**
+ * Wrap the gimpspinscale class
+ * A combo widget with label, scale slider, spinbutton and adjustment
+ */
+class SpinScale : public Gtk::HBox, public AttrWidget
+{
+
+public:
+ SpinScale(const char* label, double value, double lower, double upper, double step_inc, double climb_rate,
+ int digits, const SPAttributeEnum a = SP_ATTR_INVALID, const char* tip_text = NULL);
+
+ SpinScale(const char* label,
+#if WITH_GTKMM_3_0
+ Glib::RefPtr<Gtk::Adjustment> adj,
+#else
+ Gtk::Adjustment *adj,
+#endif
+ int digits, const SPAttributeEnum a = SP_ATTR_INVALID, const char* tip_text = NULL);
+
+ virtual Glib::ustring get_as_attribute() const;
+ virtual void set_from_attribute(SPObject*);
+
+ // Shortcuts to _adjustment
+ Glib::SignalProxy0<void> signal_value_changed();
+ double get_value() const;
+ void set_value(const double);
+ void set_focuswidget(GtkWidget *widget);
+ void set_appearance(const gchar* appearance);
+
+#if WITH_GTKMM_3_0
+ const Glib::RefPtr<Gtk::Adjustment> get_adjustment() const;
+ Glib::RefPtr<Gtk::Adjustment> get_adjustment();
+#else
+ const Gtk::Adjustment *get_adjustment() const;
+ Gtk::Adjustment *get_adjustment();
+#endif
+
+private:
+#if WITH_GTKMM_3_0
+ Glib::RefPtr<Gtk::Adjustment> _adjustment;
+#else
+ Gtk::Adjustment *_adjustment;
+#endif
+
+ GtkWidget *_spinscale;
+};
+
+
+/**
+ * Contains two SpinScales for controlling number-opt-number attributes.
+ *
+ * @see SpinScale
+ */
+class DualSpinScale : public Gtk::HBox, public AttrWidget
+{
+public:
+ DualSpinScale(const char* label1, const char* label2, double value, double lower, double upper, double step_inc,
+ double climb_rate, int digits, const SPAttributeEnum, char* tip_text1, char* tip_text2);
+
+ virtual Glib::ustring get_as_attribute() const;
+ virtual void set_from_attribute(SPObject*);
+
+ sigc::signal<void>& signal_value_changed();
+
+ const SpinScale& get_SpinScale1() const;
+ SpinScale& get_SpinScale1();
+
+ const SpinScale& get_SpinScale2() const;
+ SpinScale& get_SpinScale2();
+
+ //void remove_scale();
+private:
+ void link_toggled();
+ void update_linked();
+ sigc::signal<void> _signal_value_changed;
+ SpinScale _s1, _s2;
+ Gtk::ToggleButton _link;
+};
+
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+
+#endif // INKSCAPE_UI_WIDGET_SPIN_SCALE_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :