diff options
author | Havoc Pennington <hp@pobox.com> | 2001-06-04 02:31:12 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 2001-06-04 02:31:12 +0000 |
commit | 42f429be76e96f1861a17da2cd5ef56741172e25 (patch) | |
tree | 3ca33e80692cfb0f73e4621113bce3dbcb0546a9 /gtk | |
parent | 741c71eb931cb85651e9f5aba99db4017dda180a (diff) | |
download | gtk+-42f429be76e96f1861a17da2cd5ef56741172e25.tar.gz |
make this special-case hscale/vscale details, so we can use it for
2001-06-03 Havoc Pennington <hp@pobox.com>
* gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
hscale/vscale details, so we can use it for scrollbar as well.
* tests/testgtk.c (reformat_value): honor digits from GtkScale
* gtk/gtkenums.h (GtkTroughType): Remove this enum
(GtkScrollType): add START and END from GtkTroughType
* gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
its x/y arguments
* gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
Notable changes in the process:
- stepper_size style property is the height for vertical
ranges, width for horizontal; the other dimension matches
the trough size
- add ability to do NeXT-style steppers (and several other styles
that don't make any sense)
- added min_slider_length, fixed_slider_length properties to
GtkScrollbar
- cleaned some private (or at least useless) functions out of
gtkscale.h
- moved bindings to GtkScale from subclasses, even arrow keys,
since blind users don't know scale orientation.
- change move_slider action signal to use new GtkScrollType,
remove GtkTroughType argument
- digits rounds the values a range will input to the given
number of decimals, but will not try to force adjustment
values set by other controllers. That is, we no longer
modify adjustment->value inside a value_changed handler.
- added getters for GtkScale setters
- middle-click begins a slider drag
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkenums.h | 15 | ||||
-rw-r--r-- | gtk/gtkhscale.c | 506 | ||||
-rw-r--r-- | gtk/gtkhscrollbar.c | 370 | ||||
-rw-r--r-- | gtk/gtkrange.c | 2698 | ||||
-rw-r--r-- | gtk/gtkrange.h | 135 | ||||
-rw-r--r-- | gtk/gtkscale.c | 320 | ||||
-rw-r--r-- | gtk/gtkscale.h | 29 | ||||
-rw-r--r-- | gtk/gtkscrollbar.c | 98 | ||||
-rw-r--r-- | gtk/gtkstyle.c | 21 | ||||
-rw-r--r-- | gtk/gtkvscale.c | 511 | ||||
-rw-r--r-- | gtk/gtkvscrollbar.c | 366 |
11 files changed, 1981 insertions, 3088 deletions
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index 9f70e393cc..88c204a145 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -286,11 +286,11 @@ typedef enum /*< flags >*/ typedef enum { GTK_SCROLL_NONE, + GTK_SCROLL_JUMP, GTK_SCROLL_STEP_BACKWARD, GTK_SCROLL_STEP_FORWARD, GTK_SCROLL_PAGE_BACKWARD, GTK_SCROLL_PAGE_FORWARD, - GTK_SCROLL_JUMP, GTK_SCROLL_STEP_UP, GTK_SCROLL_STEP_DOWN, GTK_SCROLL_PAGE_UP, @@ -298,7 +298,9 @@ typedef enum GTK_SCROLL_STEP_LEFT, GTK_SCROLL_STEP_RIGHT, GTK_SCROLL_PAGE_LEFT, - GTK_SCROLL_PAGE_RIGHT + GTK_SCROLL_PAGE_RIGHT, + GTK_SCROLL_START, + GTK_SCROLL_END } GtkScrollType; /* list selection modes */ @@ -353,15 +355,6 @@ typedef enum GTK_TOOLBAR_BOTH_HORIZ } GtkToolbarStyle; -/* Trough types for GtkRange */ -typedef enum -{ - GTK_TROUGH_NONE, - GTK_TROUGH_START, - GTK_TROUGH_END, - GTK_TROUGH_JUMP -} GtkTroughType; - /* Data update types (for ranges) */ typedef enum { diff --git a/gtk/gtkhscale.c b/gtk/gtkhscale.c index a59efe8894..4b6e34a4cc 100644 --- a/gtk/gtkhscale.c +++ b/gtk/gtkhscale.c @@ -1,5 +1,5 @@ /* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,47 +27,14 @@ #include <stdio.h> #include "gtkhscale.h" #include "gtksignal.h" -#include "gdk/gdkkeysyms.h" #include "gtkintl.h" -#include "gtkbindings.h" -#define SCALE_CLASS(w) GTK_SCALE_GET_CLASS (w) -#define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w) - -enum { - PROP_0 -}; +static gpointer parent_class; static void gtk_hscale_class_init (GtkHScaleClass *klass); static void gtk_hscale_init (GtkHScale *hscale); -static void gtk_hscale_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_hscale_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_hscale_realize (GtkWidget *widget); -static void gtk_hscale_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_hscale_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_hscale_pos_trough (GtkHScale *hscale, - gint *x, - gint *y, - gint *w, - gint *h); -static void gtk_hscale_pos_background (GtkHScale *hscale, - gint *x, - gint *y, - gint *w, - gint *h); -static void gtk_hscale_draw_slider (GtkRange *range); -static void gtk_hscale_draw_value (GtkScale *scale); - -static void gtk_hscale_clear_background (GtkRange *range); - +static gboolean gtk_hscale_expose (GtkWidget *widget, + GdkEventExpose *event); GtkType gtk_hscale_get_type (void) @@ -94,124 +61,33 @@ gtk_hscale_get_type (void) return hscale_type; } -#define add_slider_binding(binding_set, keyval, mask, scroll, trough) \ - gtk_binding_entry_add_signal (binding_set, keyval, mask, \ - "move_slider", 2, \ - GTK_TYPE_SCROLL_TYPE, scroll, \ - GTK_TYPE_TROUGH_TYPE, trough) - static void gtk_hscale_class_init (GtkHScaleClass *class) { GObjectClass *gobject_class; - GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkRangeClass *range_class; - GtkScaleClass *scale_class; - GtkBindingSet *binding_set; - - gobject_class = (GObjectClass*) class; - object_class = (GtkObjectClass*) class; - widget_class = (GtkWidgetClass*) class; - range_class = (GtkRangeClass*) class; - scale_class = (GtkScaleClass*) class; - - gobject_class->set_property = gtk_hscale_set_property; - gobject_class->get_property = gtk_hscale_get_property; - - widget_class->realize = gtk_hscale_realize; - widget_class->size_request = gtk_hscale_size_request; - widget_class->size_allocate = gtk_hscale_size_allocate; - - range_class->slider_update = _gtk_range_default_hslider_update; - range_class->trough_click = _gtk_range_default_htrough_click; - range_class->motion = _gtk_range_default_hmotion; - range_class->draw_slider = gtk_hscale_draw_slider; - range_class->clear_background = gtk_hscale_clear_background; - scale_class->draw_value = gtk_hscale_draw_value; - - binding_set = gtk_binding_set_by_class (object_class); - - add_slider_binding (binding_set, GDK_Left, 0, - GTK_SCROLL_STEP_LEFT, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_LEFT, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Left, 0, - GTK_SCROLL_STEP_LEFT, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_LEFT, GTK_TROUGH_NONE); - - - add_slider_binding (binding_set, GDK_Right, 0, - GTK_SCROLL_STEP_RIGHT, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_RIGHT, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Right, 0, - GTK_SCROLL_STEP_RIGHT, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_RIGHT, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Home, 0, - GTK_SCROLL_NONE, GTK_TROUGH_START); - - add_slider_binding (binding_set, GDK_KP_Home, 0, - GTK_SCROLL_NONE, GTK_TROUGH_START); - + gobject_class = G_OBJECT_CLASS (class); + widget_class = GTK_WIDGET_CLASS (class); + range_class = GTK_RANGE_CLASS (class); - add_slider_binding (binding_set, GDK_End, 0, - GTK_SCROLL_NONE, GTK_TROUGH_END); + parent_class = g_type_class_peek_parent (class); - add_slider_binding (binding_set, GDK_KP_End, 0, - GTK_SCROLL_NONE, GTK_TROUGH_END); -} - -static void -gtk_hscale_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkHScale *hscale; - - hscale = GTK_HSCALE (object); - - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_hscale_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GtkHScale *hscale; - - hscale = GTK_HSCALE (object); + range_class->slider_detail = "hscale"; - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + widget_class->expose_event = gtk_hscale_expose; } static void gtk_hscale_init (GtkHScale *hscale) { - GTK_WIDGET_SET_FLAGS (hscale, GTK_NO_WINDOW); + GtkRange *range; + + range = GTK_RANGE (hscale); + + range->orientation = GTK_ORIENTATION_HORIZONTAL; + range->flippable = TRUE; } GtkWidget* @@ -223,305 +99,32 @@ gtk_hscale_new (GtkAdjustment *adjustment) "adjustment", adjustment, NULL); - GTK_RANGE (hscale) -> flippable = 1; - return hscale; } - -static void -gtk_hscale_realize (GtkWidget *widget) -{ - GtkRange *range; - GdkWindowAttr attributes; - gint attributes_mask; - gint x, y, w, h; - gint slider_width, slider_length; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_HSCALE (widget)); - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - range = GTK_RANGE (widget); - - _gtk_range_get_props (range, &slider_width, NULL, NULL, NULL); - gtk_widget_style_get (widget, "slider_length", &slider_length, NULL); - - widget->window = gtk_widget_get_parent_window (widget); - gdk_window_ref (widget->window); - - gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &w, &h); - - attributes.x = x; - attributes.y = y; - attributes.width = w; - attributes.height = h; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - - attributes.event_mask = gtk_widget_get_events (widget) | - (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - - range->trough = gdk_window_new (widget->window, &attributes, attributes_mask); - - attributes.width = slider_length; - attributes.height = slider_width; - attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - - range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); - - widget->style = gtk_style_attach (widget->style, widget->window); - - gdk_window_set_user_data (range->trough, widget); - gdk_window_set_user_data (range->slider, widget); - - gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); - gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); - - _gtk_range_slider_update (GTK_RANGE (widget)); - - gdk_window_show (range->slider); -} - -static void -gtk_hscale_clear_background (GtkRange *range) -{ - GtkWidget *widget; - gint x, y, width, height; - - g_return_if_fail (range != NULL); - - widget = GTK_WIDGET (range); - - gtk_hscale_pos_background (GTK_HSCALE (range), &x, &y, &width, &height); - - gtk_widget_queue_clear_area (GTK_WIDGET (range), - x, y, width, height); -} - -static void -gtk_hscale_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - GtkScale *scale = GTK_SCALE (widget); - gint slider_width, slider_length, trough_border; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_HSCALE (widget)); - g_return_if_fail (requisition != NULL); - - _gtk_range_get_props (GTK_RANGE (scale), - &slider_width, &trough_border, NULL, NULL); - gtk_widget_style_get (widget, "slider_length", &slider_length, NULL); - - requisition->width = (slider_length + trough_border) * 2; - requisition->height = (slider_width + trough_border * 2); - - if (scale->draw_value) - { - gint value_width, value_height; - gtk_scale_get_value_size (scale, &value_width, &value_height); - - if ((scale->value_pos == GTK_POS_LEFT) || - (scale->value_pos == GTK_POS_RIGHT)) - { - requisition->width += value_width + SCALE_CLASS (scale)->value_spacing; - if (requisition->height < value_height) - requisition->height = value_height; - } - else if ((scale->value_pos == GTK_POS_TOP) || - (scale->value_pos == GTK_POS_BOTTOM)) - { - if (requisition->width < value_width) - requisition->width = value_width; - requisition->height += value_height; - } - } -} - -static void -gtk_hscale_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +static gboolean +gtk_hscale_expose (GtkWidget *widget, + GdkEventExpose *event) { GtkRange *range; + GtkHScale *hscale; GtkScale *scale; - gint width, height; - gint x, y; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_HSCALE (widget)); - g_return_if_fail (allocation != NULL); - - widget->allocation = *allocation; - if (GTK_WIDGET_REALIZED (widget)) - { - range = GTK_RANGE (widget); - scale = GTK_SCALE (widget); - - gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height); - - gdk_window_move_resize (range->trough, - x, y, width, height); - _gtk_range_slider_update (GTK_RANGE (widget)); - } -} - -static void -gtk_hscale_pos_trough (GtkHScale *hscale, - gint *x, - gint *y, - gint *w, - gint *h) -{ - GtkWidget *widget = GTK_WIDGET (hscale); - GtkScale *scale = GTK_SCALE (hscale); - gint slider_width; - gint trough_border; - - _gtk_range_get_props (GTK_RANGE (scale), - &slider_width, &trough_border, NULL, NULL); - - *w = widget->allocation.width; - *h = (slider_width + trough_border * 2); - - if (scale->draw_value) - { - gint value_width, value_height; - gtk_scale_get_value_size (scale, &value_width, &value_height); - - *x = 0; - *y = 0; - - switch (scale->value_pos) - { - case GTK_POS_LEFT: - *x += value_width + SCALE_CLASS (scale)->value_spacing; - *y = (widget->allocation.height - *h) / 2; - *w -= *x; - break; - case GTK_POS_RIGHT: - *w -= value_width + SCALE_CLASS (scale)->value_spacing; - *y = (widget->allocation.height - *h) / 2; - break; - case GTK_POS_TOP: - *y = (value_height + (widget->allocation.height - widget->requisition.height) / 2); - break; - case GTK_POS_BOTTOM: - *y = (widget->allocation.height - widget->requisition.height) / 2; - break; - } - } - else - { - *x = 0; - *y = (widget->allocation.height - *h) / 2; - } - *x += 1; - *w -= 2; - - *x += widget->allocation.x; - *y += widget->allocation.y; -} - -static void -gtk_hscale_pos_background (GtkHScale *hscale, - gint *x, - gint *y, - gint *w, - gint *h) -{ - GtkWidget *widget; - GtkScale *scale; - - gint tx, ty, twidth, theight; - - g_return_if_fail (hscale != NULL); - g_return_if_fail (GTK_IS_HSCALE (hscale)); - g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL)); - - gtk_hscale_pos_trough (hscale, &tx, &ty, &twidth, &theight); - - widget = GTK_WIDGET (hscale); - scale = GTK_SCALE (hscale); - - *x = widget->allocation.x; - *y = widget->allocation.y; - *w = widget->allocation.width; - *h = widget->allocation.height; - - switch (scale->value_pos) - { - case GTK_POS_LEFT: - *w -= twidth; - break; - case GTK_POS_RIGHT: - *x += twidth; - *w -= twidth; - break; - case GTK_POS_TOP: - *h -= theight; - break; - case GTK_POS_BOTTOM: - *y += theight; - *h -= theight; - break; - } - *w = MAX (*w, 0); - *h = MAX (*h, 0); -} - -static void -gtk_hscale_draw_slider (GtkRange *range) -{ - GtkStateType state_type; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_HSCALE (range)); - - if (range->slider) - { - if ((range->in_child == RANGE_CLASS (range)->slider) || - (range->click_child == RANGE_CLASS (range)->slider)) - state_type = GTK_STATE_PRELIGHT; - else - state_type = GTK_STATE_NORMAL; - - gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type, - GTK_SHADOW_OUT, - NULL, GTK_WIDGET (range), "hscale", - 0, 0, -1, -1, - GTK_ORIENTATION_HORIZONTAL); - } -} - -static void -gtk_hscale_draw_value (GtkScale *scale) -{ - GtkStateType state_type; - GtkWidget *widget; - gint width, height; - gint x, y; - g_return_if_fail (scale != NULL); - g_return_if_fail (GTK_IS_HSCALE (scale)); - - widget = GTK_WIDGET (scale); + range = GTK_RANGE (widget); + scale = GTK_SCALE (widget); + hscale = GTK_HSCALE (widget); if (scale->draw_value) { PangoLayout *layout; PangoRectangle logical_rect; gchar *txt; + gint x, y; + GtkStateType state_type; + gint value_spacing; + gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL); + txt = _gtk_scale_format_value (scale, GTK_RANGE (scale)->adjustment->value); @@ -529,44 +132,37 @@ gtk_hscale_draw_value (GtkScale *scale) g_free (txt); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - + switch (scale->value_pos) { case GTK_POS_LEFT: - gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); - gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height); - - x -= SCALE_CLASS (scale)->value_spacing + logical_rect.width; - y += (height - logical_rect.height) / 2; + 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: - gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); - gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height); - x += width + SCALE_CLASS (scale)->value_spacing; - y += (height - logical_rect.height) / 2; + 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: - gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL); - gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y); - gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); - gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); - x += widget->allocation.x + (width - logical_rect.width) / 2; - x = CLAMP (x, widget->allocation.x, - widget->allocation.x + widget->allocation.width - logical_rect.width); - y -= logical_rect.height; + 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: - gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL); - gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y); - gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); - gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); - x += widget->allocation.x + (width - logical_rect.width) / 2; - x = CLAMP (x, widget->allocation.x, - widget->allocation.x + widget->allocation.width - logical_rect.width); - y += height; + 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_val_if_reached (FALSE); + x = 0; + y = 0; break; } @@ -586,4 +182,6 @@ gtk_hscale_draw_value (GtkScale *scale) g_object_unref (G_OBJECT (layout)); } + + return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); } diff --git a/gtk/gtkhscrollbar.c b/gtk/gtkhscrollbar.c index 9ec6f22c48..0894187dec 100644 --- a/gtk/gtkhscrollbar.c +++ b/gtk/gtkhscrollbar.c @@ -1,5 +1,6 @@ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,34 +30,8 @@ #include "gdk/gdkkeysyms.h" #include "gtkintl.h" - -#define EPSILON 0.01 - -#define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w) - -enum { - PROP_0 -}; - static void gtk_hscrollbar_class_init (GtkHScrollbarClass *klass); static void gtk_hscrollbar_init (GtkHScrollbar *hscrollbar); -static void gtk_hscrollbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_hscrollbar_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_hscrollbar_realize (GtkWidget *widget); -static void gtk_hscrollbar_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_hscrollbar_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_hscrollbar_draw_step_forw (GtkRange *range); -static void gtk_hscrollbar_draw_step_back (GtkRange *range); -static void gtk_hscrollbar_slider_update (GtkRange *range); -static void gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar); GtkType gtk_hscrollbar_get_type (void) @@ -86,69 +61,17 @@ gtk_hscrollbar_get_type (void) static void gtk_hscrollbar_class_init (GtkHScrollbarClass *class) { - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkRangeClass *range_class; - - gobject_class = (GObjectClass*) class; - object_class = (GtkObjectClass*) class; - widget_class = (GtkWidgetClass*) class; - range_class = (GtkRangeClass*) class; - - gobject_class->set_property = gtk_hscrollbar_set_property; - gobject_class->get_property = gtk_hscrollbar_get_property; - - widget_class->realize = gtk_hscrollbar_realize; - widget_class->size_request = gtk_hscrollbar_size_request; - widget_class->size_allocate = gtk_hscrollbar_size_allocate; - - range_class->draw_step_forw = gtk_hscrollbar_draw_step_forw; - range_class->draw_step_back = gtk_hscrollbar_draw_step_back; - range_class->slider_update = gtk_hscrollbar_slider_update; - range_class->trough_click = _gtk_range_default_htrough_click; - range_class->motion = _gtk_range_default_hmotion; -} - -static void -gtk_hscrollbar_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkHScrollbar *hscrollbar; - - hscrollbar = GTK_HSCROLLBAR (object); - - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_hscrollbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GtkHScrollbar *hscrollbar; - - hscrollbar = GTK_HSCROLLBAR (object); - - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + GTK_RANGE_CLASS (class)->stepper_detail = "hscrollbar"; } static void gtk_hscrollbar_init (GtkHScrollbar *hscrollbar) { + GtkRange *range; + + range = GTK_RANGE (hscrollbar); + + range->orientation = GTK_ORIENTATION_HORIZONTAL; } GtkWidget* @@ -163,282 +86,3 @@ gtk_hscrollbar_new (GtkAdjustment *adjustment) return hscrollbar; } - -static void -gtk_hscrollbar_realize (GtkWidget *widget) -{ - GtkRange *range; - GdkWindowAttr attributes; - gint attributes_mask; - gint slider_width; - gint trough_border; - gint stepper_size; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_HSCROLLBAR (widget)); - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - range = GTK_RANGE (widget); - - _gtk_range_get_props (range, &slider_width, &trough_border, - &stepper_size, NULL); - - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y + (widget->allocation.height - widget->requisition.height) / 2; - attributes.width = widget->allocation.width; - attributes.height = widget->requisition.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - - range->trough = widget->window; - gdk_window_ref (range->trough); - - attributes.x = trough_border; - attributes.y = trough_border; - attributes.width = stepper_size; - attributes.height = stepper_size; - - range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask); - - attributes.x = (widget->allocation.width - - trough_border - - stepper_size); - - range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask); - - attributes.x = 0; - attributes.y = trough_border; - attributes.width = RANGE_CLASS (widget)->min_slider_size; - attributes.height = slider_width; - - attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - - range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); - - gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (widget)); - _gtk_range_slider_update (GTK_RANGE (widget)); - - widget->style = gtk_style_attach (widget->style, widget->window); - - gdk_window_set_user_data (range->trough, widget); - gdk_window_set_user_data (range->slider, widget); - gdk_window_set_user_data (range->step_forw, widget); - gdk_window_set_user_data (range->step_back, widget); - - gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); - gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); - gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE); - gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE); - - gdk_window_show (range->slider); - gdk_window_show (range->step_forw); - gdk_window_show (range->step_back); -} - -static void -gtk_hscrollbar_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - gint slider_width; - gint trough_border; - gint stepper_size; - gint stepper_spacing; - - GtkRange *range = GTK_RANGE (widget); - - _gtk_range_get_props (range, &slider_width, &trough_border, - &stepper_size, &stepper_spacing); - - requisition->width = (RANGE_CLASS (widget)->min_slider_size + - stepper_size + - stepper_spacing + - trough_border) * 2; - requisition->height = (slider_width + - trough_border * 2); -} - -static void -gtk_hscrollbar_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkRange *range; - gint trough_border; - gint stepper_size; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_HSCROLLBAR (widget)); - g_return_if_fail (allocation != NULL); - - widget->allocation = *allocation; - if (GTK_WIDGET_REALIZED (widget)) - { - range = GTK_RANGE (widget); - - _gtk_range_get_props (range, NULL, &trough_border, - &stepper_size, NULL); - - gdk_window_move_resize (range->trough, - allocation->x, - allocation->y + (allocation->height - widget->requisition.height) / 2, - allocation->width, widget->requisition.height); - gdk_window_move_resize (range->step_back, - trough_border, - trough_border, - stepper_size, - widget->requisition.height - trough_border * 2); - gdk_window_move_resize (range->step_forw, - allocation->width - trough_border - - stepper_size, - trough_border, - stepper_size, - widget->requisition.height - trough_border * 2); - - _gtk_range_slider_update (GTK_RANGE (widget)); - } -} - -static void -gtk_hscrollbar_draw_step_forw (GtkRange *range) -{ - GtkStateType state_type; - GtkShadowType shadow_type; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_HSCROLLBAR (range)); - - if (GTK_WIDGET_DRAWABLE (range)) - { - if (range->in_child == RANGE_CLASS (range)->step_forw) - { - if (range->click_child == RANGE_CLASS (range)->step_forw) - state_type = GTK_STATE_ACTIVE; - else - state_type = GTK_STATE_PRELIGHT; - } - else - state_type = GTK_STATE_NORMAL; - - if (range->click_child == RANGE_CLASS (range)->step_forw) - shadow_type = GTK_SHADOW_IN; - else - shadow_type = GTK_SHADOW_OUT; - - gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw, - state_type, shadow_type, - NULL, GTK_WIDGET (range), "hscrollbar", - GTK_ARROW_RIGHT, - TRUE, 0, 0, -1, -1); - } -} - -static void -gtk_hscrollbar_draw_step_back (GtkRange *range) -{ - GtkStateType state_type; - GtkShadowType shadow_type; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_HSCROLLBAR (range)); - - if (GTK_WIDGET_DRAWABLE (range)) - { - if (range->in_child == RANGE_CLASS (range)->step_back) - { - if (range->click_child == RANGE_CLASS (range)->step_back) - state_type = GTK_STATE_ACTIVE; - else - state_type = GTK_STATE_PRELIGHT; - } - else - state_type = GTK_STATE_NORMAL; - - if (range->click_child == RANGE_CLASS (range)->step_back) - shadow_type = GTK_SHADOW_IN; - else - shadow_type = GTK_SHADOW_OUT; - - gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back, - state_type, shadow_type, - NULL, GTK_WIDGET (range), "hscrollbar", - GTK_ARROW_LEFT, - TRUE, 0, 0, -1, -1); - } -} - -static void -gtk_hscrollbar_slider_update (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_HSCROLLBAR (range)); - - gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (range)); - _gtk_range_default_hslider_update (range); -} - -static void -gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar) -{ - GtkRange *range; - gint step_back_x; - gint step_back_width; - gint step_forw_x; - gint slider_width; - gint slider_height; - gint stepper_spacing; - gint left, right; - gint width; - - g_return_if_fail (hscrollbar != NULL); - g_return_if_fail (GTK_IS_HSCROLLBAR (hscrollbar)); - - if (GTK_WIDGET_REALIZED (hscrollbar)) - { - range = GTK_RANGE (hscrollbar); - - _gtk_range_get_props (range, NULL, NULL, NULL, &stepper_spacing); - - gdk_window_get_size (range->step_back, &step_back_width, NULL); - gdk_window_get_position (range->step_back, &step_back_x, NULL); - gdk_window_get_position (range->step_forw, &step_forw_x, NULL); - - left = (step_back_x + - step_back_width + - stepper_spacing); - right = step_forw_x - stepper_spacing; - width = right - left; - - if ((range->adjustment->page_size > 0) && - (range->adjustment->lower != range->adjustment->upper)) - { - if (range->adjustment->page_size > - (range->adjustment->upper - range->adjustment->lower)) - range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower; - - width = (width * range->adjustment->page_size / - (range->adjustment->upper - range->adjustment->lower)); - - if (width < RANGE_CLASS (hscrollbar)->min_slider_size) - width = RANGE_CLASS (hscrollbar)->min_slider_size; - } - - gdk_window_get_size (range->slider, &slider_width, &slider_height); - - if (slider_width != width) - { - gdk_window_resize (range->slider, width, slider_height); - gdk_window_invalidate_rect (range->slider, NULL, FALSE); - } - } -} diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index f73244133e..e813a14321 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -1,5 +1,6 @@ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,12 +32,9 @@ #include "gtksignal.h" #include "gtkintl.h" -#define SCROLL_TIMER_LENGTH 20 #define SCROLL_INITIAL_DELAY 250 /* must hold button this long before ... */ #define SCROLL_LATER_DELAY 100 /* ... it starts repeating at this rate */ -#define SCROLL_DELAY_LENGTH 300 - -#define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w) +#define UPDATE_DELAY 300 /* Delay for queued update */ enum { PROP_0, @@ -49,59 +47,116 @@ enum { LAST_SIGNAL }; -static void gtk_range_class_init (GtkRangeClass *klass); -static void gtk_range_init (GtkRange *range); -static void gtk_range_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_range_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_range_destroy (GtkObject *object); -static void gtk_range_unrealize (GtkWidget *widget); -static gint gtk_range_expose (GtkWidget *widget, - GdkEventExpose *event); -static gint gtk_range_button_press (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_range_button_release (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_range_motion_notify (GtkWidget *widget, - GdkEventMotion *event); -static gint gtk_range_enter_notify (GtkWidget *widget, - GdkEventCrossing *event); -static gint gtk_range_leave_notify (GtkWidget *widget, - GdkEventCrossing *event); -static gint gtk_range_scroll_event (GtkWidget *widget, - GdkEventScroll *event); -static void gtk_range_style_set (GtkWidget *widget, - GtkStyle *previous_style); +typedef enum { + MOUSE_OUTSIDE, + MOUSE_STEPPER_A, + MOUSE_STEPPER_B, + MOUSE_STEPPER_C, + MOUSE_STEPPER_D, + MOUSE_TROUGH, + MOUSE_SLIDER, + MOUSE_WIDGET /* inside widget but not in any of the above GUI elements */ +} MouseLocation; + +struct _GtkRangeLayout +{ + /* These are in widget->window coordinates */ + GdkRectangle stepper_a; + GdkRectangle stepper_b; + GdkRectangle stepper_c; + GdkRectangle stepper_d; + /* The trough rectangle is the area the thumb can slide in, not the + * entire range_rect + */ + GdkRectangle trough; + GdkRectangle slider; + + /* Layout-related state */ + + MouseLocation mouse_location; + /* last mouse coords we got, or -1 if mouse is outside the range */ + gint mouse_x; + gint mouse_y; + /* "grabbed" mouse location, OUTSIDE for no grab */ + MouseLocation grab_location; + gint grab_button; /* 0 if none */ +}; + +static void gtk_range_class_init (GtkRangeClass *klass); +static void gtk_range_init (GtkRange *range); +static void gtk_range_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_range_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_range_destroy (GtkObject *object); +static void gtk_range_finalize (GObject *object); +static void gtk_range_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_range_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_range_realize (GtkWidget *widget); +static void gtk_range_unrealize (GtkWidget *widget); +static gint gtk_range_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_range_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_range_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_range_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_range_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_range_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_range_scroll_event (GtkWidget *widget, + GdkEventScroll *event); +static void gtk_range_style_set (GtkWidget *widget, + GtkStyle *previous_style); + + +/* Range methods */ static void gtk_range_move_slider (GtkRange *range, - GtkScrollType scroll, - GtkTroughType trough); - -static void gtk_real_range_draw_trough (GtkRange *range); -static void gtk_real_range_draw_slider (GtkRange *range); -static gint gtk_real_range_timer (GtkRange *range); -static gint gtk_range_scroll (GtkRange *range, - gdouble jump_perc); - -static void gtk_range_add_timer (GtkRange *range); -static void gtk_range_remove_timer (GtkRange *range); - -static void gtk_range_adjustment_changed (GtkAdjustment *adjustment, - gpointer data); -static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, - gpointer data); - -static void gtk_range_trough_hdims (GtkRange *range, - gint *left, - gint *right); -static void gtk_range_trough_vdims (GtkRange *range, - gint *top, - gint *bottom); + GtkScrollType scroll); + +/* Internals */ +static void gtk_range_scroll (GtkRange *range, + GtkScrollType scroll); +static gboolean gtk_range_update_mouse_location (GtkRange *range); +static void gtk_range_calc_layout (GtkRange *range); +static void gtk_range_get_props (GtkRange *range, + gint *slider_width, + gint *stepper_size, + gint *trough_border, + gint *stepper_spacing); +static void gtk_range_calc_request (GtkRange *range, + gint slider_width, + gint stepper_size, + gint trough_border, + gint stepper_spacing, + GdkRectangle *range_rect, + GtkBorder *border, + gint *n_steppers_p, + gint *slider_length_p); +static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); +static void gtk_range_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void gtk_range_add_step_timer (GtkRange *range, + GtkScrollType step); +static void gtk_range_remove_step_timer (GtkRange *range); +static void gtk_range_reset_update_timer (GtkRange *range); +static void gtk_range_remove_update_timer (GtkRange *range); +static GdkRectangle* get_area (GtkRange *range, + MouseLocation location); +static void gtk_range_internal_set_value (GtkRange *range, + gdouble value); +static void gtk_range_update_value (GtkRange *range); + static GtkWidgetClass *parent_class = NULL; static guint signals[LAST_SIGNAL]; @@ -143,13 +198,17 @@ gtk_range_class_init (GtkRangeClass *class) object_class = (GtkObjectClass*) class; widget_class = (GtkWidgetClass*) class; - parent_class = gtk_type_class (GTK_TYPE_WIDGET); + parent_class = g_type_class_peek_parent (class); gobject_class->set_property = gtk_range_set_property; gobject_class->get_property = gtk_range_get_property; + gobject_class->finalize = gtk_range_finalize; object_class->destroy = gtk_range_destroy; - widget_class->unrealize = gtk_range_unrealize; + widget_class->size_request = gtk_range_size_request; + widget_class->size_allocate = gtk_range_size_allocate; + widget_class->realize = gtk_range_realize; + widget_class->unrealize = gtk_range_unrealize; widget_class->expose_event = gtk_range_expose; widget_class->button_press_event = gtk_range_button_press; widget_class->button_release_event = gtk_range_button_release; @@ -158,35 +217,21 @@ gtk_range_class_init (GtkRangeClass *class) widget_class->enter_notify_event = gtk_range_enter_notify; widget_class->leave_notify_event = gtk_range_leave_notify; widget_class->style_set = gtk_range_style_set; - - class->min_slider_size = 7; - class->trough = 1; - class->slider = 2; - class->step_forw = 3; - class->step_back = 4; class->move_slider = gtk_range_move_slider; - - class->draw_background = NULL; - class->clear_background = NULL; - class->draw_trough = gtk_real_range_draw_trough; - class->draw_slider = gtk_real_range_draw_slider; - class->draw_step_forw = NULL; - class->draw_step_back = NULL; - class->trough_click = NULL; - class->motion = NULL; - class->timer = gtk_real_range_timer; + class->slider_detail = "slider"; + class->stepper_detail = "stepper"; + signals[MOVE_SLIDER] = g_signal_newc ("move_slider", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GtkRangeClass, move_slider), NULL, NULL, - gtk_marshal_VOID__ENUM_ENUM, - G_TYPE_NONE, 2, - GTK_TYPE_SCROLL_TYPE, - GTK_TYPE_TROUGH_TYPE); + gtk_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_SCROLL_TYPE); g_object_class_install_property (gobject_class, @@ -216,16 +261,16 @@ gtk_range_class_init (GtkRangeClass *class) G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("trough_border", - _("Trough Border"), - _("Width of border around range"), - 0, - G_MAXINT, - 1, - G_PARAM_READABLE)); + _("Trough Border"), + _("Spacing between thumb/steppers and outer trough bevel"), + 0, + G_MAXINT, + 1, + G_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("stepper_size", _("Stepper Size"), - _("Size of step buttons at ends"), + _("Length of step buttons at ends"), 0, G_MAXINT, 14, @@ -234,7 +279,7 @@ gtk_range_class_init (GtkRangeClass *class) g_param_spec_int ("stepper_spacing", _("Stepper Spacing"), _("Spacing between step buttons and thumb"), - G_MININT, + 0, G_MAXINT, 0, G_PARAM_READABLE)); @@ -277,7 +322,7 @@ gtk_range_get_property (GObject *object, switch (prop_id) { case PROP_UPDATE_POLICY: - g_value_set_enum (value, range->policy); + g_value_set_enum (value, range->update_policy); break; case PROP_ADJUSTMENT: g_value_set_object (value, G_OBJECT (range->adjustment)); @@ -291,27 +336,21 @@ gtk_range_get_property (GObject *object, static void gtk_range_init (GtkRange *range) { - range->trough = NULL; - range->slider = NULL; - range->step_forw = NULL; - range->step_back = NULL; - - range->x_click_point = 0; - range->y_click_point = 0; - range->button = 0; - range->digits = -1; - range->policy = GTK_UPDATE_CONTINUOUS; - range->scroll_type = GTK_SCROLL_NONE; - range->in_child = 0; - range->click_child = 0; - range->need_timer = FALSE; - range->timer = 0; - range->flippable = 0; - range->old_value = 0.0; - range->old_lower = 0.0; - range->old_upper = 0.0; - range->old_page_size = 0.0; range->adjustment = NULL; + range->update_policy = GTK_UPDATE_CONTINUOUS; + range->inverted = FALSE; + range->flippable = FALSE; + range->min_slider_size = 1; + range->has_stepper_a = FALSE; + range->has_stepper_b = FALSE; + range->has_stepper_c = FALSE; + range->has_stepper_d = FALSE; + range->need_recalc = TRUE; + range->round_digits = -1; + range->layout = g_new0 (GtkRangeLayout, 1); + range->layout->grab_location = MOUSE_OUTSIDE; + range->layout->grab_button = 0; + range->timer = NULL; } GtkAdjustment* @@ -333,9 +372,9 @@ gtk_range_set_update_policy (GtkRange *range, g_return_if_fail (range != NULL); g_return_if_fail (GTK_IS_RANGE (range)); - if (range->policy != policy) + if (range->update_policy != policy) { - range->policy = policy; + range->update_policy = policy; g_object_notify (G_OBJECT (range), "update_policy"); } } @@ -356,8 +395,12 @@ gtk_range_set_adjustment (GtkRange *range, { if (range->adjustment) { - gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment), - (gpointer) range); + gtk_signal_disconnect_by_func (GTK_OBJECT (range->adjustment), + G_CALLBACK (gtk_range_adjustment_changed), + range); + gtk_signal_disconnect_by_func (GTK_OBJECT (range->adjustment), + G_CALLBACK (gtk_range_adjustment_value_changed), + range); gtk_object_unref (GTK_OBJECT (range->adjustment)); } @@ -367,17 +410,12 @@ gtk_range_set_adjustment (GtkRange *range, gtk_signal_connect (GTK_OBJECT (adjustment), "changed", (GtkSignalFunc) gtk_range_adjustment_changed, - (gpointer) range); + range); gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", (GtkSignalFunc) gtk_range_adjustment_value_changed, - (gpointer) range); - - range->old_value = adjustment->value; - range->old_lower = adjustment->lower; - range->old_upper = adjustment->upper; - range->old_page_size = adjustment->page_size; + range); - gtk_range_adjustment_changed (adjustment, (gpointer) range); + gtk_range_adjustment_changed (adjustment, range); g_object_notify (G_OBJECT (range), "adjustment"); } } @@ -405,126 +443,10 @@ gtk_range_get_inverted (GtkRange *range) return range->inverted; } -void -_gtk_range_draw_background (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - if (range->trough && RANGE_CLASS (range)->draw_background) - (* RANGE_CLASS (range)->draw_background) (range); -} - -void -_gtk_range_clear_background (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - if (range->trough && RANGE_CLASS (range)->clear_background) - (* RANGE_CLASS (range)->clear_background) (range); -} - -void -_gtk_range_draw_trough (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - if (range->trough && RANGE_CLASS (range)->draw_trough) - (* RANGE_CLASS (range)->draw_trough) (range); -} - -void -_gtk_range_draw_slider (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - if (range->slider && RANGE_CLASS (range)->draw_slider) - (* RANGE_CLASS (range)->draw_slider) (range); -} - -void -_gtk_range_draw_step_forw (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - if (range->step_forw && RANGE_CLASS (range)->draw_step_forw) - (* RANGE_CLASS (range)->draw_step_forw) (range); -} - -void -_gtk_range_draw_step_back (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - if (range->step_back && RANGE_CLASS (range)->draw_step_back) - (* RANGE_CLASS (range)->draw_step_back) (range); -} - -void -_gtk_range_slider_update (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - if (RANGE_CLASS (range)->slider_update) - (* RANGE_CLASS (range)->slider_update) (range); -} - -gboolean -_gtk_range_trough_click (GtkRange *range, - gint x, - gint y, - gdouble *jump_perc) -{ - g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); - g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); - - if (RANGE_CLASS (range)->trough_click) - return (* RANGE_CLASS (range)->trough_click) (range, x, y, jump_perc); - - return GTK_TROUGH_NONE; -} - -static GdkRegion * -get_window_region (GdkWindow *window) -{ - GdkRectangle rect; - - gdk_window_get_position (window, &rect.x, &rect.y); - gdk_window_get_size (window, &rect.width, &rect.height); - - return gdk_region_rectangle (&rect); -} - -static void -move_and_update_window (GdkWindow *window, gint x, gint y) -{ - GdkRegion *old_region; - GdkRegion *new_region; - GdkWindow *parent = gdk_window_get_parent (window); - - old_region = get_window_region (window); - gdk_window_move (window, x, y); - new_region = get_window_region (window); - - gdk_region_subtract (old_region, new_region); - gdk_window_invalidate_region (parent, old_region, TRUE); - gdk_region_destroy (old_region); - gdk_region_destroy (new_region); - - gdk_window_process_updates (parent, TRUE); -} - static gboolean -should_invert (GtkRange *range, - gboolean horizontal) +should_invert (GtkRange *range) { - if (horizontal) + if (range->orientation == GTK_ORIENTATION_HORIZONTAL) return (range->inverted && !range->flippable) || (range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) || @@ -533,518 +455,528 @@ should_invert (GtkRange *range, return range->inverted; } -void -_gtk_range_default_hslider_update (GtkRange *range) +static void +gtk_range_finalize (GObject *object) { - gint left; - gint right; - gint x; - gint trough_border; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); - - _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL); - - if (GTK_WIDGET_REALIZED (range)) - { - gtk_range_trough_hdims (range, &left, &right); - x = left; + GtkRange *range; - if (range->adjustment->value < range->adjustment->lower) - { - range->adjustment->value = range->adjustment->lower; - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } - else if (range->adjustment->value > range->adjustment->upper) - { - range->adjustment->value = range->adjustment->upper; - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } + g_return_if_fail (GTK_IS_RANGE (object)); - if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) - x += ((right - left) * (range->adjustment->value - range->adjustment->lower) / - (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); + range = GTK_RANGE (object); - if (x < left) - x = left; - else if (x > right) - x = right; + g_free (range->layout); - if (should_invert (range, TRUE)) - x = right - (x - left); - - move_and_update_window (range->slider, x, trough_border); - } + (* G_OBJECT_CLASS (parent_class)->finalize) (object); } -void -_gtk_range_default_vslider_update (GtkRange *range) +static void +gtk_range_destroy (GtkObject *object) { - gint top; - gint bottom; - gint y; - gint trough_border; + GtkRange *range; - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_RANGE (range)); + g_return_if_fail (GTK_IS_RANGE (object)); - _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL); + range = GTK_RANGE (object); - if (GTK_WIDGET_REALIZED (range)) + gtk_range_remove_step_timer (range); + gtk_range_remove_update_timer (range); + + if (range->adjustment) { - gtk_range_trough_vdims (range, &top, &bottom); - y = top; + if (range->adjustment) + gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment), + (gpointer) range); + gtk_object_unref (GTK_OBJECT (range->adjustment)); + range->adjustment = NULL; + } - if (range->adjustment->value < range->adjustment->lower) - { - range->adjustment->value = range->adjustment->lower; - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } - else if (range->adjustment->value > range->adjustment->upper) - { - range->adjustment->value = range->adjustment->upper; - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} - if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) - y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) / - (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); +static void +gtk_range_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkRange *range; + gint slider_width, stepper_size, trough_border, stepper_spacing; + GdkRectangle range_rect; + GtkBorder border; + + range = GTK_RANGE (widget); + + gtk_range_get_props (range, + &slider_width, &stepper_size, &trough_border, &stepper_spacing); - if (y < top) - y = top; - else if (y > bottom) - y = bottom; + gtk_range_calc_request (range, + slider_width, stepper_size, trough_border, stepper_spacing, + &range_rect, &border, NULL, NULL); - if (should_invert (range, FALSE)) - y = bottom - (y - top); - - move_and_update_window (range->slider, trough_border, y); - } + requisition->width = range_rect.width + border.left + border.right; + requisition->height = range_rect.height + border.top + border.bottom; } -gboolean -_gtk_range_default_htrough_click (GtkRange *range, - gint x, - gint y, - gdouble *jump_perc) +static void +gtk_range_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) { - gint trough_border; - gint trough_width; - gint trough_height; - gint slider_x; - gint slider_length; - gint left, right; + GtkRange *range; - g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); - g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + range = GTK_RANGE (widget); - _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL); + range->need_recalc = TRUE; + gtk_range_calc_layout (range); - gtk_range_trough_hdims (range, &left, &right); - gdk_window_get_size (range->slider, &slider_length, NULL); - right += slider_length; + (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); +} - if (should_invert (range, TRUE)) - x = (right - x) + left; +static void +gtk_range_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; - if ((x > left) && (y > trough_border)) - { - gdk_window_get_size (range->trough, &trough_width, &trough_height); - - if ((x < right) && (y < (trough_height - trough_border))) - { - if (jump_perc) - { - *jump_perc = ((gdouble) (x - left)) / ((gdouble) (right - left)); - return GTK_TROUGH_JUMP; - } - - gdk_window_get_position (range->slider, &slider_x, NULL); - - if (x < slider_x) - return GTK_TROUGH_START; - else - return GTK_TROUGH_END; - } - } + range = GTK_RANGE (widget); - return GTK_TROUGH_NONE; + gtk_range_calc_layout (range); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, range); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, widget->state); } -gboolean -_gtk_range_default_vtrough_click (GtkRange *range, - gint x, - gint y, - gdouble *jump_perc) +static void +gtk_range_unrealize (GtkWidget *widget) { - gint trough_border; - gint trough_width; - gint trough_height; - gint slider_y; - gint top, bottom; - gint slider_length; + GtkRange *range; - g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); - g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); - _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL); - - gtk_range_trough_vdims (range, &top, &bottom); - gdk_window_get_size (range->slider, NULL, &slider_length); - bottom += slider_length; + range = GTK_RANGE (widget); - if (should_invert (range, FALSE)) - y = (bottom - y) + top; + gtk_range_remove_step_timer (range); + gtk_range_remove_update_timer (range); - if ((x > trough_border) && (y > top)) - { - gdk_window_get_size (range->trough, &trough_width, &trough_height); - - if ((x < (trough_width - trough_border) && (y < bottom))) - { - if (jump_perc) - { - *jump_perc = ((gdouble) (y - top)) / ((gdouble) (bottom - top)); - - return GTK_TROUGH_JUMP; - } - - gdk_window_get_position (range->slider, NULL, &slider_y); - - if (y < slider_y) - return GTK_TROUGH_START; - else - return GTK_TROUGH_END; - } - } - - return GTK_TROUGH_NONE; + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } -void -_gtk_range_default_hmotion (GtkRange *range, - gint xdelta, - gint ydelta) +static void +draw_stepper (GtkRange *range, + GdkRectangle *rect, + GtkArrowType arrow_type, + gboolean clicked, + gboolean prelighted, + GdkRectangle *area) { - gdouble old_value; - gint left, right; - gint slider_x, slider_y; - gint new_pos; - - g_return_if_fail (GTK_IS_RANGE (range)); - g_return_if_fail (GTK_WIDGET_REALIZED (range)); - - gdk_window_get_position (range->slider, &slider_x, &slider_y); - gtk_range_trough_hdims (range, &left, &right); + GtkStateType state_type; + GtkShadowType shadow_type; + GdkRectangle intersection; - if (left == right) + /* More to get the right clip region than for efficiency */ + if (!gdk_rectangle_intersect (area, rect, &intersection)) return; + + if (!GTK_WIDGET_IS_SENSITIVE (range)) + state_type = GTK_STATE_INSENSITIVE; + else if (clicked) + state_type = GTK_STATE_ACTIVE; + else if (prelighted) + state_type = GTK_STATE_PRELIGHT; + else + state_type = GTK_STATE_NORMAL; + + if (clicked) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_paint_arrow (GTK_WIDGET (range)->style, + GTK_WIDGET (range)->window, + state_type, shadow_type, + &intersection, GTK_WIDGET (range), + GTK_RANGE_GET_CLASS (range)->stepper_detail, + arrow_type, + TRUE, rect->x, rect->y, rect->width, rect->height); +} - new_pos = slider_x + xdelta; - - if (should_invert (range, TRUE)) - new_pos = (right - new_pos) + left; +static gint +gtk_range_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkRange *range; + gboolean sensitive; + GtkStateType state; + GdkRectangle area; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); - if (new_pos < left) - new_pos = left; - else if (new_pos > right) - new_pos = right; + range = GTK_RANGE (widget); - old_value = range->adjustment->value; - range->adjustment->value = ((range->adjustment->upper - - range->adjustment->lower - - range->adjustment->page_size) * - (new_pos - left) / (right - left) + - range->adjustment->lower); + gtk_range_calc_layout (range); - if (range->digits >= 0) + sensitive = GTK_WIDGET_IS_SENSITIVE (widget); + + /* Just to be confusing, we draw the trough for the whole + * range rectangle, not the trough rectangle (the trough + * rectangle is just for hit detection) + */ + /* The gdk_rectangle_intersect is more to get the right + * clip region (limited to range_rect) than for efficiency + */ + if (gdk_rectangle_intersect (&event->area, &range->range_rect, + &area)) { - char buffer[64]; - - sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); - sscanf (buffer, "%lf", &range->adjustment->value); + gtk_paint_box (widget->style, + widget->window, + sensitive ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE, + GTK_SHADOW_IN, + &area, GTK_WIDGET(range), "trough", + range->range_rect.x, + range->range_rect.y, + range->range_rect.width, + range->range_rect.height); + + + if (sensitive && + GTK_WIDGET_HAS_FOCUS (range)) + gtk_paint_focus (widget->style, + widget->window, + &area, widget, "trough", + range->range_rect.x, + range->range_rect.y, + range->range_rect.width, + range->range_rect.height); } - if (old_value != range->adjustment->value) + if (!sensitive) + state = GTK_STATE_INSENSITIVE; + else if (range->layout->mouse_location == MOUSE_SLIDER) + state = GTK_STATE_PRELIGHT; + else + state = GTK_STATE_NORMAL; + + if (gdk_rectangle_intersect (&event->area, + &range->layout->slider, + &area)) { - if (range->policy == GTK_UPDATE_CONTINUOUS) - { - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } - else - { - _gtk_range_slider_update (range); - _gtk_range_clear_background (range); - - if (range->policy == GTK_UPDATE_DELAYED) - { - gtk_range_remove_timer (range); - range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, - (GtkFunction) RANGE_CLASS (range)->timer, - (gpointer) range); - } - } + gtk_paint_slider (widget->style, + widget->window, + state, + GTK_SHADOW_OUT, + &event->area, + widget, + GTK_RANGE_GET_CLASS (range)->slider_detail, + range->layout->slider.x, + range->layout->slider.y, + range->layout->slider.width, + range->layout->slider.height, + range->orientation); } + + if (range->has_stepper_a) + draw_stepper (range, &range->layout->stepper_a, + range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, + range->layout->grab_location == MOUSE_STEPPER_A, + range->layout->mouse_location == MOUSE_STEPPER_A, + &event->area); + + if (range->has_stepper_b) + draw_stepper (range, &range->layout->stepper_b, + range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, + range->layout->grab_location == MOUSE_STEPPER_B, + range->layout->mouse_location == MOUSE_STEPPER_B, + &event->area); + + if (range->has_stepper_c) + draw_stepper (range, &range->layout->stepper_c, + range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, + range->layout->grab_location == MOUSE_STEPPER_C, + range->layout->mouse_location == MOUSE_STEPPER_C, + &event->area); + + if (range->has_stepper_d) + draw_stepper (range, &range->layout->stepper_d, + range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, + range->layout->grab_location == MOUSE_STEPPER_D, + range->layout->mouse_location == MOUSE_STEPPER_D, + &event->area); + + return FALSE; } -void -_gtk_range_default_vmotion (GtkRange *range, - gint xdelta, - gint ydelta) +static void +range_grab_add (GtkRange *range, + MouseLocation location, + gint button) { - gdouble old_value; - gint top, bottom; - gint slider_x, slider_y; - gint new_pos; - - g_return_if_fail (GTK_IS_RANGE (range)); - g_return_if_fail (GTK_WIDGET_REALIZED (range)); + /* we don't actually gtk_grab, since a button is down */ - range = GTK_RANGE (range); - - gdk_window_get_position (range->slider, &slider_x, &slider_y); - gtk_range_trough_vdims (range, &top, &bottom); - - if (bottom == top) - return; - - new_pos = slider_y + ydelta; - - if (should_invert (range, FALSE)) - new_pos = (bottom - new_pos) + top; + range->layout->grab_location = location; + range->layout->grab_button = button; - if (new_pos < top) - new_pos = top; - else if (new_pos > bottom) - new_pos = bottom; - - old_value = range->adjustment->value; - range->adjustment->value = ((range->adjustment->upper - - range->adjustment->lower - - range->adjustment->page_size) * - (new_pos - top) / (bottom - top) + - range->adjustment->lower); - - if (range->digits >= 0) - { - char buffer[64]; - - sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); - sscanf (buffer, "%lf", &range->adjustment->value); - } - - if (old_value != range->adjustment->value) - { - if (range->policy == GTK_UPDATE_CONTINUOUS) - { - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } - else - { - _gtk_range_slider_update (range); - _gtk_range_clear_background (range); - - if (range->policy == GTK_UPDATE_DELAYED) - { - gtk_range_remove_timer (range); - range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, - (GtkFunction) RANGE_CLASS (range)->timer, - (gpointer) range); - } - } - } + if (gtk_range_update_mouse_location (range)) + gtk_widget_queue_draw (GTK_WIDGET (range)); } - static void -gtk_range_destroy (GtkObject *object) +range_grab_remove (GtkRange *range) { - GtkRange *range; + range->layout->grab_location = MOUSE_OUTSIDE; + range->layout->grab_button = 0; - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_RANGE (object)); - - range = GTK_RANGE (object); + if (gtk_range_update_mouse_location (range)) + gtk_widget_queue_draw (GTK_WIDGET (range)); +} - gtk_range_remove_timer (range); - if (range->adjustment) +static GtkScrollType +range_get_scroll_for_grab (GtkRange *range) +{ + switch (range->layout->grab_location) { - if (range->adjustment) - gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment), - (gpointer) range); - gtk_object_unref (GTK_OBJECT (range->adjustment)); - range->adjustment = NULL; + /* Backward stepper */ + case MOUSE_STEPPER_A: + case MOUSE_STEPPER_C: + switch (range->layout->grab_button) + { + case 1: + return GTK_SCROLL_STEP_BACKWARD; + break; + case 2: + return GTK_SCROLL_PAGE_BACKWARD; + break; + case 3: + return GTK_SCROLL_START; + break; + } + break; + + /* Forward stepper */ + case MOUSE_STEPPER_B: + case MOUSE_STEPPER_D: + switch (range->layout->grab_button) + { + case 1: + return GTK_SCROLL_STEP_FORWARD; + break; + case 2: + return GTK_SCROLL_PAGE_FORWARD; + break; + case 3: + return GTK_SCROLL_END; + break; + } + break; + + /* In the trough */ + case MOUSE_TROUGH: + { + if (range->trough_click_forward) + { + return range->layout->grab_button == 3 + ? GTK_SCROLL_PAGE_FORWARD : GTK_SCROLL_STEP_FORWARD; + } + else + { + return range->layout->grab_button == 3 + ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_STEP_BACKWARD; + } + } + break; + + case MOUSE_OUTSIDE: + case MOUSE_SLIDER: + case MOUSE_WIDGET: + break; } - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); + return GTK_SCROLL_NONE; } -static void -gtk_range_unrealize (GtkWidget *widget) +static gdouble +coord_to_value (GtkRange *range, + gint coord) { - GtkRange *range; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_RANGE (widget)); - - range = GTK_RANGE (widget); + gdouble frac; + gdouble value; + + if (range->orientation == GTK_ORIENTATION_VERTICAL) + frac = ((coord - range->layout->trough.y) / + (gdouble) (range->layout->trough.height - range->layout->slider.height)); + else + frac = ((coord - range->layout->trough.x) / + (gdouble) (range->layout->trough.width - range->layout->slider.width)); - if (range->slider) - { - gdk_window_set_user_data (range->slider, NULL); - gdk_window_destroy (range->slider); - range->slider = NULL; - } - if (range->trough) - { - gdk_window_set_user_data (range->trough, NULL); - gdk_window_destroy (range->trough); - range->trough = NULL; - } - if (range->step_forw) - { - gdk_window_set_user_data (range->step_forw, NULL); - gdk_window_destroy (range->step_forw); - range->step_forw = NULL; - } - if (range->step_back) - { - gdk_window_set_user_data (range->step_back, NULL); - gdk_window_destroy (range->step_back); - range->step_back = NULL; - } + if (should_invert (range)) + frac = 1.0 - frac; + + value = range->adjustment->lower + + frac * (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size); - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); + return value; } static gint -gtk_range_expose (GtkWidget *widget, - GdkEventExpose *event) +gtk_range_button_press (GtkWidget *widget, + GdkEventButton *event) { GtkRange *range; - g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); - /* We should really pass another argument - - *the redrawn area - to all the drawing functions) - */ - if (event->window == range->trough) - { - _gtk_range_draw_trough (range); - } - else if (event->window == widget->window) - { - _gtk_range_draw_background (range); - } - else if (event->window == range->slider) + /* ignore presses when we're already doing something else. */ + if (range->layout->grab_location != MOUSE_OUTSIDE) + return FALSE; + + range->layout->mouse_x = event->x; + range->layout->mouse_y = event->y; + if (gtk_range_update_mouse_location (range)) + gtk_widget_queue_draw (widget); + + if (range->layout->mouse_location == MOUSE_TROUGH && + (event->button == 1 || event->button == 3)) { - _gtk_range_draw_slider (range); + /* button 1 steps by step increment, as with button 1 on a stepper, + * button 3 steps by page increment, as with button 2 on a stepper + */ + GtkScrollType scroll; + gdouble click_value; + + click_value = coord_to_value (range, + range->orientation == GTK_ORIENTATION_VERTICAL ? + event->y : event->x); + + range->trough_click_forward = click_value > range->adjustment->value; + range_grab_add (range, MOUSE_TROUGH, event->button); + + scroll = range_get_scroll_for_grab (range); + + gtk_range_add_step_timer (range, scroll); + + return TRUE; } - else if (event->window == range->step_forw) + else if ((range->layout->mouse_location == MOUSE_STEPPER_A || + range->layout->mouse_location == MOUSE_STEPPER_B || + range->layout->mouse_location == MOUSE_STEPPER_C || + range->layout->mouse_location == MOUSE_STEPPER_D) && + (event->button == 1 || event->button == 2 || event->button == 3)) { - _gtk_range_draw_step_forw (range); + GdkRectangle *stepper_area; + GtkScrollType scroll; + + range_grab_add (range, range->layout->mouse_location, event->button); + + stepper_area = get_area (range, range->layout->mouse_location); + gtk_widget_queue_draw_area (widget, + stepper_area->x, + stepper_area->y, + stepper_area->width, + stepper_area->height); + + scroll = range_get_scroll_for_grab (range); + if (scroll != GTK_SCROLL_NONE) + gtk_range_add_step_timer (range, scroll); + + return TRUE; } - else if (event->window == range->step_back) + else if ((range->layout->mouse_location == MOUSE_TROUGH && + event->button == 2) || + range->layout->mouse_location == MOUSE_SLIDER) { - _gtk_range_draw_step_back (range); + /* Any button can be used to drag the slider, but you can start + * dragging the slider with a trough click using button 2; + * On button 2 press, we warp the slider to mouse position, + * then begin the slider drag. + */ + if (event->button == 2) + { + gdouble click_value; + + click_value = coord_to_value (range, + range->orientation == GTK_ORIENTATION_VERTICAL ? + event->y : event->x); + + + /* middle button jumps to point */ + gtk_range_internal_set_value (range, click_value); + + /* Calc layout so we can set slide_initial_slider_position + * properly + */ + gtk_range_calc_layout (range); + } + + if (range->orientation == GTK_ORIENTATION_VERTICAL) + { + range->slide_initial_slider_position = range->layout->slider.y; + range->slide_initial_coordinate = event->y; + } + else + { + range->slide_initial_slider_position = range->layout->slider.x; + range->slide_initial_coordinate = event->x; + } + + range_grab_add (range, MOUSE_SLIDER, event->button); + + return TRUE; } + return FALSE; } -static gint -gtk_range_button_press (GtkWidget *widget, - GdkEventButton *event) +/* During a slide, move the slider as required given new mouse position */ +static void +update_slider_position (GtkRange *range, + gint mouse_x, + gint mouse_y) { - GtkRange *range; - gint trough_part; - gdouble jump_perc; - - g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - if (!GTK_WIDGET_HAS_FOCUS (widget)) - gtk_widget_grab_focus (widget); - - jump_perc = -1; - range = GTK_RANGE (widget); - if (range->button == 0) - { - gtk_grab_add (widget); + gint delta; + gint c; + gdouble new_value; + + if (range->orientation == GTK_ORIENTATION_VERTICAL) + delta = mouse_y - range->slide_initial_coordinate; + else + delta = mouse_x - range->slide_initial_coordinate; - range->button = event->button; - range->x_click_point = event->x; - range->y_click_point = event->y; + c = range->slide_initial_slider_position + delta; - if (event->window == range->trough) - { - range->click_child = RANGE_CLASS (range)->trough; - - if (range->button == 2) - trough_part = _gtk_range_trough_click (range, event->x, event->y, &jump_perc); - else - trough_part = _gtk_range_trough_click (range, event->x, event->y, NULL); - - range->scroll_type = GTK_SCROLL_NONE; - if (trough_part == GTK_TROUGH_START) - range->scroll_type = GTK_SCROLL_PAGE_BACKWARD; - else if (trough_part == GTK_TROUGH_END) - range->scroll_type = GTK_SCROLL_PAGE_FORWARD; - else if (trough_part == GTK_TROUGH_JUMP && - jump_perc >= 0 && jump_perc <= 1) - range->scroll_type = GTK_SCROLL_JUMP; - - if (range->scroll_type != GTK_SCROLL_NONE) - { - gtk_range_scroll (range, jump_perc); - gtk_range_add_timer (range); - } - } - else if (event->window == range->slider) - { - range->click_child = RANGE_CLASS (range)->slider; - range->scroll_type = GTK_SCROLL_NONE; - } - else if (event->window == range->step_forw || - event->window == range->step_back) - { - gboolean back = (event->window == range->step_back); - - if (range->button == 3) - { - range->scroll_type = GTK_SCROLL_JUMP; - gtk_range_scroll (range, back ? 0.0 : 1.0); - } - else - { - range->click_child = - back ? RANGE_CLASS (range)->step_back - : RANGE_CLASS (range)->step_forw; - - if (range->button == 2) - range->scroll_type = - back ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_PAGE_FORWARD; - else - range->scroll_type = - back ? GTK_SCROLL_STEP_BACKWARD : GTK_SCROLL_STEP_FORWARD; - - gtk_range_scroll (range, -1); - gtk_range_add_timer (range); - - if (back) - _gtk_range_draw_step_back (range); - else - _gtk_range_draw_step_forw (range); - } - } - } - - return TRUE; + new_value = coord_to_value (range, c); + + gtk_range_internal_set_value (range, new_value); } static gint @@ -1058,49 +990,45 @@ gtk_range_button_release (GtkWidget *widget, range = GTK_RANGE (widget); - if (range->button == event->button) + range->layout->mouse_x = event->x; + range->layout->mouse_y = event->y; + + if (range->layout->grab_button == event->button) { - gtk_grab_remove (widget); + GtkScrollType scroll; + MouseLocation grab_location; - range->button = 0; - range->x_click_point = -1; - range->y_click_point = -1; + grab_location = range->layout->grab_location; - if (range->click_child == RANGE_CLASS (range)->slider) - { - if (range->policy == GTK_UPDATE_DELAYED) - gtk_range_remove_timer (range); + scroll = range_get_scroll_for_grab (range); + + range_grab_remove (range); + gtk_range_remove_step_timer (range); + + /* We only do the move if we're still on top of the button at + * release + */ + if (grab_location == range->layout->mouse_location && + scroll != GTK_SCROLL_NONE) + { + gtk_range_scroll (range, scroll); + } - if ((range->policy != GTK_UPDATE_CONTINUOUS) && - (range->old_value != range->adjustment->value)) - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } - else if ((range->click_child == RANGE_CLASS (range)->trough) || - (range->click_child == RANGE_CLASS (range)->step_forw) || - (range->click_child == RANGE_CLASS (range)->step_back)) - { - gtk_range_remove_timer (range); - - if ((range->policy != GTK_UPDATE_CONTINUOUS) && - (range->old_value != range->adjustment->value)) - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - - if (range->click_child == RANGE_CLASS (range)->step_forw) - { - range->click_child = 0; - _gtk_range_draw_step_forw (range); - } - else if (range->click_child == RANGE_CLASS (range)->step_back) - { - range->click_child = 0; - _gtk_range_draw_step_back (range); - } - } + if (grab_location == MOUSE_SLIDER) + update_slider_position (range, event->x, event->y); - range->click_child = 0; + /* Flush any pending discontinuous/delayed updates */ + gtk_range_update_value (range); + + /* Just be lazy about this, if we scrolled it will all redraw anyway, + * so no point optimizing the button deactivate case + */ + gtk_widget_queue_draw (widget); + + return TRUE; } - return TRUE; + return FALSE; } static gint @@ -1117,11 +1045,19 @@ gtk_range_scroll_event (GtkWidget *widget, if (GTK_WIDGET_REALIZED (range)) { GtkAdjustment *adj = GTK_RANGE (range)->adjustment; - gdouble new_value = adj->value + ((event->direction == GDK_SCROLL_UP) ? + gdouble new_value = adj->value + ((event->direction == GDK_SCROLL_UP || + event->direction == GDK_SCROLL_RIGHT) ? -adj->page_increment / 2: adj->page_increment / 2); - new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size); - gtk_adjustment_set_value (adj, new_value); + + gtk_range_internal_set_value (range, new_value); + + /* Policy DELAYED makes sense with scroll events, + * but DISCONTINUOUS doesn't, so we update immediately + * for DISCONTINOUS + */ + if (range->update_policy == GTK_UPDATE_DISCONTINUOUS) + gtk_range_update_value (range); } return TRUE; @@ -1132,120 +1068,26 @@ gtk_range_motion_notify (GtkWidget *widget, GdkEventMotion *event) { GtkRange *range; + gint x, y; g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); range = GTK_RANGE (widget); - if (range->click_child == RANGE_CLASS (range)->slider) - { - GdkModifierType mods; - gint x, y, mask, x2, y2; - - gdk_window_get_pointer (range->trough, &x, &y, &mods); - gdk_window_get_position (range->slider, &x2, &y2); - - x -= x2; - y -= y2; - - switch (range->button) - { - case 1: - mask = GDK_BUTTON1_MASK; - break; - case 2: - mask = GDK_BUTTON2_MASK; - break; - case 3: - mask = GDK_BUTTON3_MASK; - break; - default: - mask = 0; - break; - } - - if (mods & mask) - { - if (RANGE_CLASS (range)->motion) - (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point); - } - } + gdk_window_get_pointer (widget->window, &x, &y, NULL); + + range->layout->mouse_x = x; + range->layout->mouse_y = y; - return TRUE; -} + if (gtk_range_update_mouse_location (range)) + gtk_widget_queue_draw (widget); -static void -gtk_range_move_slider (GtkRange *range, - GtkScrollType scroll, - GtkTroughType pos) -{ - if (scroll != GTK_SCROLL_NONE) - { - range->scroll_type = scroll; + if (range->layout->grab_location == MOUSE_SLIDER) + update_slider_position (range, event->x, event->y); - gtk_range_scroll (range, -1); - if (range->old_value != range->adjustment->value) - { - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - switch (range->scroll_type) - { - case GTK_SCROLL_STEP_LEFT: - if (should_invert (range, TRUE)) - _gtk_range_draw_step_forw (range); - else - _gtk_range_draw_step_back (range); - break; - - case GTK_SCROLL_STEP_UP: - if (should_invert (range, FALSE)) - _gtk_range_draw_step_forw (range); - else - _gtk_range_draw_step_back (range); - break; - - case GTK_SCROLL_STEP_RIGHT: - if (should_invert (range, TRUE)) - _gtk_range_draw_step_back (range); - else - _gtk_range_draw_step_forw (range); - break; - - case GTK_SCROLL_STEP_DOWN: - if (should_invert (range, FALSE)) - _gtk_range_draw_step_back (range); - else - _gtk_range_draw_step_forw (range); - break; - - case GTK_SCROLL_STEP_BACKWARD: - _gtk_range_draw_step_back (range); - break; - - case GTK_SCROLL_STEP_FORWARD: - _gtk_range_draw_step_forw (range); - break; - } - } - } - - if (pos != GTK_TROUGH_NONE) - { - if (pos == GTK_TROUGH_START) - range->adjustment->value = range->adjustment->lower; - else if (pos == GTK_TROUGH_END) - range->adjustment->value = - range->adjustment->upper - range->adjustment->page_size; - - if (range->old_value != range->adjustment->value) - { - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), - "value_changed"); - - _gtk_range_slider_update (range); - _gtk_range_clear_background (range); - } - } + /* We handled the event if the mouse was in the range_rect */ + return range->layout->mouse_location != MOUSE_OUTSIDE; } static gint @@ -1259,35 +1101,12 @@ gtk_range_enter_notify (GtkWidget *widget, range = GTK_RANGE (widget); - if (event->window == range->trough) - { - range->in_child = RANGE_CLASS (range)->trough; - } - else if (event->window == range->slider) - { - range->in_child = RANGE_CLASS (range)->slider; - - if ((range->click_child == 0) || - (range->click_child == RANGE_CLASS (range)->trough)) - _gtk_range_draw_slider (range); - } - else if (event->window == range->step_forw) - { - range->in_child = RANGE_CLASS (range)->step_forw; - - if ((range->click_child == 0) || - (range->click_child == RANGE_CLASS (range)->trough)) - _gtk_range_draw_step_forw (range); - } - else if (event->window == range->step_back) - { - range->in_child = RANGE_CLASS (range)->step_back; - - if ((range->click_child == 0) || - (range->click_child == RANGE_CLASS (range)->trough)) - _gtk_range_draw_step_back (range); - } + range->layout->mouse_x = event->x; + range->layout->mouse_y = event->y; + if (gtk_range_update_mouse_location (range)) + gtk_widget_queue_draw (widget); + return TRUE; } @@ -1302,554 +1121,955 @@ gtk_range_leave_notify (GtkWidget *widget, range = GTK_RANGE (widget); - range->in_child = 0; - - if (event->window == range->trough) - { - } - else if (event->window == range->slider) - { - if ((range->click_child == 0) || - (range->click_child == RANGE_CLASS (range)->trough)) - _gtk_range_draw_slider (range); - } - else if (event->window == range->step_forw) - { - if ((range->click_child == 0) || - (range->click_child == RANGE_CLASS (range)->trough)) - _gtk_range_draw_step_forw (range); - } - else if (event->window == range->step_back) - { - if ((range->click_child == 0) || - (range->click_child == RANGE_CLASS (range)->trough)) - _gtk_range_draw_step_back (range); - } + range->layout->mouse_x = -1; + range->layout->mouse_y = -1; + if (gtk_range_update_mouse_location (range)) + gtk_widget_queue_draw (widget); + return TRUE; } static void -gtk_real_range_draw_trough (GtkRange *range) +gtk_range_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) { - g_return_if_fail (GTK_IS_RANGE (range)); + GtkRange *range; - if (range->trough) - { - gtk_paint_box (GTK_WIDGET (range)->style, range->trough, - GTK_STATE_ACTIVE, GTK_SHADOW_IN, - NULL, GTK_WIDGET(range), "trough", - 0, 0, -1, -1); - if (GTK_WIDGET_HAS_FOCUS (range)) - gtk_paint_focus (GTK_WIDGET (range)->style, - range->trough, - NULL, GTK_WIDGET(range), "trough", - 0, 0, -1, -1); - } + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + range = GTK_RANGE (data); + + range->need_recalc = TRUE; + gtk_widget_queue_draw (GTK_WIDGET (range)); + + /* Note that we don't round off to range->round_digits here. + * that's because it's really broken to change a value + * in response to a change signal on that value; round_digits + * is therefore defined to be a filter on what the GtkRange + * can input into the adjustment, not a filter that the GtkRange + * will enforce on the adjustment. + */ } static void -gtk_real_range_draw_slider (GtkRange *range) +gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) { - GtkStateType state_type; - - g_return_if_fail (GTK_IS_RANGE (range)); - - if (range->slider) - { - if ((range->in_child == RANGE_CLASS (range)->slider) || - (range->click_child == RANGE_CLASS (range)->slider)) - state_type = GTK_STATE_PRELIGHT; - else - state_type = GTK_STATE_NORMAL; - gtk_paint_box (GTK_WIDGET (range)->style, range->slider, - state_type, GTK_SHADOW_OUT, - NULL, GTK_WIDGET (range), "slider", - 0, 0, -1, -1); - } + GtkRange *range; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + range = GTK_RANGE (data); + + range->need_recalc = TRUE; + gtk_widget_queue_draw (GTK_WIDGET (range)); + + /* Note that we don't round off to range->round_digits here. + * that's because it's really broken to change a value + * in response to a change signal on that value; round_digits + * is therefore defined to be a filter on what the GtkRange + * can input into the adjustment, not a filter that the GtkRange + * will enforce on the adjustment. + */ } -static gint -gtk_real_range_timer (GtkRange *range) +static void +gtk_range_style_set (GtkWidget *widget, + GtkStyle *previous_style) { - gint return_val; + GtkRange *range; - GDK_THREADS_ENTER (); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); - return_val = TRUE; - if (range->click_child == RANGE_CLASS (range)->slider) - { - if (range->policy == GTK_UPDATE_DELAYED) - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - return_val = FALSE; - } - else - { - GdkModifierType mods, mask; + range = GTK_RANGE (widget); - if (!range->timer) - { - return_val = FALSE; - if (range->need_timer) - range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH, - (GtkFunction) RANGE_CLASS (range)->timer, - (gpointer) range); - else - { - GDK_THREADS_LEAVE (); - return FALSE; - } - range->need_timer = FALSE; - } + range->need_recalc = TRUE; - switch (range->button) - { - case 1: - mask = GDK_BUTTON1_MASK; - break; - case 2: - mask = GDK_BUTTON2_MASK; - break; - case 3: - mask = GDK_BUTTON3_MASK; - break; - default: - mask = 0; - break; - } + (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style); +} - gdk_window_get_pointer (range->slider, NULL, NULL, &mods); +static void +step_back (GtkRange *range) +{ + gdouble newval; + + newval = range->adjustment->value - range->adjustment->step_increment; + gtk_range_internal_set_value (range, newval); +} - if (mods & mask) - return_val = gtk_range_scroll (range, -1); - } +static void +step_forward (GtkRange *range) +{ + gdouble newval; - GDK_THREADS_LEAVE (); + newval = range->adjustment->value + range->adjustment->step_increment; - return return_val; + gtk_range_internal_set_value (range, newval); } -static gint -gtk_range_scroll (GtkRange *range, - gdouble jump_perc) + +static void +page_back (GtkRange *range) { - gdouble new_value; - gint return_val; - GtkScrollType scroll_type; - - g_return_val_if_fail (GTK_IS_RANGE (range), FALSE); + gdouble newval; - new_value = range->adjustment->value; - return_val = TRUE; + newval = range->adjustment->value - range->adjustment->page_increment; + gtk_range_internal_set_value (range, newval); +} - /* Translate visual to logical */ +static void +page_forward (GtkRange *range) +{ + gdouble newval; + + newval = range->adjustment->value + range->adjustment->page_increment; - scroll_type = range->scroll_type; - switch (scroll_type) + gtk_range_internal_set_value (range, newval); +} + +static void +gtk_range_scroll (GtkRange *range, + GtkScrollType scroll) +{ + switch (scroll) { - case GTK_SCROLL_STEP_UP: - if (should_invert (range, FALSE)) - scroll_type = GTK_SCROLL_STEP_FORWARD; + case GTK_SCROLL_STEP_LEFT: + if (should_invert (range)) + step_forward (range); else - scroll_type = GTK_SCROLL_STEP_BACKWARD; + step_back (range); break; - - case GTK_SCROLL_STEP_DOWN: - if (should_invert (range, FALSE)) - scroll_type = GTK_SCROLL_STEP_BACKWARD; + + case GTK_SCROLL_STEP_UP: + if (should_invert (range)) + step_forward (range); else - scroll_type = GTK_SCROLL_STEP_FORWARD; + step_back (range); break; - case GTK_SCROLL_PAGE_UP: - if (should_invert (range, FALSE)) - scroll_type = GTK_SCROLL_PAGE_FORWARD; + case GTK_SCROLL_STEP_RIGHT: + if (should_invert (range)) + step_back (range); else - scroll_type = GTK_SCROLL_PAGE_BACKWARD; + step_forward (range); break; - - case GTK_SCROLL_PAGE_DOWN: - if (should_invert (range, FALSE)) - scroll_type = GTK_SCROLL_PAGE_BACKWARD; + + case GTK_SCROLL_STEP_DOWN: + if (should_invert (range)) + step_back (range); else - scroll_type = GTK_SCROLL_PAGE_FORWARD; + step_forward (range); break; - - case GTK_SCROLL_STEP_LEFT: - if (should_invert (range, TRUE)) - scroll_type = GTK_SCROLL_STEP_FORWARD; - else - scroll_type = GTK_SCROLL_STEP_BACKWARD; + + case GTK_SCROLL_STEP_BACKWARD: + step_back (range); break; - - case GTK_SCROLL_STEP_RIGHT: - if (should_invert (range, TRUE)) - scroll_type = GTK_SCROLL_STEP_BACKWARD; - else - scroll_type = GTK_SCROLL_STEP_FORWARD; + + case GTK_SCROLL_STEP_FORWARD: + step_forward (range); break; case GTK_SCROLL_PAGE_LEFT: - if (should_invert (range, TRUE)) - scroll_type = GTK_SCROLL_PAGE_FORWARD; + if (should_invert (range)) + page_forward (range); else - scroll_type = GTK_SCROLL_PAGE_BACKWARD; + page_back (range); break; - - case GTK_SCROLL_PAGE_RIGHT: - if (should_invert (range, TRUE)) - scroll_type = GTK_SCROLL_PAGE_BACKWARD; + + case GTK_SCROLL_PAGE_UP: + if (should_invert (range)) + page_forward (range); else - scroll_type = GTK_SCROLL_PAGE_FORWARD; + page_back (range); break; - default: + case GTK_SCROLL_PAGE_RIGHT: + if (should_invert (range)) + page_back (range); + else + page_forward (range); break; - } - - switch (scroll_type) - { - case GTK_SCROLL_NONE: + + case GTK_SCROLL_PAGE_DOWN: + if (should_invert (range)) + page_back (range); + else + page_forward (range); break; - - case GTK_SCROLL_JUMP: - if (jump_perc >= 0 && jump_perc <= 1) - { - new_value = (range->adjustment->lower + - (range->adjustment->upper - range->adjustment->page_size - - range->adjustment->lower) * jump_perc); - } + + case GTK_SCROLL_PAGE_BACKWARD: + page_back (range); break; - - case GTK_SCROLL_STEP_BACKWARD: - new_value -= range->adjustment->step_increment; - if (new_value <= range->adjustment->lower) - { - new_value = range->adjustment->lower; - return_val = FALSE; - range->timer = 0; - } + + case GTK_SCROLL_PAGE_FORWARD: + page_forward (range); break; - case GTK_SCROLL_STEP_FORWARD: - new_value += range->adjustment->step_increment; - if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) - { - new_value = range->adjustment->upper - range->adjustment->page_size; - return_val = FALSE; - range->timer = 0; - } + case GTK_SCROLL_START: + gtk_range_internal_set_value (range, + range->adjustment->lower); break; - case GTK_SCROLL_PAGE_BACKWARD: - new_value -= range->adjustment->page_increment; - if (new_value <= range->adjustment->lower) - { - new_value = range->adjustment->lower; - return_val = FALSE; - range->timer = 0; - } + case GTK_SCROLL_END: + gtk_range_internal_set_value (range, + range->adjustment->upper - range->adjustment->page_size); break; - case GTK_SCROLL_PAGE_FORWARD: - new_value += range->adjustment->page_increment; - if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) - { - new_value = range->adjustment->upper - range->adjustment->page_size; - return_val = FALSE; - range->timer = 0; - } + case GTK_SCROLL_JUMP: + /* Used by CList, range doesn't use it. */ break; - case GTK_SCROLL_STEP_UP: - case GTK_SCROLL_STEP_DOWN: - case GTK_SCROLL_PAGE_UP: - case GTK_SCROLL_PAGE_DOWN: - case GTK_SCROLL_STEP_LEFT: - case GTK_SCROLL_STEP_RIGHT: - case GTK_SCROLL_PAGE_LEFT: - case GTK_SCROLL_PAGE_RIGHT: - g_assert_not_reached (); + case GTK_SCROLL_NONE: break; - } +} + +static void +gtk_range_move_slider (GtkRange *range, + GtkScrollType scroll) +{ + gtk_range_scroll (range, scroll); + + /* Policy DELAYED makes sense with key events, + * but DISCONTINUOUS doesn't, so we update immediately + * for DISCONTINOUS + */ + if (range->update_policy == GTK_UPDATE_DISCONTINUOUS) + gtk_range_update_value (range); +} + +static void +gtk_range_get_props (GtkRange *range, + gint *slider_width, + gint *stepper_size, + gint *trough_border, + gint *stepper_spacing) +{ + GtkWidget *widget = GTK_WIDGET (range); + gint tmp_slider_width, tmp_stepper_size, tmp_trough_border, tmp_stepper_spacing; - if (new_value != range->adjustment->value) - { - range->adjustment->value = new_value; + gtk_widget_style_get (widget, + "slider_width", &tmp_slider_width, + "trough_border", &tmp_trough_border, + "stepper_size", &tmp_stepper_size, + "stepper_spacing", &tmp_stepper_spacing, + NULL); + + if (slider_width) + *slider_width = tmp_slider_width; - if ((range->policy == GTK_UPDATE_CONTINUOUS) || - (!return_val && (range->policy == GTK_UPDATE_DELAYED))) - { - gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); - } - else - { - _gtk_range_slider_update (range); - _gtk_range_clear_background (range); - } - } + if (trough_border) + *trough_border = tmp_trough_border; + + if (stepper_size) + *stepper_size = tmp_stepper_size; - return return_val; + if (stepper_spacing) + *stepper_spacing = tmp_stepper_spacing; } +#define POINT_IN_RECT(xcoord, ycoord, rect) \ + ((xcoord) >= (rect).x && \ + (xcoord) < ((rect).x + (rect).width) && \ + (ycoord) >= (rect).y && \ + (ycoord) < ((rect).y + (rect).height)) +/* Update mouse location, return TRUE if it changes */ static gboolean -gtk_range_timer_1st_time (GtkRange *range) +gtk_range_update_mouse_location (GtkRange *range) { - /* - * If the real timeout function succeeds and the timeout is still set, - * replace it with a quicker one so successive scrolling goes faster. - */ - gtk_object_ref (GTK_OBJECT (range)); + gint x, y; + MouseLocation old; + GtkWidget *widget; - if (RANGE_CLASS (range)->timer (range)) - { - if (range->timer) - { - /* We explicitely remove ourselves here in the paranoia - * that due to things happening above in the callback - * above, we might have been removed, and another added. - */ - g_source_remove (range->timer); - range->timer = gtk_timeout_add (SCROLL_LATER_DELAY, - (GtkFunction) RANGE_CLASS (range)->timer, - range); - } - } + widget = GTK_WIDGET (range); - gtk_object_unref (GTK_OBJECT (range)); + old = range->layout->mouse_location; - return FALSE; /* don't keep calling this function */ + x = range->layout->mouse_x; + y = range->layout->mouse_y; + + if (range->layout->grab_location != MOUSE_OUTSIDE) + range->layout->mouse_location = range->layout->grab_location; + else if (POINT_IN_RECT (x, y, range->layout->stepper_a)) + range->layout->mouse_location = MOUSE_STEPPER_A; + else if (POINT_IN_RECT (x, y, range->layout->stepper_b)) + range->layout->mouse_location = MOUSE_STEPPER_B; + else if (POINT_IN_RECT (x, y, range->layout->stepper_c)) + range->layout->mouse_location = MOUSE_STEPPER_C; + else if (POINT_IN_RECT (x, y, range->layout->stepper_d)) + range->layout->mouse_location = MOUSE_STEPPER_D; + else if (POINT_IN_RECT (x, y, range->layout->slider)) + range->layout->mouse_location = MOUSE_SLIDER; + else if (POINT_IN_RECT (x, y, range->layout->trough)) + range->layout->mouse_location = MOUSE_TROUGH; + else if (POINT_IN_RECT (x, y, widget->allocation)) + range->layout->mouse_location = MOUSE_WIDGET; + else + range->layout->mouse_location = MOUSE_OUTSIDE; + + return old != range->layout->mouse_location; } +/* Clamp rect, border inside widget->allocation, such that we prefer + * to take space from border not rect in all directions, and prefer to + * give space to border over rect in one direction. + */ static void -gtk_range_add_timer (GtkRange *range) +clamp_dimensions (GtkWidget *widget, + GdkRectangle *rect, + GtkBorder *border, + gboolean border_expands_horizontally) { - g_return_if_fail (GTK_IS_RANGE (range)); + gint extra, shortage; + + g_return_if_fail (rect->x == 0); + g_return_if_fail (rect->y == 0); + g_return_if_fail (rect->width >= 0); + g_return_if_fail (rect->height >= 0); + + /* Width */ + + extra = widget->allocation.width - border->left - border->right - rect->width; + if (extra > 0) + { + if (border_expands_horizontally) + { + border->left += extra / 2; + border->right += extra / 2 + extra % 2; + } + else + { + rect->width += extra; + } + } + + /* See if we can fit rect, if not kill the border */ + shortage = rect->width - widget->allocation.width; + if (shortage > 0) + { + rect->width = widget->allocation.width; + /* lose the border */ + border->left = 0; + border->right = 0; + } + else + { + /* See if we can fit rect with borders */ + shortage = rect->width + border->left + border->right - + widget->allocation.width; + if (shortage > 0) + { + /* Shrink borders */ + border->left -= shortage / 2; + border->right -= shortage / 2 + shortage % 2; + } + } - if (!range->timer) + /* Height */ + + extra = widget->allocation.height - border->top - border->bottom - rect->height; + if (extra > 0) { - range->need_timer = TRUE; - range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY, - (GtkFunction) gtk_range_timer_1st_time, - range); + if (border_expands_horizontally) + { + /* don't expand border vertically */ + rect->height += extra; + } + else + { + border->top += extra / 2; + border->bottom += extra / 2 + extra % 2; + } + } + + /* See if we can fit rect, if not kill the border */ + shortage = rect->height - widget->allocation.height; + if (shortage > 0) + { + rect->height = widget->allocation.height; + /* lose the border */ + border->top = 0; + border->bottom = 0; + } + else + { + /* See if we can fit rect with borders */ + shortage = rect->height + border->top + border->bottom - + widget->allocation.height; + if (shortage > 0) + { + /* Shrink borders */ + border->top -= shortage / 2; + border->bottom -= shortage / 2 + shortage % 2; + } } } static void -gtk_range_remove_timer (GtkRange *range) +gtk_range_calc_request (GtkRange *range, + gint slider_width, + gint stepper_size, + gint trough_border, + gint stepper_spacing, + GdkRectangle *range_rect, + GtkBorder *border, + gint *n_steppers_p, + gint *slider_length_p) { - g_return_if_fail (GTK_IS_RANGE (range)); + gint slider_length; + gint n_steppers; + + border->left = 0; + border->right = 0; + border->top = 0; + border->bottom = 0; - if (range->timer) + if (GTK_RANGE_GET_CLASS (range)->get_range_border) + (* GTK_RANGE_GET_CLASS (range)->get_range_border) (range, border); + + n_steppers = 0; + if (range->has_stepper_a) + n_steppers += 1; + if (range->has_stepper_b) + n_steppers += 1; + if (range->has_stepper_c) + n_steppers += 1; + if (range->has_stepper_d) + n_steppers += 1; + + slider_length = range->min_slider_size; + + range_rect->x = 0; + range_rect->y = 0; + + /* We never expand to fill available space in the small dimension + * (i.e. vertical scrollbars are always a fixed width) + */ + if (range->orientation == GTK_ORIENTATION_VERTICAL) { - gtk_timeout_remove (range->timer); - range->timer = 0; + range_rect->width = trough_border * 2 + slider_width; + range_rect->height = stepper_size * n_steppers + stepper_spacing * 2 + trough_border * 2 + slider_length; } - range->need_timer = FALSE; + else + { + range_rect->width = stepper_size * n_steppers + stepper_spacing * 2 + trough_border * 2 + slider_length; + range_rect->height = trough_border * 2 + slider_width; + } + + if (n_steppers_p) + *n_steppers_p = n_steppers; + + if (slider_length_p) + *slider_length_p = slider_length; } static void -gtk_range_adjustment_changed (GtkAdjustment *adjustment, - gpointer data) +gtk_range_calc_layout (GtkRange *range) { - GtkRange *range; + gint slider_width, stepper_size, trough_border, stepper_spacing; + gint slider_length; + GtkBorder border; + gint n_steppers; + GdkRectangle range_rect; + GtkRangeLayout *layout; + GtkWidget *widget; + + if (!range->need_recalc) + return; - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); + /* If we have a too-small allocation, we prefer the steppers over + * the trough/slider, probably the steppers are a more useful + * feature in small spaces. + * + * Also, we prefer to draw the range itself rather than the border + * areas if there's a conflict, since the borders will be decoration + * not controls. Though this depends on subclasses cooperating by + * not drawing on range->range_rect. + */ - range = GTK_RANGE (data); + widget = GTK_WIDGET (range); + layout = range->layout; + + gtk_range_get_props (range, + &slider_width, &stepper_size, &trough_border, &stepper_spacing); - if (((range->old_lower != adjustment->lower) || - (range->old_upper != adjustment->upper) || - (range->old_page_size != adjustment->page_size)) && - (range->old_value == adjustment->value)) + gtk_range_calc_request (range, + slider_width, stepper_size, trough_border, stepper_spacing, + &range_rect, &border, &n_steppers, &slider_length); + + /* We never expand to fill available space in the small dimension + * (i.e. vertical scrollbars are always a fixed width) + */ + if (range->orientation == GTK_ORIENTATION_VERTICAL) { - if ((adjustment->lower == adjustment->upper) || - (range->old_lower == (range->old_upper - range->old_page_size))) - { - adjustment->value = adjustment->lower; - gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed"); - } + clamp_dimensions (widget, &range_rect, &border, TRUE); } - - if ((range->old_value != adjustment->value) || - (range->old_lower != adjustment->lower) || - (range->old_upper != adjustment->upper) || - (range->old_page_size != adjustment->page_size)) + else { - _gtk_range_slider_update (range); - _gtk_range_clear_background (range); - - range->old_value = adjustment->value; - range->old_lower = adjustment->lower; - range->old_upper = adjustment->upper; - range->old_page_size = adjustment->page_size; + clamp_dimensions (widget, &range_rect, &border, FALSE); } -} + + range_rect.x = border.left; + range_rect.y = border.top; + + range->range_rect = range_rect; + + if (range->orientation == GTK_ORIENTATION_VERTICAL) + { + gint stepper_width, stepper_height; -static void -gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, - gpointer data) -{ - GtkRange *range; + /* Steppers are the width of the range, and stepper_size in + * height, or if we don't have enough height, divided equally + * among available space. + */ + stepper_width = range_rect.width - trough_border * 2; - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); + if (stepper_width < 1) + stepper_width = range_rect.width; /* screw the trough border */ - range = GTK_RANGE (data); + if (n_steppers == 0) + stepper_height = 0; /* avoid divide by n_steppers */ + else + stepper_height = MIN (stepper_size, (range_rect.height / n_steppers)); - if (range->old_value != adjustment->value) - { - _gtk_range_slider_update (range); - _gtk_range_clear_background (range); + /* Stepper A */ + + layout->stepper_a.x = range_rect.x + trough_border; + layout->stepper_a.y = range_rect.y + trough_border; - range->old_value = adjustment->value; - } -} + if (range->has_stepper_a) + { + layout->stepper_a.width = stepper_width; + layout->stepper_a.height = stepper_height; + } + else + { + layout->stepper_a.width = 0; + layout->stepper_a.height = 0; + } + /* Stepper B */ + + layout->stepper_b.x = layout->stepper_a.x; + layout->stepper_b.y = layout->stepper_a.y + layout->stepper_a.height; -static void -gtk_range_trough_hdims (GtkRange *range, - gint *left, - gint *right) -{ - gint trough_width; - gint slider_length; - gint tmp_width; - gint tleft; - gint tright; - gint stepper_spacing; - gint trough_border; + if (range->has_stepper_b) + { + layout->stepper_b.width = stepper_width; + layout->stepper_b.height = stepper_height; + } + else + { + layout->stepper_b.width = 0; + layout->stepper_b.height = 0; + } - g_return_if_fail (range != NULL); + /* Stepper D */ - gdk_window_get_size (range->trough, &trough_width, NULL); - gdk_window_get_size (range->slider, &slider_length, NULL); + if (range->has_stepper_d) + { + layout->stepper_d.width = stepper_width; + layout->stepper_d.height = stepper_height; + } + else + { + layout->stepper_d.width = 0; + layout->stepper_d.height = 0; + } + + layout->stepper_d.x = layout->stepper_a.x; + layout->stepper_d.y = range_rect.y + range_rect.height - layout->stepper_d.height - trough_border; - _gtk_range_get_props (range, NULL, &trough_border, NULL, &stepper_spacing); - - tleft = trough_border; - tright = trough_width - slider_length - trough_border; + /* Stepper C */ - if (range->step_back) + if (range->has_stepper_c) + { + layout->stepper_c.width = stepper_width; + layout->stepper_c.height = stepper_height; + } + else + { + layout->stepper_c.width = 0; + layout->stepper_c.height = 0; + } + + layout->stepper_c.x = layout->stepper_a.x; + layout->stepper_c.y = layout->stepper_d.y - layout->stepper_c.height; + + /* Now the trough is the remaining space between steppers B and C, + * if any + */ + layout->trough.x = range_rect.x; + layout->trough.y = layout->stepper_b.y + layout->stepper_b.height; + layout->trough.width = range_rect.width; + layout->trough.height = layout->stepper_c.y - (layout->stepper_b.y + layout->stepper_b.height); + + /* Slider fits into the trough, with stepper_spacing on either side, + * and the size/position based on the adjustment or fixed, depending. + */ + layout->slider.x = layout->trough.x + trough_border; + layout->slider.width = layout->trough.width - trough_border * 2; + + /* Compute slider position/length */ + { + gint y, bottom, top, height; + + top = layout->trough.y + stepper_spacing; + bottom = layout->trough.y + layout->trough.height - stepper_spacing; + + /* slider height is the fraction (page_size / + * total_adjustment_range) times the trough height in pixels + */ + height = ((bottom - top) * (range->adjustment->page_size / + (range->adjustment->upper - range->adjustment->lower))); + + if (height < range->min_slider_size || + range->slider_size_fixed) + height = range->min_slider_size; + + height = MIN (height, (layout->trough.height - stepper_spacing * 2)); + + y = top; + + y += (bottom - top - height) * ((range->adjustment->value - range->adjustment->lower) / + (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); + + y = CLAMP (y, top, bottom); + + if (should_invert (range)) + y = bottom - (y - top + height); + + layout->slider.y = y; + layout->slider.height = height; + + /* These are publically exported */ + range->slider_start = layout->slider.y; + range->slider_end = layout->slider.y + layout->slider.height; + } + } + else { - gdk_window_get_size (range->step_back, &tmp_width, NULL); - tleft += (tmp_width + stepper_spacing); + gint stepper_width, stepper_height; + + /* Steppers are the height of the range, and stepper_size in + * width, or if we don't have enough width, divided equally + * among available space. + */ + stepper_height = range_rect.height - trough_border * 2; + + if (stepper_height < 1) + stepper_height = range_rect.height; /* screw the trough border */ + + if (n_steppers == 0) + stepper_width = 0; /* avoid divide by n_steppers */ + else + stepper_width = MIN (stepper_size, (range_rect.width / n_steppers)); + + /* Stepper A */ + + layout->stepper_a.x = range_rect.x + trough_border; + layout->stepper_a.y = range_rect.y + trough_border; + + if (range->has_stepper_a) + { + layout->stepper_a.width = stepper_width; + layout->stepper_a.height = stepper_height; + } + else + { + layout->stepper_a.width = 0; + layout->stepper_a.height = 0; + } + + /* Stepper B */ + + layout->stepper_b.x = layout->stepper_a.x + layout->stepper_a.width; + layout->stepper_b.y = layout->stepper_a.y; + + if (range->has_stepper_b) + { + layout->stepper_b.width = stepper_width; + layout->stepper_b.height = stepper_height; + } + else + { + layout->stepper_b.width = 0; + layout->stepper_b.height = 0; + } + + /* Stepper D */ + + if (range->has_stepper_d) + { + layout->stepper_d.width = stepper_width; + layout->stepper_d.height = stepper_height; + } + else + { + layout->stepper_d.width = 0; + layout->stepper_d.height = 0; + } + + layout->stepper_d.x = range_rect.x + range_rect.width - layout->stepper_d.width - trough_border; + layout->stepper_d.y = layout->stepper_a.y; + + + /* Stepper C */ + + if (range->has_stepper_c) + { + layout->stepper_c.width = stepper_width; + layout->stepper_c.height = stepper_height; + } + else + { + layout->stepper_c.width = 0; + layout->stepper_c.height = 0; + } + + layout->stepper_c.x = layout->stepper_d.x - layout->stepper_c.width; + layout->stepper_c.y = layout->stepper_a.y; + + /* Now the trough is the remaining space between steppers B and C, + * if any + */ + layout->trough.x = layout->stepper_b.x + layout->stepper_b.width; + layout->trough.y = range_rect.y; + + layout->trough.width = layout->stepper_c.x - (layout->stepper_b.x + layout->stepper_b.width); + layout->trough.height = range_rect.height; + + /* Slider fits into the trough, with stepper_spacing on either side, + * and the size/position based on the adjustment or fixed, depending. + */ + layout->slider.y = layout->trough.y + trough_border; + layout->slider.height = layout->trough.height - trough_border * 2; + + /* Compute slider position/length */ + { + gint x, left, right, width; + + left = layout->trough.x + stepper_spacing; + right = layout->trough.x + layout->trough.width - stepper_spacing; + + /* slider width is the fraction (page_size / + * total_adjustment_range) times the trough width in pixels + */ + width = ((right - left) * (range->adjustment->page_size / + (range->adjustment->upper - range->adjustment->lower))); + + if (width < range->min_slider_size || + range->slider_size_fixed) + width = range->min_slider_size; + + width = MIN (width, (layout->trough.width - stepper_spacing * 2)); + + x = left; + + x += (right - left - width) * ((range->adjustment->value - range->adjustment->lower) / + (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); + + x = CLAMP (x, left, right); + + if (should_invert (range)) + x = right - (x - left + width); + + layout->slider.x = x; + layout->slider.width = width; + + /* These are publically exported */ + range->slider_start = layout->slider.x; + range->slider_end = layout->slider.x + layout->slider.width; + } } + + gtk_range_update_mouse_location (range); +} - if (range->step_forw) +static GdkRectangle* +get_area (GtkRange *range, + MouseLocation location) +{ + switch (location) { - gdk_window_get_size (range->step_forw, &tmp_width, NULL); - tright -= (tmp_width + stepper_spacing); + case MOUSE_STEPPER_A: + return &range->layout->stepper_a; + case MOUSE_STEPPER_B: + return &range->layout->stepper_b; + case MOUSE_STEPPER_C: + return &range->layout->stepper_c; + case MOUSE_STEPPER_D: + return &range->layout->stepper_d; + case MOUSE_TROUGH: + return &range->layout->trough; + case MOUSE_SLIDER: + return &range->layout->slider; + case MOUSE_WIDGET: + case MOUSE_OUTSIDE: + break; } - if (left) - *left = tleft; - if (right) - *right = tright; + g_warning (G_STRLOC": bug"); + return NULL; } static void -gtk_range_trough_vdims (GtkRange *range, - gint *top, - gint *bottom) +gtk_range_internal_set_value (GtkRange *range, + gdouble value) { - gint trough_height; - gint slider_length; - gint tmp_height; - gint ttop; - gint tbottom; - gint stepper_spacing; - gint trough_border; + value = CLAMP (value, range->adjustment->lower, + (range->adjustment->upper - range->adjustment->page_size)); - g_return_if_fail (range != NULL); - - _gtk_range_get_props (range, NULL, &trough_border, NULL, &stepper_spacing); - - gdk_window_get_size (range->trough, NULL, &trough_height); - gdk_window_get_size (range->slider, NULL, &slider_length); - - ttop = trough_border; - tbottom = trough_height - slider_length - trough_border; + if (range->round_digits >= 0) + { + char buffer[128]; - if (range->step_back) + /* This is just so darn lame. */ + g_snprintf (buffer, 128, "%0.*f", + range->round_digits, value); + sscanf (buffer, "%lf", &value); + } + + if (range->adjustment->value != value) { - gdk_window_get_size (range->step_back, NULL, &tmp_height); - ttop += (tmp_height + stepper_spacing); + range->need_recalc = TRUE; + + gtk_widget_queue_draw (GTK_WIDGET (range)); + + switch (range->update_policy) + { + case GTK_UPDATE_CONTINUOUS: + gtk_adjustment_set_value (range->adjustment, value); + break; + + /* Delayed means we update after a period of inactivity */ + case GTK_UPDATE_DELAYED: + gtk_range_reset_update_timer (range); + /* FALL THRU */ + + /* Discontinuous means we update on button release */ + case GTK_UPDATE_DISCONTINUOUS: + /* don't emit value_changed signal */ + range->adjustment->value = value; + range->update_pending = TRUE; + break; + } } +} - if (range->step_forw) +static void +gtk_range_update_value (GtkRange *range) +{ + gtk_range_remove_update_timer (range); + + if (range->update_pending) { - gdk_window_get_size (range->step_forw, NULL, &tmp_height); - tbottom -= (tmp_height + stepper_spacing); + gtk_adjustment_value_changed (range->adjustment); + + range->update_pending = FALSE; } +} + +struct _GtkRangeStepTimer +{ + guint timeout_id; + GtkScrollType step; +}; + +static gboolean +second_timeout (gpointer data) +{ + GtkRange *range; - if (top) - *top = ttop; - if (bottom) - *bottom = tbottom; + range = GTK_RANGE (data); + + gtk_range_scroll (range, range->timer->step); + + return TRUE; } -static void -gtk_range_style_set (GtkWidget *widget, - GtkStyle *previous_style) +static gboolean +initial_timeout (gpointer data) { GtkRange *range; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_RANGE (widget)); + range = GTK_RANGE (data); - range = GTK_RANGE (widget); + range->timer->timeout_id = + g_timeout_add (SCROLL_LATER_DELAY, + second_timeout, + range); - if (GTK_WIDGET_REALIZED (widget)) - { - if (range->trough) - gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + /* remove self */ + return FALSE; +} - if (range->slider) - gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); - - /* The backgrounds of the step_forw and step_back never actually - * get drawn in draw calls, so we call gdk_window_clear() here - * so they get the correct colors. This is a hack. OWT. - */ +static void +gtk_range_add_step_timer (GtkRange *range, + GtkScrollType step) +{ + g_return_if_fail (range->timer == NULL); + g_return_if_fail (step != GTK_SCROLL_NONE); + + range->timer = g_new (GtkRangeStepTimer, 1); - if (range->step_forw) - { - gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE); - gdk_window_clear (range->step_forw); - } + range->timer->timeout_id = + g_timeout_add (SCROLL_INITIAL_DELAY, + initial_timeout, + range); + range->timer->step = step; +} - if (range->step_back) - { - gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE); - gdk_window_clear (range->step_back); - } +static void +gtk_range_remove_step_timer (GtkRange *range) +{ + if (range->timer) + { + if (range->timer->timeout_id != 0) + g_source_remove (range->timer->timeout_id); + + g_free (range->timer); + + range->timer = NULL; } } -void -_gtk_range_get_props (GtkRange *range, - gint *slider_width, - gint *trough_border, - gint *stepper_size, - gint *stepper_spacing) +static gboolean +update_timeout (gpointer data) { - GtkWidget *widget = GTK_WIDGET (range); - + GtkRange *range; - if (slider_width) - gtk_widget_style_get (widget, "slider_width", slider_width, NULL); - - if (trough_border) - gtk_widget_style_get (widget, "trough_border", trough_border, NULL); + range = GTK_RANGE (data); - if (stepper_size) - gtk_widget_style_get (widget, "stepper_size", stepper_size, NULL); + gtk_range_update_value (range); - if (stepper_spacing) - gtk_widget_style_get (widget, "stepper_spacing", stepper_spacing, NULL); + range->update_timeout_id = 0; + + /* self-remove */ + return FALSE; +} + +static void +gtk_range_reset_update_timer (GtkRange *range) +{ + gtk_range_remove_update_timer (range); + + range->update_timeout_id = g_timeout_add (UPDATE_DELAY, + update_timeout, + range); } +static void +gtk_range_remove_update_timer (GtkRange *range) +{ + if (range->update_timeout_id != 0) + { + g_source_remove (range->update_timeout_id); + range->update_timeout_id = 0; + } +} diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h index 58fb89a386..6228b74e3b 100644 --- a/gtk/gtkrange.h +++ b/gtk/gtkrange.h @@ -45,6 +45,9 @@ extern "C" { #define GTK_IS_RANGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RANGE)) #define GTK_RANGE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_RANGE, GtkRangeClass)) +/* These two are private/opaque types, ignore */ +typedef struct _GtkRangeLayout GtkRangeLayout; +typedef struct _GtkRangeStepTimer GtkRangeStepTimer; typedef struct _GtkRange GtkRange; typedef struct _GtkRangeClass GtkRangeClass; @@ -53,116 +56,80 @@ struct _GtkRange { GtkWidget widget; - GdkWindow *trough; - GdkWindow *slider; - GdkWindow *step_forw; - GdkWindow *step_back; - - gint16 x_click_point; - gint16 y_click_point; - - guint8 button; - gint8 digits; - guint policy : 2; - guint scroll_type : 5; - guint in_child : 3; - guint click_child : 3; - guint need_timer : 1; - guint flippable : 1; + GtkAdjustment *adjustment; + GtkUpdateType update_policy; guint inverted : 1; + + /*< protected >*/ + + guint flippable : 1; - guint32 timer; + /* Steppers are: < > ---- < > + * a b c d + */ + + guint has_stepper_a : 1; + guint has_stepper_b : 1; + guint has_stepper_c : 1; + guint has_stepper_d : 1; + + guint need_recalc : 1; + + guint slider_size_fixed : 1; + + gint min_slider_size; - gdouble old_value; - gdouble old_lower; - gdouble old_upper; - gdouble old_page_size; + GtkOrientation orientation; - GtkAdjustment *adjustment; + /* Area of entire stepper + trough assembly in widget->window coords */ + GdkRectangle range_rect; + /* Slider range along the long dimension, in widget->window coords */ + gint slider_start, slider_end; + + /* Round off value to this many digits, -1 for no rounding */ + gint round_digits; + + /*< private >*/ + guint trough_click_forward : 1; /* trough click was on the forward side of slider */ + guint update_pending : 1; /* need to emit value_changed */ + GtkRangeLayout *layout; + GtkRangeStepTimer *timer; + gint slide_initial_slider_position; + gint slide_initial_coordinate; + guint update_timeout_id; }; struct _GtkRangeClass { GtkWidgetClass parent_class; - gint min_slider_size; - - guint8 trough; - guint8 slider; - guint8 step_forw; - guint8 step_back; + /* what detail to pass to GTK drawing functions */ + gchar *slider_detail; + gchar *stepper_detail; /* action signals for keybindings */ void (* move_slider) (GtkRange *range, - GtkScrollType scroll, - GtkTroughType trough); - - /* Completely broken virtual functions, please ignore */ - - void (* draw_background) (GtkRange *range); - void (* clear_background) (GtkRange *range); - void (* draw_trough) (GtkRange *range); - void (* draw_slider) (GtkRange *range); - void (* draw_step_forw) (GtkRange *range); - void (* draw_step_back) (GtkRange *range); - void (* slider_update) (GtkRange *range); - gboolean (* trough_click) (GtkRange *range, - gint x, - gint y, - gdouble *jump_perc); - void (* motion) (GtkRange *range, - gint xdelta, - gint ydelta); - gboolean (* timer) (GtkRange *range); + GtkScrollType scroll); + + /* Virtual functions */ + void (* get_range_border) (GtkRange *range, + GtkBorder *border); }; GtkType gtk_range_get_type (void) G_GNUC_CONST; -GtkAdjustment* gtk_range_get_adjustment (GtkRange *range); + void gtk_range_set_update_policy (GtkRange *range, GtkUpdateType policy); + void gtk_range_set_adjustment (GtkRange *range, GtkAdjustment *adjustment); +GtkAdjustment* gtk_range_get_adjustment (GtkRange *range); void gtk_range_set_inverted (GtkRange *range, gboolean setting); gboolean gtk_range_get_inverted (GtkRange *range); -void _gtk_range_draw_background (GtkRange *range); -void _gtk_range_clear_background (GtkRange *range); -void _gtk_range_draw_trough (GtkRange *range); -void _gtk_range_draw_slider (GtkRange *range); -void _gtk_range_draw_step_forw (GtkRange *range); -void _gtk_range_draw_step_back (GtkRange *range); -void _gtk_range_slider_update (GtkRange *range); -gboolean _gtk_range_trough_click (GtkRange *range, - gint x, - gint y, - gdouble *jump_perc); - -void _gtk_range_default_hslider_update (GtkRange *range); -void _gtk_range_default_vslider_update (GtkRange *range); -gboolean _gtk_range_default_htrough_click (GtkRange *range, - gint x, - gint y, - gdouble *jump_perc); -gboolean _gtk_range_default_vtrough_click (GtkRange *range, - gint x, - gint y, - gdouble *jump_perc); -void _gtk_range_default_hmotion (GtkRange *range, - gint xdelta, - gint ydelta); -void _gtk_range_default_vmotion (GtkRange *range, - gint xdelta, - gint ydelta); - -void _gtk_range_get_props (GtkRange *range, - gint *slider_width, - gint *trough_border, - gint *stepper_size, - gint *stepper_spacing); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c index de5c180bc7..f51d7d4fe1 100644 --- a/gtk/gtkscale.c +++ b/gtk/gtkscale.c @@ -1,5 +1,6 @@ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +29,8 @@ #include "gtkintl.h" #include "gtkscale.h" #include "gtkmarshal.h" +#include "gdk/gdkkeysyms.h" +#include "gtkbindings.h" enum { PROP_0, @@ -42,25 +45,22 @@ enum { }; static guint signals[LAST_SIGNAL]; - -static void gtk_scale_class_init (GtkScaleClass *klass); -static void gtk_scale_init (GtkScale *scale); -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_map (GtkWidget *widget); -static void gtk_scale_unmap (GtkWidget *widget); - -static void gtk_scale_draw_background (GtkRange *range); - - static GtkRangeClass *parent_class = NULL; +static void gtk_scale_class_init (GtkScaleClass *klass); +static void gtk_scale_init (GtkScale *scale); +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); GtkType gtk_scale_get_type (void) @@ -103,6 +103,12 @@ single_string_accumulator (GSignalInvocationHint *ihint, return continue_emission; } + +#define add_slider_binding(binding_set, keyval, mask, scroll) \ + gtk_binding_entry_add_signal (binding_set, keyval, mask, \ + "move_slider", 1, \ + GTK_TYPE_SCROLL_TYPE, scroll) + static void gtk_scale_class_init (GtkScaleClass *class) { @@ -110,7 +116,8 @@ gtk_scale_class_init (GtkScaleClass *class) GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkRangeClass *range_class; - + GtkBindingSet *binding_set; + gobject_class = G_OBJECT_CLASS (class); object_class = (GtkObjectClass*) class; range_class = (GtkRangeClass*) class; @@ -121,11 +128,10 @@ gtk_scale_class_init (GtkScaleClass *class) gobject_class->set_property = gtk_scale_set_property; gobject_class->get_property = gtk_scale_get_property; - widget_class->map = gtk_scale_map; - widget_class->unmap = gtk_scale_unmap; - - range_class->draw_background = gtk_scale_draw_background; + widget_class->style_set = gtk_scale_style_set; + range_class->get_range_border = gtk_scale_get_range_border; + signals[FORMAT_VALUE] = g_signal_newc ("format_value", G_TYPE_FROM_CLASS (object_class), @@ -171,8 +177,99 @@ gtk_scale_class_init (GtkScaleClass *class) G_MAXINT, 31, G_PARAM_READABLE)); - class->value_spacing = 2; - class->draw_value = NULL; + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("value_spacing", + _("Value spacing"), + _("Space between value text and the slider/trough area"), + 0, + G_MAXINT, + 2, + G_PARAM_READABLE)); + + /* All bindings (even arrow keys) are on both h/v scale, because + * blind users etc. don't care about scale orientation. + */ + + binding_set = gtk_binding_set_by_class (class); + + add_slider_binding (binding_set, GDK_Left, 0, + GTK_SCROLL_STEP_LEFT); + + add_slider_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_LEFT); + + add_slider_binding (binding_set, GDK_KP_Left, 0, + GTK_SCROLL_STEP_LEFT); + + add_slider_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_LEFT); + + + add_slider_binding (binding_set, GDK_Right, 0, + GTK_SCROLL_STEP_RIGHT); + + add_slider_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_RIGHT); + + add_slider_binding (binding_set, GDK_KP_Right, 0, + GTK_SCROLL_STEP_RIGHT); + + add_slider_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_RIGHT); + + add_slider_binding (binding_set, GDK_Up, 0, + GTK_SCROLL_STEP_UP); + + add_slider_binding (binding_set, GDK_Up, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_UP); + + add_slider_binding (binding_set, GDK_KP_Up, 0, + GTK_SCROLL_STEP_UP); + + add_slider_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_UP); + + + add_slider_binding (binding_set, GDK_Down, 0, + GTK_SCROLL_STEP_DOWN); + + add_slider_binding (binding_set, GDK_Down, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_DOWN); + + add_slider_binding (binding_set, GDK_KP_Down, 0, + GTK_SCROLL_STEP_DOWN); + + add_slider_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK, + GTK_SCROLL_PAGE_DOWN); + + /* I think most users will find it strange that these move + * logically instead of visually... + */ + + add_slider_binding (binding_set, GDK_Page_Up, 0, + GTK_SCROLL_PAGE_BACKWARD); + + add_slider_binding (binding_set, GDK_KP_Page_Up, 0, + GTK_SCROLL_PAGE_BACKWARD); + + add_slider_binding (binding_set, GDK_Page_Down, 0, + GTK_SCROLL_PAGE_FORWARD); + + add_slider_binding (binding_set, GDK_KP_Page_Down, 0, + GTK_SCROLL_PAGE_FORWARD); + + add_slider_binding (binding_set, GDK_Home, 0, + GTK_SCROLL_START); + + add_slider_binding (binding_set, GDK_KP_Home, 0, + GTK_SCROLL_START); + + add_slider_binding (binding_set, GDK_End, 0, + GTK_SCROLL_END); + + add_slider_binding (binding_set, GDK_KP_End, 0, + GTK_SCROLL_END); } static void @@ -215,7 +312,7 @@ gtk_scale_get_property (GObject *object, switch (prop_id) { case PROP_DIGITS: - g_value_set_int (value, GTK_RANGE (scale)->digits); + g_value_set_int (value, scale->digits); break; case PROP_DRAW_VALUE: g_value_set_boolean (value, scale->draw_value); @@ -232,63 +329,55 @@ gtk_scale_get_property (GObject *object, static void gtk_scale_init (GtkScale *scale) { - GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS); - GTK_WIDGET_SET_FLAGS (scale, GTK_NO_WINDOW); - GTK_RANGE (scale)->digits = 1; - scale->draw_value = TRUE; - scale->value_pos = GTK_POS_TOP; -} - -static void -gtk_scale_map (GtkWidget *widget) -{ GtkRange *range; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_SCALE (widget)); - - GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); - range = GTK_RANGE (widget); - - gdk_window_show (range->trough); -} - -static void -gtk_scale_unmap (GtkWidget *widget) -{ - GtkRange *range; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_SCALE (widget)); - - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); - range = GTK_RANGE (widget); - - if (GTK_WIDGET_NO_WINDOW (widget)) - gtk_widget_queue_clear (widget); + range = GTK_RANGE (scale); + + GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS); - gdk_window_hide (range->trough); + 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; } void gtk_scale_set_digits (GtkScale *scale, gint digits) { - g_return_if_fail (scale != NULL); + GtkRange *range; + g_return_if_fail (GTK_IS_SCALE (scale)); + range = GTK_RANGE (scale); + digits = CLAMP (digits, -1, 16); - if (GTK_RANGE (scale)->digits != digits) + if (scale->digits != digits) { - GTK_RANGE (scale)->digits = digits; - + scale->digits = digits; + range->round_digits = digits; + gtk_widget_queue_resize (GTK_WIDGET (scale)); g_object_notify (G_OBJECT (scale), "digits"); } } +gint +gtk_scale_get_digits (GtkScale *scale) +{ + g_return_val_if_fail (GTK_IS_SCALE (scale), -1); + + return scale->digits; +} + void gtk_scale_set_draw_value (GtkScale *scale, gboolean draw_value) @@ -308,11 +397,18 @@ gtk_scale_set_draw_value (GtkScale *scale, } } +gboolean +gtk_scale_get_draw_value (GtkScale *scale) +{ + g_return_val_if_fail (GTK_IS_SCALE (scale), FALSE); + + return scale->draw_value; +} + void gtk_scale_set_value_pos (GtkScale *scale, GtkPositionType pos) { - g_return_if_fail (scale != NULL); g_return_if_fail (GTK_IS_SCALE (scale)); if (scale->value_pos != pos) @@ -326,10 +422,60 @@ gtk_scale_set_value_pos (GtkScale *scale, } } +GtkPositionType +gtk_scale_get_value_pos (GtkScale *scale) +{ + g_return_val_if_fail (GTK_IS_SCALE (scale), 0); + + return scale->value_pos; +} + +static void +gtk_scale_get_range_border (GtkRange *range, + GtkBorder *border) +{ + GtkWidget *widget; + GtkScale *scale; + gint w, h; + + widget = GTK_WIDGET (range); + scale = GTK_SCALE (range); + + _gtk_scale_get_value_size (scale, &w, &h); + + border->left = 0; + border->right = 0; + border->top = 0; + border->bottom = 0; + + if (scale->draw_value) + { + gint value_spacing; + gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL); + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + border->left += w + value_spacing; + break; + case GTK_POS_RIGHT: + border->right += w + value_spacing; + break; + case GTK_POS_TOP: + border->top += h + value_spacing; + break; + case GTK_POS_BOTTOM: + border->bottom += h + value_spacing; + break; + } + } +} + +/* FIXME this could actually be static at the moment. */ void -gtk_scale_get_value_size (GtkScale *scale, - gint *width, - gint *height) +_gtk_scale_get_value_size (GtkScale *scale, + gint *width, + gint *height) { GtkRange *range; @@ -380,39 +526,25 @@ gtk_scale_get_value_size (GtkScale *scale, } -gint -gtk_scale_get_value_width (GtkScale *scale) +static void +gtk_scale_style_set (GtkWidget *widget, + GtkStyle *previous) { - gint width; + gint slider_length; + GtkRange *range; - g_return_val_if_fail (scale != NULL, 0); - g_return_val_if_fail (GTK_IS_SCALE (scale), 0); + range = GTK_RANGE (widget); - gtk_scale_get_value_size (scale, &width, NULL); - - return width; -} - -void -gtk_scale_draw_value (GtkScale *scale) -{ - g_return_if_fail (scale != NULL); - g_return_if_fail (GTK_IS_SCALE (scale)); - - if (GTK_SCALE_GET_CLASS (scale)->draw_value) - GTK_SCALE_GET_CLASS (scale)->draw_value (scale); + gtk_widget_style_get (widget, + "slider_length", &slider_length, + NULL); + + range->min_slider_size = slider_length; + + (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous); } -static void -gtk_scale_draw_background (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_SCALE (range)); - - gtk_scale_draw_value (GTK_SCALE (range)); -} - /** * _gtk_scale_format_value: * @scale: a #GtkScale @@ -438,6 +570,6 @@ _gtk_scale_format_value (GtkScale *scale, if (fmt) return fmt; else - return g_strdup_printf ("%0.*f", GTK_RANGE (scale)->digits, + return g_strdup_printf ("%0.*f", scale->digits, value); } diff --git a/gtk/gtkscale.h b/gtk/gtkscale.h index b6cd719547..bfb099ef1b 100644 --- a/gtk/gtkscale.h +++ b/gtk/gtkscale.h @@ -52,6 +52,7 @@ struct _GtkScale { GtkRange range; + gint digits; guint draw_value : 1; guint value_pos : 2; }; @@ -60,8 +61,6 @@ struct _GtkScaleClass { GtkRangeClass parent_class; - gint value_spacing; - gchar* (* format_value) (GtkRange *range, gdouble value); @@ -69,19 +68,21 @@ struct _GtkScaleClass }; GtkType gtk_scale_get_type (void) G_GNUC_CONST; -void gtk_scale_set_digits (GtkScale *scale, - gint digits); -void gtk_scale_set_draw_value (GtkScale *scale, - gboolean draw_value); -void gtk_scale_set_value_pos (GtkScale *scale, - GtkPositionType pos); -gint gtk_scale_get_value_width (GtkScale *scale); -void gtk_scale_get_value_size (GtkScale *scale, - gint *width, - gint *height); - -void gtk_scale_draw_value (GtkScale *scale); +void gtk_scale_set_digits (GtkScale *scale, + gint digits); +gint gtk_scale_get_digits (GtkScale *scale); +void gtk_scale_set_draw_value (GtkScale *scale, + gboolean draw_value); +gboolean gtk_scale_get_draw_value (GtkScale *scale); +void gtk_scale_set_value_pos (GtkScale *scale, + GtkPositionType pos); +GtkPositionType gtk_scale_get_value_pos (GtkScale *scale); + + +void _gtk_scale_get_value_size (GtkScale *scale, + gint *width, + gint *height); gchar *_gtk_scale_format_value (GtkScale *scale, gdouble value); diff --git a/gtk/gtkscrollbar.c b/gtk/gtkscrollbar.c index c62fc13c2e..28e7ff694d 100644 --- a/gtk/gtkscrollbar.c +++ b/gtk/gtkscrollbar.c @@ -1,5 +1,6 @@ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,9 +26,14 @@ */ #include "gtkscrollbar.h" +#include "gtkintl.h" static void gtk_scrollbar_class_init (GtkScrollbarClass *klass); static void gtk_scrollbar_init (GtkScrollbar *scrollbar); +static void gtk_scrollbar_style_set (GtkWidget *widget, + GtkStyle *previous); + +static gpointer parent_class; GtkType gtk_scrollbar_get_type (void) @@ -57,9 +63,101 @@ gtk_scrollbar_get_type (void) static void gtk_scrollbar_class_init (GtkScrollbarClass *class) { + GtkWidgetClass *widget_class; + + widget_class = GTK_WIDGET_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + + widget_class->style_set = gtk_scrollbar_style_set; + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("min_slider_length", + _("Minimum Slider Length"), + _("Minimum length of scrollbar slider"), + 0, + G_MAXINT, + 7, + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boolean ("fixed_slider_length", + _("Fixed slider size"), + _("Don't change slider size, just lock it to the minimum length"), + FALSE, + + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boolean ("has_backward_stepper", + _("Backward stepper"), + _("Display the standard backward arrow button"), + TRUE, + + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boolean ("has_forward_stepper", + _("Forward stepper"), + _("Display the standard forward arrow button"), + TRUE, + + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boolean ("has_secondary_backward_stepper", + _("Secondary backward stepper"), + _("Display a second backward arrow button on the opposite end of the scrollbar"), + FALSE, + + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boolean ("has_secondary_forward_stepper", + _("Secondary forward stepper"), + _("Display a secondary forward arrow button on the opposite end of the scrollbar"), + FALSE, + + G_PARAM_READABLE)); } static void gtk_scrollbar_init (GtkScrollbar *scrollbar) { + GtkRange *range; + + range = GTK_RANGE (scrollbar); +} + +static void +gtk_scrollbar_style_set (GtkWidget *widget, + GtkStyle *previous) +{ + gint slider_length; + gboolean fixed_size; + gboolean has_a, has_b, has_c, has_d; + GtkRange *range; + + range = GTK_RANGE (widget); + + gtk_widget_style_get (widget, + "min_slider_length", &slider_length, + "fixed_slider_length", &fixed_size, + "has_backward_stepper", &has_a, + "has_secondary_forward_stepper", &has_b, + "has_secondary_backward_stepper", &has_c, + "has_forward_stepper", &has_d, + NULL); + + range->min_slider_size = slider_length; + range->slider_size_fixed = fixed_size; + + range->has_stepper_a = has_a; + range->has_stepper_b = has_b; + range->has_stepper_c = has_c; + range->has_stepper_d = has_d; + + (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous); } + + diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c index d65355b0e4..6aaf330549 100644 --- a/gtk/gtkstyle.c +++ b/gtk/gtkstyle.c @@ -3754,14 +3754,19 @@ gtk_default_draw_slider (GtkStyle *style, gtk_paint_box (style, window, state_type, shadow_type, area, widget, detail, x, y, width, height); - if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_paint_vline (style, window, state_type, area, widget, detail, - style->ythickness, - height - style->ythickness - 1, width / 2); - else - gtk_paint_hline (style, window, state_type, area, widget, detail, - style->xthickness, - width - style->xthickness - 1, height / 2); + if (detail && + (strcmp ("hscale", detail) == 0 || + strcmp ("vscale", detail) == 0)) + { + if (orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_paint_vline (style, window, state_type, area, widget, detail, + y + style->ythickness, + y + height - style->ythickness - 1, x + width / 2); + else + gtk_paint_hline (style, window, state_type, area, widget, detail, + x + style->xthickness, + x + width - style->xthickness - 1, y + height / 2); + } } static void diff --git a/gtk/gtkvscale.c b/gtk/gtkvscale.c index d233e985e0..9a60d5ad84 100644 --- a/gtk/gtkvscale.c +++ b/gtk/gtkvscale.c @@ -1,5 +1,5 @@ /* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,46 +27,16 @@ #include <stdio.h> #include "gtkvscale.h" #include "gtksignal.h" -#include "gdk/gdkkeysyms.h" #include "gtkintl.h" -#include "gtkbindings.h" +#define VALUE_SPACING 2 -#define SCALE_CLASS(w) GTK_SCALE_GET_CLASS (w) -#define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w) - -enum { - PROP_0 -}; +static gpointer parent_class; static void gtk_vscale_class_init (GtkVScaleClass *klass); static void gtk_vscale_init (GtkVScale *vscale); -static void gtk_vscale_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_vscale_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_vscale_realize (GtkWidget *widget); -static void gtk_vscale_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_vscale_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_vscale_pos_trough (GtkVScale *vscale, - gint *x, - gint *y, - gint *w, - gint *h); -static void gtk_vscale_pos_background (GtkVScale *vscale, - gint *x, - gint *y, - gint *w, - gint *h); -static void gtk_vscale_draw_slider (GtkRange *range); -static void gtk_vscale_draw_value (GtkScale *scale); -static void gtk_vscale_clear_background (GtkRange *range); +static gboolean gtk_vscale_expose (GtkWidget *widget, + GdkEventExpose *event); GtkType gtk_vscale_get_type (void) @@ -93,136 +63,32 @@ gtk_vscale_get_type (void) return vscale_type; } -#define add_slider_binding(binding_set, keyval, mask, scroll, trough) \ - gtk_binding_entry_add_signal (binding_set, keyval, mask, \ - "move_slider", 2, \ - GTK_TYPE_SCROLL_TYPE, scroll, \ - GTK_TYPE_TROUGH_TYPE, trough) - static void gtk_vscale_class_init (GtkVScaleClass *class) { - GtkObjectClass *object_class; GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkRangeClass *range_class; - GtkScaleClass *scale_class; - GtkBindingSet *binding_set; - object_class = (GtkObjectClass*) class; gobject_class = G_OBJECT_CLASS (class); - widget_class = (GtkWidgetClass*) class; - range_class = (GtkRangeClass*) class; - scale_class = (GtkScaleClass*) class; - - gobject_class->set_property = gtk_vscale_set_property; - gobject_class->get_property = gtk_vscale_get_property; - - widget_class->realize = gtk_vscale_realize; - widget_class->size_request = gtk_vscale_size_request; - widget_class->size_allocate = gtk_vscale_size_allocate; - - range_class->slider_update = _gtk_range_default_vslider_update; - range_class->trough_click = _gtk_range_default_vtrough_click; - range_class->motion = _gtk_range_default_vmotion; - range_class->draw_slider = gtk_vscale_draw_slider; - range_class->clear_background = gtk_vscale_clear_background; - - scale_class->draw_value = gtk_vscale_draw_value; - - binding_set = gtk_binding_set_by_class (object_class); - - add_slider_binding (binding_set, GDK_Up, 0, - GTK_SCROLL_STEP_UP, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Up, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_UP, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Up, 0, - GTK_SCROLL_STEP_UP, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_UP, GTK_TROUGH_NONE); - - - add_slider_binding (binding_set, GDK_Down, 0, - GTK_SCROLL_STEP_DOWN, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Down, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_DOWN, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Down, 0, - GTK_SCROLL_STEP_DOWN, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK, - GTK_SCROLL_PAGE_DOWN, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Page_Up, 0, - GTK_SCROLL_PAGE_BACKWARD, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Page_Up, 0, - GTK_SCROLL_PAGE_BACKWARD, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Page_Down, 0, - GTK_SCROLL_PAGE_FORWARD, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_KP_Page_Down, 0, - GTK_SCROLL_PAGE_FORWARD, GTK_TROUGH_NONE); - - add_slider_binding (binding_set, GDK_Home, 0, - GTK_SCROLL_NONE, GTK_TROUGH_START); + widget_class = GTK_WIDGET_CLASS (class); + range_class = GTK_RANGE_CLASS (class); - add_slider_binding (binding_set, GDK_KP_Home, 0, - GTK_SCROLL_NONE, GTK_TROUGH_START); + parent_class = g_type_class_peek_parent (class); - - add_slider_binding (binding_set, GDK_End, 0, - GTK_SCROLL_NONE, GTK_TROUGH_END); - - add_slider_binding (binding_set, GDK_KP_End, 0, - GTK_SCROLL_NONE, GTK_TROUGH_END); -} - -static void -gtk_vscale_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkVScale *vscale; - - vscale = GTK_VSCALE (object); - - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_vscale_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GtkVScale *vscale; - - vscale = GTK_VSCALE (object); + range_class->slider_detail = "vscale"; - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + widget_class->expose_event = gtk_vscale_expose; } static void gtk_vscale_init (GtkVScale *vscale) { - GTK_WIDGET_SET_FLAGS (vscale, GTK_NO_WINDOW); + GtkRange *range; + + range = GTK_RANGE (vscale); + + range->orientation = GTK_ORIENTATION_VERTICAL; } GtkWidget* @@ -237,298 +103,28 @@ gtk_vscale_new (GtkAdjustment *adjustment) return vscale; } - -static void -gtk_vscale_realize (GtkWidget *widget) -{ - GtkRange *range; - GdkWindowAttr attributes; - gint attributes_mask; - gint x, y, w, h; - gint slider_width, slider_length; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_VSCALE (widget)); - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - range = GTK_RANGE (widget); - - _gtk_range_get_props (range, &slider_width, NULL, NULL, NULL); - gtk_widget_style_get (widget, "slider_length", &slider_length, NULL); - - widget->window = gtk_widget_get_parent_window (widget); - gdk_window_ref (widget->window); - - gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &w, &h); - - attributes.x = x; - attributes.y = y; - attributes.width = w; - attributes.height = h; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - - attributes.event_mask = gtk_widget_get_events (widget) | - (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - - range->trough = gdk_window_new (widget->window, &attributes, attributes_mask); - - attributes.width = slider_width; - attributes.height = slider_length; - attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - - range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); - - widget->style = gtk_style_attach (widget->style, widget->window); - - gdk_window_set_user_data (range->trough, widget); - gdk_window_set_user_data (range->slider, widget); - - gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); - gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); - - _gtk_range_slider_update (GTK_RANGE (widget)); - - gdk_window_show (range->slider); -} - -static void -gtk_vscale_clear_background (GtkRange *range) -{ - GtkWidget *widget; - GtkScale *scale; - gint x, y, width, height; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_SCALE (range)); - - widget = GTK_WIDGET (range); - scale = GTK_SCALE (range); - - gtk_vscale_pos_background (GTK_VSCALE (widget), &x, &y, &width, &height); - - gtk_widget_queue_clear_area (GTK_WIDGET (range), - x, y, width, height); -} - -static void -gtk_vscale_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - GtkScale *scale = GTK_SCALE (widget); - gint slider_width, slider_length, trough_border; - - _gtk_range_get_props (GTK_RANGE (scale), - &slider_width, &trough_border, NULL, NULL); - gtk_widget_style_get (widget, "slider_length", &slider_length, NULL); - - requisition->width = (slider_width + trough_border * 2); - requisition->height = (slider_length + trough_border) * 2; - - if (scale->draw_value) - { - gint value_width, value_height; - gtk_scale_get_value_size (scale, &value_width, &value_height); - - if ((scale->value_pos == GTK_POS_LEFT) || - (scale->value_pos == GTK_POS_RIGHT)) - { - requisition->width += value_width + SCALE_CLASS (scale)->value_spacing; - if (requisition->height < (value_height)) - requisition->height = value_height; - } - else if ((scale->value_pos == GTK_POS_TOP) || - (scale->value_pos == GTK_POS_BOTTOM)) - { - if (requisition->width < value_width) - requisition->width = value_width; - requisition->height += value_height; - } - } -} - -static void -gtk_vscale_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +static gboolean +gtk_vscale_expose (GtkWidget *widget, + GdkEventExpose *event) { GtkRange *range; + GtkVScale *vscale; GtkScale *scale; - gint width, height; - gint x, y; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_VSCALE (widget)); - g_return_if_fail (allocation != NULL); - - widget->allocation = *allocation; - if (GTK_WIDGET_REALIZED (widget)) - { - range = GTK_RANGE (widget); - scale = GTK_SCALE (widget); - - gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &width, &height); - - gdk_window_move_resize (range->trough, x, y, width, height); - _gtk_range_slider_update (GTK_RANGE (widget)); - } -} - -static void -gtk_vscale_pos_trough (GtkVScale *vscale, - gint *x, - gint *y, - gint *w, - gint *h) -{ - GtkWidget *widget = GTK_WIDGET (vscale); - GtkScale *scale = GTK_SCALE (vscale); - gint value_width, value_height; - gint slider_width, trough_border; - - _gtk_range_get_props (GTK_RANGE (scale), - &slider_width, &trough_border, NULL, NULL); - - *w = (slider_width + trough_border * 2); - *h = widget->allocation.height; - - if (scale->draw_value) - { - *x = 0; - *y = 0; - - gtk_scale_get_value_size (scale, &value_width, &value_height); - - switch (scale->value_pos) - { - case GTK_POS_LEFT: - *x = (value_width + SCALE_CLASS (scale)->value_spacing + - (widget->allocation.width - widget->requisition.width) / 2); - break; - case GTK_POS_RIGHT: - *x = (widget->allocation.width - widget->requisition.width) / 2; - break; - case GTK_POS_TOP: - *x = (widget->allocation.width - *w) / 2; - *y = value_height; - *h -= *y; - break; - case GTK_POS_BOTTOM: - *x = (widget->allocation.width - *w) / 2; - *h -= value_height; - break; - } - } - else - { - *x = (widget->allocation.width - *w) / 2; - *y = 0; - } - *y += 1; - *h -= 2; - - *x += widget->allocation.x; - *y += widget->allocation.y; -} - -static void -gtk_vscale_pos_background (GtkVScale *vscale, - gint *x, - gint *y, - gint *w, - gint *h) -{ - GtkWidget *widget; - GtkScale *scale; - gint slider_width, trough_border; - - gint tx, ty, twidth, theight; - - g_return_if_fail (vscale != NULL); - g_return_if_fail (GTK_IS_VSCALE (vscale)); - g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL)); - - gtk_vscale_pos_trough (vscale, &tx, &ty, &twidth, &theight); - - widget = GTK_WIDGET (vscale); - scale = GTK_SCALE (vscale); - - *x = widget->allocation.x; - *y = widget->allocation.y; - *w = widget->allocation.width; - *h = widget->allocation.height; - - switch (scale->value_pos) - { - case GTK_POS_LEFT: - *w -= twidth; - break; - case GTK_POS_RIGHT: - *x += twidth; - *w -= twidth; - break; - case GTK_POS_TOP: - *h -= theight; - break; - case GTK_POS_BOTTOM: - *y += theight; - *h -= theight; - break; - } - *w = MAX (*w, 0); - *h = MAX (*h, 0); -} - -static void -gtk_vscale_draw_slider (GtkRange *range) -{ - GtkStateType state_type; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_VSCALE (range)); - - if (range->slider) - { - if ((range->in_child == RANGE_CLASS (range)->slider) || - (range->click_child == RANGE_CLASS (range)->slider)) - state_type = GTK_STATE_PRELIGHT; - else - state_type = GTK_STATE_NORMAL; - - gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type, - GTK_SHADOW_OUT, - NULL, GTK_WIDGET (range), "vscale", - 0, 0, -1, -1, - GTK_ORIENTATION_VERTICAL); - } -} - -static void -gtk_vscale_draw_value (GtkScale *scale) -{ - GtkStateType state_type; - GtkWidget *widget; - gint width, height; - gint x, y; - g_return_if_fail (scale != NULL); - g_return_if_fail (GTK_IS_VSCALE (scale)); - - widget = GTK_WIDGET (scale); + range = GTK_RANGE (widget); + scale = GTK_SCALE (widget); + vscale = GTK_VSCALE (widget); if (scale->draw_value) { PangoLayout *layout; PangoRectangle logical_rect; gchar *txt; + gint x, y; + GtkStateType state_type; + gint value_spacing; + + gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL); txt = _gtk_scale_format_value (scale, GTK_RANGE (scale)->adjustment->value); @@ -537,44 +133,35 @@ gtk_vscale_draw_value (GtkScale *scale) g_free (txt); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - + switch (scale->value_pos) { case GTK_POS_LEFT: - gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL); - gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y); - gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL); - gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height); - - x -= SCALE_CLASS (scale)->value_spacing + logical_rect.width; - y += widget->allocation.y + (height - logical_rect.height) / 2 + - PANGO_ASCENT (logical_rect); + 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: - gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL); - gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y); - gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL); - gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height); - x += width + SCALE_CLASS (scale)->value_spacing; - y += widget->allocation.y + (height - logical_rect.height) / 2 + - PANGO_ASCENT (logical_rect); + 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: - gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); - gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); - gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); - x += (width - logical_rect.width) / 2; - y -= PANGO_DESCENT (logical_rect); + 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: - gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); - gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); - gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); - x += (width - logical_rect.width) / 2; - y += height + PANGO_ASCENT (logical_rect); + 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_val_if_reached (FALSE); + x = 0; + y = 0; break; } @@ -590,8 +177,10 @@ gtk_vscale_draw_value (GtkScale *scale) widget, "vscale", x, y, - layout); + layout); g_object_unref (G_OBJECT (layout)); } + + return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); } diff --git a/gtk/gtkvscrollbar.c b/gtk/gtkvscrollbar.c index 54fb337324..795255b5eb 100644 --- a/gtk/gtkvscrollbar.c +++ b/gtk/gtkvscrollbar.c @@ -1,5 +1,6 @@ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 2001 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,34 +30,8 @@ #include "gdk/gdkkeysyms.h" #include "gtkintl.h" - -#define EPSILON 0.01 - -#define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w) - -enum { - PROP_0, -}; - static void gtk_vscrollbar_class_init (GtkVScrollbarClass *klass); static void gtk_vscrollbar_init (GtkVScrollbar *vscrollbar); -static void gtk_vscrollbar_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gtk_vscrollbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_vscrollbar_realize (GtkWidget *widget); -static void gtk_vscrollbar_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_vscrollbar_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_vscrollbar_draw_step_forw (GtkRange *range); -static void gtk_vscrollbar_draw_step_back (GtkRange *range); -static void gtk_vscrollbar_slider_update (GtkRange *range); -static void gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar); GtkType gtk_vscrollbar_get_type (void) @@ -86,67 +61,17 @@ gtk_vscrollbar_get_type (void) static void gtk_vscrollbar_class_init (GtkVScrollbarClass *class) { - GObjectClass *gobject_class; - GtkWidgetClass *widget_class; - GtkRangeClass *range_class; - - gobject_class = G_OBJECT_CLASS (class); - widget_class = (GtkWidgetClass*) class; - range_class = (GtkRangeClass*) class; - - gobject_class->set_property = gtk_vscrollbar_set_property; - gobject_class->get_property = gtk_vscrollbar_get_property; - - widget_class->realize = gtk_vscrollbar_realize; - widget_class->size_request = gtk_vscrollbar_size_request; - widget_class->size_allocate = gtk_vscrollbar_size_allocate; - - range_class->draw_step_forw = gtk_vscrollbar_draw_step_forw; - range_class->draw_step_back = gtk_vscrollbar_draw_step_back; - range_class->slider_update = gtk_vscrollbar_slider_update; - range_class->trough_click = _gtk_range_default_vtrough_click; - range_class->motion = _gtk_range_default_vmotion; + GTK_RANGE_CLASS (class)->stepper_detail = "vscrollbar"; } static void -gtk_vscrollbar_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +gtk_vscrollbar_init (GtkVScrollbar *vscrollbar) { - GtkVScrollbar *vscrollbar; - - vscrollbar = GTK_VSCROLLBAR (object); - - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} + GtkRange *range; -static void -gtk_vscrollbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GtkVScrollbar *vscrollbar; - - vscrollbar = GTK_VSCROLLBAR (object); - - switch (prop_id) - { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} + range = GTK_RANGE (vscrollbar); -static void -gtk_vscrollbar_init (GtkVScrollbar *vscrollbar) -{ + range->orientation = GTK_ORIENTATION_VERTICAL; } GtkWidget* @@ -160,282 +85,3 @@ gtk_vscrollbar_new (GtkAdjustment *adjustment) return vscrollbar; } - - -static void -gtk_vscrollbar_realize (GtkWidget *widget) -{ - GtkRange *range; - GdkWindowAttr attributes; - gint attributes_mask; - gint slider_width; - gint stepper_size; - gint trough_border; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_VSCROLLBAR (widget)); - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - range = GTK_RANGE (widget); - - _gtk_range_get_props (range, &slider_width, &trough_border, - &stepper_size, NULL); - - attributes.x = widget->allocation.x + (widget->allocation.width - widget->requisition.width) / 2; - attributes.y = widget->allocation.y; - attributes.width = widget->requisition.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - - range->trough = widget->window; - gdk_window_ref (range->trough); - - attributes.x = trough_border; - attributes.y = trough_border; - attributes.width = stepper_size; - attributes.height = stepper_size; - - range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask); - - attributes.y = (widget->allocation.height - - trough_border - - stepper_size); - - range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask); - - attributes.x = trough_border; - attributes.y = 0; - attributes.width = slider_width; - attributes.height = RANGE_CLASS (widget)->min_slider_size; - attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); - - range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); - - gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (widget)); - _gtk_range_slider_update (GTK_RANGE (widget)); - - widget->style = gtk_style_attach (widget->style, widget->window); - - gdk_window_set_user_data (range->trough, widget); - gdk_window_set_user_data (range->slider, widget); - gdk_window_set_user_data (range->step_forw, widget); - gdk_window_set_user_data (range->step_back, widget); - - gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); - gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); - gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE); - gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE); - - gdk_window_show (range->slider); - gdk_window_show (range->step_forw); - gdk_window_show (range->step_back); -} - -static void -gtk_vscrollbar_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - gint slider_width; - gint trough_border; - gint stepper_size; - gint stepper_spacing; - - GtkRange *range = GTK_RANGE (widget); - - _gtk_range_get_props (range, &slider_width, &trough_border, - &stepper_size, &stepper_spacing); - - requisition->width = (slider_width + - trough_border * 2); - requisition->height = (RANGE_CLASS (widget)->min_slider_size + - stepper_size + - stepper_spacing + - trough_border) * 2; -} - -static void -gtk_vscrollbar_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkRange *range; - gint trough_border; - gint stepper_size; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_VSCROLLBAR (widget)); - g_return_if_fail (allocation != NULL); - - widget->allocation = *allocation; - if (GTK_WIDGET_REALIZED (widget)) - { - range = GTK_RANGE (widget); - - _gtk_range_get_props (range, NULL, &trough_border, - &stepper_size, NULL); - - gdk_window_move_resize (range->trough, - allocation->x + (allocation->width - widget->requisition.width) / 2, - allocation->y, - widget->requisition.width, allocation->height); - gdk_window_move_resize (range->step_back, - trough_border, - trough_border, - widget->requisition.width - trough_border * 2, - stepper_size); - gdk_window_move_resize (range->step_forw, - trough_border, - allocation->height - trough_border - - stepper_size, - widget->requisition.width - trough_border * 2, - stepper_size); - - _gtk_range_slider_update (GTK_RANGE (widget)); - } -} - -static void -gtk_vscrollbar_draw_step_forw (GtkRange *range) -{ - GtkStateType state_type; - GtkShadowType shadow_type; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_VSCROLLBAR (range)); - - if (GTK_WIDGET_DRAWABLE (range)) - { - if (range->in_child == RANGE_CLASS (range)->step_forw) - { - if (range->click_child == RANGE_CLASS (range)->step_forw) - state_type = GTK_STATE_ACTIVE; - else - state_type = GTK_STATE_PRELIGHT; - } - else - state_type = GTK_STATE_NORMAL; - - if (range->click_child == RANGE_CLASS (range)->step_forw) - shadow_type = GTK_SHADOW_IN; - else - shadow_type = GTK_SHADOW_OUT; - - gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw, - state_type, shadow_type, - NULL, GTK_WIDGET (range), "vscrollbar", - GTK_ARROW_DOWN, - TRUE, 0, 0, -1, -1); - } -} - -static void -gtk_vscrollbar_draw_step_back (GtkRange *range) -{ - GtkStateType state_type; - GtkShadowType shadow_type; - - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_VSCROLLBAR (range)); - - if (GTK_WIDGET_DRAWABLE (range)) - { - if (range->in_child == RANGE_CLASS (range)->step_back) - { - if (range->click_child == RANGE_CLASS (range)->step_back) - state_type = GTK_STATE_ACTIVE; - else - state_type = GTK_STATE_PRELIGHT; - } - else - state_type = GTK_STATE_NORMAL; - - if (range->click_child == RANGE_CLASS (range)->step_back) - shadow_type = GTK_SHADOW_IN; - else - shadow_type = GTK_SHADOW_OUT; - - gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back, - state_type, shadow_type, - NULL, GTK_WIDGET (range), "vscrollbar", - GTK_ARROW_UP, - TRUE, 0, 0, -1, -1); - } -} - -static void -gtk_vscrollbar_slider_update (GtkRange *range) -{ - g_return_if_fail (range != NULL); - g_return_if_fail (GTK_IS_VSCROLLBAR (range)); - - gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (range)); - _gtk_range_default_vslider_update (range); -} - -static void -gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar) -{ - GtkRange *range; - gint step_back_y; - gint step_back_height; - gint step_forw_y; - gint stepper_spacing; - gint slider_width; - gint slider_height; - gint top, bottom; - gint height; - - g_return_if_fail (vscrollbar != NULL); - g_return_if_fail (GTK_IS_VSCROLLBAR (vscrollbar)); - - if (GTK_WIDGET_REALIZED (vscrollbar)) - { - range = GTK_RANGE (vscrollbar); - - _gtk_range_get_props (range, NULL, NULL, NULL, &stepper_spacing); - - gdk_window_get_size (range->step_back, NULL, &step_back_height); - gdk_window_get_position (range->step_back, NULL, &step_back_y); - gdk_window_get_position (range->step_forw, NULL, &step_forw_y); - - top = (step_back_y + - step_back_height + - stepper_spacing); - bottom = step_forw_y - stepper_spacing; - height = bottom - top; - - if ((range->adjustment->page_size > 0) && - (range->adjustment->lower != range->adjustment->upper)) - { - if (range->adjustment->page_size > - (range->adjustment->upper - range->adjustment->lower)) - range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower; - - height = (height * range->adjustment->page_size / - (range->adjustment->upper - range->adjustment->lower)); - - if (height < RANGE_CLASS (vscrollbar)->min_slider_size) - height = RANGE_CLASS (vscrollbar)->min_slider_size; - } - - gdk_window_get_size (range->slider, &slider_width, &slider_height); - - if (slider_height != height) - { - gdk_window_resize (range->slider, slider_width, height); - gdk_window_invalidate_rect (range->slider, NULL, FALSE); - } - } -} |