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