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