]> Pileus Git - ~andy/gtk/blob - gtk/gtkhscrollbar.c
voc Pennington <hp@redhat.com>
[~andy/gtk] / gtk / gtkhscrollbar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include "gtkhscrollbar.h"
28 #include "gtksignal.h"
29 #include "gdk/gdkkeysyms.h"
30 #include "gtkintl.h"
31
32
33 #define EPSILON 0.01
34
35 #define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
36
37 enum {
38   PROP_0,
39   PROP_ADJUSTMENT
40 };
41
42 static void     gtk_hscrollbar_class_init       (GtkHScrollbarClass *klass);
43 static void     gtk_hscrollbar_init             (GtkHScrollbar      *hscrollbar);
44 static void     gtk_hscrollbar_get_property     (GObject            *object,
45                                                  guint               prop_id,
46                                                  GValue             *value,
47                                                  GParamSpec         *pspec);
48 static void     gtk_hscrollbar_set_property     (GObject            *object,
49                                                  guint               prop_id,
50                                                  const GValue       *value,
51                                                  GParamSpec         *pspec);
52 static void     gtk_hscrollbar_realize          (GtkWidget          *widget);
53 static void     gtk_hscrollbar_size_request     (GtkWidget          *widget,
54                                                  GtkRequisition     *requisition);
55 static void     gtk_hscrollbar_size_allocate    (GtkWidget          *widget,
56                                                  GtkAllocation      *allocation);
57 static void     gtk_hscrollbar_draw_step_forw   (GtkRange           *range);
58 static void     gtk_hscrollbar_draw_step_back   (GtkRange           *range);
59 static void     gtk_hscrollbar_slider_update    (GtkRange           *range);
60 static void     gtk_hscrollbar_calc_slider_size (GtkHScrollbar      *hscrollbar);
61
62 GtkType
63 gtk_hscrollbar_get_type (void)
64 {
65   static GtkType hscrollbar_type = 0;
66   
67   if (!hscrollbar_type)
68     {
69       static const GtkTypeInfo hscrollbar_info =
70       {
71         "GtkHScrollbar",
72         sizeof (GtkHScrollbar),
73         sizeof (GtkHScrollbarClass),
74         (GtkClassInitFunc) gtk_hscrollbar_class_init,
75         (GtkObjectInitFunc) gtk_hscrollbar_init,
76         /* reserved_1 */ NULL,
77         /* reserved_2 */ NULL,
78         (GtkClassInitFunc) NULL,
79       };
80       
81       hscrollbar_type = gtk_type_unique (GTK_TYPE_SCROLLBAR, &hscrollbar_info);
82     }
83   
84   return hscrollbar_type;
85 }
86
87 static void
88 gtk_hscrollbar_class_init (GtkHScrollbarClass *class)
89 {
90   GObjectClass *gobject_class;
91   GtkObjectClass *object_class;
92   GtkWidgetClass *widget_class;
93   GtkRangeClass *range_class;
94   
95   gobject_class = (GObjectClass*) class;
96   object_class = (GtkObjectClass*) class;
97   widget_class = (GtkWidgetClass*) class;
98   range_class = (GtkRangeClass*) class;
99   
100   gobject_class->set_property = gtk_hscrollbar_set_property;
101   gobject_class->get_property = gtk_hscrollbar_get_property;
102
103   widget_class->realize = gtk_hscrollbar_realize;
104   widget_class->size_request = gtk_hscrollbar_size_request;
105   widget_class->size_allocate = gtk_hscrollbar_size_allocate;
106   
107   range_class->draw_step_forw = gtk_hscrollbar_draw_step_forw;
108   range_class->draw_step_back = gtk_hscrollbar_draw_step_back;
109   range_class->slider_update = gtk_hscrollbar_slider_update;
110   range_class->trough_click = _gtk_range_default_htrough_click;
111   range_class->motion = _gtk_range_default_hmotion;
112
113   g_object_class_install_property (gobject_class,
114                                    PROP_ADJUSTMENT,
115                                    g_param_spec_object ("adjustment",
116                                                         _("Adjustment"),
117                                                         _("The GtkAdjustment that determines the values to use for this scrollbar."),
118                                                         GTK_TYPE_ADJUSTMENT,
119                                                         G_PARAM_READWRITE));
120
121 }
122
123 static void 
124 gtk_hscrollbar_set_property (GObject                    *object,
125                              guint                       prop_id,
126                              const GValue               *value,
127                              GParamSpec                 *pspec)
128 {
129   GtkHScrollbar *hscrollbar;
130   
131   hscrollbar = GTK_HSCROLLBAR (object);
132   
133   switch (prop_id)
134     {
135     case PROP_ADJUSTMENT:
136       gtk_range_set_adjustment (GTK_RANGE (hscrollbar), 
137                                 g_value_get_object (value));
138       break;
139     default:
140       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
141       break;
142     }
143 }
144
145 static void 
146 gtk_hscrollbar_get_property (GObject                    *object,
147                              guint                       prop_id,
148                              GValue                     *value,
149                              GParamSpec                 *pspec)
150 {
151   GtkHScrollbar *hscrollbar;
152   
153   hscrollbar = GTK_HSCROLLBAR (object);
154   
155   switch (prop_id)
156     {
157     case PROP_ADJUSTMENT:
158       g_value_set_object (value, G_OBJECT (hscrollbar));
159       break;
160     default:
161       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
162       break;
163     }
164 }
165
166 static void
167 gtk_hscrollbar_init (GtkHScrollbar *hscrollbar)
168 {
169 }
170
171 GtkWidget*
172 gtk_hscrollbar_new (GtkAdjustment *adjustment)
173 {
174   GtkWidget *hscrollbar;
175   
176   hscrollbar = gtk_widget_new (GTK_TYPE_HSCROLLBAR,
177                                "adjustment", adjustment,
178                                NULL);
179
180   return hscrollbar;
181 }
182
183
184 static void
185 gtk_hscrollbar_realize (GtkWidget *widget)
186 {
187   GtkRange *range;
188   GdkWindowAttr attributes;
189   gint attributes_mask;
190   gint slider_width;
191   gint trough_border;
192   gint stepper_size;
193   
194   g_return_if_fail (widget != NULL);
195   g_return_if_fail (GTK_IS_HSCROLLBAR (widget));
196   
197   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
198   range = GTK_RANGE (widget);
199   
200   _gtk_range_get_props (range, &slider_width, &trough_border,
201                         &stepper_size, NULL);
202
203   attributes.x = widget->allocation.x;
204   attributes.y = widget->allocation.y + (widget->allocation.height - widget->requisition.height) / 2;
205   attributes.width = widget->allocation.width;
206   attributes.height = widget->requisition.height;
207   attributes.wclass = GDK_INPUT_OUTPUT;
208   attributes.window_type = GDK_WINDOW_CHILD;
209   attributes.visual = gtk_widget_get_visual (widget);
210   attributes.colormap = gtk_widget_get_colormap (widget);
211   attributes.event_mask = gtk_widget_get_events (widget);
212   attributes.event_mask |= (GDK_EXPOSURE_MASK |
213                             GDK_BUTTON_PRESS_MASK |
214                             GDK_BUTTON_RELEASE_MASK |
215                             GDK_ENTER_NOTIFY_MASK |
216                             GDK_LEAVE_NOTIFY_MASK);
217   
218   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
219   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
220   
221   range->trough = widget->window;
222   gdk_window_ref (range->trough);
223   
224   attributes.x = trough_border;
225   attributes.y = trough_border;
226   attributes.width = stepper_size;
227   attributes.height = stepper_size;
228   
229   range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask);
230   
231   attributes.x = (widget->allocation.width -
232                   trough_border -
233                   stepper_size);
234   
235   range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask);
236   
237   attributes.x = 0;
238   attributes.y = trough_border;
239   attributes.width = RANGE_CLASS (widget)->min_slider_size;
240   attributes.height = slider_width;
241   
242   attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
243                             GDK_POINTER_MOTION_HINT_MASK);
244   
245   range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
246   
247   gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (widget));
248   _gtk_range_slider_update (GTK_RANGE (widget));
249   
250   widget->style = gtk_style_attach (widget->style, widget->window);
251   
252   gdk_window_set_user_data (range->trough, widget);
253   gdk_window_set_user_data (range->slider, widget);
254   gdk_window_set_user_data (range->step_forw, widget);
255   gdk_window_set_user_data (range->step_back, widget);
256   
257   gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
258   gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
259   gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
260   gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
261   
262   gdk_window_show (range->slider);
263   gdk_window_show (range->step_forw);
264   gdk_window_show (range->step_back);
265 }
266
267 static void
268 gtk_hscrollbar_size_request (GtkWidget      *widget,
269                              GtkRequisition *requisition)
270 {
271   gint slider_width;
272   gint trough_border;
273   gint stepper_size;
274   gint stepper_spacing;
275   
276   GtkRange *range = GTK_RANGE (widget);
277
278   _gtk_range_get_props (range, &slider_width, &trough_border, 
279                         &stepper_size, &stepper_spacing);
280   
281   requisition->width = (RANGE_CLASS (widget)->min_slider_size +
282                         stepper_size +
283                         stepper_spacing +
284                         trough_border) * 2;
285   requisition->height = (slider_width +
286                          trough_border * 2);
287 }
288
289 static void
290 gtk_hscrollbar_size_allocate (GtkWidget     *widget,
291                               GtkAllocation *allocation)
292 {
293   GtkRange *range;
294   gint trough_border;
295   gint stepper_size;
296   
297   g_return_if_fail (widget != NULL);
298   g_return_if_fail (GTK_IS_HSCROLLBAR (widget));
299   g_return_if_fail (allocation != NULL);
300   
301   widget->allocation = *allocation;
302   if (GTK_WIDGET_REALIZED (widget))
303     {
304       range = GTK_RANGE (widget);
305       
306       _gtk_range_get_props (range, NULL, &trough_border, 
307                             &stepper_size, NULL);
308   
309       gdk_window_move_resize (range->trough,
310                               allocation->x,
311                               allocation->y + (allocation->height - widget->requisition.height) / 2,
312                               allocation->width, widget->requisition.height);
313       gdk_window_move_resize (range->step_back,
314                               trough_border,
315                               trough_border,
316                               stepper_size,
317                               widget->requisition.height - trough_border * 2);
318       gdk_window_move_resize (range->step_forw,
319                               allocation->width - trough_border -
320                               stepper_size,
321                               trough_border,
322                               stepper_size,
323                               widget->requisition.height - trough_border * 2);
324       
325       _gtk_range_slider_update (GTK_RANGE (widget));
326     }
327 }
328
329 static void
330 gtk_hscrollbar_draw_step_forw (GtkRange *range)
331 {
332   GtkStateType state_type;
333   GtkShadowType shadow_type;
334   
335   g_return_if_fail (range != NULL);
336   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
337   
338   if (GTK_WIDGET_DRAWABLE (range))
339     {
340       if (range->in_child == RANGE_CLASS (range)->step_forw)
341         {
342           if (range->click_child == RANGE_CLASS (range)->step_forw)
343             state_type = GTK_STATE_ACTIVE;
344           else
345             state_type = GTK_STATE_PRELIGHT;
346         }
347       else
348         state_type = GTK_STATE_NORMAL;
349       
350       if (range->click_child == RANGE_CLASS (range)->step_forw)
351         shadow_type = GTK_SHADOW_IN;
352       else
353         shadow_type = GTK_SHADOW_OUT;
354       
355       gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw,
356                        state_type, shadow_type, 
357                        NULL, GTK_WIDGET (range), "hscrollbar",
358                        GTK_ARROW_RIGHT,
359                        TRUE, 0, 0, -1, -1);
360     }
361 }
362
363 static void
364 gtk_hscrollbar_draw_step_back (GtkRange *range)
365 {
366   GtkStateType state_type;
367   GtkShadowType shadow_type;
368   
369   g_return_if_fail (range != NULL);
370   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
371   
372   if (GTK_WIDGET_DRAWABLE (range))
373     {
374       if (range->in_child == RANGE_CLASS (range)->step_back)
375         {
376           if (range->click_child == RANGE_CLASS (range)->step_back)
377             state_type = GTK_STATE_ACTIVE;
378           else
379             state_type = GTK_STATE_PRELIGHT;
380         }
381       else
382         state_type = GTK_STATE_NORMAL;
383       
384       if (range->click_child == RANGE_CLASS (range)->step_back)
385         shadow_type = GTK_SHADOW_IN;
386       else
387         shadow_type = GTK_SHADOW_OUT;
388       
389       gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back,
390                        state_type, shadow_type, 
391                        NULL, GTK_WIDGET (range), "hscrollbar",
392                        GTK_ARROW_LEFT,
393                        TRUE, 0, 0, -1, -1);
394     }
395 }
396
397 static void
398 gtk_hscrollbar_slider_update (GtkRange *range)
399 {
400   g_return_if_fail (range != NULL);
401   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
402   
403   gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (range));
404   _gtk_range_default_hslider_update (range);
405 }
406
407 static void
408 gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar)
409 {
410   GtkRange *range;
411   gint step_back_x;
412   gint step_back_width;
413   gint step_forw_x;
414   gint slider_width;
415   gint slider_height;
416   gint stepper_spacing;
417   gint left, right;
418   gint width;
419   
420   g_return_if_fail (hscrollbar != NULL);
421   g_return_if_fail (GTK_IS_HSCROLLBAR (hscrollbar));
422
423   if (GTK_WIDGET_REALIZED (hscrollbar))
424     {
425       range = GTK_RANGE (hscrollbar);
426
427       _gtk_range_get_props (range, NULL, NULL, NULL, &stepper_spacing);
428       
429       gdk_window_get_size (range->step_back, &step_back_width, NULL);
430       gdk_window_get_position (range->step_back, &step_back_x, NULL);
431       gdk_window_get_position (range->step_forw, &step_forw_x, NULL);
432       
433       left = (step_back_x +
434               step_back_width +
435               stepper_spacing);
436       right = step_forw_x - stepper_spacing;
437       width = right - left;
438       
439       if ((range->adjustment->page_size > 0) &&
440           (range->adjustment->lower != range->adjustment->upper))
441         {
442           if (range->adjustment->page_size >
443               (range->adjustment->upper - range->adjustment->lower))
444             range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower;
445           
446           width = (width * range->adjustment->page_size /
447                    (range->adjustment->upper - range->adjustment->lower));
448           
449           if (width < RANGE_CLASS (hscrollbar)->min_slider_size)
450             width = RANGE_CLASS (hscrollbar)->min_slider_size;
451         }
452       
453       gdk_window_get_size (range->slider, &slider_width, &slider_height);
454       
455       if (slider_width != width)
456         {
457           gdk_window_resize (range->slider, width, slider_height);
458           gdk_window_invalidate_rect (range->slider, NULL, FALSE);
459         }
460     }
461 }