gtkvscrollbar.c 13.8 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19 20

/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

Elliot Lee's avatar
Elliot Lee committed
27 28 29
#include "gtkvscrollbar.h"
#include "gtksignal.h"
#include "gdk/gdkkeysyms.h"
Alexander Larsson's avatar
Alexander Larsson committed
30
#include "gtkintl.h"
Elliot Lee's avatar
Elliot Lee committed
31 32 33 34


#define EPSILON 0.01

35
#define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
Elliot Lee's avatar
Elliot Lee committed
36

37
enum {
Alexander Larsson's avatar
Alexander Larsson committed
38
  PROP_0,
39
};
Elliot Lee's avatar
Elliot Lee committed
40

41 42
static void     gtk_vscrollbar_class_init       (GtkVScrollbarClass *klass);
static void     gtk_vscrollbar_init             (GtkVScrollbar      *vscrollbar);
Alexander Larsson's avatar
Alexander Larsson committed
43 44 45 46 47 48 49 50
static void     gtk_vscrollbar_set_property	(GObject            *object,
						 guint               prop_id,
						 const GValue       *value,
						 GParamSpec         *pspec);
static void     gtk_vscrollbar_get_property     (GObject            *object,
						 guint               prop_id,
						 GValue             *value,
						 GParamSpec         *pspec);
51
static void     gtk_vscrollbar_realize          (GtkWidget          *widget);
52 53
static void     gtk_vscrollbar_size_request     (GtkWidget          *widget,
						 GtkRequisition     *requisition);
54 55 56 57 58 59
static void     gtk_vscrollbar_size_allocate    (GtkWidget          *widget,
						 GtkAllocation      *allocation);
static void     gtk_vscrollbar_draw_step_forw   (GtkRange           *range);
static void     gtk_vscrollbar_draw_step_back   (GtkRange           *range);
static void     gtk_vscrollbar_slider_update    (GtkRange           *range);
static void     gtk_vscrollbar_calc_slider_size (GtkVScrollbar      *vscrollbar);
Elliot Lee's avatar
Elliot Lee committed
60

61
GtkType
62
gtk_vscrollbar_get_type (void)
Elliot Lee's avatar
Elliot Lee committed
63
{
64 65
  static GtkType vscrollbar_type = 0;
  
Elliot Lee's avatar
Elliot Lee committed
66 67
  if (!vscrollbar_type)
    {
68
      static const GtkTypeInfo vscrollbar_info =
Elliot Lee's avatar
Elliot Lee committed
69
      {
70 71 72 73 74 75
        "GtkVScrollbar",
        sizeof (GtkVScrollbar),
        sizeof (GtkVScrollbarClass),
        (GtkClassInitFunc) gtk_vscrollbar_class_init,
        (GtkObjectInitFunc) gtk_vscrollbar_init,
        /* reserved_1 */ NULL,
76
        /* reserved_2 */ NULL,
77
        (GtkClassInitFunc) NULL,
Elliot Lee's avatar
Elliot Lee committed
78
      };
79 80
      
      vscrollbar_type = gtk_type_unique (GTK_TYPE_SCROLLBAR, &vscrollbar_info);
Elliot Lee's avatar
Elliot Lee committed
81
    }
82
  
Elliot Lee's avatar
Elliot Lee committed
83 84 85 86
  return vscrollbar_type;
}

static void
87
gtk_vscrollbar_class_init (GtkVScrollbarClass *class)
Elliot Lee's avatar
Elliot Lee committed
88
{
Alexander Larsson's avatar
Alexander Larsson committed
89
  GObjectClass   *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
90 91
  GtkWidgetClass *widget_class;
  GtkRangeClass *range_class;
92
  
Alexander Larsson's avatar
Alexander Larsson committed
93
  gobject_class = G_OBJECT_CLASS (class);
94 95 96
  widget_class = (GtkWidgetClass*) class;
  range_class = (GtkRangeClass*) class;
  
Alexander Larsson's avatar
Alexander Larsson committed
97 98
  gobject_class->set_property = gtk_vscrollbar_set_property;
  gobject_class->get_property = gtk_vscrollbar_get_property;
99
  
Elliot Lee's avatar
Elliot Lee committed
100
  widget_class->realize = gtk_vscrollbar_realize;
101
  widget_class->size_request = gtk_vscrollbar_size_request;
Elliot Lee's avatar
Elliot Lee committed
102
  widget_class->size_allocate = gtk_vscrollbar_size_allocate;
103
  
Elliot Lee's avatar
Elliot Lee committed
104 105 106
  range_class->draw_step_forw = gtk_vscrollbar_draw_step_forw;
  range_class->draw_step_back = gtk_vscrollbar_draw_step_back;
  range_class->slider_update = gtk_vscrollbar_slider_update;
107 108
  range_class->trough_click = _gtk_range_default_vtrough_click;
  range_class->motion = _gtk_range_default_vmotion;
Elliot Lee's avatar
Elliot Lee committed
109 110
}

