root/sweep/trunk/src/time_ruler.c

Revision 691, 9.8 kB (checked in by erikd, 2 years ago)

Remove needless #defines of buffer lengths.

Code had many instances of:

#undef BUF_LEN
#define BUF_LEN 64
char buf[BUF_LEN];
snprintf (buf, BUF_LEN, ....);

which can be replaced with:

char buf[64];
snprintf (buf, sizeof (buf), ....);

which is far cleaner and more difficult to get wrong.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Sweep, a sound wave editor.
3  *
4  * time_ruler, modified from hruler in GTK+ 1.2.x
5  * by Conrad Parker 2000 for Sweep.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * GTK - The GIMP Toolkit
24  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
25  */
26
27 /*
28  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
29  * file for a list of people on the GTK+ Team.  See the ChangeLog
30  * files for a list of changes.  These files are distributed with
31  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
32  */
33
34
35 #ifdef HAVE_CONFIG_H
36 #  include <config.h>
37 #endif
38
39 #include <math.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include "time_ruler.h"
43
44 #include <sweep/sweep_typeconvert.h>
45
46 #include "print.h"
47
48 #define RULER_HEIGHT          14
49 #define MINIMUM_INCR          5
50 #define MAXIMUM_SUBDIVIDE     5
51 #define MAXIMUM_SCALES        21
52
53 #define ROUND(x) ((int) ((x) + 0.5))
54
55
56 static void time_ruler_class_init    (TimeRulerClass *klass);
57 static void time_ruler_init          (TimeRuler      *time_ruler);
58 static gint time_ruler_button_press  (GtkWidget * widget,
59                                       GdkEventButton * event);
60 static gint time_ruler_motion_notify (GtkWidget      *widget,
61                                       GdkEventMotion *event);
62 static void time_ruler_draw_ticks    (GtkRuler       *ruler);
63 static void time_ruler_draw_pos      (GtkRuler       *ruler);
64
65 GType
66 time_ruler_get_type (void)
67 {
68   static GType time_ruler_type = 0;
69
70   if (!time_ruler_type)
71     {
72       static const GTypeInfo time_ruler_info =
73       {
74                  
75         sizeof (TimeRulerClass),
76         NULL, /* base_init */
77         NULL, /* base_finalize */
78         (GClassInitFunc) time_ruler_class_init,
79         NULL, /* class_finalize */
80         NULL, /* class_data */
81         sizeof (TimeRuler),
82         0,    /* n_preallocs */
83         (GInstanceInitFunc) time_ruler_init,     
84
85       };
86
87       time_ruler_type = g_type_register_static (GTK_TYPE_RULER, "TimeRuler", &time_ruler_info, 0);
88     }
89
90   return time_ruler_type;
91 }
92
93 static void
94 time_ruler_class_init (TimeRulerClass *klass)
95 {
96   GtkWidgetClass *widget_class;
97   GtkRulerClass *ruler_class;
98
99   widget_class = (GtkWidgetClass*) klass;
100   ruler_class = (GtkRulerClass*) klass;
101
102   /*  widget_class->realize = time_ruler_realize;*/
103   widget_class->button_press_event = time_ruler_button_press;
104   widget_class->motion_notify_event = time_ruler_motion_notify;
105
106   ruler_class->draw_ticks = time_ruler_draw_ticks;
107   ruler_class->draw_pos = time_ruler_draw_pos;
108 }
109
110 static gfloat ruler_scale[MAXIMUM_SCALES] =
111 { 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1,
112   2.5, 5, 10, 15, 30, 60, 300, 600, 1800, 3600, 18000, 36000 };
113
114 static gint subdivide[MAXIMUM_SUBDIVIDE] = { 1, 2, 5, 10, 100 };
115
116 static void
117 time_ruler_init (TimeRuler *time_ruler)
118 {
119   GtkWidget *widget;
120
121   time_ruler->samplerate = 44100;
122
123   widget = GTK_WIDGET (time_ruler);
124   widget->requisition.width = widget->style->xthickness * 2 + 1;
125   widget->requisition.height = widget->style->ythickness * 2 + RULER_HEIGHT;
126 }
127
128 GtkWidget*
129 time_ruler_new (void)
130 {
131   return GTK_WIDGET (g_object_new (time_ruler_get_type (), NULL));
132 }
133
134 static gint
135 time_ruler_motion_notify (GtkWidget *widget, GdkEventMotion *event)
136 {
137   GtkRuler *ruler;
138   gint x;
139
140   g_return_val_if_fail (widget != NULL, FALSE);
141   g_return_val_if_fail (GTK_IS_TIME_RULER (widget), FALSE);
142   g_return_val_if_fail (event != NULL, FALSE);
143
144   ruler = GTK_RULER (widget);
145
146   if (event->is_hint)
147     gdk_window_get_pointer (widget->window, &x, NULL, NULL);
148   else
149     x = event->x;
150
151   ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * x) / widget->allocation.width;
152
153   /*  Make sure the ruler has been allocated already  */
154   if (ruler->backing_store != NULL)
155     gtk_ruler_draw_pos (ruler);
156
157   return FALSE;
158 }
159
160 static gint
161 time_ruler_button_press (GtkWidget * widget, GdkEventButton * event)
162 {
163   GdkModifierType state;
164   int x, y;
165
166   gdk_window_get_pointer (event->window, &x, &y, &state);
167
168   return TRUE;
169 }
170
171 static void
172 time_ruler_draw_ticks (GtkRuler *ruler)
173 {
174   GtkWidget *widget;
175   GdkGC *gc, *bg_gc;
176   gint i;
177   gint width, height;
178   gint xthickness;
179   gint ythickness;
180   gint length, ideal_length;
181   gdouble lower, upper;         /* Upper and lower limits, in ruler units */
182   gdouble increment, abs_increment; /* Number of pixels per unit */
183   gint scale;                   /* Number of units per major unit */
184   gdouble subd_incr;
185   gdouble start, end, cur;
186   gchar unit_str[32];
187   gint digit_height;
188   gint digit_offset;
189   gint text_width;
190   gint pos;
191   PangoLayout *layout;
192   PangoRectangle logical_rect, ink_rect;
193
194   g_return_if_fail (ruler != NULL);
195   g_return_if_fail (GTK_IS_TIME_RULER (ruler));
196
197   if (!GTK_WIDGET_DRAWABLE (ruler))
198     return;
199
200   widget = GTK_WIDGET (ruler);
201
202   gc = widget->style->fg_gc[GTK_STATE_NORMAL];
203   bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
204
205   xthickness = widget->style->xthickness;
206   ythickness = widget->style->ythickness;
207
208   width = widget->allocation.width;
209   height = widget->allocation.height - ythickness * 2;
210
211   layout = gtk_widget_create_pango_layout (widget, "012456789");
212   pango_layout_get_extents (layout, &ink_rect, &logical_rect);
213  
214   digit_height = PANGO_PIXELS (ink_rect.height) + 2;
215   digit_offset = ink_rect.y;
216
217    
218   gtk_paint_box (widget->style, ruler->backing_store,
219                  GTK_STATE_NORMAL, GTK_SHADOW_OUT,
220                  NULL, widget, "time_ruler",
221                  0, 0,
222                  widget->allocation.width, widget->allocation.height);
223
224
225   gdk_draw_line (ruler->backing_store, gc,
226                  xthickness,
227                  height + ythickness,
228                  widget->allocation.width - xthickness,
229                  height + ythickness);
230
231   upper = ruler->upper / TIME_RULER(ruler)->samplerate;
232   lower = ruler->lower / TIME_RULER(ruler)->samplerate;
233
234   if ((upper - lower) == 0)
235     return;
236
237   increment = (gdouble) width / (upper - lower);
238   abs_increment = (gdouble) fabs((double)increment);
239
240   /* determine the scale
241    *  We calculate the text size as for the vruler instead of using
242    *  text_width = gdk_string_width(font, unit_str), so that the result
243    *  for the scale looks consistent with an accompanying vruler
244    */
245   scale = ceil (ruler->max_size / TIME_RULER(ruler)->samplerate);
246   snprint_time (unit_str, sizeof (unit_str), (sw_time_t)scale);
247
248  text_width = strlen (unit_str) * digit_height + 1;
249
250   for (scale = 0; scale < MAXIMUM_SCALES; scale++)
251     if (ruler_scale[scale] * abs_increment > 2 * text_width)
252       break;
253
254   if (scale == MAXIMUM_SCALES)
255     scale = MAXIMUM_SCALES - 1;
256
257   /* drawing starts here */
258   length = 0;
259   for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--)
260     {
261       subd_incr = (gdouble) ruler_scale[scale] /
262                   (gdouble) subdivide[i];
263       if (subd_incr * fabs(increment) <= MINIMUM_INCR)
264         continue;
265
266       /* Calculate the length of the tickmarks. Make sure that
267        * this length increases for each set of ticks
268        */
269       ideal_length = height / (i + 1) - 1;
270       if (ideal_length > ++length)
271         length = ideal_length;
272
273       if (lower < upper)
274         {
275           start = floor (lower / subd_incr) * subd_incr;
276           end   = ceil  (upper / subd_incr) * subd_incr;
277         }
278       else
279         {
280           start = floor (upper / subd_incr) * subd_incr;
281           end   = ceil  (lower / subd_incr) * subd_incr;
282         }
283
284  
285       for (cur = start; cur <= end; cur += subd_incr)
286         {
287           pos = ROUND ((cur - lower) * increment);
288
289           gdk_draw_line (ruler->backing_store, gc,
290                          pos, height + ythickness,
291                          pos, height - length + ythickness);
292
293           /* draw label */
294           if (i == 0)
295             {
296               snprint_time (unit_str, sizeof (unit_str), (sw_time_t)cur);
297                   pango_layout_set_text (layout, unit_str, -1);
298                   pango_layout_get_extents (layout, NULL, &logical_rect);
299
300                   gtk_paint_layout (widget->style,
301                   ruler->backing_store,
302                   GTK_WIDGET_STATE (widget),
303                                   FALSE,
304                   NULL,
305                   widget,
306                   "vruler",
307                   pos +2,
308                   2,
309                   layout);
310             }
311          }
312    }
313 }
314
315 static void
316 time_ruler_draw_pos (GtkRuler *ruler)
317 {
318   GtkWidget *widget;
319   GdkGC *gc;
320   int i;
321   gint x, y;
322   gint width, height;
323   gint bs_width, bs_height;
324   gint xthickness;
325   gint ythickness;
326   gfloat increment;
327
328   g_return_if_fail (ruler != NULL);
329   g_return_if_fail (GTK_IS_TIME_RULER (ruler));
330
331   if (GTK_WIDGET_DRAWABLE (ruler))
332     {
333       widget = GTK_WIDGET (ruler);
334
335       gc = widget->style->fg_gc[GTK_STATE_NORMAL];
336       xthickness = widget->style->xthickness;
337       ythickness = widget->style->ythickness;
338       width = widget->allocation.width;
339       height = widget->allocation.height - ythickness * 2;
340
341       bs_width = height / 2;
342       bs_width |= 1;  /* make sure it's odd */
343       bs_height = bs_width / 2 + 1;
344
345       if ((bs_width > 0) && (bs_height > 0))
346         {
347           /*  If a backing store exists, restore the ruler  */
348           if (ruler->backing_store && ruler->non_gr_exp_gc)
349             gdk_draw_drawable (ruler->widget.window,
350                              ruler->non_gr_exp_gc,
351                              ruler->backing_store,
352                              ruler->xsrc, ruler->ysrc,
353                              ruler->xsrc, ruler->ysrc,
354                              bs_width, bs_height);
355
356           increment = (gfloat) width / (ruler->upper - ruler->lower);
357
358           x = ROUND ((ruler->position - ruler->lower) * increment) +
359             (xthickness - bs_width) / 2 - 1;
360           y = (height + bs_height) / 2 + ythickness;
361
362           for (i = 0; i < bs_height; i++)
363             gdk_draw_line (widget->window, gc,
364                            x + i, y + i,
365                            x + bs_width - 1 - i, y + i);
366
367
368           ruler->xsrc = x;
369           ruler->ysrc = y;
370         }
371     }
372 }
373
374 void
375 time_ruler_set_format (TimeRuler * time_ruler, sw_format * f)
376 {
377   time_ruler->samplerate = f->rate;
378 }
Note: See TracBrowser for help on using the browser.