diff options
Diffstat (limited to 'gtk/gtkscale.c')
-rw-r--r-- | gtk/gtkscale.c | 306 |
1 files changed, 269 insertions, 37 deletions
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c index 9535823c90..929bb64529 100644 --- a/gtk/gtkscale.c +++ b/gtk/gtkscale.c @@ -22,17 +22,20 @@ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include "config.h" + #include <math.h> -#include "gtkintl.h" +#include <stdlib.h> + +#include "gdk/gdkkeysyms.h" #include "gtkscale.h" #include "gtkmarshalers.h" -#include "gdk/gdkkeysyms.h" #include "gtkbindings.h" #include "gtkprivate.h" +#include "gtkintl.h" #include "gtkalias.h" @@ -65,23 +68,28 @@ enum { static guint signals[LAST_SIGNAL]; -static void gtk_scale_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_scale_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_scale_style_set (GtkWidget *widget, - GtkStyle *previous); -static void gtk_scale_get_range_border (GtkRange *range, - GtkBorder *border); -static void gtk_scale_finalize (GObject *object); -static void gtk_scale_screen_changed (GtkWidget *widget, - GdkScreen *old_screen); - -G_DEFINE_ABSTRACT_TYPE (GtkScale, gtk_scale, GTK_TYPE_RANGE) +static void gtk_scale_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_scale_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_scale_style_set (GtkWidget *widget, + GtkStyle *previous); +static void gtk_scale_get_range_border (GtkRange *range, + GtkBorder *border); +static void gtk_scale_finalize (GObject *object); +static void gtk_scale_screen_changed (GtkWidget *widget, + GdkScreen *old_screen); +static gboolean gtk_scale_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_scale_real_get_layout_offsets (GtkScale *scale, + gint *x, + gint *y); + +G_DEFINE_TYPE (GtkScale, gtk_scale, GTK_TYPE_RANGE) static gboolean single_string_accumulator (GSignalInvocationHint *ihint, @@ -123,9 +131,13 @@ gtk_scale_class_init (GtkScaleClass *class) widget_class->style_set = gtk_scale_style_set; widget_class->screen_changed = gtk_scale_screen_changed; + widget_class->expose_event = gtk_scale_expose; + range_class->slider_detail = "Xscale"; range_class->get_range_border = gtk_scale_get_range_border; - + + class->get_layout_offsets = gtk_scale_real_get_layout_offsets; + signals[FORMAT_VALUE] = g_signal_new (I_("format-value"), G_TYPE_FROM_CLASS (gobject_class), @@ -303,6 +315,37 @@ gtk_scale_class_init (GtkScaleClass *class) } static void +gtk_scale_orientation_notify (GtkRange *range, + const GParamSpec *pspec) +{ + range->flippable = (range->orientation == GTK_ORIENTATION_HORIZONTAL); +} + +static void +gtk_scale_init (GtkScale *scale) +{ + GtkRange *range = GTK_RANGE (scale); + + GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS); + + range->slider_size_fixed = TRUE; + range->has_stepper_a = FALSE; + range->has_stepper_b = FALSE; + range->has_stepper_c = FALSE; + range->has_stepper_d = FALSE; + + scale->draw_value = TRUE; + scale->value_pos = GTK_POS_TOP; + scale->digits = 1; + range->round_digits = scale->digits; + + gtk_scale_orientation_notify (range, NULL); + g_signal_connect (scale, "notify::orientation", + G_CALLBACK (gtk_scale_orientation_notify), + NULL); +} + +static void gtk_scale_set_property (GObject *object, guint prop_id, const GValue *value, @@ -356,25 +399,82 @@ gtk_scale_get_property (GObject *object, } } -static void -gtk_scale_init (GtkScale *scale) +/** + * gtk_scale_new: + * @orientation: the scale's orientation. + * @adjustment: the #GtkAdjustment which sets the range of the scale, or + * %NULL to create a new adjustment. + * + * Creates a new #GtkScale. + * + * Return value: a new #GtkScale + * + * Since: 2.16 + **/ +GtkWidget * +gtk_scale_new (GtkOrientation orientation, + GtkAdjustment *adjustment) { - GtkRange *range; + g_return_val_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment), + NULL); - range = GTK_RANGE (scale); - - GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS); + return g_object_new (GTK_TYPE_SCALE, + "orientation", orientation, + "adjustment", adjustment, + NULL); +} - range->slider_size_fixed = TRUE; - range->has_stepper_a = FALSE; - range->has_stepper_b = FALSE; - range->has_stepper_c = FALSE; - range->has_stepper_d = FALSE; - - scale->draw_value = TRUE; - scale->value_pos = GTK_POS_TOP; - scale->digits = 1; - range->round_digits = scale->digits; +/** + * gtk_scale_new_with_range: + * @orientation: the scale's orientation. + * @min: minimum value + * @max: maximum value + * @step: step increment (tick size) used with keyboard shortcuts + * + * Creates a new scale widget with the given orientation that lets the + * user input a number between @min and @max (including @min and @max) + * with the increment @step. @step must be nonzero; it's the distance + * the slider moves when using the arrow keys to adjust the scale + * value. + * + * Note that the way in which the precision is derived works best if @step + * is a power of ten. If the resulting precision is not suitable for your + * needs, use gtk_scale_set_digits() to correct it. + * + * Return value: a new #GtkScale + * + * Since: 2.16 + **/ +GtkWidget * +gtk_scale_new_with_range (GtkOrientation orientation, + gdouble min, + gdouble max, + gdouble step) +{ + GtkObject *adj; + gint digits; + + g_return_val_if_fail (min < max, NULL); + g_return_val_if_fail (step != 0.0, NULL); + + adj = gtk_adjustment_new (min, min, max, step, 10 * step, 0); + + if (fabs (step) >= 1.0 || step == 0.0) + { + digits = 0; + } + else + { + digits = abs ((gint) floor (log10 (fabs (step)))); + if (digits > 5) + digits = 5; + } + + return g_object_new (GTK_TYPE_SCALE, + "orientation", orientation, + "adjustment", adj, + "digits", digits, + NULL); } void @@ -590,6 +690,138 @@ gtk_scale_screen_changed (GtkWidget *widget, _gtk_scale_clear_layout (GTK_SCALE (widget)); } +static gboolean +gtk_scale_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkScale *scale = GTK_SCALE (widget); + + /* We need to chain up _first_ so the various geometry members of + * GtkRange struct are updated. + */ + GTK_WIDGET_CLASS (gtk_scale_parent_class)->expose_event (widget, event); + + if (scale->draw_value) + { + GtkRange *range = GTK_RANGE (scale); + PangoLayout *layout; + gint x, y; + GtkStateType state_type; + + layout = gtk_scale_get_layout (scale); + gtk_scale_get_layout_offsets (scale, &x, &y); + + state_type = GTK_STATE_NORMAL; + if (!GTK_WIDGET_IS_SENSITIVE (scale)) + state_type = GTK_STATE_INSENSITIVE; + + gtk_paint_layout (widget->style, + widget->window, + state_type, + FALSE, + NULL, + widget, + range->orientation == GTK_ORIENTATION_HORIZONTAL ? + "hscale" : "vscale", + x, y, + layout); + + } + + return FALSE; +} + +static void +gtk_scale_real_get_layout_offsets (GtkScale *scale, + gint *x, + gint *y) +{ + GtkWidget *widget = GTK_WIDGET (scale); + GtkRange *range = GTK_RANGE (widget); + PangoLayout *layout = gtk_scale_get_layout (scale); + PangoRectangle logical_rect; + gint value_spacing; + + if (!layout) + { + *x = 0; + *y = 0; + + return; + } + + gtk_widget_style_get (widget, "value-spacing", &value_spacing, NULL); + + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + + if (range->orientation == GTK_ORIENTATION_HORIZONTAL) + { + switch (scale->value_pos) + { + case GTK_POS_LEFT: + *x = range->range_rect.x - value_spacing - logical_rect.width; + *y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2; + break; + + case GTK_POS_RIGHT: + *x = range->range_rect.x + range->range_rect.width + value_spacing; + *y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2; + break; + + case GTK_POS_TOP: + *x = range->slider_start + + (range->slider_end - range->slider_start - logical_rect.width) / 2; + *x = CLAMP (*x, 0, widget->allocation.width - logical_rect.width); + *y = range->range_rect.y - logical_rect.height - value_spacing; + break; + + case GTK_POS_BOTTOM: + *x = range->slider_start + + (range->slider_end - range->slider_start - logical_rect.width) / 2; + *x = CLAMP (*x, 0, widget->allocation.width - logical_rect.width); + *y = range->range_rect.y + range->range_rect.height + value_spacing; + break; + + default: + g_return_if_reached (); + break; + } + } + else + { + switch (scale->value_pos) + { + case GTK_POS_LEFT: + *x = range->range_rect.x - logical_rect.width - value_spacing; + *y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2; + *y = CLAMP (*y, 0, widget->allocation.height - logical_rect.height); + break; + + case GTK_POS_RIGHT: + *x = range->range_rect.x + range->range_rect.width + value_spacing; + *y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2; + *y = CLAMP (*y, 0, widget->allocation.height - logical_rect.height); + break; + + case GTK_POS_TOP: + *x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2; + *y = range->range_rect.y - logical_rect.height - value_spacing; + break; + + case GTK_POS_BOTTOM: + *x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2; + *y = range->range_rect.y + range->range_rect.height + value_spacing; + break; + + default: + g_return_if_reached (); + } + } + + *x += widget->allocation.x; + *y += widget->allocation.y; +} + /** * _gtk_scale_format_value: * @scale: a #GtkScale |