111
static void
Alexander Larsson's avatar
Alexander Larsson committed
112 113 114 115
gtk_vscrollbar_set_property (GObject         *object,
			     guint            prop_id,
			     const GValue    *value,
			     GParamSpec      *pspec)
116 117 118 119 120
{
  GtkVScrollbar *vscrollbar;
  
  vscrollbar = GTK_VSCROLLBAR (object);
  
Alexander Larsson's avatar
Alexander Larsson committed
121
  switch (prop_id)
122 123
    {
    default:
Alexander Larsson's avatar
Alexander Larsson committed
124
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
125 126 127 128 129
      break;
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
130 131 132 133
gtk_vscrollbar_get_property (GObject         *object,
			     guint            prop_id,
			     GValue          *value,
			     GParamSpec      *pspec)
134 135 136 137 138
{
  GtkVScrollbar *vscrollbar;
  
  vscrollbar = GTK_VSCROLLBAR (object);
  
Alexander Larsson's avatar
Alexander Larsson committed
139
  switch (prop_id)
140 141
    {
    default:
Alexander Larsson's avatar
Alexander Larsson committed
142
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
143 144 145 146
      break;
    }
}

Elliot Lee's avatar
Elliot Lee committed
147 148 149 150 151 152 153 154
static void
gtk_vscrollbar_init (GtkVScrollbar *vscrollbar)
{
}

GtkWidget*
gtk_vscrollbar_new (GtkAdjustment *adjustment)
{
155 156 157 158 159 160 161
  GtkWidget *vscrollbar;
  
  vscrollbar = gtk_widget_new (GTK_TYPE_VSCROLLBAR,
			       "adjustment", adjustment,
			       NULL);
  
  return vscrollbar;
Elliot Lee's avatar
Elliot Lee committed
162 163 164 165 166 167 168 169 170
}


static void
gtk_vscrollbar_realize (GtkWidget *widget)
{
  GtkRange *range;
  GdkWindowAttr attributes;
  gint attributes_mask;
171 172 173
  gint slider_width;
  gint stepper_size;
  gint trough_border;
174
  
Elliot Lee's avatar
Elliot Lee committed
175 176
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_VSCROLLBAR (widget));
177
  
Elliot Lee's avatar
Elliot Lee committed
178 179
  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
  range = GTK_RANGE (widget);
180
  
181 182 183
  _gtk_range_get_props (range, &slider_width, &trough_border,
			&stepper_size, NULL);

Elliot Lee's avatar
Elliot Lee committed
184 185 186 187 188 189 190 191 192 193
  attributes.x = widget->allocation.x + (widget->allocation.width - widget->requisition.width) / 2;
  attributes.y = widget->allocation.y;
  attributes.width = widget->requisition.width;
  attributes.height = widget->allocation.height;
  attributes.wclass = GDK_INPUT_OUTPUT;
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.visual = gtk_widget_get_visual (widget);
  attributes.colormap = gtk_widget_get_colormap (widget);
  attributes.event_mask = gtk_widget_get_events (widget);
  attributes.event_mask |= (GDK_EXPOSURE_MASK |
194 195 196 197 198
                            GDK_BUTTON_PRESS_MASK |
                            GDK_BUTTON_RELEASE_MASK |
                            GDK_ENTER_NOTIFY_MASK |
                            GDK_LEAVE_NOTIFY_MASK);
  
Elliot Lee's avatar
Elliot Lee committed
199
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
200
  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
201
  
Elliot Lee's avatar
Elliot Lee committed
202
  range->trough = widget->window;
203
  gdk_window_ref (range->trough);
204
  
205 206 207 208
  attributes.x = trough_border;
  attributes.y = trough_border;
  attributes.width = stepper_size;
  attributes.height = stepper_size;
209
  
Elliot Lee's avatar
Elliot Lee committed
210
  range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask);
211
  
Elliot Lee's avatar
Elliot Lee committed
212
  attributes.y = (widget->allocation.height -
213 214
                  trough_border -
                  stepper_size);
215
  
Elliot Lee's avatar
Elliot Lee committed
216
  range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask);
217
  
218
  attributes.x = trough_border;
Elliot Lee's avatar
Elliot Lee committed
219
  attributes.y = 0;
220
  attributes.width = slider_width;
Elliot Lee's avatar
Elliot Lee committed
221 222
  attributes.height = RANGE_CLASS (widget)->min_slider_size;
  attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
223 224
                            GDK_POINTER_MOTION_HINT_MASK);
  
Elliot Lee's avatar
Elliot Lee committed
225
  range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
226
  
