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

Revision 14482, 8.5 KB checked in by ghudson, 24 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 <math.h>
28#include <stdio.h>
29#include <string.h>
30#include "gtkvruler.h"
31
32
33#define RULER_WIDTH           14
34#define MINIMUM_INCR          5
35#define MAXIMUM_SUBDIVIDE     5
36#define MAXIMUM_SCALES        10
37
38#define ROUND(x) ((int) ((x) + 0.5))
39
40
41static void gtk_vruler_class_init    (GtkVRulerClass *klass);
42static void gtk_vruler_init          (GtkVRuler      *vruler);
43static gint gtk_vruler_motion_notify (GtkWidget      *widget,
44                                      GdkEventMotion *event);
45static void gtk_vruler_draw_ticks    (GtkRuler       *ruler);
46static void gtk_vruler_draw_pos      (GtkRuler       *ruler);
47
48
49guint
50gtk_vruler_get_type (void)
51{
52  static guint vruler_type = 0;
53
54  if (!vruler_type)
55    {
56      static const GtkTypeInfo vruler_info =
57      {
58        "GtkVRuler",
59        sizeof (GtkVRuler),
60        sizeof (GtkVRulerClass),
61        (GtkClassInitFunc) gtk_vruler_class_init,
62        (GtkObjectInitFunc) gtk_vruler_init,
63        /* reserved_1 */ NULL,
64        /* reserved_2 */ NULL,
65        (GtkClassInitFunc) NULL,
66      };
67
68      vruler_type = gtk_type_unique (gtk_ruler_get_type (), &vruler_info);
69    }
70
71  return vruler_type;
72}
73
74static void
75gtk_vruler_class_init (GtkVRulerClass *klass)
76{
77  GtkWidgetClass *widget_class;
78  GtkRulerClass *ruler_class;
79
80  widget_class = (GtkWidgetClass*) klass;
81  ruler_class = (GtkRulerClass*) klass;
82
83  widget_class->motion_notify_event = gtk_vruler_motion_notify;
84
85  ruler_class->draw_ticks = gtk_vruler_draw_ticks;
86  ruler_class->draw_pos = gtk_vruler_draw_pos;
87}
88
89static void
90gtk_vruler_init (GtkVRuler *vruler)
91{
92  GtkWidget *widget;
93
94  widget = GTK_WIDGET (vruler);
95  widget->requisition.width = widget->style->klass->xthickness * 2 + RULER_WIDTH;
96  widget->requisition.height = widget->style->klass->ythickness * 2 + 1;
97}
98
99GtkWidget*
100gtk_vruler_new (void)
101{
102  return GTK_WIDGET (gtk_type_new (gtk_vruler_get_type ()));
103}
104
105
106static gint
107gtk_vruler_motion_notify (GtkWidget      *widget,
108                          GdkEventMotion *event)
109{
110  GtkRuler *ruler;
111  gint y;
112
113  g_return_val_if_fail (widget != NULL, FALSE);
114  g_return_val_if_fail (GTK_IS_VRULER (widget), FALSE);
115  g_return_val_if_fail (event != NULL, FALSE);
116
117  ruler = GTK_RULER (widget);
118
119  if (event->is_hint)
120    gdk_window_get_pointer (widget->window, NULL, &y, NULL);
121  else
122    y = event->y;
123
124  ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * y) / widget->allocation.height;
125
126  /*  Make sure the ruler has been allocated already  */
127  if (ruler->backing_store != NULL)
128    gtk_ruler_draw_pos (ruler);
129
130  return FALSE;
131}
132
133static void
134gtk_vruler_draw_ticks (GtkRuler *ruler)
135{
136  GtkWidget *widget;
137  GdkGC *gc, *bg_gc;
138  GdkFont *font;
139  gint i, j;
140  gint width, height;
141  gint xthickness;
142  gint ythickness;
143  gint length, ideal_length;
144  gfloat lower, upper;          /* Upper and lower limits, in ruler units */
145  gfloat increment;             /* Number of pixels per unit */
146  gint scale;                   /* Number of units per major unit */
147  gfloat subd_incr;
148  gfloat start, end, cur;
149  gchar unit_str[32];
150  gchar digit_str[2] = { '\0', '\0' };
151  gint digit_height;
152  gint text_height;
153  gint pos;
154
155  g_return_if_fail (ruler != NULL);
156  g_return_if_fail (GTK_IS_VRULER (ruler));
157
158  if (!GTK_WIDGET_DRAWABLE (ruler))
159    return;
160
161  widget = GTK_WIDGET (ruler);
162
163  gc = widget->style->fg_gc[GTK_STATE_NORMAL];
164  bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
165  font = widget->style->font;
166  xthickness = widget->style->klass->xthickness;
167  ythickness = widget->style->klass->ythickness;
168  digit_height = font->ascent; /* assume descent == 0 ? */
169
170  width = widget->allocation.height;
171  height = widget->allocation.width - ythickness * 2;
172
173   gtk_paint_box (widget->style, ruler->backing_store,
174                  GTK_STATE_NORMAL, GTK_SHADOW_OUT,
175                  NULL, widget, "vruler",
176                  0, 0,
177                  widget->allocation.width, widget->allocation.height);
178
179   gdk_draw_line (ruler->backing_store, gc,
180                 height + xthickness,
181                 ythickness,
182                 height + xthickness,
183                 widget->allocation.height - ythickness);
184
185  upper = ruler->upper / ruler->metric->pixels_per_unit;
186  lower = ruler->lower / ruler->metric->pixels_per_unit;
187
188  if ((upper - lower) == 0)
189    return;
190  increment = (gfloat) width / (upper - lower);
191
192  /* determine the scale
193   *   use the maximum extents of the ruler to determine the largest
194   *   possible number to be displayed.  Calculate the height in pixels
195   *   of this displayed text. Use this height to find a scale which
196   *   leaves sufficient room for drawing the ruler. 
197   */
198  scale = ceil (ruler->max_size / ruler->metric->pixels_per_unit);
199  sprintf (unit_str, "%d", scale);
200  text_height = strlen (unit_str) * digit_height + 1;
201
202  for (scale = 0; scale < MAXIMUM_SCALES; scale++)
203    if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_height)
204      break;
205
206  if (scale == MAXIMUM_SCALES)
207    scale = MAXIMUM_SCALES - 1;
208
209  /* drawing starts here */
210  length = 0;
211  for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--)
212    {
213      subd_incr = (gfloat) ruler->metric->ruler_scale[scale] /
214                  (gfloat) ruler->metric->subdivide[i];
215      if (subd_incr * fabs(increment) <= MINIMUM_INCR)
216        continue;
217
218      /* Calculate the length of the tickmarks. Make sure that
219       * this length increases for each set of ticks
220       */
221      ideal_length = height / (i + 1) - 1;
222      if (ideal_length > ++length)
223        length = ideal_length;
224
225      if (lower < upper)
226        {
227          start = floor (lower / subd_incr) * subd_incr;
228          end   = ceil  (upper / subd_incr) * subd_incr;
229        }
230      else
231        {
232          start = floor (upper / subd_incr) * subd_incr;
233          end   = ceil  (lower / subd_incr) * subd_incr;
234        }
235
236      for (cur = start; cur <= end; cur += subd_incr)
237        {
238          pos = ROUND ((cur - lower) * increment);
239
240          gdk_draw_line (ruler->backing_store, gc,
241                         height + xthickness - length, pos,
242                         height + xthickness, pos);
243
244          /* draw label */
245          if (i == 0)
246            {
247              sprintf (unit_str, "%d", (int) cur);
248              for (j = 0; j < (int) strlen (unit_str); j++)
249                {
250                  digit_str[0] = unit_str[j];
251                  gdk_draw_string (ruler->backing_store, font, gc,
252                                   xthickness + 1,
253                                   pos + digit_height * (j + 1) + 1,
254                                   digit_str);
255                }
256            }
257        }
258    }
259}
260
261
262static void
263gtk_vruler_draw_pos (GtkRuler *ruler)
264{
265  GtkWidget *widget;
266  GdkGC *gc;
267  int i;
268  gint x, y;
269  gint width, height;
270  gint bs_width, bs_height;
271  gint xthickness;
272  gint ythickness;
273  gfloat increment;
274
275  g_return_if_fail (ruler != NULL);
276  g_return_if_fail (GTK_IS_VRULER (ruler));
277
278  if (GTK_WIDGET_DRAWABLE (ruler))
279    {
280      widget = GTK_WIDGET (ruler);
281
282      gc = widget->style->fg_gc[GTK_STATE_NORMAL];
283      xthickness = widget->style->klass->xthickness;
284      ythickness = widget->style->klass->ythickness;
285      width = widget->allocation.width - xthickness * 2;
286      height = widget->allocation.height;
287
288      bs_height = width / 2;
289      bs_height |= 1;  /* make sure it's odd */
290      bs_width = bs_height / 2 + 1;
291
292      if ((bs_width > 0) && (bs_height > 0))
293        {
294          /*  If a backing store exists, restore the ruler  */
295          if (ruler->backing_store && ruler->non_gr_exp_gc)
296            gdk_draw_pixmap (ruler->widget.window,
297                             ruler->non_gr_exp_gc,
298                             ruler->backing_store,
299                             ruler->xsrc, ruler->ysrc,
300                             ruler->xsrc, ruler->ysrc,
301                             bs_width, bs_height);
302
303          increment = (gfloat) height / (ruler->upper - ruler->lower);
304
305          x = (width + bs_width) / 2 + xthickness;
306          y = ROUND ((ruler->position - ruler->lower) * increment) + (ythickness - bs_height) / 2 - 1;
307
308          for (i = 0; i < bs_width; i++)
309            gdk_draw_line (widget->window, gc,
310                           x + i, y + i,
311                           x + i, y + bs_height - 1 - i);
312
313          ruler->xsrc = x;
314          ruler->ysrc = y;
315        }
316    }
317}
Note: See TracBrowser for help on using the repository browser.