source: trunk/third/gtk/gtk/gtkhscale.c @ 14482

Revision 14482, 18.4 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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 <stdio.h>
28#include "gtkhscale.h"
29#include "gtksignal.h"
30#include "gdk/gdkkeysyms.h"
31
32
33#define SCALE_CLASS(w)  GTK_SCALE_CLASS (GTK_OBJECT (w)->klass)
34#define RANGE_CLASS(w)  GTK_RANGE_CLASS (GTK_OBJECT (w)->klass)
35
36enum {
37  ARG_0,
38  ARG_ADJUSTMENT
39};
40
41static void gtk_hscale_class_init    (GtkHScaleClass *klass);
42static void gtk_hscale_init          (GtkHScale      *hscale);
43static void gtk_hscale_set_arg       (GtkObject      *object,
44                                      GtkArg         *arg,
45                                      guint           arg_id);
46static void gtk_hscale_get_arg       (GtkObject      *object,
47                                      GtkArg         *arg,
48                                      guint           arg_id);
49static void gtk_hscale_realize       (GtkWidget      *widget);
50static void gtk_hscale_size_request  (GtkWidget      *widget,
51                                      GtkRequisition *requisition);
52static void gtk_hscale_size_allocate (GtkWidget      *widget,
53                                      GtkAllocation  *allocation);
54static void gtk_hscale_pos_trough    (GtkHScale      *hscale,
55                                      gint           *x,
56                                      gint           *y,
57                                      gint           *w,
58                                      gint           *h);
59static void gtk_hscale_pos_background (GtkHScale     *hscale,
60                                       gint          *x,
61                                       gint          *y,
62                                       gint          *w,
63                                       gint          *h);
64static void gtk_hscale_draw_slider   (GtkRange       *range);
65static void gtk_hscale_draw_value    (GtkScale       *scale);
66static void gtk_hscale_draw          (GtkWidget      *widget,
67                                      GdkRectangle   *area);
68static gint gtk_hscale_trough_keys   (GtkRange *range,
69                                      GdkEventKey *key,
70                                      GtkScrollType *scroll,
71                                      GtkTroughType *pos);
72static void gtk_hscale_clear_background (GtkRange    *range);
73
74GtkType
75gtk_hscale_get_type (void)
76{
77  static GtkType hscale_type = 0;
78 
79  if (!hscale_type)
80    {
81      static const GtkTypeInfo hscale_info =
82      {
83        "GtkHScale",
84        sizeof (GtkHScale),
85        sizeof (GtkHScaleClass),
86        (GtkClassInitFunc) gtk_hscale_class_init,
87        (GtkObjectInitFunc) gtk_hscale_init,
88        /* reserved_1 */ NULL,
89        /* reserved_2 */ NULL,
90        (GtkClassInitFunc) NULL,
91      };
92     
93      hscale_type = gtk_type_unique (GTK_TYPE_SCALE, &hscale_info);
94    }
95 
96  return hscale_type;
97}
98
99static void
100gtk_hscale_class_init (GtkHScaleClass *class)
101{
102  GtkObjectClass *object_class;
103  GtkWidgetClass *widget_class;
104  GtkRangeClass *range_class;
105  GtkScaleClass *scale_class;
106 
107  object_class = (GtkObjectClass*) class;
108  widget_class = (GtkWidgetClass*) class;
109  range_class = (GtkRangeClass*) class;
110  scale_class = (GtkScaleClass*) class;
111 
112  gtk_object_add_arg_type ("GtkHScale::adjustment",
113                           GTK_TYPE_ADJUSTMENT,
114                           GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
115                           ARG_ADJUSTMENT);
116 
117  object_class->set_arg = gtk_hscale_set_arg;
118  object_class->get_arg = gtk_hscale_get_arg;
119 
120  widget_class->realize = gtk_hscale_realize;
121  widget_class->size_request = gtk_hscale_size_request;
122  widget_class->size_allocate = gtk_hscale_size_allocate;
123  widget_class->draw = gtk_hscale_draw;
124 
125  range_class->slider_update = gtk_range_default_hslider_update;
126  range_class->trough_click = gtk_range_default_htrough_click;
127  range_class->motion = gtk_range_default_hmotion;
128  range_class->draw_slider = gtk_hscale_draw_slider;
129  range_class->trough_keys = gtk_hscale_trough_keys;
130  range_class->clear_background = gtk_hscale_clear_background;
131 
132  scale_class->draw_value = gtk_hscale_draw_value;
133}
134
135static void
136gtk_hscale_set_arg (GtkObject          *object,
137                    GtkArg             *arg,
138                    guint               arg_id)
139{
140  GtkHScale *hscale;
141 
142  hscale = GTK_HSCALE (object);
143 
144  switch (arg_id)
145    {
146    case ARG_ADJUSTMENT:
147      gtk_range_set_adjustment (GTK_RANGE (hscale), GTK_VALUE_POINTER (*arg));
148      break;
149    default:
150      break;
151    }
152}
153
154static void
155gtk_hscale_get_arg (GtkObject          *object,
156                    GtkArg             *arg,
157                    guint               arg_id)
158{
159  GtkHScale *hscale;
160 
161  hscale = GTK_HSCALE (object);
162 
163  switch (arg_id)
164    {
165    case ARG_ADJUSTMENT:
166      GTK_VALUE_POINTER (*arg) = GTK_RANGE (hscale);
167      break;
168    default:
169      arg->type = GTK_TYPE_INVALID;
170      break;
171    }
172}
173
174static void
175gtk_hscale_init (GtkHScale *hscale)
176{
177  GTK_WIDGET_SET_FLAGS (hscale, GTK_NO_WINDOW);
178}
179
180GtkWidget*
181gtk_hscale_new (GtkAdjustment *adjustment)
182{
183  GtkWidget *hscale;
184 
185  hscale = gtk_widget_new (GTK_TYPE_HSCALE,
186                           "adjustment", adjustment,
187                           NULL);
188
189  return hscale;
190}
191
192
193static void
194gtk_hscale_realize (GtkWidget *widget)
195{
196  GtkRange *range;
197  GdkWindowAttr attributes;
198  gint attributes_mask;
199  gint x, y, w, h;
200 
201  g_return_if_fail (widget != NULL);
202  g_return_if_fail (GTK_IS_HSCALE (widget));
203 
204  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
205  range = GTK_RANGE (widget);
206 
207  widget->window = gtk_widget_get_parent_window (widget);
208  gdk_window_ref (widget->window);
209 
210  gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &w, &h);
211
212  attributes.x = x;
213  attributes.y = y;
214  attributes.width = w;
215  attributes.height = h;
216  attributes.wclass = GDK_INPUT_OUTPUT;
217  attributes.window_type = GDK_WINDOW_CHILD;
218 
219  attributes.event_mask = gtk_widget_get_events (widget) |
220    (GDK_EXPOSURE_MASK |
221     GDK_BUTTON_PRESS_MASK |
222     GDK_BUTTON_RELEASE_MASK |
223     GDK_ENTER_NOTIFY_MASK |
224     GDK_LEAVE_NOTIFY_MASK);
225  attributes.visual = gtk_widget_get_visual (widget);
226  attributes.colormap = gtk_widget_get_colormap (widget);
227 
228  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
229 
230  range->trough = gdk_window_new (widget->window, &attributes, attributes_mask);
231 
232  attributes.width = SCALE_CLASS (range)->slider_length;
233  attributes.height = RANGE_CLASS (range)->slider_width;
234  attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
235                            GDK_POINTER_MOTION_HINT_MASK);
236 
237  range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
238 
239  widget->style = gtk_style_attach (widget->style, widget->window);
240 
241  gdk_window_set_user_data (range->trough, widget);
242  gdk_window_set_user_data (range->slider, 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 
247  gtk_range_slider_update (GTK_RANGE (widget));
248 
249  gdk_window_show (range->slider);
250}
251
252static void
253gtk_hscale_draw (GtkWidget    *widget,
254                 GdkRectangle *area)
255{
256  GtkRange *range;
257  GdkRectangle tmp_area;
258  GdkRectangle child_area;
259  gint x, y, width, height;
260 
261  g_return_if_fail (widget != NULL);
262  g_return_if_fail (GTK_IS_RANGE (widget));
263  g_return_if_fail (area != NULL);
264 
265  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
266    {
267      range = GTK_RANGE (widget);
268     
269      gtk_hscale_pos_background (GTK_HSCALE (widget), &x, &y, &width, &height);
270     
271      tmp_area.x = x;
272      tmp_area.y = y;
273      tmp_area.width = width;
274      tmp_area.height = height;
275     
276      if (gdk_rectangle_intersect (area, &tmp_area, &child_area))
277        gtk_range_draw_background (range);
278     
279      gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height);
280     
281      tmp_area.x = x;
282      tmp_area.y = y;
283      tmp_area.width = width;
284      tmp_area.height = height;
285     
286      if (gdk_rectangle_intersect (area, &tmp_area, &child_area))
287        {
288          gtk_range_draw_trough (range);
289          gtk_range_draw_slider (range);
290          gtk_range_draw_step_forw (range);
291          gtk_range_draw_step_back (range);
292        }
293    }
294}
295
296static void
297gtk_hscale_clear_background (GtkRange    *range)
298{
299  GtkWidget *widget;
300  gint x, y, width, height;
301 
302  g_return_if_fail (range != NULL);
303 
304  widget = GTK_WIDGET (range);
305 
306  gtk_hscale_pos_background (GTK_HSCALE (range), &x, &y, &width, &height);
307 
308  gtk_widget_queue_clear_area (GTK_WIDGET (range),
309                               x, y, width, height);
310}
311
312static void
313gtk_hscale_size_request (GtkWidget      *widget,
314                         GtkRequisition *requisition)
315{
316  GtkScale *scale;
317  gint value_width;
318 
319  g_return_if_fail (widget != NULL);
320  g_return_if_fail (GTK_IS_HSCALE (widget));
321  g_return_if_fail (requisition != NULL);
322 
323  scale = GTK_SCALE (widget);
324 
325  requisition->width = (SCALE_CLASS (scale)->slider_length +
326                        widget->style->klass->xthickness) * 2;
327  requisition->height = (RANGE_CLASS (scale)->slider_width +
328                         widget->style->klass->ythickness * 2);
329 
330  if (scale->draw_value)
331    {
332      value_width = gtk_scale_get_value_width (scale);
333     
334      if ((scale->value_pos == GTK_POS_LEFT) ||
335          (scale->value_pos == GTK_POS_RIGHT))
336        {
337          requisition->width += value_width + SCALE_CLASS (scale)->value_spacing;
338          if (requisition->height < (widget->style->font->ascent + widget->style->font->descent))
339            requisition->height = widget->style->font->ascent + widget->style->font->descent;
340        }
341      else if ((scale->value_pos == GTK_POS_TOP) ||
342               (scale->value_pos == GTK_POS_BOTTOM))
343        {
344          if (requisition->width < value_width)
345            requisition->width = value_width;
346          requisition->height += widget->style->font->ascent + widget->style->font->descent;
347        }
348    }
349}
350
351static void
352gtk_hscale_size_allocate (GtkWidget     *widget,
353                          GtkAllocation *allocation)
354{
355  GtkRange *range;
356  GtkScale *scale;
357  gint width, height;
358  gint x, y;
359 
360  g_return_if_fail (widget != NULL);
361  g_return_if_fail (GTK_IS_HSCALE (widget));
362  g_return_if_fail (allocation != NULL);
363 
364  widget->allocation = *allocation;
365  if (GTK_WIDGET_REALIZED (widget))
366    {
367      range = GTK_RANGE (widget);
368      scale = GTK_SCALE (widget);
369     
370      gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height);
371     
372      gdk_window_move_resize (range->trough,
373                              x, y, width, height);
374      gtk_range_slider_update (GTK_RANGE (widget));
375    }
376}
377
378static void
379gtk_hscale_pos_trough (GtkHScale *hscale,
380                       gint      *x,
381                       gint      *y,
382                       gint      *w,
383                       gint      *h)
384{
385  GtkWidget *widget;
386  GtkScale *scale;
387 
388  g_return_if_fail (hscale != NULL);
389  g_return_if_fail (GTK_IS_HSCALE (hscale));
390  g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
391 
392  widget = GTK_WIDGET (hscale);
393  scale = GTK_SCALE (hscale);
394 
395  *w = widget->allocation.width;
396  *h = (RANGE_CLASS (scale)->slider_width +
397        widget->style->klass->ythickness * 2);
398 
399  if (scale->draw_value)
400    {
401      *x = 0;
402      *y = 0;
403     
404      switch (scale->value_pos)
405        {
406        case GTK_POS_LEFT:
407          *x += gtk_scale_get_value_width (scale) + SCALE_CLASS (scale)->value_spacing;
408          *y = (widget->allocation.height - *h) / 2;
409          *w -= *x;
410          break;
411        case GTK_POS_RIGHT:
412          *w -= gtk_scale_get_value_width (scale) + SCALE_CLASS (scale)->value_spacing;
413          *y = (widget->allocation.height - *h) / 2;
414          break;
415        case GTK_POS_TOP:
416          *y = (widget->style->font->ascent + widget->style->font->descent +
417                (widget->allocation.height - widget->requisition.height) / 2);
418          break;
419        case GTK_POS_BOTTOM:
420          *y = (widget->allocation.height - widget->requisition.height) / 2;
421          break;
422        }
423    }
424  else
425    {
426      *x = 0;
427      *y = (widget->allocation.height - *h) / 2;
428    }
429  *x += 1;
430  *w -= 2;
431 
432  *x += widget->allocation.x;
433  *y += widget->allocation.y;
434}
435
436static void
437gtk_hscale_pos_background (GtkHScale *hscale,
438                           gint      *x,
439                           gint      *y,
440                           gint      *w,
441                           gint      *h)
442{
443  GtkWidget *widget;
444  GtkScale *scale;
445 
446  gint tx, ty, twidth, theight;
447 
448  g_return_if_fail (hscale != NULL);
449  g_return_if_fail (GTK_IS_HSCALE (hscale));
450  g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
451 
452  gtk_hscale_pos_trough (hscale, &tx, &ty, &twidth, &theight);
453 
454  widget = GTK_WIDGET (hscale);
455  scale = GTK_SCALE (hscale);
456 
457  *x = widget->allocation.x;
458  *y = widget->allocation.y;
459  *w = widget->allocation.width;
460  *h = widget->allocation.height;
461 
462  switch (scale->value_pos)
463    {
464    case GTK_POS_LEFT:
465      *w -= twidth;
466      break;
467    case GTK_POS_RIGHT:
468      *x += twidth;
469      *w -= twidth;
470      break;
471    case GTK_POS_TOP:
472      *h -= theight;
473      break;
474    case GTK_POS_BOTTOM:
475      *y += theight;
476      *h -= theight;
477      break;
478    }
479  *w = MAX (*w, 0);
480  *h = MAX (*h, 0);
481}
482
483static void
484gtk_hscale_draw_slider (GtkRange *range)
485{
486  GtkStateType state_type;
487 
488  g_return_if_fail (range != NULL);
489  g_return_if_fail (GTK_IS_HSCALE (range));
490 
491  if (range->slider)
492    {
493      if ((range->in_child == RANGE_CLASS (range)->slider) ||
494          (range->click_child == RANGE_CLASS (range)->slider))
495        state_type = GTK_STATE_PRELIGHT;
496      else
497        state_type = GTK_STATE_NORMAL;
498     
499      gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type,
500                        GTK_SHADOW_OUT,
501                        NULL, GTK_WIDGET (range), "hscale",
502                        0, 0, -1, -1,
503                        GTK_ORIENTATION_HORIZONTAL);
504    }
505}
506
507static void
508gtk_hscale_draw_value (GtkScale *scale)
509{
510  GtkStateType state_type;
511  GtkWidget *widget;
512  gchar buffer[32];
513  gint text_width;
514  gint width, height;
515  gint x, y;
516 
517  g_return_if_fail (scale != NULL);
518  g_return_if_fail (GTK_IS_HSCALE (scale));
519 
520  widget = GTK_WIDGET (scale);
521 
522  if (scale->draw_value)
523    {
524      sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
525      text_width = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer);
526     
527      switch (scale->value_pos)
528        {
529        case GTK_POS_LEFT:
530          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
531          gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
532         
533          x -= SCALE_CLASS (scale)->value_spacing + text_width;
534          y += ((height -
535                 (GTK_WIDGET (scale)->style->font->ascent +
536                  GTK_WIDGET (scale)->style->font->descent)) / 2 +
537                GTK_WIDGET (scale)->style->font->ascent);
538          break;
539        case GTK_POS_RIGHT:
540          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
541          gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
542         
543          x += width + SCALE_CLASS (scale)->value_spacing;
544          y += ((height -
545                 (GTK_WIDGET (scale)->style->font->ascent +
546                  GTK_WIDGET (scale)->style->font->descent)) / 2 +
547                GTK_WIDGET (scale)->style->font->ascent);
548          break;
549        case GTK_POS_TOP:
550          gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
551          gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
552          gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
553          gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
554         
555          x += widget->allocation.x + (width - text_width) / 2;
556          x = CLAMP (x, widget->allocation.x,
557                     widget->allocation.x + widget->allocation.width - text_width);
558          y -= GTK_WIDGET (scale)->style->font->descent;
559          break;
560        case GTK_POS_BOTTOM:
561          gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
562          gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
563          gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
564          gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
565         
566          x += widget->allocation.x + (width - text_width) / 2;
567          x = CLAMP (x, widget->allocation.x,
568                     widget->allocation.x + widget->allocation.width - text_width);
569          y += height + GTK_WIDGET (scale)->style->font->ascent;
570          break;
571        }
572     
573      state_type = GTK_STATE_NORMAL;
574      if (!GTK_WIDGET_IS_SENSITIVE (scale))
575        state_type = GTK_STATE_INSENSITIVE;
576     
577      gtk_paint_string (GTK_WIDGET (scale)->style,
578                        GTK_WIDGET (scale)->window,
579                        state_type,
580                        NULL, GTK_WIDGET (scale), "hscale",
581                        x, y, buffer);
582    }
583}
584
585static gint
586gtk_hscale_trough_keys (GtkRange *range,
587                        GdkEventKey *key,
588                        GtkScrollType *scroll,
589                        GtkTroughType *pos)
590{
591  gint return_val = FALSE;
592  switch (key->keyval)
593    {
594    case GDK_Left:
595      return_val = TRUE;
596      if (key->state & GDK_CONTROL_MASK)
597        *scroll = GTK_SCROLL_PAGE_BACKWARD;
598      else
599        *scroll = GTK_SCROLL_STEP_BACKWARD;
600      break;
601    case GDK_Right:
602      return_val = TRUE;
603      if (key->state & GDK_CONTROL_MASK)
604        *scroll = GTK_SCROLL_PAGE_FORWARD;
605      else
606        *scroll = GTK_SCROLL_STEP_FORWARD;
607      break;
608    case GDK_Home:
609      return_val = TRUE;
610      *pos = GTK_TROUGH_START;
611      break;
612    case GDK_End:
613      return_val = TRUE;
614      *pos = GTK_TROUGH_END;
615      break;
616    }
617  return return_val;
618}
Note: See TracBrowser for help on using the repository browser.