Elliot Lee's avatar
Elliot Lee committed
227
  gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (widget));
228
  _gtk_range_slider_update (GTK_RANGE (widget));
229
  
Elliot Lee's avatar
Elliot Lee committed
230
  widget->style = gtk_style_attach (widget->style, widget->window);
231
  
Elliot Lee's avatar
Elliot Lee committed
232 233 234 235
  gdk_window_set_user_data (range->trough, widget);
  gdk_window_set_user_data (range->slider, widget);
  gdk_window_set_user_data (range->step_forw, widget);
  gdk_window_set_user_data (range->step_back, widget);
236
  
Elliot Lee's avatar
Elliot Lee committed
237 238 239 240
  gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
  gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
  gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
  gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
241
  
Elliot Lee's avatar
Elliot Lee committed
242 243 244 245 246
  gdk_window_show (range->slider);
  gdk_window_show (range->step_forw);
  gdk_window_show (range->step_back);
}

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
static void
gtk_vscrollbar_size_request (GtkWidget      *widget,
			     GtkRequisition *requisition)
{
  gint slider_width;
  gint trough_border;
  gint stepper_size;
  gint stepper_spacing;
  
  GtkRange *range = GTK_RANGE (widget);

  _gtk_range_get_props (range, &slider_width, &trough_border,
			&stepper_size, &stepper_spacing);
  
  requisition->width = (slider_width +
                        trough_border * 2);
  requisition->height = (RANGE_CLASS (widget)->min_slider_size +
                         stepper_size +
                         stepper_spacing +
                         trough_border) * 2;
}

Elliot Lee's avatar
Elliot Lee committed
269 270
static void
gtk_vscrollbar_size_allocate (GtkWidget     *widget,
271
                              GtkAllocation *allocation)
Elliot Lee's avatar
Elliot Lee committed
272 273
{
  GtkRange *range;
274 275
  gint trough_border;
  gint stepper_size;
276
  
Elliot Lee's avatar
Elliot Lee committed
277 278 279
  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_VSCROLLBAR (widget));
  g_return_if_fail (allocation != NULL);
280
  
Elliot Lee's avatar
Elliot Lee committed
281 282 283 284
  widget->allocation = *allocation;
  if (GTK_WIDGET_REALIZED (widget))
    {
      range = GTK_RANGE (widget);
285
      
286 287 288
      _gtk_range_get_props (range, NULL, &trough_border, 
			    &stepper_size, NULL);
  
Elliot Lee's avatar
Elliot Lee committed
289
      gdk_window_move_resize (range->trough,
290 291 292
                              allocation->x + (allocation->width - widget->requisition.width) / 2,
                              allocation->y,
                              widget->requisition.width, allocation->height);
Elliot Lee's avatar
Elliot Lee committed
293
      gdk_window_move_resize (range->step_back,
294 295 296 297
                              trough_border,
                              trough_border,
                              widget->requisition.width - trough_border * 2,
                              stepper_size);
Elliot Lee's avatar
Elliot Lee committed
298
      gdk_window_move_resize (range->step_forw,
299 300 301 302 303
                              trough_border,
                              allocation->height - trough_border -
                              stepper_size,
                              widget->requisition.width - trough_border * 2,
                              stepper_size);
304
      
305
      _gtk_range_slider_update (GTK_RANGE (widget));
Elliot Lee's avatar
Elliot Lee committed
306 307 308 309 310 311 312 313
    }
}

static void
gtk_vscrollbar_draw_step_forw (GtkRange *range)
{
  GtkStateType state_type;
  GtkShadowType shadow_type;
314
  
Elliot Lee's avatar
Elliot Lee committed
315 316
  g_return_if_fail (range != NULL);
  g_return_if_fail (GTK_IS_VSCROLLBAR (range));
317
  
Elliot Lee's avatar
Elliot Lee committed
318 319 320
  if (GTK_WIDGET_DRAWABLE (range))
    {
      if (range->in_child == RANGE_CLASS (range)->step_forw)
321 322 323 324 325 326
        {
          if (range->click_child == RANGE_CLASS (range)->step_forw)
            state_type = GTK_STATE_ACTIVE;
          else
            state_type = GTK_STATE_PRELIGHT;
        }
Elliot Lee's avatar
Elliot Lee committed
327
      else
328 329
        state_type = GTK_STATE_NORMAL;
      
Elliot Lee's avatar
Elliot Lee committed
330
      if (range->click_child == RANGE_CLASS (range)->step_forw)
331
        shadow_type = GTK_SHADOW_IN;
Elliot Lee's avatar
Elliot Lee committed
332
      else
333 334
        shadow_type = GTK_SHADOW_OUT;
      
335
      gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw,
336 337 338 339
                       state_type, shadow_type, 
                       NULL, GTK_WIDGET (range), "vscrollbar",
                       GTK_ARROW_DOWN,
                       TRUE, 0, 0, -1, -1);
Elliot Lee's avatar
Elliot Lee committed
340 341 342 343 344 345 346 347
    }
}

