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 *
11 * Copyright (C) 1999-2005 authors
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #include <cmath>
17 #include <cstdio>
18 #include <string.h>
19 #include "widget-sizes.h"
20 #include "desktop-widget.h"
21 #include "ruler.h"
22 #include "unit-constants.h"
23 #include "round.h"
25 #define MINIMUM_INCR 5
26 #define MAXIMUM_SUBDIVIDE 5
27 #define MAXIMUM_SCALES 10
28 #define UNUSED_PIXELS 2 // There appear to be two pixels that are not being used at each end of the ruler
30 static void sp_hruler_class_init (SPHRulerClass *klass);
31 static void sp_hruler_init (SPHRuler *hruler);
32 static gint sp_hruler_motion_notify (GtkWidget *widget, GdkEventMotion *event);
33 static void sp_hruler_draw_ticks (GtkRuler *ruler);
34 static void sp_hruler_draw_pos (GtkRuler *ruler);
35 static void sp_hruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
37 static GtkWidgetClass *hruler_parent_class;
39 GtkType
40 sp_hruler_get_type (void)
41 {
42 static GtkType hruler_type = 0;
44 if (!hruler_type)
45 {
46 static const GtkTypeInfo hruler_info =
47 {
48 "SPHRuler",
49 sizeof (SPHRuler),
50 sizeof (SPHRulerClass),
51 (GtkClassInitFunc) sp_hruler_class_init,
52 (GtkObjectInitFunc) sp_hruler_init,
53 /* reserved_1 */ NULL,
54 /* reserved_2 */ NULL,
55 (GtkClassInitFunc) NULL,
56 };
58 hruler_type = gtk_type_unique (gtk_ruler_get_type (), &hruler_info);
59 }
61 return hruler_type;
62 }
64 static void
65 sp_hruler_class_init (SPHRulerClass *klass)
66 {
67 GtkWidgetClass *widget_class;
68 GtkRulerClass *ruler_class;
70 hruler_parent_class = (GtkWidgetClass *) gtk_type_class (GTK_TYPE_RULER);
72 widget_class = (GtkWidgetClass*) klass;
73 ruler_class = (GtkRulerClass*) klass;
75 widget_class->motion_notify_event = sp_hruler_motion_notify;
76 widget_class->size_allocate = sp_hruler_size_allocate;
78 ruler_class->draw_ticks = sp_hruler_draw_ticks;
79 ruler_class->draw_pos = sp_hruler_draw_pos;
80 }
82 static void
83 sp_hruler_init (SPHRuler *hruler)
84 {
85 GtkWidget *widget;
87 widget = GTK_WIDGET (hruler);
88 widget->requisition.width = widget->style->xthickness * 2 + 1;
89 widget->requisition.height = widget->style->ythickness * 2 + RULER_HEIGHT;
90 }
93 GtkWidget*
94 sp_hruler_new (void)
95 {
96 return GTK_WIDGET (gtk_type_new (sp_hruler_get_type ()));
97 }
99 static gint
100 sp_hruler_motion_notify (GtkWidget *widget,
101 GdkEventMotion *event)
102 {
103 GtkRuler *ruler;
105 g_return_val_if_fail (widget != NULL, FALSE);
106 g_return_val_if_fail (SP_IS_HRULER (widget), FALSE);
107 g_return_val_if_fail (event != NULL, FALSE);
109 ruler = GTK_RULER (widget);
110 double x = event->x; //Although event->x is double according to the docs, it only appears to return integers
111 ruler->position = ruler->lower + (ruler->upper - ruler->lower) * (x + UNUSED_PIXELS) / (widget->allocation.width + 2*UNUSED_PIXELS);
113 /* Make sure the ruler has been allocated already */
114 if (ruler->backing_store != NULL)
115 gtk_ruler_draw_pos (ruler);
117 return FALSE;
118 }
120 static void
121 sp_hruler_draw_ticks (GtkRuler *ruler)
122 {
123 GtkWidget *widget;
124 GdkGC *gc, *bg_gc;
125 PangoFontDescription *pango_desc;
126 PangoContext *pango_context;
127 PangoLayout *pango_layout;
128 gint i, tick_index;
129 gint width, height;
130 gint xthickness;
131 gint ythickness;
132 gint length, ideal_length;
133 double lower, upper; /* Upper and lower limits, in ruler units */
134 double increment; /* Number of pixels per unit */
135 gint scale; /* Number of units per major unit */
136 double subd_incr;
137 double start, end, cur;
138 gchar unit_str[32];
139 gint digit_height;
140 gint text_width;
141 gint pos;
143 g_return_if_fail (ruler != NULL);
144 g_return_if_fail (SP_IS_HRULER (ruler));
146 if (!GTK_WIDGET_DRAWABLE (ruler))
147 return;
149 widget = GTK_WIDGET (ruler);
151 gc = widget->style->fg_gc[GTK_STATE_NORMAL];
152 bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
154 pango_desc = widget->style->font_desc;
156 // Create the pango layout
157 pango_context = gtk_widget_get_pango_context (widget);
159 pango_layout = pango_layout_new (pango_context);
161 PangoFontDescription *fs = pango_font_description_new ();
162 pango_font_description_set_size (fs, RULER_FONT_SIZE);
163 pango_layout_set_font_description (pango_layout, fs);
164 pango_font_description_free (fs);
166 digit_height = (int) floor (RULER_FONT_SIZE * RULER_FONT_VERTICAL_SPACING / PANGO_SCALE + 0.5);
168 xthickness = widget->style->xthickness;
169 ythickness = widget->style->ythickness;
171 width = widget->allocation.width; // in pixels; is apparently 2 pixels shorter than the canvas at each end
172 height = widget->allocation.height;// - ythickness * 2;
174 gtk_paint_box (widget->style, ruler->backing_store,
175 GTK_STATE_NORMAL, GTK_SHADOW_NONE,
176 NULL, widget, "hruler",
177 0, 0,
178 widget->allocation.width, widget->allocation.height);
180 upper = ruler->upper / ruler->metric->pixels_per_unit;
181 lower = ruler->lower / ruler->metric->pixels_per_unit;
183 if ((upper - lower) == 0)
184 return;
185 increment = (double) (width + 2*UNUSED_PIXELS) / (upper - lower);
187 /* determine the scale
188 * We calculate the text size as for the vruler instead of using
189 * text_width = gdk_string_width(font, unit_str), so that the result
190 * for the scale looks consistent with an accompanying vruler
191 */
192 scale = (int)(ceil (ruler->max_size / ruler->metric->pixels_per_unit));
193 sprintf (unit_str, "%d", scale);
194 text_width = strlen (unit_str) * digit_height + 1;
196 for (scale = 0; scale < MAXIMUM_SCALES; scale++)
197 if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_width)
198 break;
200 if (scale == MAXIMUM_SCALES)
201 scale = MAXIMUM_SCALES - 1;
203 /* drawing starts here */
204 length = 0;
205 for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--)
206 {
207 subd_incr = ruler->metric->ruler_scale[scale] /
208 ruler->metric->subdivide[i];
209 if (subd_incr * fabs(increment) <= MINIMUM_INCR)
210 continue;
212 /* Calculate the length of the tickmarks. Make sure that
213 * this length increases for each set of ticks
214 */
215 ideal_length = height / (i + 1) - 1;
216 if (ideal_length > ++length)
217 length = ideal_length;
219 if (lower < upper)
220 {
221 start = floor (lower / subd_incr) * subd_incr;
222 end = ceil (upper / subd_incr) * subd_incr;
223 }
224 else
225 {
226 start = floor (upper / subd_incr) * subd_incr;
227 end = ceil (lower / subd_incr) * subd_incr;
228 }
230 tick_index = 0;
231 cur = start;
233 while (cur <= end)
234 {
235 pos = int(Inkscape::round ((cur - lower) * increment) - UNUSED_PIXELS);
237 gdk_draw_line (ruler->backing_store, gc,
238 pos, height + ythickness,
239 pos, height - length + ythickness);
241 /* draw label */
242 double label_spacing_px = (increment*(double)ruler->metric->ruler_scale[scale])/ruler->metric->subdivide[i];
243 if (i == 0 &&
244 (label_spacing_px > 6*digit_height || tick_index%2 == 0 || cur == 0) &&
245 (label_spacing_px > 3*digit_height || tick_index%4 == 0 || cur == 0))
246 {
247 if (fabs((int)cur) >= 2000 && (((int) cur)/1000)*1000 == ((int) cur))
248 sprintf (unit_str, "%dk", ((int) cur)/1000);
249 else
250 sprintf (unit_str, "%d", (int) cur);
252 pango_layout_set_text (pango_layout, unit_str, -1);
254 gdk_draw_layout (ruler->backing_store, gc,
255 pos + 2, 0, pango_layout);
256 }
258 /* Calculate cur from start rather than incrementing by subd_incr
259 * in each iteration. This is to avoid propagation of floating point
260 * errors in subd_incr.
261 */
262 ++tick_index;
263 cur = start + (((double)tick_index) * (double)ruler->metric->ruler_scale[scale])/ ruler->metric->subdivide[i];
264 }
265 }
266 }
268 static void
269 sp_hruler_draw_pos (GtkRuler *ruler)
270 {
271 GtkWidget *widget;
272 GdkGC *gc;
273 int i;
274 gint x, y;
275 gint width, height;
276 gint bs_width, bs_height;
277 gint xthickness;
278 gint ythickness;
279 gfloat increment;
281 g_return_if_fail (ruler != NULL);
282 g_return_if_fail (SP_IS_HRULER (ruler));
284 if (GTK_WIDGET_DRAWABLE (ruler))
285 {
286 widget = GTK_WIDGET (ruler);
288 gc = widget->style->fg_gc[GTK_STATE_NORMAL];
289 xthickness = widget->style->xthickness;
290 ythickness = widget->style->ythickness;
291 width = widget->allocation.width; // in pixels; is apparently 2 pixels shorter than the canvas at each end
292 height = widget->allocation.height - ythickness * 2;
294 bs_width = height / 2;
295 bs_width |= 1; /* make sure it's odd */
296 bs_height = bs_width / 2 + 1;
298 if ((bs_width > 0) && (bs_height > 0))
299 {
300 /* If a backing store exists, restore the ruler */
301 if (ruler->backing_store && ruler->non_gr_exp_gc)
302 gdk_draw_pixmap (ruler->widget.window,
303 ruler->non_gr_exp_gc,
304 ruler->backing_store,
305 ruler->xsrc, ruler->ysrc,
306 ruler->xsrc, ruler->ysrc,
307 bs_width, bs_height);
309 increment = (gfloat) (width + 2*UNUSED_PIXELS) / (ruler->upper - ruler->lower);
311 x = int(Inkscape::round((ruler->position - ruler->lower) * increment + double(xthickness - bs_width) / 2.0) - 1);
312 y = (height + bs_height) / 2 + ythickness;
314 for (i = 0; i < bs_height; i++)
315 gdk_draw_line (widget->window, gc,
316 x + i, y + i,
317 x + bs_width - 1 - i, y + i);
320 ruler->xsrc = x;
321 ruler->ysrc = y;
322 }
323 }
324 }
326 /**
327 * The hruler widget's size_allocate callback.
328 */
329 static void
330 sp_hruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
331 {
332 g_assert (widget != NULL);
333 g_assert (SP_IS_HRULER (widget));
335 // First call the default gtk_widget_size_allocate() method (which is being overridden here)
336 if (GTK_WIDGET_CLASS (hruler_parent_class)->size_allocate)
337 (* GTK_WIDGET_CLASS (hruler_parent_class)->size_allocate) (widget, allocation);
339 // Now the size of the ruler has changed, the ruler bounds (upper & lower) need to be updated
340 // For this we first need to obtain a pointer to the desktop, by walking up the tree of ancestors
341 GtkWidget *parent = gtk_widget_get_parent(widget);
342 do {
343 if (SP_IS_DESKTOP_WIDGET(parent)) {
344 // Now we've found the desktop widget we can have the ruler boundaries updated
345 sp_desktop_widget_update_hruler(SP_DESKTOP_WIDGET(parent));
346 // If the size of the ruler has increased, then a blank part is uncovered; therefore
347 // it must be redrawn
348 sp_hruler_draw_ticks(GTK_RULER(widget));
349 break;
350 }
351 parent = gtk_widget_get_parent(parent);
352 } while (parent != NULL);
353 }
358 // vruler
360 static void sp_vruler_class_init (SPVRulerClass *klass);
361 static void sp_vruler_init (SPVRuler *vruler);
362 static gint sp_vruler_motion_notify (GtkWidget *widget,
363 GdkEventMotion *event);
364 static void sp_vruler_draw_ticks (GtkRuler *ruler);
365 static void sp_vruler_draw_pos (GtkRuler *ruler);
366 static void sp_vruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
368 static GtkWidgetClass *vruler_parent_class;
370 GtkType
371 sp_vruler_get_type (void)
372 {
373 static GtkType vruler_type = 0;
375 if (!vruler_type)
376 {
377 static const GtkTypeInfo vruler_info =
378 {
379 "SPVRuler",
380 sizeof (SPVRuler),
381 sizeof (SPVRulerClass),
382 (GtkClassInitFunc) sp_vruler_class_init,
383 (GtkObjectInitFunc) sp_vruler_init,
384 /* reserved_1 */ NULL,
385 /* reserved_2 */ NULL,
386 (GtkClassInitFunc) NULL,
387 };
389 vruler_type = gtk_type_unique (gtk_ruler_get_type (), &vruler_info);
390 }
392 return vruler_type;
393 }
395 static void
396 sp_vruler_class_init (SPVRulerClass *klass)
397 {
398 GtkWidgetClass *widget_class;
399 GtkRulerClass *ruler_class;
401 vruler_parent_class = (GtkWidgetClass *) gtk_type_class (GTK_TYPE_RULER);
403 widget_class = (GtkWidgetClass*) klass;
404 ruler_class = (GtkRulerClass*) klass;
406 widget_class->motion_notify_event = sp_vruler_motion_notify;
407 widget_class->size_allocate = sp_vruler_size_allocate;
409 ruler_class->draw_ticks = sp_vruler_draw_ticks;
410 ruler_class->draw_pos = sp_vruler_draw_pos;
411 }
413 static void
414 sp_vruler_init (SPVRuler *vruler)
415 {
416 GtkWidget *widget;
418 widget = GTK_WIDGET (vruler);
419 widget->requisition.width = widget->style->xthickness * 2 + RULER_WIDTH;
420 widget->requisition.height = widget->style->ythickness * 2 + 1;
421 }
423 GtkWidget*
424 sp_vruler_new (void)
425 {
426 return GTK_WIDGET (gtk_type_new (sp_vruler_get_type ()));
427 }
430 static gint
431 sp_vruler_motion_notify (GtkWidget *widget,
432 GdkEventMotion *event)
433 {
434 GtkRuler *ruler;
436 g_return_val_if_fail (widget != NULL, FALSE);
437 g_return_val_if_fail (SP_IS_VRULER (widget), FALSE);
438 g_return_val_if_fail (event != NULL, FALSE);
440 ruler = GTK_RULER (widget);
441 double y = event->y; //Although event->y is double according to the docs, it only appears to return integers
442 ruler->position = ruler->lower + (ruler->upper - ruler->lower) * (y + UNUSED_PIXELS) / (widget->allocation.height + 2*UNUSED_PIXELS);
444 /* Make sure the ruler has been allocated already */
445 if (ruler->backing_store != NULL)
446 gtk_ruler_draw_pos (ruler);
448 return FALSE;
449 }
451 static void
452 sp_vruler_draw_ticks (GtkRuler *ruler)
453 {
454 GtkWidget *widget;
455 GdkGC *gc, *bg_gc;
456 PangoFontDescription *pango_desc;
457 PangoContext *pango_context;
458 PangoLayout *pango_layout;
459 gint i, j, tick_index;
460 gint width, height;
461 gint xthickness;
462 gint ythickness;
463 gint length, ideal_length;
464 double lower, upper; /* Upper and lower limits, in ruler units */
465 double increment; /* Number of pixels per unit */
466 gint scale; /* Number of units per major unit */
467 double subd_incr;
468 double start, end, cur;
469 gchar unit_str[32];
470 gchar digit_str[2] = { '\0', '\0' };
471 gint digit_height;
472 gint text_height;
473 gint pos;
475 g_return_if_fail (ruler != NULL);
476 g_return_if_fail (SP_IS_VRULER (ruler));
478 if (!GTK_WIDGET_DRAWABLE (ruler))
479 return;
481 widget = GTK_WIDGET (ruler);
483 gc = widget->style->fg_gc[GTK_STATE_NORMAL];
484 bg_gc = widget->style->bg_gc[GTK_STATE_NORMAL];
486 pango_desc = widget->style->font_desc;
488 // Create the pango layout
489 pango_context = gtk_widget_get_pango_context (widget);
491 pango_layout = pango_layout_new (pango_context);
493 PangoFontDescription *fs = pango_font_description_new ();
494 pango_font_description_set_size (fs, RULER_FONT_SIZE);
495 pango_layout_set_font_description (pango_layout, fs);
496 pango_font_description_free (fs);
498 digit_height = (int) floor (RULER_FONT_SIZE * RULER_FONT_VERTICAL_SPACING / PANGO_SCALE + 0.5);
500 xthickness = widget->style->xthickness;
501 ythickness = widget->style->ythickness;
503 width = widget->allocation.height; //in pixels; is apparently 2 pixels shorter than the canvas at each end
504 height = widget->allocation.width;// - ythickness * 2;
506 gtk_paint_box (widget->style, ruler->backing_store,
507 GTK_STATE_NORMAL, GTK_SHADOW_NONE,
508 NULL, widget, "vruler",
509 0, 0,
510 widget->allocation.width, widget->allocation.height);
512 upper = ruler->upper / ruler->metric->pixels_per_unit;
513 lower = ruler->lower / ruler->metric->pixels_per_unit;
515 if ((upper - lower) == 0)
516 return;
517 increment = (double) (width + 2*UNUSED_PIXELS) / (upper - lower);
519 /* determine the scale
520 * use the maximum extents of the ruler to determine the largest
521 * possible number to be displayed. Calculate the height in pixels
522 * of this displayed text. Use this height to find a scale which
523 * leaves sufficient room for drawing the ruler.
524 */
525 scale = (int)ceil (ruler->max_size / ruler->metric->pixels_per_unit);
526 sprintf (unit_str, "%d", scale);
527 text_height = strlen (unit_str) * digit_height + 1;
529 for (scale = 0; scale < MAXIMUM_SCALES; scale++)
530 if (ruler->metric->ruler_scale[scale] * fabs(increment) > 2 * text_height)
531 break;
533 if (scale == MAXIMUM_SCALES)
534 scale = MAXIMUM_SCALES - 1;
536 /* drawing starts here */
537 length = 0;
538 for (i = MAXIMUM_SUBDIVIDE - 1; i >= 0; i--) {
539 subd_incr = (double) ruler->metric->ruler_scale[scale] /
540 (double) ruler->metric->subdivide[i];
541 if (subd_incr * fabs(increment) <= MINIMUM_INCR)
542 continue;
544 /* Calculate the length of the tickmarks. Make sure that
545 * this length increases for each set of ticks
546 */
547 ideal_length = height / (i + 1) - 1;
548 if (ideal_length > ++length)
549 length = ideal_length;
551 if (lower < upper)
552 {
553 start = floor (lower / subd_incr) * subd_incr;
554 end = ceil (upper / subd_incr) * subd_incr;
555 }
556 else
557 {
558 start = floor (upper / subd_incr) * subd_incr;
559 end = ceil (lower / subd_incr) * subd_incr;
560 }
562 tick_index = 0;
563 cur = start;
565 while (cur < end) {
566 pos = int(Inkscape::round ((cur - lower) * increment) - UNUSED_PIXELS);
568 gdk_draw_line (ruler->backing_store, gc,
569 height + xthickness - length, pos,
570 height + xthickness, pos);
572 /* draw label */
573 double label_spacing_px = fabs((increment*(double)ruler->metric->ruler_scale[scale])/ruler->metric->subdivide[i]);
574 if (i == 0 &&
575 (label_spacing_px > 6*digit_height || tick_index%2 == 0 || cur == 0) &&
576 (label_spacing_px > 3*digit_height || tick_index%4 == 0 || cur == 0))
577 {
578 if (fabs((int)cur) >= 2000 && (((int) cur)/1000)*1000 == ((int) cur))
579 sprintf (unit_str, "%dk", ((int) cur)/1000);
580 else
581 sprintf (unit_str, "%d", (int) cur);
582 for (j = 0; j < (int) strlen (unit_str); j++)
583 {
584 digit_str[0] = unit_str[j];
586 pango_layout_set_text (pango_layout, digit_str, 1);
588 gdk_draw_layout (ruler->backing_store, gc,
589 xthickness + 1,
590 pos + digit_height * (j) + 1,
591 pango_layout);
592 }
593 }
595 /* Calculate cur from start rather than incrementing by subd_incr
596 * in each iteration. This is to avoid propagation of floating point
597 * errors in subd_incr.
598 */
599 ++tick_index;
600 cur = start + (((double)tick_index) * (double)ruler->metric->ruler_scale[scale])/ ruler->metric->subdivide[i];
601 }
602 }
603 }
605 static void
606 sp_vruler_draw_pos (GtkRuler *ruler)
607 {
608 GtkWidget *widget;
609 GdkGC *gc;
610 int i;
611 gint x, y;
612 gint width, height;
613 gint bs_width, bs_height;
614 gint xthickness;
615 gint ythickness;
616 gfloat increment;
618 g_return_if_fail (ruler != NULL);
619 g_return_if_fail (SP_IS_VRULER (ruler));
621 if (GTK_WIDGET_DRAWABLE (ruler))
622 {
623 widget = GTK_WIDGET (ruler);
625 gc = widget->style->fg_gc[GTK_STATE_NORMAL];
626 xthickness = widget->style->xthickness;
627 ythickness = widget->style->ythickness;
628 width = widget->allocation.width - xthickness * 2;
629 height = widget->allocation.height; // in pixels; is apparently 2 pixels shorter than the canvas at each end
631 bs_height = width / 2;
632 bs_height |= 1; /* make sure it's odd */
633 bs_width = bs_height / 2 + 1;
635 if ((bs_width > 0) && (bs_height > 0))
636 {
637 /* If a backing store exists, restore the ruler */
638 if (ruler->backing_store && ruler->non_gr_exp_gc)
639 gdk_draw_pixmap (ruler->widget.window,
640 ruler->non_gr_exp_gc,
641 ruler->backing_store,
642 ruler->xsrc, ruler->ysrc,
643 ruler->xsrc, ruler->ysrc,
644 bs_width, bs_height);
646 increment = (gfloat) (height + 2*UNUSED_PIXELS) / (ruler->upper - ruler->lower);
648 x = (width + bs_width) / 2 + xthickness;
649 y = int(Inkscape::round((ruler->position - ruler->lower) * increment + double(ythickness - bs_height) / 2.0) - 1);
651 for (i = 0; i < bs_width; i++)
652 gdk_draw_line (widget->window, gc,
653 x + i, y + i,
654 x + i, y + bs_height - 1 - i);
656 ruler->xsrc = x;
657 ruler->ysrc = y;
658 }
659 }
660 }
662 /**
663 * The vruler widget's size_allocate callback.
664 */
665 static void
666 sp_vruler_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
667 {
668 g_assert (widget != NULL);
669 g_assert (SP_IS_VRULER (widget));
671 // First call the default gtk_widget_size_allocate() method (which is being overridden here)
672 if (GTK_WIDGET_CLASS (vruler_parent_class)->size_allocate)
673 (* GTK_WIDGET_CLASS (vruler_parent_class)->size_allocate) (widget, allocation);
675 // Now the size of the ruler has changed, the ruler bounds (upper & lower) need to be updated
676 // For this we first need to obtain a pointer to the desktop, by walking up the tree of ancestors
677 GtkWidget *parent = gtk_widget_get_parent(widget);
678 do {
679 if (SP_IS_DESKTOP_WIDGET(parent)) {
680 // Now we've found the desktop widget we can have the ruler boundaries updated
681 sp_desktop_widget_update_vruler(SP_DESKTOP_WIDGET(parent));
682 // If the size of the ruler has increased, then a blank part is uncovered; therefore
683 // it must be redrawn
684 sp_vruler_draw_ticks(GTK_RULER(widget));
685 break;
686 }
687 parent = gtk_widget_get_parent(parent);
688 } while (parent != NULL);
689 }
692 /// Ruler metrics.
693 static GtkRulerMetric const sp_ruler_metrics[] = {
694 // NOTE: the order of records in this struct must correspond to the SPMetric enum.
695 {"NONE", "", 1, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
696 {"millimeters", "mm", PX_PER_MM, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
697 {"centimeters", "cm", PX_PER_CM, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
698 {"inches", "in", PX_PER_IN, { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }, { 1, 2, 4, 8, 16 }},
699 {"points", "pt", PX_PER_PT, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
700 {"pixels", "px", PX_PER_PX, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
701 {"meters", "m", PX_PER_M, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }},
702 };
704 void
705 sp_ruler_set_metric (GtkRuler *ruler,
706 SPMetric metric)
707 {
708 g_return_if_fail (ruler != NULL);
709 g_return_if_fail (GTK_IS_RULER (ruler));
710 g_return_if_fail((unsigned) metric < G_N_ELEMENTS(sp_ruler_metrics));
712 if (metric == 0)
713 return;
715 ruler->metric = const_cast<GtkRulerMetric *>(&sp_ruler_metrics[metric]);
717 if (GTK_WIDGET_DRAWABLE (ruler))
718 gtk_widget_queue_draw (GTK_WIDGET (ruler));
719 }