]> Pileus Git - ~andy/gtk/blob - gtk/gtkvscrollbar.c
call the base class init fucntions from all parent types upon class
[~andy/gtk] / gtk / gtkvscrollbar.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 "gtkvscrollbar.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
29 static void gtk_vscrollbar_class_init       (GtkVScrollbarClass *klass);
30 static void gtk_vscrollbar_init             (GtkVScrollbar      *vscrollbar);
31 static void gtk_vscrollbar_realize          (GtkWidget          *widget);
32 static void gtk_vscrollbar_size_allocate    (GtkWidget          *widget,
33                                              GtkAllocation      *allocation);
34 static void gtk_vscrollbar_draw_step_forw   (GtkRange           *range);
35 static void gtk_vscrollbar_draw_step_back   (GtkRange           *range);
36 static void gtk_vscrollbar_slider_update    (GtkRange           *range);
37 static void gtk_vscrollbar_calc_slider_size (GtkVScrollbar      *vscrollbar);
38 static gint gtk_vscrollbar_trough_keys      (GtkRange *range,
39                                              GdkEventKey *key,
40                                              GtkScrollType *scroll,
41                                              GtkTroughType *pos);
42
43 guint
44 gtk_vscrollbar_get_type (void)
45 {
46   static guint vscrollbar_type = 0;
47
48   if (!vscrollbar_type)
49     {
50       GtkTypeInfo vscrollbar_info =
51       {
52         "GtkVScrollbar",
53         sizeof (GtkVScrollbar),
54         sizeof (GtkVScrollbarClass),
55         (GtkClassInitFunc) gtk_vscrollbar_class_init,
56         (GtkObjectInitFunc) gtk_vscrollbar_init,
57         /* reversed_1 */ NULL,
58         /* reversed_2 */ NULL,
59         (GtkClassInitFunc) NULL,
60       };
61
62       vscrollbar_type = gtk_type_unique (gtk_scrollbar_get_type (), &vscrollbar_info);
63     }
64
65   return vscrollbar_type;
66 }
67
68 static void
69 gtk_vscrollbar_class_init (GtkVScrollbarClass *klass)
70 {
71   GtkWidgetClass *widget_class;
72   GtkRangeClass *range_class;
73
74   widget_class = (GtkWidgetClass*) klass;
75   range_class = (GtkRangeClass*) klass;
76
77   widget_class->realize = gtk_vscrollbar_realize;
78   widget_class->size_allocate = gtk_vscrollbar_size_allocate;
79
80   range_class->draw_step_forw = gtk_vscrollbar_draw_step_forw;
81   range_class->draw_step_back = gtk_vscrollbar_draw_step_back;
82   range_class->slider_update = gtk_vscrollbar_slider_update;
83   range_class->trough_click = gtk_range_default_vtrough_click;
84   range_class->trough_keys = gtk_vscrollbar_trough_keys;
85   range_class->motion = gtk_range_default_vmotion;
86 }
87
88 static void
89 gtk_vscrollbar_init (GtkVScrollbar *vscrollbar)
90 {
91   GtkWidget *widget;
92   GtkRequisition *requisition;
93
94   widget = GTK_WIDGET (vscrollbar);
95   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
96   requisition = &widget->requisition;
97
98   requisition->width = (RANGE_CLASS (widget)->slider_width +
99                         widget->style->klass->xthickness * 2);
100   requisition->height = (RANGE_CLASS (widget)->min_slider_size +
101                          RANGE_CLASS (widget)->stepper_size +
102                          RANGE_CLASS (widget)->stepper_slider_spacing +
103                          widget->style->klass->ythickness) * 2;
104 }
105
106 GtkWidget*
107 gtk_vscrollbar_new (GtkAdjustment *adjustment)
108 {
109   GtkVScrollbar *vscrollbar;
110
111   vscrollbar = gtk_type_new (gtk_vscrollbar_get_type ());
112
113   if (!adjustment)
114     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
115
116   gtk_range_set_adjustment (GTK_RANGE (vscrollbar), adjustment);
117
118   return GTK_WIDGET (vscrollbar);
119 }
120
121
122 static void
123 gtk_vscrollbar_realize (GtkWidget *widget)
124 {
125   GtkRange *range;
126   GdkWindowAttr attributes;
127   gint attributes_mask;
128
129   g_return_if_fail (widget != NULL);
130   g_return_if_fail (GTK_IS_VSCROLLBAR (widget));
131
132   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
133   range = GTK_RANGE (widget);
134
135   attributes.x = widget->allocation.x + (widget->allocation.width - widget->requisition.width) / 2;
136   attributes.y = widget->allocation.y;
137   attributes.width = widget->requisition.width;
138   attributes.height = widget->allocation.height;
139   attributes.wclass = GDK_INPUT_OUTPUT;
140   attributes.window_type = GDK_WINDOW_CHILD;
141   attributes.visual = gtk_widget_get_visual (widget);
142   attributes.colormap = gtk_widget_get_colormap (widget);
143   attributes.event_mask = gtk_widget_get_events (widget);
144   attributes.event_mask |= (GDK_EXPOSURE_MASK |
145                             GDK_BUTTON_PRESS_MASK |
146                             GDK_BUTTON_RELEASE_MASK |
147                             GDK_ENTER_NOTIFY_MASK |
148                             GDK_LEAVE_NOTIFY_MASK);
149
150   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
151   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
152
153   range->trough = widget->window;
154   gdk_window_ref (range->trough);
155
156   attributes.x = widget->style->klass->xthickness;
157   attributes.y = widget->style->klass->ythickness;
158   attributes.width = RANGE_CLASS (widget)->stepper_size;
159   attributes.height = RANGE_CLASS (widget)->stepper_size;
160
161   range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask);
162
163   attributes.y = (widget->allocation.height -
164                   widget->style->klass->ythickness -
165                   RANGE_CLASS (widget)->stepper_size);
166
167   range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask);
168
169   attributes.x = widget->style->klass->ythickness;
170   attributes.y = 0;
171   attributes.width = RANGE_CLASS (widget)->slider_width;
172   attributes.height = RANGE_CLASS (widget)->min_slider_size;
173   attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
174                             GDK_POINTER_MOTION_HINT_MASK);
175
176   range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
177
178   gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (widget));
179   gtk_range_slider_update (GTK_RANGE (widget));
180
181   widget->style = gtk_style_attach (widget->style, widget->window);
182
183   gdk_window_set_user_data (range->trough, widget);
184   gdk_window_set_user_data (range->slider, widget);
185   gdk_window_set_user_data (range->step_forw, widget);
186   gdk_window_set_user_data (range->step_back, widget);
187
188   gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
189   gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
190   gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
191   gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
192
193   gdk_window_show (range->slider);
194   gdk_window_show (range->step_forw);
195   gdk_window_show (range->step_back);
196 }
197
198 static void
199 gtk_vscrollbar_size_allocate (GtkWidget     *widget,
200                               GtkAllocation *allocation)
201 {
202   GtkRange *range;
203
204   g_return_if_fail (widget != NULL);
205   g_return_if_fail (GTK_IS_VSCROLLBAR (widget));
206   g_return_if_fail (allocation != NULL);
207
208   widget->allocation = *allocation;
209   if (GTK_WIDGET_REALIZED (widget))
210     {
211       range = GTK_RANGE (widget);
212
213       gdk_window_move_resize (range->trough,
214                               allocation->x + (allocation->width - widget->requisition.width) / 2,
215                               allocation->y,
216                               widget->requisition.width, allocation->height);
217       gdk_window_move_resize (range->step_back,
218                               widget->style->klass->xthickness,
219                               widget->style->klass->ythickness,
220                               widget->requisition.width - widget->style->klass->xthickness * 2,
221                               RANGE_CLASS (widget)->stepper_size);
222       gdk_window_move_resize (range->step_forw,
223                               widget->style->klass->xthickness,
224                               allocation->height - widget->style->klass->ythickness -
225                               RANGE_CLASS (widget)->stepper_size,
226                               widget->requisition.width - widget->style->klass->xthickness * 2,
227                               RANGE_CLASS (widget)->stepper_size);
228       gdk_window_resize (range->slider,
229                          widget->requisition.width - widget->style->klass->xthickness * 2,
230                          RANGE_CLASS (range)->min_slider_size);
231
232       gtk_range_slider_update (GTK_RANGE (widget));
233     }
234 }
235
236 static void
237 gtk_vscrollbar_draw_step_forw (GtkRange *range)
238 {
239   GtkStateType state_type;
240   GtkShadowType shadow_type;
241
242   g_return_if_fail (range != NULL);
243   g_return_if_fail (GTK_IS_VSCROLLBAR (range));
244
245   if (GTK_WIDGET_DRAWABLE (range))
246     {
247       if (range->in_child == RANGE_CLASS (range)->step_forw)
248         {
249           if (range->click_child == RANGE_CLASS (range)->step_forw)
250             state_type = GTK_STATE_ACTIVE;
251           else
252             state_type = GTK_STATE_PRELIGHT;
253         }
254       else
255         state_type = GTK_STATE_NORMAL;
256
257       if (range->click_child == RANGE_CLASS (range)->step_forw)
258         shadow_type = GTK_SHADOW_IN;
259       else
260         shadow_type = GTK_SHADOW_OUT;
261
262       gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_forw,
263                       state_type, shadow_type, GTK_ARROW_DOWN,
264                       TRUE, 0, 0, -1, -1);
265     }
266 }
267
268 static void
269 gtk_vscrollbar_draw_step_back (GtkRange *range)
270 {
271   GtkStateType state_type;
272   GtkShadowType shadow_type;
273
274   g_return_if_fail (range != NULL);
275   g_return_if_fail (GTK_IS_VSCROLLBAR (range));
276
277   if (GTK_WIDGET_DRAWABLE (range))
278     {
279       if (range->in_child == RANGE_CLASS (range)->step_back)
280         {
281           if (range->click_child == RANGE_CLASS (range)->step_back)
282             state_type = GTK_STATE_ACTIVE;
283           else
284             state_type = GTK_STATE_PRELIGHT;
285         }
286       else
287         state_type = GTK_STATE_NORMAL;
288
289       if (range->click_child == RANGE_CLASS (range)->step_back)
290         shadow_type = GTK_SHADOW_IN;
291       else
292         shadow_type = GTK_SHADOW_OUT;
293
294       gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_back,
295                       state_type, shadow_type, GTK_ARROW_UP,
296                       TRUE, 0, 0, -1, -1);
297     }
298 }
299
300 static void
301 gtk_vscrollbar_slider_update (GtkRange *range)
302 {
303   g_return_if_fail (range != NULL);
304   g_return_if_fail (GTK_IS_VSCROLLBAR (range));
305
306   gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (range));
307   gtk_range_default_vslider_update (range);
308 }
309
310 static void
311 gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar)
312 {
313   GtkRange *range;
314   gint step_back_y;
315   gint step_back_height;
316   gint step_forw_y;
317   gint slider_width;
318   gint slider_height;
319   gint top, bottom;
320   gint height;
321
322   g_return_if_fail (vscrollbar != NULL);
323   g_return_if_fail (GTK_IS_VSCROLLBAR (vscrollbar));
324
325   if (GTK_WIDGET_REALIZED (vscrollbar))
326     {
327       range = GTK_RANGE (vscrollbar);
328
329       gdk_window_get_size (range->step_back, NULL, &step_back_height);
330       gdk_window_get_position (range->step_back, NULL, &step_back_y);
331       gdk_window_get_position (range->step_forw, NULL, &step_forw_y);
332
333       top = (step_back_y +
334               step_back_height +
335              RANGE_CLASS (vscrollbar)->stepper_slider_spacing);
336       bottom = step_forw_y - RANGE_CLASS (vscrollbar)->stepper_slider_spacing;
337       height = bottom - top;
338
339       if ((range->adjustment->page_size > 0) &&
340           (range->adjustment->lower != range->adjustment->upper))
341         {
342           if (range->adjustment->page_size >
343               (range->adjustment->upper - range->adjustment->lower))
344             range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower;
345
346           height = (height * range->adjustment->page_size /
347                    (range->adjustment->upper - range->adjustment->lower));
348
349           if (height < RANGE_CLASS (vscrollbar)->min_slider_size)
350             height = RANGE_CLASS (vscrollbar)->min_slider_size;
351         }
352
353       gdk_window_get_size (range->slider, &slider_width, &slider_height);
354
355       if (slider_height != height)
356         gdk_window_resize (range->slider, slider_width, height);
357     }
358 }
359
360 static gint
361 gtk_vscrollbar_trough_keys(GtkRange *range,
362                            GdkEventKey *key,
363                            GtkScrollType *scroll,
364                            GtkTroughType *pos)
365 {
366   gint return_val = FALSE;
367   switch (key->keyval)
368     {
369     case GDK_Up:
370       return_val = TRUE;
371       *scroll = GTK_SCROLL_STEP_BACKWARD;
372       break;
373     case GDK_Down:
374       return_val = TRUE;
375       *scroll = GTK_SCROLL_STEP_FORWARD;
376       break;
377     case GDK_Page_Up:
378       return_val = TRUE;
379       if (key->state & GDK_CONTROL_MASK)
380         *pos = GTK_TROUGH_START;
381       else
382         *scroll = GTK_SCROLL_PAGE_BACKWARD;
383       break;
384     case GDK_Page_Down:
385       return_val = TRUE;
386       if (key->state & GDK_CONTROL_MASK)
387         *pos = GTK_TROUGH_END;
388       else
389         *scroll = GTK_SCROLL_PAGE_FORWARD;
390       break;
391     }
392   return return_val;
393 }