]> Pileus Git - ~andy/gtk/blob - gtk/gtkhscrollbar.c
Merges from gtk-1-2
[~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
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  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_CLASS (GTK_OBJECT (w)->klass)
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 | GTK_ARG_CONSTRUCT,
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->klass->xthickness) * 2;
169   requisition->height = (RANGE_CLASS (widget)->slider_width +
170                          widget->style->klass->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->klass->xthickness;
221   attributes.y = widget->style->klass->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->klass->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->klass->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->klass->xthickness,
283                               widget->style->klass->ythickness,
284                               RANGE_CLASS (widget)->stepper_size,
285                               widget->requisition.height - widget->style->klass->ythickness * 2);
286       gdk_window_move_resize (range->step_forw,
287                               allocation->width - widget->style->klass->xthickness -
288                               RANGE_CLASS (widget)->stepper_size,
289                               widget->style->klass->ythickness,
290                               RANGE_CLASS (widget)->stepper_size,
291                               widget->requisition.height - widget->style->klass->ythickness * 2);
292       gdk_window_resize (range->slider,
293                          RANGE_CLASS (widget)->min_slider_size,
294                          widget->requisition.height - widget->style->klass->ythickness * 2);
295       
296       gtk_range_slider_update (GTK_RANGE (widget));
297     }
298 }
299
300 static void
301 gtk_hscrollbar_draw_step_forw (GtkRange *range)
302 {
303   GtkStateType state_type;
304   GtkShadowType shadow_type;
305   
306   g_return_if_fail (range != NULL);
307   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
308   
309   if (GTK_WIDGET_DRAWABLE (range))
310     {
311       if (range->in_child == RANGE_CLASS (range)->step_forw)
312         {
313           if (range->click_child == RANGE_CLASS (range)->step_forw)
314             state_type = GTK_STATE_ACTIVE;
315           else
316             state_type = GTK_STATE_PRELIGHT;
317         }
318       else
319         state_type = GTK_STATE_NORMAL;
320       
321       if (range->click_child == RANGE_CLASS (range)->step_forw)
322         shadow_type = GTK_SHADOW_IN;
323       else
324         shadow_type = GTK_SHADOW_OUT;
325       
326       gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw,
327                        state_type, shadow_type, 
328                        NULL, GTK_WIDGET (range), "hscrollbar",
329                        GTK_ARROW_RIGHT,
330                        TRUE, 0, 0, -1, -1);
331     }
332 }
333
334 static void
335 gtk_hscrollbar_draw_step_back (GtkRange *range)
336 {
337   GtkStateType state_type;
338   GtkShadowType shadow_type;
339   
340   g_return_if_fail (range != NULL);
341   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
342   
343   if (GTK_WIDGET_DRAWABLE (range))
344     {
345       if (range->in_child == RANGE_CLASS (range)->step_back)
346         {
347           if (range->click_child == RANGE_CLASS (range)->step_back)
348             state_type = GTK_STATE_ACTIVE;
349           else
350             state_type = GTK_STATE_PRELIGHT;
351         }
352       else
353         state_type = GTK_STATE_NORMAL;
354       
355       if (range->click_child == RANGE_CLASS (range)->step_back)
356         shadow_type = GTK_SHADOW_IN;
357       else
358         shadow_type = GTK_SHADOW_OUT;
359       
360       gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back,
361                        state_type, shadow_type, 
362                        NULL, GTK_WIDGET (range), "hscrollbar",
363                        GTK_ARROW_LEFT,
364                        TRUE, 0, 0, -1, -1);
365     }
366 }
367
368 static void
369 gtk_hscrollbar_slider_update (GtkRange *range)
370 {
371   g_return_if_fail (range != NULL);
372   g_return_if_fail (GTK_IS_HSCROLLBAR (range));
373   
374   gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (range));
375   gtk_range_default_hslider_update (range);
376 }
377
378 static void
379 gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar)
380 {
381   GtkRange *range;
382   gint step_back_x;
383   gint step_back_width;
384   gint step_forw_x;
385   gint slider_width;
386   gint slider_height;
387   gint left, right;
388   gint width;
389   
390   g_return_if_fail (hscrollbar != NULL);
391   g_return_if_fail (GTK_IS_HSCROLLBAR (hscrollbar));
392   
393   if (GTK_WIDGET_REALIZED (hscrollbar))
394     {
395       range = GTK_RANGE (hscrollbar);
396       
397       gdk_window_get_size (range->step_back, &step_back_width, NULL);
398       gdk_window_get_position (range->step_back, &step_back_x, NULL);
399       gdk_window_get_position (range->step_forw, &step_forw_x, NULL);
400       
401       left = (step_back_x +
402               step_back_width +
403               RANGE_CLASS (hscrollbar)->stepper_slider_spacing);
404       right = step_forw_x - RANGE_CLASS (hscrollbar)->stepper_slider_spacing;
405       width = right - left;
406       
407       if ((range->adjustment->page_size > 0) &&
408           (range->adjustment->lower != range->adjustment->upper))
409         {
410           if (range->adjustment->page_size >
411               (range->adjustment->upper - range->adjustment->lower))
412             range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower;
413           
414           width = (width * range->adjustment->page_size /
415                    (range->adjustment->upper - range->adjustment->lower));
416           
417           if (width < RANGE_CLASS (hscrollbar)->min_slider_size)
418             width = RANGE_CLASS (hscrollbar)->min_slider_size;
419         }
420       
421       gdk_window_get_size (range->slider, &slider_width, &slider_height);
422       
423       if (slider_width != width)
424         gdk_window_resize (range->slider, width, slider_height);
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 }