Code

gcc warning cleanup
[inkscape.git] / src / widgets / ruler.cpp
1 #define __SP_RULER_C__
3 /*
4  * Customized ruler class for inkscape
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   Frank Felfe <innerspace@iname.com>
9  *   bulia byak <buliabyak@users.sf.net>
10  *   Diederik van Lierop <mail@diedenrezi.nl>
11  *
12  * Copyright (C) 1999-2008 authors
13  *
14  * Released under GNU GPL, read the file 'COPYING' for more information
15  */
17 #include <cstring>
18 #include <cmath>
19 #include <cstdio>
21 #include "widget-sizes.h"
22 #include "desktop-widget.h"
23 #include "ruler.h"
24 #include "unit-constants.h"
25 #include "round.h"
27 #define MINIMUM_INCR          5
28 #define MAXIMUM_SUBDIVIDE     5
29 #define MAXIMUM_SCALES        10
30 #define UNUSED_PIXELS         2     // There appear to be two pixels that are not being used at each end of the ruler
32 static void sp_hruler_class_init    (SPHRulerClass *klass);
33 static void sp_hruler_init          (SPHRuler      *hruler);
34 static gint sp_hruler_motion_notify (GtkWidget      *widget, GdkEventMotion *event);
35 static void sp_hruler_draw_ticks    (GtkRuler       *ruler);
36 static void sp_hruler_draw_pos      (GtkRuler       *ruler);
37 static void sp_hruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
39 static GtkWidgetClass *hruler_parent_class;
41 GtkType
42 sp_hruler_get_type (void)
43 {
44   static GtkType hruler_type = 0;
46   if (!hruler_type)
47     {
48       static const GtkTypeInfo hruler_info =
49       {
50         (gchar*) "SPHRuler",
51         sizeof (SPHRuler),
52         sizeof (SPHRulerClass),
53         (GtkClassInitFunc) sp_hruler_class_init,
54         (GtkObjectInitFunc) sp_hruler_init,
55         /* reserved_1 */ NULL,
56         /* reserved_2 */ NULL,
57         (GtkClassInitFunc) NULL,
58       };
59   
60       hruler_type = gtk_type_unique (gtk_ruler_get_type (), &hruler_info);
61     }
63   return hruler_type;
64 }
66 static void
67 sp_hruler_class_init (SPHRulerClass *klass)
68 {
69   GtkWidgetClass *widget_class;
70   GtkRulerClass *ruler_class;
72   hruler_parent_class = (GtkWidgetClass *) gtk_type_class (GTK_TYPE_RULER);
74   widget_class = (GtkWidgetClass*) klass;
75   ruler_class = (GtkRulerClass*) klass;
77   widget_class->motion_notify_event = sp_hruler_motion_notify;
78   widget_class->size_allocate = sp_hruler_size_allocate;
80   ruler_class->draw_ticks = sp_hruler_draw_ticks;
81   ruler_class->draw_pos = sp_hruler_draw_pos;
82 }
84 static void
85 sp_hruler_init (SPHRuler *hruler)
86 {
87   GtkWidget *widget;
89   widget = GTK_WIDGET (hruler);
90   widget->requisition.width = widget->style->xthickness * 2 + 1;
91   widget->requisition.height = widget->style->ythickness * 2 + RULER_HEIGHT;
92 }
95 GtkWidget*
96 sp_hruler_new (void)
97 {
98   return GTK_WIDGET (gtk_type_new (sp_hruler_get_type ()));
99 }
101 static gint
102 sp_hruler_motion_notify (GtkWidget      *widget,
103                           GdkEventMotion *event)
105   GtkRuler *ruler;
106   
107   g_return_val_if_fail (widget != NULL, FALSE);
108   g_return_val_if_fail (SP_IS_HRULER (widget), FALSE);
109   g_return_val_if_fail (event != NULL, FALSE);
111   ruler = GTK_RULER (widget);
112   double x = event->x; //Although event->x is double according to the docs, it only appears to return integers
113   ruler->position = ruler->lower + (ruler->upper - ruler->lower) * (x + UNUSED_PIXELS) / (widget->allocation.width + 2*UNUSED_PIXELS);
114   
115   /*  Make sure the ruler has been allocated already  */
116   if (ruler->backing_store != NULL)
117     gtk_ruler_draw_pos (ruler);
119   return FALSE;
122 static void
123 sp_hruler_draw_ticks (GtkRuler *ruler)
125   GtkWidget *widget;
126   GdkGC *gc, *bg_gc;
127   PangoFontDescription *pango_desc;
128   PangoContext *pango_context;
129   PangoLayout *pango_layout;
130   gint i, tick_index;
131   gint width, height;
132   gint xthickness;
133   gint ythickness;
134   gint length, ideal_length;
135   double lower, upper;          /* Upper and lower limits, in ruler units */
136   double increment;             /* Number of pixels per unit */
137   gint scale;                   /* Number of units per major unit */
138   double subd_incr;
139   double start, end, cur;
140   gchar unit_str[32];
141   gint digit_height;
142   gint text_width;
143   gint pos;
145   g_return_if_fail (ruler != NULL);
146   g_return_if_fail (SP_IS_HRULER (ruler));
148   if (!GTK_WIDGET_DRAWABLE (ruler)) 
149     return;
151   widget = GTK_WIDGET (ruler);
153   gc = widget->style->fg_gc[GTK_STATE_NORMAL];
154   bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
155   
156   pango_desc = widget->style->font_desc;
157   
158   // Create the pango layout
159   pango_context = gtk_widget_get_pango_context (widget);
161   pango_layout = pango_layout_new (pango_context);
163   PangoFontDescription *fs = pango_font_description_new ();
164   pango_font_description_set_size (fs, RULER_FONT_SIZE);
165   pango_layout_set_font_description (pango_layout, fs);
166   pango_font_description_free (fs);
168   digit_height = (int) floor (RULER_FONT_SIZE * RULER_FONT_VERTICAL_SPACING / PANGO_SCALE + 0.5);
170   xthickness = widget->style->xthickness;
171   ythickness = widget->style->ythickness;
173   width = widget->allocation.width; // in pixels; is apparently 2 pixels shorter than the canvas at each end
174   height = widget->allocation.height;// - ythickness * 2;
175     
176   gtk_paint_box (widget->style, ruler->backing_store,
177                  GTK_STATE_NORMAL, GTK_SHADOW_NONE, 
178                  NULL, widget, "hruler",
179                  0, 0, 
180                  widget->allocation.width, widget->allocation.height);
182   upper = ruler->upper / ruler->metric->pixels_per_unit; // upper and lower are expressed in ruler units
183   lower = ruler->lower / ruler->metric->pixels_per_unit;
184   /* "pixels_per_unit" should be "points_per_unit". This is the size of the unit
185    * in 1/72nd's of an inch and has nothing to do with screen pixels */
186   
187   if ((upper - lower) == 0) 
188     return;
189   increment = (double) (width + 2*UNUSED_PIXELS) / (upper - lower); // screen pixels per ruler unit
190   
191    /* determine the scale
192    *  We calculate the text size as for the vruler instead of using
193    *  text_width = gdk_string_width(font, unit_str), so that the result
194    *  for the scale looks consistent with an accompanying vruler
195    */
196   scale = (int)(ceil (ruler->max_size / ruler->metric->pixels_per_unit));
197   sprintf (unit_str, "%d", scale);
198   text_width = strlen (unit_str) * digit_height + 1;
200   for (scale = 0; scale < MAXIMUM_SCALES; scale++)
201     if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_width)
202       break;
204   if (scale == MAXIMUM_SCALES)
205     scale = MAXIMUM_SCALES - 1;
207   /* drawing starts here */
208   length = 0;
209   for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--)
210     {
211       subd_incr = ruler->metric->ruler_scale[scale] / 
212                   ruler->metric->subdivide[i];
213       if (subd_incr * fabs(increment) <= MINIMUM_INCR) 
214     continue;
216       /* Calculate the length of the tickmarks. Make sure that
217        * this length increases for each set of ticks
218        */
219       ideal_length = height / (i + 1) - 1;
220       if (ideal_length > ++length)
221         length = ideal_length;
223       if (lower < upper)
224         {
225           start = floor (lower / subd_incr) * subd_incr;
226           end   = ceil  (upper / subd_incr) * subd_incr;
227         }
228       else
229         {
230           start = floor (upper / subd_incr) * subd_incr;
231           end   = ceil  (lower / subd_incr) * subd_incr;
232         }
234     tick_index = 0;
235     cur = start; // location (in ruler units) of the first invisible tick at the left side of the canvas 
237         while (cur <= end)
238         {
239           // due to the typical values for cur, lower and increment, pos will often end up to
240       // be e.g. 641.50000000000; rounding behaviour is not defined in such a case (see round.h)
241       // and jitter will be apparent (upon redrawing some of the lines on the ruler might jump a
242       // by a pixel, and jump back on the next redraw). This is suppressed by adding 1e-9 (that's only one nanopixel ;-))
243       pos = int(Inkscape::round((cur - lower) * increment + 1e-12)) - UNUSED_PIXELS; 
244       gdk_draw_line (ruler->backing_store, gc,
245                          pos, height + ythickness, 
246                          pos, height - length + ythickness);
248           /* draw label */
249         double label_spacing_px = (increment*(double)ruler->metric->ruler_scale[scale])/ruler->metric->subdivide[i];
250           if (i == 0 && 
251                                 (label_spacing_px > 6*digit_height || tick_index%2 == 0 || cur == 0) && 
252                                 (label_spacing_px > 3*digit_height || tick_index%4 == 0 ||  cur == 0))
253             {
254                                 if (fabs((int)cur) >= 2000 && (((int) cur)/1000)*1000 == ((int) cur))
255                                         sprintf (unit_str, "%dk", ((int) cur)/1000);
256                                 else
257                                         sprintf (unit_str, "%d", (int) cur);
258         
259                                 pango_layout_set_text (pango_layout, unit_str, -1);
260               
261                                 gdk_draw_layout (ruler->backing_store, gc,
262                                pos + 2, 0, pango_layout);
263             }
265       /* Calculate cur from start rather than incrementing by subd_incr
266        * in each iteration. This is to avoid propagation of floating point 
267        * errors in subd_incr.
268        */
269       ++tick_index;
270       cur = start + tick_index * subd_incr;
271         }
272     }
275 static void
276 sp_hruler_draw_pos (GtkRuler *ruler)
278   GtkWidget *widget;
279   GdkGC *gc;
280   int i;
281   gint x, y;
282   gint width, height;
283   gint bs_width, bs_height;
284   gint xthickness;
285   gint ythickness;
286   gfloat increment;
288   g_return_if_fail (ruler != NULL);
289   g_return_if_fail (SP_IS_HRULER (ruler));
291   if (GTK_WIDGET_DRAWABLE (ruler))
292     {
293       widget = GTK_WIDGET (ruler);
295       gc = widget->style->fg_gc[GTK_STATE_NORMAL];
296       xthickness = widget->style->xthickness;
297       ythickness = widget->style->ythickness;
298       width = widget->allocation.width; // in pixels; is apparently 2 pixels shorter than the canvas at each end
299       height = widget->allocation.height - ythickness * 2;
301       bs_width = height / 2;
302       bs_width |= 1;  /* make sure it's odd */
303       bs_height = bs_width / 2 + 1;
305       if ((bs_width > 0) && (bs_height > 0))
306         {
307           /*  If a backing store exists, restore the ruler  */
308           if (ruler->backing_store && ruler->non_gr_exp_gc)
309             gdk_draw_pixmap (ruler->widget.window,
310                              ruler->non_gr_exp_gc,
311                              ruler->backing_store,
312                              ruler->xsrc, ruler->ysrc,
313                              ruler->xsrc, ruler->ysrc,
314                              bs_width, bs_height);
316           increment = (gfloat) (width + 2*UNUSED_PIXELS) / (ruler->upper - ruler->lower);
318           // Calculate the coordinates (x, y, in pixels) of the tip of the triangle
319       x = int(Inkscape::round((ruler->position - ruler->lower) * increment + double(xthickness - bs_width) / 2.0) - UNUSED_PIXELS);
320           y = (height + bs_height) / 2 + ythickness;
322           for (i = 0; i < bs_height; i++)
323             gdk_draw_line (widget->window, gc,
324                            x + i, y + i,
325                            x + bs_width - 1 - i, y + i);
328           ruler->xsrc = x;
329           ruler->ysrc = y;
330         }
331     }
334 /**
335  * The hruler widget's size_allocate callback.
336  */
337 static void
338 sp_hruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
340     g_assert (widget != NULL);
341     g_assert (SP_IS_HRULER (widget));    
342     
343     // First call the default gtk_widget_size_allocate() method (which is being overridden here)
344     if (GTK_WIDGET_CLASS (hruler_parent_class)->size_allocate)
345         (* GTK_WIDGET_CLASS (hruler_parent_class)->size_allocate) (widget, allocation);
346  
347     // Now the size of the ruler has changed, the ruler bounds (upper & lower) need to be updated
348     // For this we first need to obtain a pointer to the desktop, by walking up the tree of ancestors    
349     GtkWidget *parent = gtk_widget_get_parent(widget);    
350     do {
351         if (SP_IS_DESKTOP_WIDGET(parent)) {
352             // Now we've found the desktop widget we can have the ruler boundaries updated 
353             sp_desktop_widget_update_hruler(SP_DESKTOP_WIDGET(parent));
354             // If the size of the ruler has increased, then a blank part is uncovered; therefore
355             // it must be redrawn  
356             sp_hruler_draw_ticks(GTK_RULER(widget));
357             break;   
358         }
359         parent = gtk_widget_get_parent(parent);
360     } while (parent != NULL);
366 // vruler
368 static void sp_vruler_class_init    (SPVRulerClass *klass);
369 static void sp_vruler_init          (SPVRuler      *vruler);
370 static gint sp_vruler_motion_notify (GtkWidget      *widget,
371                                       GdkEventMotion *event);
372 static void sp_vruler_draw_ticks    (GtkRuler       *ruler);
373 static void sp_vruler_draw_pos      (GtkRuler       *ruler);
374 static void sp_vruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
376 static GtkWidgetClass *vruler_parent_class;
378 GtkType
379 sp_vruler_get_type (void)
381   static GtkType vruler_type = 0;
383   if (!vruler_type)
384     {
385       static const GtkTypeInfo vruler_info =
386       {
387         (gchar*) "SPVRuler",
388         sizeof (SPVRuler),
389         sizeof (SPVRulerClass),
390         (GtkClassInitFunc) sp_vruler_class_init,
391         (GtkObjectInitFunc) sp_vruler_init,
392         /* reserved_1 */ NULL,
393         /* reserved_2 */ NULL,
394         (GtkClassInitFunc) NULL,
395       };
397       vruler_type = gtk_type_unique (gtk_ruler_get_type (), &vruler_info);
398     }
400   return vruler_type;
403 static void
404 sp_vruler_class_init (SPVRulerClass *klass)
406   GtkWidgetClass *widget_class;
407   GtkRulerClass *ruler_class;
409   vruler_parent_class = (GtkWidgetClass *) gtk_type_class (GTK_TYPE_RULER);
411   widget_class = (GtkWidgetClass*) klass;
412   ruler_class = (GtkRulerClass*) klass;
414   widget_class->motion_notify_event = sp_vruler_motion_notify;
415   widget_class->size_allocate = sp_vruler_size_allocate;
417   ruler_class->draw_ticks = sp_vruler_draw_ticks;
418   ruler_class->draw_pos = sp_vruler_draw_pos;
421 static void
422 sp_vruler_init (SPVRuler *vruler)
424   GtkWidget *widget;
426   widget = GTK_WIDGET (vruler);
427   widget->requisition.width = widget->style->xthickness * 2 + RULER_WIDTH;
428   widget->requisition.height = widget->style->ythickness * 2 + 1;
431 GtkWidget*
432 sp_vruler_new (void)
434   return GTK_WIDGET (gtk_type_new (sp_vruler_get_type ()));
438 static gint
439 sp_vruler_motion_notify (GtkWidget      *widget,
440                           GdkEventMotion *event)
442   GtkRuler *ruler;
443   
444   g_return_val_if_fail (widget != NULL, FALSE);
445   g_return_val_if_fail (SP_IS_VRULER (widget), FALSE);
446   g_return_val_if_fail (event != NULL, FALSE);
448   ruler = GTK_RULER (widget);
449   double y = event->y; //Although event->y is double according to the docs, it only appears to return integers
450   ruler->position = ruler->lower + (ruler->upper - ruler->lower) * (y + UNUSED_PIXELS) / (widget->allocation.height + 2*UNUSED_PIXELS);
452   /*  Make sure the ruler has been allocated already  */
453   if (ruler->backing_store != NULL)
454     gtk_ruler_draw_pos (ruler);
456   return FALSE;
459 static void
460 sp_vruler_draw_ticks (GtkRuler *ruler)
462   GtkWidget *widget;
463   GdkGC *gc, *bg_gc;
464   PangoFontDescription *pango_desc;
465   PangoContext *pango_context;
466   PangoLayout *pango_layout;
467   gint i, j, tick_index;
468   gint width, height;
469   gint xthickness;
470   gint ythickness;
471   gint length, ideal_length;
472   double lower, upper;          /* Upper and lower limits, in ruler units */
473   double increment;             /* Number of pixels per unit */
474   gint scale;                   /* Number of units per major unit */
475   double subd_incr;
476   double start, end, cur;
477   gchar unit_str[32];
478   gchar digit_str[2] = { '\0', '\0' };
479   gint digit_height;
480   gint text_height;
481   gint pos;
483   g_return_if_fail (ruler != NULL);
484   g_return_if_fail (SP_IS_VRULER (ruler));
486   if (!GTK_WIDGET_DRAWABLE (ruler)) 
487     return;
489   widget = GTK_WIDGET (ruler);
491   gc = widget->style->fg_gc[GTK_STATE_NORMAL];
492   bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
493   
494   pango_desc = widget->style->font_desc;
495   
496   // Create the pango layout
497   pango_context = gtk_widget_get_pango_context (widget);
499   pango_layout = pango_layout_new (pango_context);
501   PangoFontDescription *fs = pango_font_description_new ();
502   pango_font_description_set_size (fs, RULER_FONT_SIZE);
503   pango_layout_set_font_description (pango_layout, fs);
504   pango_font_description_free (fs);
506   digit_height = (int) floor (RULER_FONT_SIZE * RULER_FONT_VERTICAL_SPACING / PANGO_SCALE + 0.5);
507   
508   xthickness = widget->style->xthickness;
509   ythickness = widget->style->ythickness;
511   width = widget->allocation.height; //in pixels; is apparently 2 pixels shorter than the canvas at each end
512   height = widget->allocation.width;// - ythickness * 2;
514   gtk_paint_box (widget->style, ruler->backing_store,
515                  GTK_STATE_NORMAL, GTK_SHADOW_NONE, 
516                  NULL, widget, "vruler",
517                  0, 0, 
518                  widget->allocation.width, widget->allocation.height);
519   
520   upper = ruler->upper / ruler->metric->pixels_per_unit; // upper and lower are expressed in ruler units
521   lower = ruler->lower / ruler->metric->pixels_per_unit;
522   /* "pixels_per_unit" should be "points_per_unit". This is the size of the unit
523    * in 1/72nd's of an inch and has nothing to do with screen pixels */
524   
525   if ((upper - lower) == 0)
526     return;
527   increment = (double) (width + 2*UNUSED_PIXELS) / (upper - lower); // screen pixels per ruler unit
529   /* determine the scale
530    *   use the maximum extents of the ruler to determine the largest
531    *   possible number to be displayed.  Calculate the height in pixels
532    *   of this displayed text. Use this height to find a scale which
533    *   leaves sufficient room for drawing the ruler.  
534    */
535   scale = (int)ceil (ruler->max_size / ruler->metric->pixels_per_unit);
536   sprintf (unit_str, "%d", scale);
537   text_height = strlen (unit_str) * digit_height + 1;
539   for (scale = 0; scale < MAXIMUM_SCALES; scale++)
540     if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_height)
541       break;
543   if (scale == MAXIMUM_SCALES)
544     scale = MAXIMUM_SCALES - 1;
546   /* drawing starts here */
547   length = 0;
548   for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--) {
549                 subd_incr = (double) ruler->metric->ruler_scale[scale] / 
550                         (double) ruler->metric->subdivide[i];
551                 if (subd_incr * fabs(increment) <= MINIMUM_INCR) 
552                         continue;
554                 /* Calculate the length of the tickmarks. Make sure that
555                  * this length increases for each set of ticks
556                  */
557                 ideal_length = height / (i + 1) - 1;
558                 if (ideal_length > ++length)
559                         length = ideal_length;
561                 if (lower < upper)
562                         {
563                                 start = floor (lower / subd_incr) * subd_incr;
564                                 end   = ceil  (upper / subd_incr) * subd_incr;
565                         }
566                 else
567                         {
568                                 start = floor (upper / subd_incr) * subd_incr;
569                                 end   = ceil  (lower / subd_incr) * subd_incr;
570                         }
572     tick_index = 0;
573     cur = start; // location (in ruler units) of the first invisible tick at the top side of the canvas       
575     while (cur < end) {
576           // due to the typical values for cur, lower and increment, pos will often end up to
577           // be e.g. 641.50000000000; rounding behaviour is not defined in such a case (see round.h)
578           // and jitter will be apparent (upon redrawing some of the lines on the ruler might jump a
579           // by a pixel, and jump back on the next redraw). This is suppressed by adding 1e-9 (that's only one nanopixel ;-))
580             pos = int(Inkscape::round((cur - lower) * increment + 1e-12)) - UNUSED_PIXELS;
582                         gdk_draw_line (ruler->backing_store, gc,
583                                                                                  height + xthickness - length, pos,
584                                                                                  height + xthickness, pos);
586                         /* draw label */
587                         double label_spacing_px = fabs((increment*(double)ruler->metric->ruler_scale[scale])/ruler->metric->subdivide[i]);
588                         if (i == 0 && 
589                                         (label_spacing_px > 6*digit_height || tick_index%2 == 0 || cur == 0) && 
590                                         (label_spacing_px > 3*digit_height || tick_index%4 == 0 || cur == 0))
591                                 {
592                                         if (fabs((int)cur) >= 2000 && (((int) cur)/1000)*1000 == ((int) cur))
593                                                 sprintf (unit_str, "%dk", ((int) cur)/1000);
594                                         else
595                                                 sprintf (unit_str, "%d", (int) cur);
596                                         for (j = 0; j < (int) strlen (unit_str); j++)
597                                                 {
598                                                         digit_str[0] = unit_str[j];
599                   
600                                                         pango_layout_set_text (pango_layout, digit_str, 1);
601       
602                                                         gdk_draw_layout (ruler->backing_store, gc,
603                                                                                                                          xthickness + 1, 
604                                                                                                                          pos + digit_height * (j) + 1,
605                                                                                                                          pango_layout); 
606                                                 }
607                                 }
609                         /* Calculate cur from start rather than incrementing by subd_incr
610                          * in each iteration. This is to avoid propagation of floating point 
611                          * errors in subd_incr.
612                          */
613                         ++tick_index;
614                         cur = start + tick_index * subd_incr;
615                 }
616         }
619 static void
620 sp_vruler_draw_pos (GtkRuler *ruler)
622   GtkWidget *widget;
623   GdkGC *gc;
624   int i;
625   gint x, y;
626   gint width, height;
627   gint bs_width, bs_height;
628   gint xthickness;
629   gint ythickness;
630   gfloat increment;
632   g_return_if_fail (ruler != NULL);
633   g_return_if_fail (SP_IS_VRULER (ruler));
635   if (GTK_WIDGET_DRAWABLE (ruler))
636     {
637       widget = GTK_WIDGET (ruler);
639       gc = widget->style->fg_gc[GTK_STATE_NORMAL];
640       xthickness = widget->style->xthickness;
641       ythickness = widget->style->ythickness;
642       width = widget->allocation.width - xthickness * 2;
643       height = widget->allocation.height; // in pixels; is apparently 2 pixels shorter than the canvas at each end
645       bs_height = width / 2;
646       bs_height |= 1;  /* make sure it's odd */
647       bs_width = bs_height / 2 + 1;
649       if ((bs_width > 0) && (bs_height > 0))
650         {
651           /*  If a backing store exists, restore the ruler  */
652           if (ruler->backing_store && ruler->non_gr_exp_gc)
653             gdk_draw_pixmap (ruler->widget.window,
654                              ruler->non_gr_exp_gc,
655                              ruler->backing_store,
656                              ruler->xsrc, ruler->ysrc,
657                              ruler->xsrc, ruler->ysrc,
658                              bs_width, bs_height);
660           increment = (gfloat) (height + 2*UNUSED_PIXELS) / (ruler->upper - ruler->lower);
662           // Calculate the coordinates (x, y, in pixels) of the tip of the triangle
663       x = (width + bs_width) / 2 + xthickness;
664           y = int(Inkscape::round((ruler->position - ruler->lower) * increment + double(ythickness - bs_height) / 2.0) - UNUSED_PIXELS);
666           for (i = 0; i < bs_width; i++)
667             gdk_draw_line (widget->window, gc,
668                            x + i, y + i,
669                            x + i, y + bs_height - 1 - i);
671           ruler->xsrc = x;
672           ruler->ysrc = y;
673         }
674     }
677 /**
678  * The vruler widget's size_allocate callback.
679  */
680 static void
681 sp_vruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
683     g_assert (widget != NULL);
684     g_assert (SP_IS_VRULER (widget));    
685     
686     // First call the default gtk_widget_size_allocate() method (which is being overridden here)
687     if (GTK_WIDGET_CLASS (vruler_parent_class)->size_allocate)
688         (* GTK_WIDGET_CLASS (vruler_parent_class)->size_allocate) (widget, allocation);
689  
690     // Now the size of the ruler has changed, the ruler bounds (upper & lower) need to be updated
691     // For this we first need to obtain a pointer to the desktop, by walking up the tree of ancestors    
692     GtkWidget *parent = gtk_widget_get_parent(widget);    
693     do {
694         if (SP_IS_DESKTOP_WIDGET(parent)) {
695             // Now we've found the desktop widget we can have the ruler boundaries updated 
696             sp_desktop_widget_update_vruler(SP_DESKTOP_WIDGET(parent));
697             // If the size of the ruler has increased, then a blank part is uncovered; therefore
698             // it must be redrawn  
699             sp_vruler_draw_ticks(GTK_RULER(widget));
700             break;   
701         }
702         parent = gtk_widget_get_parent(parent);
703     } while (parent != NULL);
707 /// Ruler metrics.
708 static GtkRulerMetric const sp_ruler_metrics[] = {
709   // NOTE: the order of records in this struct must correspond to the SPMetric enum.
710   {(gchar*) "NONE",  (gchar*) "", 1, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
711   {(gchar*) "millimeters", (gchar*) "mm", PX_PER_MM, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
712   {(gchar*) "centimeters", (gchar*) "cm", PX_PER_CM, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
713   {(gchar*) "inches",      (gchar*) "in", PX_PER_IN, { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }, { 1, 2, 4, 8, 16 }},
714   {(gchar*) "feet",        (gchar*) "ft", PX_PER_FT, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
715   {(gchar*) "points",      (gchar*) "pt", PX_PER_PT, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
716   {(gchar*) "picas",       (gchar*) "pc", PX_PER_PC, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
717   {(gchar*) "pixels",      (gchar*) "px", PX_PER_PX, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
718   {(gchar*) "meters",      (gchar*) "m",  PX_PER_M,  { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
719 };
721 void
722 sp_ruler_set_metric (GtkRuler *ruler,
723                      SPMetric  metric)
725   g_return_if_fail (ruler != NULL);
726   g_return_if_fail (GTK_IS_RULER (ruler));
727   g_return_if_fail((unsigned) metric < G_N_ELEMENTS(sp_ruler_metrics));
729   if (metric == 0) 
730         return;
732   ruler->metric = const_cast<GtkRulerMetric *>(&sp_ruler_metrics[metric]);
734   if (GTK_WIDGET_DRAWABLE (ruler))
735     gtk_widget_queue_draw (GTK_WIDGET (ruler));