static void
gtk_vscrollbar_draw_step_back (GtkRange *range)
{
  GtkStateType state_type;
  GtkShadowType shadow_type;
348
  
Elliot Lee's avatar
Elliot Lee committed
349 350
  g_return_if_fail (range != NULL);
  g_return_if_fail (GTK_IS_VSCROLLBAR (range));
351
  
Elliot Lee's avatar
Elliot Lee committed
352 353 354
  if (GTK_WIDGET_DRAWABLE (range))
    {
      if (range->in_child == RANGE_CLASS (range)->step_back)
355 356 357 358 359 360
        {
          if (range->click_child == RANGE_CLASS (range)->step_back)
            state_type = GTK_STATE_ACTIVE;
          else
            state_type = GTK_STATE_PRELIGHT;
        }
Elliot Lee's avatar
Elliot Lee committed
361
      else
362 363
        state_type = GTK_STATE_NORMAL;
      
Elliot Lee's avatar
Elliot Lee committed
364
      if (range->click_child == RANGE_CLASS (range)->step_back)
365
        shadow_type = GTK_SHADOW_IN;
Elliot Lee's avatar
Elliot Lee committed
366
      else
367 368
        shadow_type = GTK_SHADOW_OUT;
      
369
      gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back,
370 371 372 373
                       state_type, shadow_type, 
                       NULL, GTK_WIDGET (range), "vscrollbar",
                       GTK_ARROW_UP,
                       TRUE, 0, 0, -1, -1);
Elliot Lee's avatar
Elliot Lee committed
374 375 376 377 378 379 380 381
    }
}

static void
gtk_vscrollbar_slider_update (GtkRange *range)
{
  g_return_if_fail (range != NULL);
  g_return_if_fail (GTK_IS_VSCROLLBAR (range));
382
  
Elliot Lee's avatar
Elliot Lee committed
383
  gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (range));
384
  _gtk_range_default_vslider_update (range);
Elliot Lee's avatar
Elliot Lee committed
385 386 387 388 389 390 391 392 393
}

static void
gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar)
{
  GtkRange *range;
  gint step_back_y;
  gint step_back_height;
  gint step_forw_y;
394
  gint stepper_spacing;
Elliot Lee's avatar
Elliot Lee committed
395 396 397 398
  gint slider_width;
  gint slider_height;
  gint top, bottom;
  gint height;
399
  
Elliot Lee's avatar
Elliot Lee committed
400 401
  g_return_if_fail (vscrollbar != NULL);
  g_return_if_fail (GTK_IS_VSCROLLBAR (vscrollbar));
402
  
Elliot Lee's avatar
Elliot Lee committed
403 404 405
  if (GTK_WIDGET_REALIZED (vscrollbar))
    {
      range = GTK_RANGE (vscrollbar);
406
      
407 408
      _gtk_range_get_props (range, NULL, NULL, NULL, &stepper_spacing);
      
Elliot Lee's avatar
Elliot Lee committed
409 410 411
      gdk_window_get_size (range->step_back, NULL, &step_back_height);
      gdk_window_get_position (range->step_back, NULL, &step_back_y);
      gdk_window_get_position (range->step_forw, NULL, &step_forw_y);
412
      
Elliot Lee's avatar
Elliot Lee committed
413
      top = (step_back_y +
414
             step_back_height +
415 416
             stepper_spacing);
      bottom = step_forw_y - stepper_spacing;
Elliot Lee's avatar
Elliot Lee committed
417
      height = bottom - top;
418
      
Elliot Lee's avatar
Elliot Lee committed
419
      if ((range->adjustment->page_size > 0) &&
420 421 422 423 424 425 426 427 428 429 430 431 432
          (range->adjustment->lower != range->adjustment->upper))
        {
          if (range->adjustment->page_size >
              (range->adjustment->upper - range->adjustment->lower))
            range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower;
          
          height = (height * range->adjustment->page_size /
                    (range->adjustment->upper - range->adjustment->lower));
          
          if (height < RANGE_CLASS (vscrollbar)->min_slider_size)
            height = RANGE_CLASS (vscrollbar)->min_slider_size;
        }
      
Elliot Lee's avatar
Elliot Lee committed
433
      gdk_window_get_size (range->slider, &slider_width, &slider_height);
434
      
Elliot Lee's avatar
Elliot Lee committed
435
      if (slider_height != height)
436 437 438 439
	{
	  gdk_window_resize (range->slider, slider_width, height);
	  gdk_window_invalidate_rect (range->slider, NULL, FALSE);
	}
Elliot Lee's avatar
Elliot Lee committed
440 441
    }
}