1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 #include "gtkhscale.h"
29 #include "gtksignal.h"
30 #include "gdk/gdkkeysyms.h"
33 #define SCALE_CLASS(w) GTK_SCALE_GET_CLASS (w)
34 #define RANGE_CLASS(w) GTK_RANGE_GET_CLASS (w)
41 static void gtk_hscale_class_init (GtkHScaleClass *klass);
42 static void gtk_hscale_init (GtkHScale *hscale);
43 static void gtk_hscale_get_property (GObject *object,
47 static void gtk_hscale_set_property (GObject *object,
51 static void gtk_hscale_realize (GtkWidget *widget);
52 static void gtk_hscale_size_request (GtkWidget *widget,
53 GtkRequisition *requisition);
54 static void gtk_hscale_size_allocate (GtkWidget *widget,
55 GtkAllocation *allocation);
56 static void gtk_hscale_pos_trough (GtkHScale *hscale,
61 static void gtk_hscale_pos_background (GtkHScale *hscale,
66 static void gtk_hscale_draw_slider (GtkRange *range);
67 static void gtk_hscale_draw_value (GtkScale *scale);
68 static gboolean gtk_hscale_trough_keys (GtkRange *range,
70 GtkScrollType *scroll,
72 static void gtk_hscale_clear_background (GtkRange *range);
76 gtk_hscale_get_type (void)
78 static GtkType hscale_type = 0;
82 static const GtkTypeInfo hscale_info =
86 sizeof (GtkHScaleClass),
87 (GtkClassInitFunc) gtk_hscale_class_init,
88 (GtkObjectInitFunc) gtk_hscale_init,
89 /* reserved_1 */ NULL,
90 /* reserved_2 */ NULL,
91 (GtkClassInitFunc) NULL,
94 hscale_type = gtk_type_unique (GTK_TYPE_SCALE, &hscale_info);
101 gtk_hscale_class_init (GtkHScaleClass *class)
103 GObjectClass *gobject_class;
104 GtkObjectClass *object_class;
105 GtkWidgetClass *widget_class;
106 GtkRangeClass *range_class;
107 GtkScaleClass *scale_class;
109 gobject_class = (GObjectClass*) class;
110 object_class = (GtkObjectClass*) class;
111 widget_class = (GtkWidgetClass*) class;
112 range_class = (GtkRangeClass*) class;
113 scale_class = (GtkScaleClass*) class;
115 gobject_class->set_property = gtk_hscale_set_property;
116 gobject_class->get_property = gtk_hscale_get_property;
118 widget_class->realize = gtk_hscale_realize;
119 widget_class->size_request = gtk_hscale_size_request;
120 widget_class->size_allocate = gtk_hscale_size_allocate;
122 range_class->slider_update = _gtk_range_default_hslider_update;
123 range_class->trough_click = _gtk_range_default_htrough_click;
124 range_class->motion = _gtk_range_default_hmotion;
125 range_class->draw_slider = gtk_hscale_draw_slider;
126 range_class->trough_keys = gtk_hscale_trough_keys;
127 range_class->clear_background = gtk_hscale_clear_background;
129 scale_class->draw_value = gtk_hscale_draw_value;
131 g_object_class_install_property (gobject_class,
133 g_param_spec_object ("adjustment",
135 _("The GtkAdjustment that determines the values to use for this HScale."),
142 gtk_hscale_set_property (GObject *object,
149 hscale = GTK_HSCALE (object);
153 case PROP_ADJUSTMENT:
154 gtk_range_set_adjustment (GTK_RANGE (hscale), g_value_get_object (value));
157 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
163 gtk_hscale_get_property (GObject *object,
170 hscale = GTK_HSCALE (object);
174 case PROP_ADJUSTMENT:
175 g_value_set_object (value,
176 G_OBJECT (gtk_range_get_adjustment (GTK_RANGE (hscale))));
179 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
185 gtk_hscale_init (GtkHScale *hscale)
187 GTK_WIDGET_SET_FLAGS (hscale, GTK_NO_WINDOW);
191 gtk_hscale_new (GtkAdjustment *adjustment)
195 hscale = gtk_widget_new (GTK_TYPE_HSCALE,
196 "adjustment", adjustment,
199 GTK_RANGE (hscale) -> flippable = 1;
206 gtk_hscale_realize (GtkWidget *widget)
209 GdkWindowAttr attributes;
210 gint attributes_mask;
212 gint slider_width, slider_length;
214 g_return_if_fail (widget != NULL);
215 g_return_if_fail (GTK_IS_HSCALE (widget));
217 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
218 range = GTK_RANGE (widget);
220 _gtk_range_get_props (range, &slider_width, NULL, NULL, NULL);
221 gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
223 widget->window = gtk_widget_get_parent_window (widget);
224 gdk_window_ref (widget->window);
226 gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &w, &h);
230 attributes.width = w;
231 attributes.height = h;
232 attributes.wclass = GDK_INPUT_OUTPUT;
233 attributes.window_type = GDK_WINDOW_CHILD;
235 attributes.event_mask = gtk_widget_get_events (widget) |
237 GDK_BUTTON_PRESS_MASK |
238 GDK_BUTTON_RELEASE_MASK |
239 GDK_ENTER_NOTIFY_MASK |
240 GDK_LEAVE_NOTIFY_MASK);
241 attributes.visual = gtk_widget_get_visual (widget);
242 attributes.colormap = gtk_widget_get_colormap (widget);
244 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
246 range->trough = gdk_window_new (widget->window, &attributes, attributes_mask);
248 attributes.width = slider_length;
249 attributes.height = slider_width;
250 attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
251 GDK_POINTER_MOTION_HINT_MASK);
253 range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
255 widget->style = gtk_style_attach (widget->style, widget->window);
257 gdk_window_set_user_data (range->trough, widget);
258 gdk_window_set_user_data (range->slider, widget);
260 gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
261 gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
263 _gtk_range_slider_update (GTK_RANGE (widget));
265 gdk_window_show (range->slider);
269 gtk_hscale_clear_background (GtkRange *range)
272 gint x, y, width, height;
274 g_return_if_fail (range != NULL);
276 widget = GTK_WIDGET (range);
278 gtk_hscale_pos_background (GTK_HSCALE (range), &x, &y, &width, &height);
280 gtk_widget_queue_clear_area (GTK_WIDGET (range),
281 x, y, width, height);
285 gtk_hscale_size_request (GtkWidget *widget,
286 GtkRequisition *requisition)
288 GtkScale *scale = GTK_SCALE (widget);
289 gint slider_width, slider_length, trough_border;
291 g_return_if_fail (widget != NULL);
292 g_return_if_fail (GTK_IS_HSCALE (widget));
293 g_return_if_fail (requisition != NULL);
295 _gtk_range_get_props (GTK_RANGE (scale),
296 &slider_width, &trough_border, NULL, NULL);
297 gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
299 requisition->width = (slider_length + trough_border) * 2;
300 requisition->height = (slider_width + trough_border * 2);
302 if (scale->draw_value)
304 gint value_width, value_height;
305 gtk_scale_get_value_size (scale, &value_width, &value_height);
307 if ((scale->value_pos == GTK_POS_LEFT) ||
308 (scale->value_pos == GTK_POS_RIGHT))
310 requisition->width += value_width + SCALE_CLASS (scale)->value_spacing;
311 if (requisition->height < value_height)
312 requisition->height = value_height;
314 else if ((scale->value_pos == GTK_POS_TOP) ||
315 (scale->value_pos == GTK_POS_BOTTOM))
317 if (requisition->width < value_width)
318 requisition->width = value_width;
319 requisition->height += value_height;
325 gtk_hscale_size_allocate (GtkWidget *widget,
326 GtkAllocation *allocation)
333 g_return_if_fail (widget != NULL);
334 g_return_if_fail (GTK_IS_HSCALE (widget));
335 g_return_if_fail (allocation != NULL);
337 widget->allocation = *allocation;
338 if (GTK_WIDGET_REALIZED (widget))
340 range = GTK_RANGE (widget);
341 scale = GTK_SCALE (widget);
343 gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height);
345 gdk_window_move_resize (range->trough,
346 x, y, width, height);
347 _gtk_range_slider_update (GTK_RANGE (widget));
352 gtk_hscale_pos_trough (GtkHScale *hscale,
358 GtkWidget *widget = GTK_WIDGET (hscale);
359 GtkScale *scale = GTK_SCALE (hscale);
363 _gtk_range_get_props (GTK_RANGE (scale),
364 &slider_width, &trough_border, NULL, NULL);
366 *w = widget->allocation.width;
367 *h = (slider_width + trough_border * 2);
369 if (scale->draw_value)
371 gint value_width, value_height;
372 gtk_scale_get_value_size (scale, &value_width, &value_height);
377 switch (scale->value_pos)
380 *x += value_width + SCALE_CLASS (scale)->value_spacing;
381 *y = (widget->allocation.height - *h) / 2;
385 *w -= value_width + SCALE_CLASS (scale)->value_spacing;
386 *y = (widget->allocation.height - *h) / 2;
389 *y = (value_height + (widget->allocation.height - widget->requisition.height) / 2);
392 *y = (widget->allocation.height - widget->requisition.height) / 2;
399 *y = (widget->allocation.height - *h) / 2;
404 *x += widget->allocation.x;
405 *y += widget->allocation.y;
409 gtk_hscale_pos_background (GtkHScale *hscale,
418 gint tx, ty, twidth, theight;
420 g_return_if_fail (hscale != NULL);
421 g_return_if_fail (GTK_IS_HSCALE (hscale));
422 g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
424 gtk_hscale_pos_trough (hscale, &tx, &ty, &twidth, &theight);
426 widget = GTK_WIDGET (hscale);
427 scale = GTK_SCALE (hscale);
429 *x = widget->allocation.x;
430 *y = widget->allocation.y;
431 *w = widget->allocation.width;
432 *h = widget->allocation.height;
434 switch (scale->value_pos)
456 gtk_hscale_draw_slider (GtkRange *range)
458 GtkStateType state_type;
460 g_return_if_fail (range != NULL);
461 g_return_if_fail (GTK_IS_HSCALE (range));
465 if ((range->in_child == RANGE_CLASS (range)->slider) ||
466 (range->click_child == RANGE_CLASS (range)->slider))
467 state_type = GTK_STATE_PRELIGHT;
469 state_type = GTK_STATE_NORMAL;
471 gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type,
473 NULL, GTK_WIDGET (range), "hscale",
475 GTK_ORIENTATION_HORIZONTAL);
480 gtk_hscale_draw_value (GtkScale *scale)
482 GtkStateType state_type;
488 g_return_if_fail (scale != NULL);
489 g_return_if_fail (GTK_IS_HSCALE (scale));
491 widget = GTK_WIDGET (scale);
493 if (scale->draw_value)
496 PangoRectangle logical_rect;
498 sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
499 layout = gtk_widget_create_pango_layout (widget, buffer);
500 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
502 switch (scale->value_pos)
505 gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
506 gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
508 x -= SCALE_CLASS (scale)->value_spacing + logical_rect.width;
509 y += (height - logical_rect.height) / 2;
512 gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
513 gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
515 x += width + SCALE_CLASS (scale)->value_spacing;
516 y += (height - logical_rect.height) / 2;
519 gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
520 gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
521 gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
522 gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
524 x += widget->allocation.x + (width - logical_rect.width) / 2;
525 x = CLAMP (x, widget->allocation.x,
526 widget->allocation.x + widget->allocation.width - logical_rect.width);
527 y -= logical_rect.height;
530 gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
531 gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
532 gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
533 gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
535 x += widget->allocation.x + (width - logical_rect.width) / 2;
536 x = CLAMP (x, widget->allocation.x,
537 widget->allocation.x + widget->allocation.width - logical_rect.width);
542 state_type = GTK_STATE_NORMAL;
543 if (!GTK_WIDGET_IS_SENSITIVE (scale))
544 state_type = GTK_STATE_INSENSITIVE;
546 gtk_paint_layout (widget->style,
555 g_object_unref (G_OBJECT (layout));
560 gtk_hscale_trough_keys (GtkRange *range,
562 GtkScrollType *scroll,
565 gint return_val = FALSE;
570 if (key->state & GDK_CONTROL_MASK)
571 *scroll = GTK_SCROLL_PAGE_LEFT;
573 *scroll = GTK_SCROLL_STEP_LEFT;
577 if (key->state & GDK_CONTROL_MASK)
578 *scroll = GTK_SCROLL_PAGE_RIGHT;
580 *scroll = GTK_SCROLL_STEP_RIGHT;
584 *pos = GTK_TROUGH_START;
588 *pos = GTK_TROUGH_END;