]> Pileus Git - ~andy/gtk/blob - gtk/gtkhscrollbar.c
remove validation idle
[~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
31
32 #define EPSILON 0.01
33
34 #define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
35
36 enum {
37   ARG_0,
38   ARG_ADJUSTMENT
39 };
40
41 static void gtk_hscrollbar_class_init       (GtkHScrollbarClass *klass);
42 static void gtk_hscrollbar_init             (GtkHScrollbar      *hscrollbar);
43 static void gtk_hscrollbar_set_arg          (GtkObject          *object,
44                                              GtkArg             *arg,
45                                              guint               arg_id);
46 static void gtk_hscrollbar_get_arg          (GtkObject          *object,
47                                              GtkArg             *arg,
48                                              guint               arg_id);
49 static void gtk_hscrollbar_realize          (GtkWidget          *widget);
50 static void gtk_hscrollbar_size_allocate    (GtkWidget          *widget,
51                                              GtkAllocation      *allocation);
52 static void gtk_hscrollbar_draw_step_forw   (GtkRange           *range);
53 static void gtk_hscrollbar_draw_step_back   (GtkRange           *range);
54 static void gtk_hscrollbar_slider_update    (GtkRange           *range);
55 static void gtk_hscrollbar_calc_slider_size (GtkHScrollbar      *hscrollbar);
56 static gint gtk_hscrollbar_trough_keys      (GtkRange *range,
57                                              GdkEventKey *key,
58                                              GtkScrollType *scroll,
59                                              GtkTroughType *pos);
60
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   GtkObjectClass *object_class;
91   GtkWidgetClass *widget_class;
92   GtkRangeClass *range_class;
93   
94   object_class = (GtkObjectClass*) class;
95   widget_class = (GtkWidgetClass*) class;
96   range_class = (GtkRangeClass*) class;
97   
98   gtk_object_add_arg_type ("GtkHScrollbar::adjustment",
99                            GTK_TYPE_ADJUSTMENT,
100                            GTK_ARG_READWRITE,
101                            ARG_ADJUSTMENT);
102   
103   object_class->set_arg = gtk_hscrollbar_set_arg;
104   object_class->get_arg = gtk_hscrollbar_get_arg;
105   
106   widget_class->realize = gtk_hscrollbar_realize;
107   widget_class->size_allocate = gtk_hscrollbar_size_allocate;
108   
109   range_class->draw_step_forw = gtk_hscrollbar_draw_step_forw;
110   range_class->draw_step_back = gtk_hscrollbar_draw_step_back;
111   range_class->slider_update = gtk_hscrollbar_slider_update;
112   range_class->trough_click = gtk_range_default_htrough_click;
113   range_class->trough_keys = gtk_hscrollbar_trough_keys;
114   range_class->motion = gtk_range_default_hmotion;
115 }
116
117 static void
118 gtk_hscrollbar_set_arg (GtkObject          *object,
119                         GtkArg             *arg,
120                         guint               arg_id)
121 {
122   GtkHScrollbar *hscrollbar;
123   
124   hscrollbar = GTK_HSCROLLBAR (object);
125   
126   switch (arg_id)
127     {
128     case ARG_ADJUSTMENT:
129       gtk_range_set_adjustment (GTK_RANGE (hscrollbar), GTK_VALUE_POINTER (*arg));
130       break;
131     default:
132       break;
133     }
134 }
135
136 static void
137 gtk_hscrollbar_get_arg (GtkObject          *object,
138                         GtkArg             *arg,
139                         guint               arg_id)
140 {
141   GtkHScrollbar *hscrollbar;
142   
143   hscrollbar = GTK_HSCROLLBAR (object);
144   
145   switch (arg_id)
146     {
147     case ARG_ADJUSTMENT:
148       GTK_VALUE_POINTER (*arg) = GTK_RANGE (hscrollbar);
149       break;
150     default:
151       arg->type = GTK_TYPE_INVALID;
152       break;
153     }
154 }
155
156 static void
157 gtk_hscrollbar_init (GtkHScrollbar *hscrollbar)
158 {
159   GtkWidget *widget;
160   GtkRequisition *requisition;
161   
162   widget = GTK_WIDGET (hscrollbar);
163   requisition = &widget->requisition;
164   
165   requisition->width = (RANGE_CLASS (widget)->min_slider_size +
166                         RANGE_CLASS (widget)->stepper_size +
167                         RANGE_CLASS (widget)->stepper_slider_spacing +
168                         widget->style->xthickness) * 2;
169   requisition->height = (RANGE_CLASS (widget)->slider_width +
170                          widget->style->ythickness * 2);
171 }
172
173 GtkWidget*
174 gtk_hscrollbar_new (GtkAdjustment *adjustment)
175 {
176   GtkWidget *hscrollbar;
177   
178   hscrollbar = gtk_widget_new (GTK_TYPE_HSCROLLBAR,
179                                "adjustment", adjustment,
180                                NULL);
181
182   return hscrollbar;
183 }
184
185
186 static void
187 gtk_hscrollbar_realize (GtkWidget *widget)
188 {
189   GtkRange *range;
190   GdkWindowAttr attributes;
191   gint attributes_mask;
192   
193   g_return_if_fail (widget != NULL);
194   g_return_if_fail (GTK_IS_HSCROLLBAR (widget));
195   
196   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
197   range = GTK_RANGE (widget);
198   
199   attributes.x = widget->allocation.x;
200   attributes.y = widget->allocation.y + (widget->allocation.height - widget->requisition.height) / 2;
201   attributes.width = widget->allocation.width;
202   attributes.height = widget->requisition.height;
203   attributes.wclass = GDK_INPUT_OUTPUT;
204   attributes.window_type = GDK_WINDOW_CHILD;
205   attributes.visual = gtk_widget_get_visual (widget);
206   attributes.colormap = gtk_widget_get_colormap (widget);
207   attributes.event_mask = gtk_widget_get_events (widget);
208   attributes.event_mask |= (GDK_EXPOSURE_MASK |
209                             GDK_BUTTON_PRESS_MASK |
210                             GDK_BUTTON_RELEASE_MASK |
211                             GDK_ENTER_NOTIFY_MASK |
212                             GDK_LEAVE_NOTIFY_MASK);
213   
214   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
215   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
216   
217   range->trough = widget->window;
218   gdk_window_ref (range->trough);
219   
220   attributes.x = widget->style->xthickness;
221   attributes.y = widget->style->ythickness;
222   attributes.width = RANGE_CLASS (widget)->stepper_size;
223   attributes.height = RANGE_CLASS (widget)->stepper_size;
224   
225   range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask);
226   
227   attributes.x = (widget->allocation.width -
228                   widget->style->xthickness -
229                   RANGE_CLASS (widget)->stepper_size);
230   
231   range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask);
232   
233   attributes.x = 0;
234   attributes.y = widget->style->ythickness;
235   attributes.width = RANGE_CLASS (widget)->min_slider_size;
236   attributes.height = RANGE_CLASS (widget)->slider_width;
237   attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
238                             GDK_POINTER_MOTION_HINT_MASK);
239   
240   range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
241   
242   gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (widget));
243   gtk_range_slider_update (GTK_RANGE (widget));
244   
245   widget->style = gtk_style_attach (widget->style, widget->window);
246   
247   gdk_window_set_user_data (range->trough, widget);
248   gdk_window_set_user_data (range->slider, widget);
249   gdk_window_set_user_data (range->step_forw, widget);
250   gdk_window_set_user_data (range->step_back, widget);
251   
252   gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
253   gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
254   gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
255   gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
256   
257   gdk_window_show (range->slider);
258   gdk_window_show (range->step_forw);
259   gdk_window_show (range->step_back);
260 }
261
262 static void
263 gtk_hscrollbar_size_allocate (GtkWidget     *widget,
264                               GtkAllocation *allocation)
265 {
266   GtkRange *range;
267   
268   g_return_if_fail (widget != NULL);
269   g_return_if_fail (GTK_IS_HSCROLLBAR (widget));
270   g_return_if_fail (allocation != NULL);
271   
272   widget->allocation = *allocation;
273   if (GTK_WIDGET_REALIZED (widget))
274     {
275       range = GTK_RANGE (widget);
276       
277       gdk_window_move_resize (range->trough,
278                               allocation->x,
279                               allocation->y + (allocation->height - widget->requisition.height) / 2,
280                               allocation->width, widget->requisition.height);
281       gdk_window_move_resize (range->step_back,
282                               widget->style->xthickness,
283                               widget->style->ythickness,
284                               RANGE_CLASS (widget)->stepper_size,
285                               widget->requisition.height - widget->style->ythickness * 2);
286       gdk_window_move_resize (range->step_forw,
287                               allocation->width - widget->style->xthickness -
288                               RANGE_CLASS (widget)->stepper_size,
289                               widget->style->ythickness,
290                               RANGE_CLASS (widget)->stepper_size,
291                               widget->requisition.height - widget->style->ythickness * 2);
292       
293       gtk_range_slider_update (GTK_RANGE (widget));
294     }
295 }
296
297 static void
298 gtk_hscrollbar_draw_step_forw (GtkRange *range)
299 {
300   GtkStateType state_type;
301   GtkShadowType shadow_type;
302   
303   g_return_if_fail (range != NULL);
304   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
305   
306   if (GTK_WIDGET_DRAWABLE (range))
307     {
308       if (range->in_child == RANGE_CLASS (range)->step_forw)
309         {
310           if (range->click_child == RANGE_CLASS (range)->step_forw)
311             state_type = GTK_STATE_ACTIVE;
312           else
313             state_type = GTK_STATE_PRELIGHT;
314         }
315       else
316         state_type = GTK_STATE_NORMAL;
317       
318       if (range->click_child == RANGE_CLASS (range)->step_forw)
319         shadow_type = GTK_SHADOW_IN;
320       else
321         shadow_type = GTK_SHADOW_OUT;
322       
323       gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw,
324                        state_type, shadow_type, 
325                        NULL, GTK_WIDGET (range), "hscrollbar",
326                        GTK_ARROW_RIGHT,
327                        TRUE, 0, 0, -1, -1);
328     }
329 }
330
331 static void
332 gtk_hscrollbar_draw_step_back (GtkRange *range)
333 {
334   GtkStateType state_type;
335   GtkShadowType shadow_type;
336   
337   g_return_if_fail (range != NULL);
338   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
339   
340   if (GTK_WIDGET_DRAWABLE (range))
341     {
342       if (range->in_child == RANGE_CLASS (range)->step_back)
343         {
344           if (range->click_child == RANGE_CLASS (range)->step_back)
345             state_type = GTK_STATE_ACTIVE;
346           else
347             state_type = GTK_STATE_PRELIGHT;
348         }
349       else
350         state_type = GTK_STATE_NORMAL;
351       
352       if (range->click_child == RANGE_CLASS (range)->step_back)
353         shadow_type = GTK_SHADOW_IN;
354       else
355         shadow_type = GTK_SHADOW_OUT;
356       
357       gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back,
358                        state_type, shadow_type, 
359                        NULL, GTK_WIDGET (range), "hscrollbar",
360                        GTK_ARROW_LEFT,
361                        TRUE, 0, 0, -1, -1);
362     }
363 }
364
365 static void
366 gtk_hscrollbar_slider_update (GtkRange *range)
367 {
368   g_return_if_fail (range != NULL);
369   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
370   
371   gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (range));
372   gtk_range_default_hslider_update (range);
373 }
374
375 static void
376 gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar)
377 {
378   GtkRange *range;
379   gint step_back_x;
380   gint step_back_width;
381   gint step_forw_x;
382   gint slider_width;
383   gint slider_height;
384   gint left, right;
385   gint width;
386   
387   g_return_if_fail (hscrollbar != NULL);
388   g_return_if_fail (GTK_IS_HSCROLLBAR (hscrollbar));
389   
390   if (GTK_WIDGET_REALIZED (hscrollbar))
391     {
392       range = GTK_RANGE (hscrollbar);
393       
394       gdk_window_get_size (range->step_back, &step_back_width, NULL);
395       gdk_window_get_position (range->step_back, &step_back_x, NULL);
396       gdk_window_get_position (range->step_forw, &step_forw_x, NULL);
397       
398       left = (step_back_x +
399               step_back_width +
400               RANGE_CLASS (hscrollbar)->stepper_slider_spacing);
401       right = step_forw_x - RANGE_CLASS (hscrollbar)->stepper_slider_spacing;
402       width = right - left;
403       
404       if ((range->adjustment->page_size > 0) &&
405           (range->adjustment->lower != range->adjustment->upper))
406         {
407           if (range->adjustment->page_size >
408               (range->adjustment->upper - range->adjustment->lower))
409             range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower;
410           
411           width = (width * range->adjustment->page_size /
412                    (range->adjustment->upper - range->adjustment->lower));
413           
414           if (width < RANGE_CLASS (hscrollbar)->min_slider_size)
415             width = RANGE_CLASS (hscrollbar)->min_slider_size;
416         }
417       
418       gdk_window_get_size (range->slider, &slider_width, &slider_height);
419       
420       if (slider_width != width)
421         {
422           gdk_window_resize (range->slider, width, slider_height);
423           gdk_window_invalidate_rect (range->slider, NULL, FALSE);
424         }
425     }
426 }
427
428 static gint
429 gtk_hscrollbar_trough_keys(GtkRange *range,
430                            GdkEventKey *key,
431                            GtkScrollType *scroll,
432                            GtkTroughType *pos)
433 {
434   gint return_val = FALSE;
435   switch (key->keyval)
436     {
437     case GDK_Left:
438       return_val = TRUE;
439       *scroll = GTK_SCROLL_STEP_BACKWARD;
440       break;
441     case GDK_Right:
442       return_val = TRUE;
443       *scroll = GTK_SCROLL_STEP_FORWARD;
444       break;
445     case GDK_Home:
446       return_val = TRUE;
447       if (key->state & GDK_CONTROL_MASK)
448         *scroll = GTK_SCROLL_PAGE_BACKWARD;
449       else
450         *pos = GTK_TROUGH_START;
451       break;
452     case GDK_End:
453       return_val = TRUE;
454       if (key->state & GDK_CONTROL_MASK)
455         *scroll = GTK_SCROLL_PAGE_FORWARD;
456       else
457         *pos = GTK_TROUGH_END;
458       break;
459     }
460   return return_val;
461 }