]> Pileus Git - ~andy/gtk/blob - gtk/gtkhruler.c
Changed LGPL address for FSF in all .h and .c files
[~andy/gtk] / gtk / gtkhruler.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 <math.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include "gtkhruler.h"
23
24
25 #define RULER_HEIGHT          14
26 #define MINIMUM_INCR          5
27 #define MAXIMUM_SUBDIVIDE     5
28 #define MAXIMUM_SCALES        10
29
30 #define ROUND(x) ((int) ((x) + 0.5))
31
32
33 static void gtk_hruler_class_init    (GtkHRulerClass *klass);
34 static void gtk_hruler_init          (GtkHRuler      *hruler);
35 static gint gtk_hruler_motion_notify (GtkWidget      *widget,
36                                       GdkEventMotion *event);
37 static void gtk_hruler_draw_ticks    (GtkRuler       *ruler);
38 static void gtk_hruler_draw_pos      (GtkRuler       *ruler);
39
40
41 guint
42 gtk_hruler_get_type ()
43 {
44   static guint hruler_type = 0;
45
46   if (!hruler_type)
47     {
48       GtkTypeInfo hruler_info =
49       {
50         "GtkHRuler",
51         sizeof (GtkHRuler),
52         sizeof (GtkHRulerClass),
53         (GtkClassInitFunc) gtk_hruler_class_init,
54         (GtkObjectInitFunc) gtk_hruler_init,
55         (GtkArgSetFunc) NULL,
56         (GtkArgGetFunc) NULL,
57       };
58
59       hruler_type = gtk_type_unique (gtk_ruler_get_type (), &hruler_info);
60     }
61
62   return hruler_type;
63 }
64
65 static void
66 gtk_hruler_class_init (GtkHRulerClass *klass)
67 {
68   GtkWidgetClass *widget_class;
69   GtkRulerClass *ruler_class;
70
71   widget_class = (GtkWidgetClass*) klass;
72   ruler_class = (GtkRulerClass*) klass;
73
74   widget_class->motion_notify_event = gtk_hruler_motion_notify;
75
76   ruler_class->draw_ticks = gtk_hruler_draw_ticks;
77   ruler_class->draw_pos = gtk_hruler_draw_pos;
78 }
79
80 static void
81 gtk_hruler_init (GtkHRuler *hruler)
82 {
83   GtkWidget *widget;
84
85   widget = GTK_WIDGET (hruler);
86   widget->requisition.width = widget->style->klass->xthickness * 2 + 1;
87   widget->requisition.height = widget->style->klass->ythickness * 2 + RULER_HEIGHT;
88 }
89
90
91 GtkWidget*
92 gtk_hruler_new ()
93 {
94   return GTK_WIDGET (gtk_type_new (gtk_hruler_get_type ()));
95 }
96
97 static gint
98 gtk_hruler_motion_notify (GtkWidget      *widget,
99                           GdkEventMotion *event)
100 {
101   GtkRuler *ruler;
102   gint x;
103
104   g_return_val_if_fail (widget != NULL, FALSE);
105   g_return_val_if_fail (GTK_IS_HRULER (widget), FALSE);
106   g_return_val_if_fail (event != NULL, FALSE);
107
108   ruler = GTK_RULER (widget);
109
110   if (event->is_hint)
111     gdk_window_get_pointer (widget->window, &x, NULL, NULL);
112   else
113     x = event->x;
114
115   ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * x) / widget->allocation.width;
116
117   /*  Make sure the ruler has been allocated already  */
118   if (ruler->backing_store != NULL)
119     gtk_ruler_draw_pos (ruler);
120
121   return FALSE;
122 }
123
124 static void
125 gtk_hruler_draw_ticks (GtkRuler *ruler)
126 {
127   GtkWidget *widget;
128   GdkGC *gc, *bg_gc;
129   GdkFont *font;
130   gint i;
131   gint width, height;
132   gint xthickness;
133   gint ythickness;
134   gint length, ideal_length;
135   gfloat subd_incr;
136   gfloat step_incr;
137   gfloat increment;
138   gfloat start, end, cur;
139   gchar unit_str[12];
140   gint text_height;
141   gint digit_height;
142   gint pos;
143   gint scale;
144
145   g_return_if_fail (ruler != NULL);
146   g_return_if_fail (GTK_IS_HRULER (ruler));
147
148   if (GTK_WIDGET_DRAWABLE (ruler))
149     {
150       widget = GTK_WIDGET (ruler);
151
152       gc = widget->style->fg_gc[GTK_STATE_NORMAL];
153       bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
154       font = widget->style->font;
155       
156       xthickness = widget->style->klass->xthickness;
157       ythickness = widget->style->klass->ythickness;
158       digit_height = font->ascent; /* assume descent == 0? */
159
160       width = widget->allocation.width;
161       height = widget->allocation.height - ythickness * 2;
162       gdk_draw_line (ruler->backing_store, gc,
163                      xthickness,
164                      height + ythickness,
165                      widget->allocation.width - xthickness,
166                      height + ythickness);
167
168       if ((ruler->upper - ruler->lower) == 0)
169         return;
170
171       increment = (gfloat) width * ruler->metric->pixels_per_unit / (ruler->upper - ruler->lower);
172
173       /*  determine the scale
174        *   use the maximum extents of the ruler to determine the largest possible
175        *   number to be displayed.  calculate the height in pixels of this displayed
176        *   text as for the vertical ruler case.  use this height to find a scale
177        *   which leaves sufficient room for drawing the ruler.
178        */
179       scale = ceil (ruler->max_size / ruler->metric->pixels_per_unit);
180       sprintf (unit_str, "%d", scale);
181       text_height = strlen (unit_str) * digit_height + 1;
182
183       for (scale = 0; scale < MAXIMUM_SCALES; scale++)
184         if (ruler->metric->ruler_scale[scale] * increment > 2 * text_height)
185           break;
186
187       if (scale == MAXIMUM_SCALES)
188         scale = MAXIMUM_SCALES - 1;
189
190       length = 0;
191       for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--)
192         {
193           subd_incr = (gfloat) ruler->metric->ruler_scale[scale] / (gfloat) ruler->metric->subdivide[i];
194           step_incr = subd_incr * increment;
195           if (step_incr <= MINIMUM_INCR)
196             continue;
197
198           start = floor ((ruler->lower / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr;
199           end = ceil ((ruler->upper / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr;
200
201           ideal_length = height / (i + 1) - 1;
202           if (ideal_length > ++length)
203               length = ideal_length;
204           
205           cur = start;
206           while (cur <= end)
207             {
208               pos = ROUND ((cur - (ruler->lower / ruler->metric->pixels_per_unit)) * increment);
209
210               gdk_draw_line (ruler->backing_store, gc,
211                              pos, height + ythickness, pos,
212                              height - length + ythickness);
213               if (i == 0)
214                 {
215                   sprintf (unit_str, "%d", (int) cur);
216                   gdk_draw_rectangle (ruler->backing_store,
217                                       bg_gc, TRUE,
218                                       pos + 1, ythickness,
219                                       gdk_string_width(font, unit_str) + 1,
220                                       digit_height);
221                   gdk_draw_string (ruler->backing_store, font, gc,
222                                    pos + 2, ythickness + font->ascent - 1,
223                                    unit_str);
224                 }
225
226               cur += subd_incr;
227             }
228         }
229     }
230 }
231
232 static void
233 gtk_hruler_draw_pos (GtkRuler *ruler)
234 {
235   GtkWidget *widget;
236   GdkGC *gc;
237   int i;
238   gint x, y;
239   gint width, height;
240   gint bs_width, bs_height;
241   gint xthickness;
242   gint ythickness;
243   gfloat increment;
244
245   g_return_if_fail (ruler != NULL);
246   g_return_if_fail (GTK_IS_HRULER (ruler));
247
248   if (GTK_WIDGET_DRAWABLE (ruler))
249     {
250       widget = GTK_WIDGET (ruler);
251
252       gc = widget->style->fg_gc[GTK_STATE_NORMAL];
253       xthickness = widget->style->klass->xthickness;
254       ythickness = widget->style->klass->ythickness;
255       width = widget->allocation.width;
256       height = widget->allocation.height - ythickness * 2;
257
258       bs_width = height / 2;
259       bs_width |= 1;  /* make sure it's odd */
260       bs_height = bs_width / 2 + 1;
261
262       if ((bs_width > 0) && (bs_height > 0))
263         {
264           /*  If a backing store exists, restore the ruler  */
265           if (ruler->backing_store && ruler->non_gr_exp_gc)
266             gdk_draw_pixmap (ruler->widget.window,
267                              ruler->non_gr_exp_gc,
268                              ruler->backing_store,
269                              ruler->xsrc, ruler->ysrc,
270                              ruler->xsrc, ruler->ysrc,
271                              bs_width, bs_height);
272
273           increment = (gfloat) width / (ruler->upper - ruler->lower);
274
275           x = ROUND ((ruler->position - ruler->lower) * increment) + (xthickness - bs_width) / 2 - 1;
276           y = (height + bs_height) / 2 + ythickness;
277
278           for (i = 0; i < bs_height; i++)
279             gdk_draw_line (widget->window, gc,
280                            x + i, y + i,
281                            x + bs_width - 1 - i, y + i);
282
283
284           ruler->xsrc = x;
285           ruler->ysrc = y;
286         }
287     }
288 }