1 /* $Id: gtkdatabox_ruler.c 4 2008-06-22 09:19:11Z rbock $ */
2 /* GTK - The GIMP Toolkit
3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26  */
27 
28 /* Modified by Roland Bock 2007, see ChangeLog */
29 
30 #include <gtkdatabox_ruler.h>
31 
32 #include <math.h>
33 #include <glib/gprintf.h>
34 
35 #include <string.h>
36 
37 #define RULER_SIZE          20
38 
39 #define ROUND(x) ((int) ((x) + 0.5))
40 
41 #define FORMAT_LENGTH 20 /* the length of the label format string */
42 
43 #define LINEAR_FORMAT_MARKUP "%%-+%dg"
44 #define LOG_FORMAT_MARKUP "%%-%dg"
45 
46 static void gtk_databox_ruler_draw_ticks (GtkDataboxRuler * ruler);
47 static void gtk_databox_ruler_draw_pos (GtkDataboxRuler * ruler);
48 static gint gtk_databox_ruler_motion_notify (GtkWidget * widget,
49         GdkEventMotion * event);
50 static void gtk_databox_ruler_realize (GtkWidget * widget);
51 static void gtk_databox_ruler_unrealize (GtkWidget * widget);
52 static void gtk_databox_ruler_size_allocate (GtkWidget * widget,
53         GtkAllocation * allocation);
54 static gint gtk_databox_ruler_draw (GtkWidget * widget,
55 	cairo_t * cr);
56 static void gtk_databox_ruler_get_preferred_width (GtkWidget *widget,
57 	gint *minimal_width,
58 	gint *natural_width);
59 static void gtk_databox_ruler_get_preferred_height (GtkWidget *widget,
60 	gint *minimal_height,
61 	gint *natural_height);
62 static void gtk_databox_ruler_create_backing_surface (GtkDataboxRuler * ruler);
63 static void gtk_databox_ruler_set_property (GObject * object,
64         guint prop_id,
65         const GValue * value,
66         GParamSpec * pspec);
67 static void gtk_databox_ruler_get_property (GObject * object,
68         guint prop_id,
69         GValue * value,
70         GParamSpec * pspec);
71 
72 enum {
73     PROP_0,
74     PROP_LOWER,
75     PROP_UPPER,
76     PROP_POSITION,
77     PROP_DRAW_POSITION,
78     PROP_MAX_LENGTH,
79     PROP_ORIENTATION,
80     PROP_TEXT_ORIENTATION,
81     PROP_TEXT_ALIGNMENT,
82     PROP_TEXT_HOFFSET,
83     PROP_DRAW_TICKS,
84     PROP_DRAW_SUBTICKS,
85     PROP_MANUAL_TICKS,
86     PROP_MANUAL_TICK_CNT,
87     PROP_MANUAL_TICK_LABELS,
88     PROP_INVERT_EDGE,
89     PROP_LINEAR_LABEL_FORMAT,
90     PROP_LOG_LABEL_FORMAT,
91     PROP_BOX_SHADOW,
92     PROP_END_OF_LIST
93 };
94 
95 struct _GtkDataboxRulerPrivate
96 {
97 	cairo_surface_t *backing_surface;
98 	gint old_width;
99 	gint old_height;
100 
101     gint xsrc;
102     gint ysrc;
103     /* The lower limit of the ruler */
104     gdouble lower;
105     /* The upper limit of the ruler */
106     gdouble upper;
107     /* The position of the mark on the ruler */
108     gdouble position;
109     /* whether to draw the position arrows*/
110     gboolean draw_position;
111 
112     /* The maximum length of the labels (in characters) */
113     guint max_length;
114     /* The scale type of the ruler */
115     GtkDataboxScaleType scale_type;
116     /* Orientation of the ruler */
117     GtkOrientation orientation;
118     /* Orientation of the tick marks on the vertical ruler */
119     GtkOrientation text_orientation;
120 
121     /* Whether the horizontal text on the vertical ruler is aligned left or right or center */
122     PangoAlignment text_alignment;
123     /* horizontal tick offset (shift ticks left or right) */
124     gint text_hoffset;
125 
126     /* The maximum height of text on the horizontal ruler */
127     gint max_x_text_height;
128     /* The maximum width of text on the horizontal ruler */
129     gint max_y_text_width;
130 
131     /* When true draw the ticks */
132     gboolean draw_ticks;
133 
134     /* When true draw the subticks */
135     gboolean draw_subticks;
136 
137     /* Whether the ruler is inverted (i.e. drawn with the edge on the left or right, top or bottom) */
138     gboolean invert_edge;
139 
140     /* Strings used to mark up the g_sprintf label format - one for log scaling and one for linear scaling */
141     gchar linear_format[FORMAT_LENGTH], log_format[FORMAT_LENGTH];
142 
143     /* If we are manually setting ticks, this will be non-null */
144     gfloat *manual_ticks;
145     guint manual_tick_cnt;
146     /* we have the option of manually setting the tick labels. */
147     gchar **manual_tick_labels;
148 
149     GtkShadowType box_shadow; /* The type of shadow drawn on the ruler pixmap */
150 };
151 
G_DEFINE_TYPE(GtkDataboxRuler,gtk_databox_ruler,GTK_TYPE_WIDGET)152 G_DEFINE_TYPE (GtkDataboxRuler, gtk_databox_ruler, GTK_TYPE_WIDGET)
153 
154 static void gtk_databox_ruler_class_init (GtkDataboxRulerClass * class) {
155     GObjectClass *gobject_class;
156     GtkWidgetClass *widget_class;
157 
158     gobject_class = G_OBJECT_CLASS (class);
159     widget_class = (GtkWidgetClass *) class;
160 
161     gobject_class->set_property = gtk_databox_ruler_set_property;
162     gobject_class->get_property = gtk_databox_ruler_get_property;
163 
164     widget_class->realize = gtk_databox_ruler_realize;
165     widget_class->unrealize = gtk_databox_ruler_unrealize;
166     widget_class->size_allocate = gtk_databox_ruler_size_allocate;
167     widget_class->draw = gtk_databox_ruler_draw;
168     widget_class->motion_notify_event = gtk_databox_ruler_motion_notify;
169     widget_class->get_preferred_width = gtk_databox_ruler_get_preferred_width;
170     widget_class->get_preferred_height = gtk_databox_ruler_get_preferred_height;
171 
172     g_object_class_install_property (gobject_class,
173                                      PROP_LOWER,
174                                      g_param_spec_double ("lower",
175                                              "Lower",
176                                              "Lower limit of ruler",
177                                              -G_MAXDOUBLE,
178                                              G_MAXDOUBLE,
179                                              0.0,
180                                              G_PARAM_READWRITE));
181 
182     g_object_class_install_property (gobject_class,
183                                      PROP_UPPER,
184                                      g_param_spec_double ("upper",
185                                              "Upper",
186                                              "Upper limit of ruler",
187                                              -G_MAXDOUBLE,
188                                              G_MAXDOUBLE,
189                                              0.0,
190                                              G_PARAM_READWRITE));
191 
192     g_object_class_install_property (gobject_class,
193                                      PROP_POSITION,
194                                      g_param_spec_double ("position",
195                                              "Position",
196                                              "Position of mark on the ruler",
197                                              -G_MAXDOUBLE,
198                                              G_MAXDOUBLE,
199                                              0.0,
200                                              G_PARAM_READWRITE));
201 
202     g_object_class_install_property (gobject_class,
203                                      PROP_DRAW_POSITION,
204                                      g_param_spec_uint ("draw-position",
205                                              "Draw Position Arrows",
206                                              "Draw the position arrows: true or false",
207                                              FALSE,
208                                              TRUE,
209                                              TRUE,
210                                              G_PARAM_READWRITE));
211 
212     g_object_class_install_property (gobject_class,
213                                      PROP_MAX_LENGTH,
214                                      g_param_spec_uint ("max-length",
215                                              "Max Length",
216                                              "Maximum length of the labels (in digits)",
217                                              2,
218                                              GTK_DATABOX_RULER_MAX_MAX_LENGTH,
219                                              6, G_PARAM_READWRITE));
220     g_object_class_install_property (gobject_class,
221                                      PROP_ORIENTATION,
222                                      g_param_spec_uint ("orientation",
223                                              "Orientation",
224                                              "Orientation of the ruler: horizontal or vertical",
225                                              GTK_ORIENTATION_HORIZONTAL,
226                                              GTK_ORIENTATION_VERTICAL,
227                                              GTK_ORIENTATION_HORIZONTAL,
228                                              G_PARAM_READWRITE |
229                                              G_PARAM_CONSTRUCT_ONLY));
230     g_object_class_install_property (gobject_class,
231                                      PROP_TEXT_ORIENTATION,
232                                      g_param_spec_uint ("text-orientation",
233                                              "Text Orientation",
234                                              "Orientation of the tick mark text (on the vertical ruler): horizontal or vertical",
235                                              GTK_ORIENTATION_HORIZONTAL,
236                                              GTK_ORIENTATION_VERTICAL,
237                                              GTK_ORIENTATION_VERTICAL,
238                                              G_PARAM_READWRITE));
239     g_object_class_install_property (gobject_class,
240                                      PROP_TEXT_ALIGNMENT,
241                                      g_param_spec_uint ("text-alignment",
242                                              "Text Alignment",
243                                              "Alignment of the tick mark text (on the vertical ruler when using horizonal text): { PANGO_ALIGN_LEFT, PANGO_ALIGN_CENTER, PANGO_ALIGN_RIGHT}",
244                                              PANGO_ALIGN_LEFT,
245                                              PANGO_ALIGN_RIGHT,
246                                              PANGO_ALIGN_LEFT,
247                                              G_PARAM_READWRITE));
248     g_object_class_install_property (gobject_class,
249                                      PROP_TEXT_HOFFSET,
250                                      g_param_spec_uint ("text-hoffset",
251                                              "Text Horizonal offset",
252                                              "Move the tick mark text left or right : pixels",
253                                              0,
254                                              20,
255                                              0,
256                                              G_PARAM_READWRITE));
257     g_object_class_install_property (gobject_class,
258                                      PROP_DRAW_TICKS,
259                                      g_param_spec_uint ("draw-ticks",
260                                              "Draw Ticks",
261                                              "Draw the Ticks: true or false",
262                                              FALSE,
263                                              TRUE,
264                                              TRUE,
265                                              G_PARAM_READWRITE));
266     g_object_class_install_property (gobject_class,
267                                      PROP_DRAW_SUBTICKS,
268                                      g_param_spec_uint ("draw-subticks",
269                                              "Draw Subticks",
270                                              "Draw the subticks: true or false",
271                                              FALSE,
272                                              TRUE,
273                                              TRUE,
274                                              G_PARAM_READWRITE));
275     g_object_class_install_property (gobject_class,
276                                      PROP_MANUAL_TICKS,
277                                      g_param_spec_pointer ("manual-ticks",
278                                              "Manual Ticks",
279                                              "Manually specify the tick locations",
280                                              G_PARAM_READWRITE));
281     g_object_class_install_property (gobject_class,
282                                      PROP_MANUAL_TICK_CNT,
283                                      g_param_spec_uint ("manual-tick-cnt",
284                                              "Manual Tick Count",
285                                              "The number of manual ticks in the manual_tick array: horizontal or vertical",
286                                              0,
287                                              G_MAXUINT,
288                                              0,
289                                              G_PARAM_READWRITE));
290     g_object_class_install_property (gobject_class,
291                                      PROP_MANUAL_TICK_LABELS,
292                                      g_param_spec_pointer ("manual-tick-labels",
293                                              "Manual Tick Labels",
294                                              "Manually specify the tick labels",
295                                              G_PARAM_READWRITE));
296     g_object_class_install_property (gobject_class,
297                                      PROP_INVERT_EDGE,
298                                      g_param_spec_uint ("invert-edge",
299                                              "Invert Edge",
300                                              "Invert the Edge - the edge is drawn inverted: true or false",
301                                              FALSE,
302                                              TRUE,
303                                              FALSE,
304                                              G_PARAM_READWRITE));
305     g_object_class_install_property (gobject_class,
306                                      PROP_LINEAR_LABEL_FORMAT,
307                                      g_param_spec_string ("linear-label-format",
308                                              "Linear Label Format",
309                                              "Linear Label format mark up strings: marked up formatting strings for linear labels (i.e. \"%%-+%dg\")",
310                                              LINEAR_FORMAT_MARKUP,
311                                              G_PARAM_READWRITE));
312     g_object_class_install_property (gobject_class,
313                                      PROP_LOG_LABEL_FORMAT,
314                                      g_param_spec_string ("log-label-format",
315                                              "Log Label Format",
316                                              "Log Label format mark up strings: marked up formatting strings for log labels (i.e. \"%%-%dg\")",
317                                              LOG_FORMAT_MARKUP,
318                                              G_PARAM_READWRITE));
319     g_object_class_install_property (gobject_class,
320                                      PROP_BOX_SHADOW,
321                                      g_param_spec_uint ("box-shadow",
322                                              "Box Shadow",
323                                              "Style of the box shadow: GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT",
324                                              GTK_SHADOW_NONE,
325                                              GTK_SHADOW_ETCHED_OUT,
326                                              GTK_SHADOW_OUT,
327                                              G_PARAM_READWRITE));
328 }
329 
330 static void
gtk_databox_ruler_init(GtkDataboxRuler * ruler)331 gtk_databox_ruler_init (GtkDataboxRuler * ruler) {
332     ruler->priv = g_new0 (GtkDataboxRulerPrivate, 1);
333     ruler->priv->backing_surface = NULL;
334     ruler->priv->xsrc = 0;
335     ruler->priv->ysrc = 0;
336     ruler->priv->lower = 0;
337     ruler->priv->upper = 0;
338     ruler->priv->position = 0;
339     ruler->priv->draw_position = TRUE;
340     ruler->priv->max_length = 6;
341     ruler->priv->scale_type = GTK_DATABOX_SCALE_LINEAR;
342     ruler->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
343     ruler->priv->text_orientation = GTK_ORIENTATION_VERTICAL;
344     ruler->priv->text_hoffset=0;
345     ruler->priv->max_x_text_height = 0;
346     ruler->priv->max_y_text_width = 0;
347     ruler->priv->draw_ticks = TRUE;
348     ruler->priv->draw_subticks = TRUE;
349     ruler->priv->invert_edge = FALSE;
350     g_stpcpy(ruler->priv->linear_format, LINEAR_FORMAT_MARKUP);
351     g_stpcpy(ruler->priv->log_format, LOG_FORMAT_MARKUP);
352     ruler->priv->manual_ticks=NULL;
353     ruler->priv->manual_tick_cnt=0;
354     ruler->priv->manual_tick_labels=NULL;
355     ruler->priv->box_shadow=GTK_SHADOW_OUT;
356 }
357 
358 /**
359  * gtk_databox_ruler_new:
360  * @orientation: orientation of the ruler
361  *
362  * Creates a new #GtkDataboxRuler widget with the given @orientation (horizontal or vertical).
363  *
364  * Return value: A new #GtkDataboxRuler
365  **/
366 GtkWidget *
gtk_databox_ruler_new(GtkOrientation orientation)367 gtk_databox_ruler_new (GtkOrientation orientation) {
368     return g_object_new (GTK_DATABOX_TYPE_RULER, "orientation", orientation,
369                          NULL);
370 }
371 
372 static gint
gtk_databox_ruler_motion_notify(GtkWidget * widget,GdkEventMotion * event)373 gtk_databox_ruler_motion_notify (GtkWidget * widget, GdkEventMotion * event) {
374     GtkDataboxRuler *ruler;
375     gint x;
376     gint y;
377 	GtkAllocation allocation;
378 
379     ruler = GTK_DATABOX_RULER (widget);
380 	gtk_widget_get_allocation(widget, &allocation);
381 
382     if (gtk_databox_ruler_get_draw_position (ruler)) {
383 
384         if (event->is_hint) {
385             gdk_window_get_device_position (gtk_widget_get_window(widget), event->device, &x, &y, NULL);
386         } else {
387             x = event->x;
388             y = event->y;
389         }
390 
391         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
392             ruler->priv->position =
393                 ruler->priv->lower +
394                 ((ruler->priv->upper - ruler->priv->lower) * x) / allocation.width;
395         else
396             ruler->priv->position =
397                 ruler->priv->lower +
398                 ((ruler->priv->upper - ruler->priv->lower) * y) / allocation.height;
399 
400         g_object_notify (G_OBJECT (ruler), "position");
401 
402         /*  Make sure the ruler has been allocated already  */
403         if (ruler->priv->backing_surface != NULL)
404             if (ruler->priv->draw_position)
405                 gtk_databox_ruler_draw_pos (ruler);
406     }
407     return FALSE;
408 }
409 
410 static void
gtk_databox_ruler_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)411 gtk_databox_ruler_set_property (GObject * object,
412                                 guint prop_id,
413                                 const GValue * value, GParamSpec * pspec) {
414     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (object);
415 
416     switch (prop_id) {
417     case PROP_LOWER:
418         gtk_databox_ruler_set_range (ruler, g_value_get_double (value),
419                                      ruler->priv->upper, ruler->priv->position);
420         break;
421     case PROP_UPPER:
422         gtk_databox_ruler_set_range (ruler, ruler->priv->lower,
423                                      g_value_get_double (value),
424                                      ruler->priv->position);
425         break;
426     case PROP_POSITION:
427         gtk_databox_ruler_set_range (ruler, ruler->priv->lower, ruler->priv->upper,
428                                      g_value_get_double (value));
429         break;
430     case PROP_DRAW_POSITION:
431         gtk_databox_ruler_set_draw_position (ruler, (gboolean) g_value_get_boolean (value));
432         break;
433     case PROP_MAX_LENGTH:
434         gtk_databox_ruler_set_max_length (ruler, g_value_get_uint (value));
435         break;
436     case PROP_ORIENTATION:
437         gtk_databox_ruler_set_orientation (ruler, (GtkOrientation) g_value_get_uint (value));
438         break;
439     case PROP_TEXT_ORIENTATION:
440         gtk_databox_ruler_set_text_orientation (ruler, (GtkOrientation) g_value_get_uint (value));
441         break;
442     case PROP_TEXT_ALIGNMENT:
443         gtk_databox_ruler_set_text_alignment (ruler, (GtkOrientation) g_value_get_uint (value));
444         break;
445     case PROP_TEXT_HOFFSET:
446         gtk_databox_ruler_set_text_hoffset (ruler, (GtkOrientation) g_value_get_uint (value));
447         break;
448     case PROP_DRAW_TICKS:
449         gtk_databox_ruler_set_draw_ticks (ruler, (gboolean) g_value_get_boolean (value));
450         break;
451     case PROP_DRAW_SUBTICKS:
452         gtk_databox_ruler_set_draw_subticks (ruler, (gboolean) g_value_get_boolean (value));
453         break;
454     case PROP_MANUAL_TICKS:
455         gtk_databox_ruler_set_manual_ticks (ruler, (gfloat *) g_value_get_pointer (value));
456         break;
457     case PROP_MANUAL_TICK_CNT:
458         gtk_databox_ruler_set_manual_tick_cnt (ruler, g_value_get_uint (value));
459         break;
460     case PROP_MANUAL_TICK_LABELS:
461         gtk_databox_ruler_set_manual_tick_labels (ruler, (gchar **) g_value_get_pointer (value));
462         break;
463     case PROP_INVERT_EDGE:
464         gtk_databox_ruler_set_invert_edge (ruler, (gboolean) g_value_get_boolean (value));
465         break;
466     case PROP_LINEAR_LABEL_FORMAT:
467         gtk_databox_ruler_set_linear_label_format (ruler, (gchar *) g_value_get_string (value));
468         break;
469     case PROP_LOG_LABEL_FORMAT:
470         gtk_databox_ruler_set_log_label_format (ruler, (gchar *) g_value_get_string (value));
471         break;
472     case PROP_BOX_SHADOW:
473         gtk_databox_ruler_set_box_shadow (ruler, (GtkShadowType) g_value_get_uint (value));
474         break;
475     default:
476         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
477         break;
478     }
479 }
480 
481 static void
gtk_databox_ruler_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)482 gtk_databox_ruler_get_property (GObject * object,
483                                 guint prop_id,
484                                 GValue * value, GParamSpec * pspec) {
485     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (object);
486 
487     switch (prop_id) {
488     case PROP_LOWER:
489         g_value_set_double (value, ruler->priv->lower);
490         break;
491     case PROP_UPPER:
492         g_value_set_double (value, ruler->priv->upper);
493         break;
494     case PROP_POSITION:
495         g_value_set_double (value, ruler->priv->position);
496         break;
497     case PROP_DRAW_POSITION:
498         g_value_set_boolean (value, ruler->priv->draw_position);
499         break;
500     case PROP_MAX_LENGTH:
501         g_value_set_uint (value, ruler->priv->max_length);
502         break;
503     case PROP_ORIENTATION:
504         g_value_set_uint (value, ruler->priv->orientation);
505         break;
506     case PROP_TEXT_ORIENTATION:
507         g_value_set_uint (value, ruler->priv->text_orientation);
508         break;
509     case PROP_TEXT_ALIGNMENT:
510         g_value_set_uint (value, ruler->priv->text_alignment);
511         break;
512     case PROP_TEXT_HOFFSET:
513         g_value_set_uint (value, ruler->priv->text_hoffset);
514         break;
515     case PROP_DRAW_TICKS:
516         g_value_set_boolean (value, ruler->priv->draw_ticks);
517         break;
518     case PROP_DRAW_SUBTICKS:
519         g_value_set_boolean (value, ruler->priv->draw_subticks);
520         break;
521     case PROP_MANUAL_TICKS:
522         g_value_set_pointer (value, ruler->priv->manual_ticks);
523         break;
524     case PROP_MANUAL_TICK_CNT:
525         g_value_set_uint (value, ruler->priv->manual_tick_cnt);
526         break;
527     case PROP_MANUAL_TICK_LABELS:
528         g_value_set_pointer (value, ruler->priv->manual_tick_labels);
529         break;
530     case PROP_INVERT_EDGE:
531         g_value_set_boolean (value, ruler->priv->invert_edge);
532         break;
533     case PROP_LINEAR_LABEL_FORMAT:
534         g_value_set_string (value, ruler->priv->linear_format);
535         break;
536     case PROP_LOG_LABEL_FORMAT:
537         g_value_set_string (value, ruler->priv->log_format);
538         break;
539     case PROP_BOX_SHADOW:
540         g_value_set_uint (value, ruler->priv->box_shadow);
541         break;
542     default:
543         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
544         break;
545     }
546 }
547 
548 /**
549  * gtk_databox_ruler_set_range:
550  * @ruler: a #GtkDataboxRuler
551  * @lower: lower limit of the ruler
552  * @upper: upper limit of the ruler
553  * @position: current position of the mark on the ruler
554  *
555  * Sets values indicating the range and current position of a #GtkDataboxRuler.
556  *
557  * See gtk_databox_ruler_get_range().
558  **/
559 void
gtk_databox_ruler_set_range(GtkDataboxRuler * ruler,gdouble lower,gdouble upper,gdouble position)560 gtk_databox_ruler_set_range (GtkDataboxRuler * ruler,
561                              gdouble lower, gdouble upper, gdouble position) {
562     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
563 
564     g_object_freeze_notify (G_OBJECT (ruler));
565     if (ruler->priv->lower != lower) {
566         ruler->priv->lower = lower;
567         g_object_notify (G_OBJECT (ruler), "lower");
568     }
569     if (ruler->priv->upper != upper) {
570         ruler->priv->upper = upper;
571         g_object_notify (G_OBJECT (ruler), "upper");
572     }
573     if (ruler->priv->position != position) {
574         ruler->priv->position = position;
575         g_object_notify (G_OBJECT (ruler), "position");
576     }
577     g_object_thaw_notify (G_OBJECT (ruler));
578 
579     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
580         gtk_widget_queue_draw (GTK_WIDGET (ruler));
581 }
582 
583 /**
584  * gtk_databox_ruler_set_max_length:
585  * @ruler: A #GtkDataboxRuler widget
586  * @max_length: Maximum length (digits) of tick labels
587  *
588  * This function sets the maximum number of digits to be used for each tick
589  * label of the @ruler.
590  *
591  * The @max_length cannot be smaller than 2 and not bigger than
592  * #GTK_DATABOX_RULER_MAX_MAX_LENGTH.
593  *
594  */
595 void
gtk_databox_ruler_set_max_length(GtkDataboxRuler * ruler,guint max_length)596 gtk_databox_ruler_set_max_length (GtkDataboxRuler * ruler, guint max_length) {
597     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
598     g_return_if_fail (max_length < GTK_DATABOX_RULER_MAX_MAX_LENGTH + 1);
599 
600     g_object_freeze_notify (G_OBJECT (ruler));
601     if (ruler->priv->max_length != max_length) {
602         ruler->priv->max_length = max_length;
603         g_object_notify (G_OBJECT (ruler), "max-length");
604     }
605     g_object_thaw_notify (G_OBJECT (ruler));
606 
607     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
608         gtk_widget_queue_draw (GTK_WIDGET (ruler));
609 }
610 
611 /**
612  * gtk_databox_ruler_set_scale_type:
613  * @ruler: A #GtkDataboxRuler widget
614  * @scale_type: The new scale type for @ruler (linear or logarithmic)
615  *
616  * This function sets the scale type of the @ruler.
617  *
618  */
619 void
gtk_databox_ruler_set_scale_type(GtkDataboxRuler * ruler,GtkDataboxScaleType scale_type)620 gtk_databox_ruler_set_scale_type (GtkDataboxRuler * ruler,
621                                   GtkDataboxScaleType scale_type) {
622     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
623 
624     if (ruler->priv->scale_type != scale_type) {
625         ruler->priv->scale_type = scale_type;
626         /* g_object_notify (G_OBJECT (ruler), "scale-type"); */
627     }
628 
629     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
630         gtk_widget_queue_draw (GTK_WIDGET (ruler));
631 }
632 
633 /**
634  * gtk_databox_ruler_set_orientation:
635  * @ruler: a #GtkDataboxRuler
636  * @orientation: new orientation of the ruler
637  *
638  * Sets the orientation of the @ruler (horizontal or vertical).
639  **/
640 void
gtk_databox_ruler_set_orientation(GtkDataboxRuler * ruler,GtkOrientation orientation)641 gtk_databox_ruler_set_orientation (GtkDataboxRuler * ruler,
642                                    GtkOrientation orientation) {
643     GtkWidget *widget;
644     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
645 
646     if (ruler->priv->orientation != orientation) {
647         ruler->priv->orientation = orientation;
648         g_object_notify (G_OBJECT (ruler), "orientation");
649     }
650 
651     widget = GTK_WIDGET (ruler);
652 
653     // get the padding
654 	GtkRequisition gtkRequisition;
655     GtkStyleContext *context= gtk_widget_get_style_context (widget);
656     GtkBorder padding;
657     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
658 
659     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
660         gtkRequisition.width = (padding.left+padding.right) * 2 + 1;
661         gtkRequisition.height = (padding.top+padding.bottom) * 2 + RULER_SIZE;
662     } else {
663     	    gtkRequisition.height = (padding.top+padding.bottom) * 2 + 1;
664         if (ruler->priv->max_y_text_width==0)
665     	    gtkRequisition.width = (padding.left+padding.right) * 2 + RULER_SIZE;
666         else
667 	        gtkRequisition.width = (padding.left+padding.right) + ruler->priv->max_y_text_width;
668     }
669 	gtk_widget_set_size_request(widget, gtkRequisition.width, gtkRequisition.height);
670 
671     if (gtk_widget_is_drawable (widget)) {
672         gtk_widget_queue_resize (widget);
673         gtk_widget_queue_draw (widget);
674     }
675 }
676 
gtk_databox_ruler_get_preferred_width(GtkWidget * widget,gint * minimal_width,gint * natural_width)677 static void gtk_databox_ruler_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)
678 {
679     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
680 	GtkOrientation orientation;
681 	gint width;
682     GtkStyleContext *context= gtk_widget_get_style_context (widget);
683     GtkBorder padding;
684     gint xthickness;
685     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
686     xthickness=padding.left+padding.right;
687 
688 	orientation = ruler->priv->orientation;
689 
690     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
691         width = xthickness * 2 + 1;
692     }
693 	else
694 	{
695         if (ruler->priv->max_y_text_width==0)
696             width = xthickness * 2 + RULER_SIZE;
697         else
698             width = ruler->priv->max_y_text_width;
699     }
700         *minimal_width = *natural_width = width;
701 }
702 
gtk_databox_ruler_get_preferred_height(GtkWidget * widget,gint * minimal_height,gint * natural_height)703 static void gtk_databox_ruler_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height)
704 {
705     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
706 	GtkOrientation orientation;
707 	gint height;
708 
709     GtkStyleContext *context= gtk_widget_get_style_context (widget);
710     GtkBorder padding;
711     gint ythickness;
712     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
713     ythickness=padding.top+padding.bottom;
714 
715 	orientation = ruler->priv->orientation;
716 
717     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
718         height = ythickness * 2 + RULER_SIZE;
719     } else {
720         height = ythickness * 2 + 1;
721     }
722 	*minimal_height = *natural_height = height;
723 }
724 
725 
726 /**
727  * gtk_databox_ruler_get_orientation:
728  * @ruler: a #GtkDataboxRuler
729  *
730  * Gets the orientation of the @ruler (horizontal or vertical).
731  *
732  * Return value: Orientation of the @ruler.
733  **/
734 GtkOrientation
gtk_databox_ruler_get_orientation(GtkDataboxRuler * ruler)735 gtk_databox_ruler_get_orientation (GtkDataboxRuler * ruler) {
736 
737     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
738 
739     return ruler->priv->orientation;
740 }
741 
742 /**
743  * gtk_databox_ruler_set_text_orientation:
744  * @ruler: a #GtkDataboxRuler
745  * @orientation: new orientation of the tick marks in the vertical ruler
746  *
747  * Sets the text orientation of the @ruler (vertical).
748  **/
749 void
gtk_databox_ruler_set_text_orientation(GtkDataboxRuler * ruler,GtkOrientation orientation)750 gtk_databox_ruler_set_text_orientation (GtkDataboxRuler * ruler,
751                                         GtkOrientation orientation) {
752     GtkWidget *widget;
753 	GtkRequisition gtkRequisition;
754     GtkStyleContext *context;
755     GtkBorder padding;
756     gint minimal_height, natural_height;
757 
758     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
759 
760     /* check this is a vertical ruler */
761     if (ruler->priv->orientation != GTK_ORIENTATION_VERTICAL)
762         return;
763 
764     if (ruler->priv->text_orientation != orientation) {
765         ruler->priv->text_orientation = orientation;
766         g_object_notify (G_OBJECT (ruler), "text-orientation");
767     }
768 
769     widget = GTK_WIDGET (ruler);
770 
771     // get the padding
772     context= gtk_widget_get_style_context (widget);
773     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
774     gtk_databox_ruler_get_preferred_height (widget, &minimal_height, &natural_height);
775     gtkRequisition.height=natural_height;
776     if (ruler->priv->max_y_text_width==0)
777         gtkRequisition.width = (padding.left + padding.right) * 2 + RULER_SIZE;
778     else
779         gtkRequisition.width = ruler->priv->max_y_text_width;
780     gtk_widget_set_size_request(widget, gtkRequisition.width, gtkRequisition.height);
781 
782     if (gtk_widget_is_drawable (widget)) {
783         gtk_widget_queue_draw (widget);
784     }
785 }
786 
787 /**
788  * gtk_databox_ruler_get_text_orientation:
789  * @ruler: a #GtkDataboxRuler
790  *
791  * Gets the text orientation of the @ruler (horizontal or vertical).
792  * Horizontal rulers always have horizontal text
793  *
794  * Return value: Text orientation of the @ruler.
795  **/
796 GtkOrientation
gtk_databox_ruler_get_text_orientation(GtkDataboxRuler * ruler)797 gtk_databox_ruler_get_text_orientation (GtkDataboxRuler * ruler) {
798 
799     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
800 
801     return ruler->priv->text_orientation;
802 }
803 
804 /**
805  * gtk_databox_ruler_set_text_alignment:
806  * @ruler: a #GtkDataboxRuler
807  * @alignment: new alignment of the tick label in the vertical ruler when horizontal text is set
808  *
809  * Sets the text alignment of the @ruler (vertical with horizontal text).
810  **/
811 void
gtk_databox_ruler_set_text_alignment(GtkDataboxRuler * ruler,PangoAlignment alignment)812 gtk_databox_ruler_set_text_alignment (GtkDataboxRuler * ruler,
813                                         PangoAlignment alignment) {
814     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
815 
816     /* check this is a vertical ruler */
817     if (ruler->priv->orientation != GTK_ORIENTATION_VERTICAL)
818         return;
819 
820     if (ruler->priv->text_alignment != alignment) {
821         ruler->priv->text_alignment = alignment;
822         g_object_notify (G_OBJECT (ruler), "text-alignment");
823     }
824 
825     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
826         gtk_widget_queue_draw (GTK_WIDGET (ruler));
827 }
828 
829 /**
830  * gtk_databox_ruler_get_text_alignment:
831  * @ruler: a #GtkDataboxRuler
832  *
833  * Gets the text alignment of the @ruler (vertical).
834  * Vertical rulers with vertical text do not use this flag
835  *
836  * Return value: Text alignment of the @ruler.
837  **/
838 PangoAlignment
gtk_databox_ruler_get_text_alignment(GtkDataboxRuler * ruler)839 gtk_databox_ruler_get_text_alignment (GtkDataboxRuler * ruler) {
840 
841     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
842 
843     return ruler->priv->text_alignment;
844 }
845 
846 /**
847  * gtk_databox_ruler_set_text_hoffset:
848  * @ruler: a #GtkDataboxRuler
849  * @offset: new x offset of the tick label in the ruler
850  *
851  * Sets the text x (horizontal) offset of the @ruler.
852  **/
853 void
gtk_databox_ruler_set_text_hoffset(GtkDataboxRuler * ruler,gint offset)854 gtk_databox_ruler_set_text_hoffset (GtkDataboxRuler * ruler,
855                                         gint offset) {
856     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
857 
858     if (ruler->priv->text_hoffset != offset) {
859         ruler->priv->text_hoffset = offset;
860         g_object_notify (G_OBJECT (ruler), "text-hoffset");
861     }
862 
863     if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
864         gtk_widget_queue_draw (GTK_WIDGET (ruler));
865 }
866 
867 /**
868  * gtk_databox_ruler_get_text_hoffset:
869  * @ruler: a #GtkDataboxRuler
870  *
871  * Gets the text x (horizontal) offset of the @ruler.
872  *
873  * Return value: Text horizontal (x) offset of the @ruler.
874  **/
875 gint
gtk_databox_ruler_get_text_hoffset(GtkDataboxRuler * ruler)876 gtk_databox_ruler_get_text_hoffset (GtkDataboxRuler * ruler) {
877 
878     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
879 
880     return ruler->priv->text_hoffset;
881 }
882 
883 /**
884  * gtk_databox_ruler_set_draw_position:
885  * @ruler: a #GtkDataboxRuler
886  * @draw: whether to draw the position arrows on the ruler at all
887  *
888  * Sets the option for drawing the position arrows. If false, don't draw any arrows,
889  * If true draw arrows.
890  **/
891 void
gtk_databox_ruler_set_draw_position(GtkDataboxRuler * ruler,gboolean draw)892 gtk_databox_ruler_set_draw_position(GtkDataboxRuler * ruler, gboolean draw) {
893     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
894 
895     if (ruler->priv->draw_position!= draw) {
896         ruler->priv->draw_position = draw;
897         g_object_notify (G_OBJECT (ruler), "draw-position");
898 
899         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
900             gtk_widget_queue_draw (GTK_WIDGET (ruler));
901     }
902 }
903 
904 /**
905  * gtk_databox_ruler_get_draw_position:
906  * @ruler: a #GtkDataboxRuler
907  *
908  * Gets the draw position arrows option from the @ruler (horizontal or vertical).
909  *
910  * Return value: Position drawing option of the @ruler.
911  **/
912 gboolean
gtk_databox_ruler_get_draw_position(GtkDataboxRuler * ruler)913 gtk_databox_ruler_get_draw_position(GtkDataboxRuler * ruler) {
914 
915     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
916 
917     return ruler->priv->draw_position;
918 }
919 
920 /**
921  * gtk_databox_ruler_set_draw_ticks:
922  * @ruler: a #GtkDataboxRuler
923  * @draw: whether to draw the ticks on the ruler at all
924  *
925  * Sets the option for drawing the ticks. If false, don't draw any ticks,
926  * If true draw major ticks and subticks if the draw_subticks boolean is set.
927  **/
928 void
gtk_databox_ruler_set_draw_ticks(GtkDataboxRuler * ruler,gboolean draw)929 gtk_databox_ruler_set_draw_ticks(GtkDataboxRuler * ruler, gboolean draw) {
930     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
931 
932     if (ruler->priv->draw_ticks!= draw) {
933         ruler->priv->draw_ticks = draw;
934         g_object_notify (G_OBJECT (ruler), "draw-ticks");
935 
936         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
937             gtk_widget_queue_draw (GTK_WIDGET (ruler));
938     }
939 }
940 
941 /**
942  * gtk_databox_ruler_get_draw_ticks:
943  * @ruler: a #GtkDataboxRuler
944  *
945  * Gets the draw ticks option from the @ruler (horizontal or vertical).
946  *
947  * Return value: Tick drawing option of the @ruler.
948  **/
949 gboolean
gtk_databox_ruler_get_draw_ticks(GtkDataboxRuler * ruler)950 gtk_databox_ruler_get_draw_ticks(GtkDataboxRuler * ruler) {
951 
952     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
953 
954     return ruler->priv->draw_ticks;
955 }
956 
957 /**
958  * gtk_databox_ruler_set_draw_subticks:
959  * @ruler: a #GtkDataboxRuler
960  * @draw: whether to draw the subticks on the ruler
961  *
962  * Sets the option for drawing the subticks
963  **/
964 void
gtk_databox_ruler_set_draw_subticks(GtkDataboxRuler * ruler,gboolean draw)965 gtk_databox_ruler_set_draw_subticks(GtkDataboxRuler * ruler, gboolean draw) {
966     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
967 
968     if (ruler->priv->draw_subticks!= draw) {
969         ruler->priv->draw_subticks = draw;
970         g_object_notify (G_OBJECT (ruler), "draw-subticks");
971 
972         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
973             gtk_widget_queue_draw (GTK_WIDGET (ruler));
974     }
975 }
976 
977 /**
978  * gtk_databox_ruler_get_draw_subticks:
979  * @ruler: a #GtkDataboxRuler
980  *
981  * Gets the draw subticks option from the @ruler (horizontal or vertical).
982  *
983  * Return value: Subtick drawing option of the @ruler.
984  **/
985 gboolean
gtk_databox_ruler_get_draw_subticks(GtkDataboxRuler * ruler)986 gtk_databox_ruler_get_draw_subticks(GtkDataboxRuler * ruler) {
987 
988     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
989 
990     return ruler->priv->draw_subticks;
991 }
992 
993 /**
994  * gtk_databox_grid_set_manual_ticks:
995  * @ruler: a #GtkDataboxRuler
996  * @manual_ticks: sets the pointer to the hline values for the @ruler
997  *
998  * Sets the ticks for the @ruler (horizontal or vertical).
999  **/
1000 void
gtk_databox_ruler_set_manual_ticks(GtkDataboxRuler * ruler,gfloat * manual_ticks)1001 gtk_databox_ruler_set_manual_ticks (GtkDataboxRuler * ruler, gfloat *manual_ticks) {
1002     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1003 
1004     ruler->priv->manual_ticks = manual_ticks;
1005 
1006     g_object_notify (G_OBJECT(ruler), "manual-ticks");
1007 }
1008 
1009 /**
1010  * gtk_databox_grid_get_manual_ticks:
1011  * @ruler: a #GtkDataboxRuler
1012  *
1013  * Gets the pointer to the manual tick values for the @ruler.
1014  *
1015  * Return value: Pointer to the manual tick values for the @ruler.
1016  **/
1017 gfloat*
gtk_databox_ruler_get_manual_ticks(GtkDataboxRuler * ruler)1018 gtk_databox_ruler_get_manual_ticks (GtkDataboxRuler * ruler) {
1019     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
1020 
1021     return ruler->priv->manual_ticks;
1022 }
1023 
1024 /**
1025  * gtk_databox_grid_set_manual_tick_cnt:
1026  * @ruler: a #GtkDataboxRuler
1027  * @manual_tick_cnt: sets the number of manual ticks for the @ruler
1028  *
1029  * Sets the number of manual ticks for the @ruler (horizontal or vertical).
1030  **/
1031 void
gtk_databox_ruler_set_manual_tick_cnt(GtkDataboxRuler * ruler,guint manual_tick_cnt)1032 gtk_databox_ruler_set_manual_tick_cnt (GtkDataboxRuler * ruler, guint manual_tick_cnt) {
1033     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1034 
1035     ruler->priv->manual_tick_cnt = manual_tick_cnt;
1036 
1037     g_object_notify (G_OBJECT(ruler), "manual-tick-cnt");
1038 }
1039 
1040 /**
1041  * gtk_databox_grid_get_manual_tick_cnt:
1042  * @ruler: a #GtkDataboxRuler
1043  *
1044  * Gets the number manual tick values for the @ruler.
1045  *
1046  * Return value: The number of manual tick values for the @ruler.
1047  **/
1048 guint
gtk_databox_ruler_get_manual_tick_cnt(GtkDataboxRuler * ruler)1049 gtk_databox_ruler_get_manual_tick_cnt (GtkDataboxRuler * ruler) {
1050     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
1051 
1052     return ruler->priv->manual_tick_cnt;
1053 }
1054 
1055 /**
1056  * gtk_databox_grid_set_manual_tick_labels:
1057  * @ruler: a #GtkDataboxRuler
1058  * @manual_tick_labels: sets the pointer to the labels for the ticks on the @ruler
1059  *
1060  * Note: This function should be preceeded by calls to gtk_databox_ruler_set_manual_ticks() and  gtk_databox_ruler_set_manual_tick_cnt().
1061  *       The number of tick labels should match gtk_databox_ruler_get_manual_tick_cnt().
1062  *
1063  * Sets the tick labels of the @ruler (horizontal or vertical).
1064  **/
1065 void
gtk_databox_ruler_set_manual_tick_labels(GtkDataboxRuler * ruler,gchar ** manual_tick_labels)1066 gtk_databox_ruler_set_manual_tick_labels (GtkDataboxRuler * ruler, gchar **manual_tick_labels) {
1067     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1068 
1069     ruler->priv->manual_tick_labels = manual_tick_labels;
1070 
1071     g_object_notify (G_OBJECT(ruler), "manual-tick-labels");
1072 }
1073 
1074 /**
1075  * gtk_databox_grid_get_manual_tick_labels:
1076  * @ruler: a #GtkDataboxRuler
1077  *
1078  * Gets the pointer to the manual tick labels for the @ruler.
1079  *
1080  * Return value: Pointer to the manual tick labels for the @ruler.
1081  **/
1082 gchar**
gtk_databox_ruler_get_manual_tick_labels(GtkDataboxRuler * ruler)1083 gtk_databox_ruler_get_manual_tick_labels (GtkDataboxRuler * ruler) {
1084     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
1085 
1086     return ruler->priv->manual_tick_labels;
1087 }
1088 
1089 /**
1090  * gtk_databox_ruler_set_invert_edge:
1091  * @ruler: a #GtkDataboxRuler
1092  * @invert: whether to draw the ruler detail with the edge inverted
1093  *
1094  * Sets the option for drawing the ruler detail on the opposite edge
1095  **/
1096 void
gtk_databox_ruler_set_invert_edge(GtkDataboxRuler * ruler,gboolean invert)1097 gtk_databox_ruler_set_invert_edge(GtkDataboxRuler * ruler, gboolean invert) {
1098     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1099 
1100     if (ruler->priv->invert_edge!= invert) {
1101         ruler->priv->invert_edge = invert;
1102         g_object_notify (G_OBJECT (ruler), "invert-edge");
1103 
1104         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
1105             gtk_widget_queue_draw (GTK_WIDGET (ruler));
1106     }
1107 }
1108 
1109 /**
1110  * gtk_databox_ruler_get_invert_edge:
1111  * @ruler: a #GtkDataboxRuler
1112  *
1113  * Gets the invert edge option from the @ruler (horizontal or vertical).
1114  *
1115  * Return value: Edge inversion option of the @ruler.
1116  **/
1117 gboolean
gtk_databox_ruler_get_invert_edge(GtkDataboxRuler * ruler)1118 gtk_databox_ruler_get_invert_edge(GtkDataboxRuler * ruler) {
1119 
1120     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
1121 
1122     return ruler->priv->invert_edge;
1123 }
1124 
1125 /**
1126  * gtk_databox_ruler_set_linear_label_format:
1127  * @ruler: a #GtkDataboxRuler
1128  * @invert: How to format the labels for linear rulers
1129  *
1130  * Sets the meta format string for the labels of linear rulers, for example "%%+-%dg" will become "%+-#g" where # is the int variable
1131  **/
1132 void
gtk_databox_ruler_set_linear_label_format(GtkDataboxRuler * ruler,gchar * format)1133 gtk_databox_ruler_set_linear_label_format(GtkDataboxRuler * ruler, gchar *format) {
1134     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1135 
1136     if (g_strcmp0(ruler->priv->linear_format, format)!=0) {
1137         if (strlen(format)>FORMAT_LENGTH) {
1138             g_warning("maximum format length = %d chars exceeded, truncating to the maximum from %d",FORMAT_LENGTH,(int)strlen(format));
1139             format[FORMAT_LENGTH]='\0';
1140         }
1141 
1142         g_stpcpy(ruler->priv->linear_format, format);
1143         g_object_notify (G_OBJECT (ruler), "linear-label-format");
1144 
1145         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
1146             gtk_widget_queue_draw (GTK_WIDGET (ruler));
1147     }
1148 }
1149 
1150 /**
1151  * gtk_databox_ruler_get_linear_label_format:
1152  * @ruler: a #GtkDataboxRuler
1153  *
1154  * Gets the linear label meta format of the @ruler (horizontal or vertical).
1155  *
1156  * Return value: The string meta format the @ruler NULL on failure.
1157  **/
1158 gchar*
gtk_databox_ruler_get_linear_label_format(GtkDataboxRuler * ruler)1159 gtk_databox_ruler_get_linear_label_format(GtkDataboxRuler * ruler) {
1160 
1161     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
1162 
1163     return ruler->priv->linear_format;
1164 }
1165 
1166 /**
1167  * gtk_databox_ruler_set_log_label_format:
1168  * @ruler: a #GtkDataboxRuler
1169  * @invert: How to format the labels for log scaled rulers
1170  *
1171  * Sets the meta format string for the labels of log scaled rulers, for example "%%-%dg" will become "%-#g" where # is the int variable
1172  **/
1173 void
gtk_databox_ruler_set_log_label_format(GtkDataboxRuler * ruler,gchar * format)1174 gtk_databox_ruler_set_log_label_format(GtkDataboxRuler * ruler, gchar *format) {
1175     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1176 
1177     if (g_strcmp0(ruler->priv->log_format, format)!=0) {
1178         if (strlen(format)>FORMAT_LENGTH) {
1179             g_warning("maximum format length = %d chars exceeded, truncating to the maximum from %d",FORMAT_LENGTH,(int)strlen(format));
1180             format[FORMAT_LENGTH]='\0';
1181         }
1182 
1183         g_stpcpy(ruler->priv->log_format, format);
1184         g_object_notify (G_OBJECT (ruler), "log-label-format");
1185 
1186         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
1187             gtk_widget_queue_draw (GTK_WIDGET (ruler));
1188     }
1189 }
1190 
1191 /**
1192  * gtk_databox_ruler_get_log_label_format:
1193  * @ruler: a #GtkDataboxRuler
1194  *
1195  * Gets the log label meta format of the @ruler (horizontal or vertical).
1196  *
1197  * Return value: The string meta format the @ruler, NULL on failure.
1198  **/
1199 gchar*
gtk_databox_ruler_get_log_label_format(GtkDataboxRuler * ruler)1200 gtk_databox_ruler_get_log_label_format(GtkDataboxRuler * ruler) {
1201 
1202     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), NULL);
1203 
1204     return ruler->priv->log_format;
1205 }
1206 
1207 /**
1208  * gtk_databox_ruler_get_range:
1209  * @ruler: a #GtkDataboxRuler
1210  * @lower: location to store lower limit of the ruler, or %NULL
1211  * @upper: location to store upper limit of the ruler, or %NULL
1212  * @position: location to store the current position of the mark on the ruler, or %NULL
1213  *
1214  * Retrieves values indicating the range and current position of a #GtkDataboxRuler.
1215  * See gtk_databox_ruler_set_range().
1216  **/
1217 void
gtk_databox_ruler_get_range(GtkDataboxRuler * ruler,gdouble * lower,gdouble * upper,gdouble * position)1218 gtk_databox_ruler_get_range (GtkDataboxRuler * ruler,
1219                              gdouble * lower,
1220                              gdouble * upper, gdouble * position) {
1221     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1222 
1223     if (lower)
1224         *lower = ruler->priv->lower;
1225     if (upper)
1226         *upper = ruler->priv->upper;
1227     if (position)
1228         *position = ruler->priv->position;
1229 }
1230 
1231 /**
1232  * gtk_databox_ruler_get_max_length:
1233  * @ruler: A #GtkDataboxRuler widget
1234  *
1235  * This function returns the maximum number of digits to be used for each tick
1236  * label of the @ruler.
1237  *
1238  * Return value: The maximum length of the tick labels.
1239  *
1240  */
1241 guint
gtk_databox_ruler_get_max_length(GtkDataboxRuler * ruler)1242 gtk_databox_ruler_get_max_length (GtkDataboxRuler * ruler) {
1243     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), 0);
1244 
1245     return ruler->priv->max_length;
1246 }
1247 
1248 /**
1249  * gtk_databox_ruler_get_scale_type:
1250  * @ruler: A #GtkDataboxRuler widget
1251  *
1252  * This function returns the scale type of the @ruler (linear or logarithmic).
1253  *
1254  * Return value: The scale type (linear or logarithmic)
1255  *
1256  */
1257 GtkDataboxScaleType
gtk_databox_ruler_get_scale_type(GtkDataboxRuler * ruler)1258 gtk_databox_ruler_get_scale_type (GtkDataboxRuler * ruler) {
1259     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), 0);
1260 
1261     return ruler->priv->scale_type;
1262 }
1263 
1264 /**
1265  * gtk_databox_ruler_set_box_shadow:
1266  * @ruler: a #GtkDataboxRuler
1267  * @which_shadow: How to render the box shadow on the ruler edges.
1268  *
1269  * Sets the shadow type when using gtk_paint_box. This will draw the desired edge shadow.
1270  **/
1271 void
gtk_databox_ruler_set_box_shadow(GtkDataboxRuler * ruler,GtkShadowType which_shadow)1272 gtk_databox_ruler_set_box_shadow(GtkDataboxRuler * ruler, GtkShadowType which_shadow) {
1273     g_return_if_fail (GTK_DATABOX_IS_RULER (ruler));
1274     g_return_if_fail (which_shadow<=GTK_SHADOW_ETCHED_OUT);
1275 
1276     if (ruler->priv->box_shadow!=which_shadow) {
1277         ruler->priv->box_shadow=which_shadow;
1278         if (gtk_widget_is_drawable (GTK_WIDGET (ruler)))
1279             gtk_widget_queue_draw (GTK_WIDGET (ruler));
1280     }
1281 }
1282 
1283 /**
1284  * gtk_databox_ruler_get_box_shadow:
1285  * @ruler: a #GtkDataboxRuler
1286  *
1287  * Gets the type of shadow being rendered to the @ruler (GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT).
1288  *
1289  * Return value: The currently used shadow type of the @ruler, -1 on failure.
1290  **/
1291 GtkShadowType
gtk_databox_ruler_get_box_shadow(GtkDataboxRuler * ruler)1292 gtk_databox_ruler_get_box_shadow(GtkDataboxRuler * ruler) {
1293 
1294     g_return_val_if_fail (GTK_DATABOX_IS_RULER (ruler), -1);
1295 
1296     return ruler->priv->box_shadow;
1297 }
1298 
1299 static void
gtk_databox_ruler_draw_ticks(GtkDataboxRuler * ruler)1300 gtk_databox_ruler_draw_ticks (GtkDataboxRuler * ruler) {
1301     GtkWidget *widget = GTK_WIDGET (ruler);
1302     cairo_t *cr;
1303 	GtkStyleContext *stylecontext = gtk_widget_get_style_context (widget);
1304     gint i;
1305     gint width, height;
1306     gint xthickness;
1307     gint ythickness;
1308     gint length;
1309     gdouble lower, upper;	/* Upper and lower limits */
1310     gdouble increment;		/* pixel per value unit */
1311     gint power;
1312     gint digit;
1313     gdouble subd_incr;
1314     gdouble start, end, cur, cur_text;
1315     gchar unit_str[GTK_DATABOX_RULER_MAX_MAX_LENGTH + 1];	/* buffer for writing numbers */
1316     gint digit_width;
1317     gint text_width;
1318     gint pos;
1319     gint y_loc, x_loc;
1320     gint subtick_start;
1321     gchar format_string[FORMAT_LENGTH];
1322     PangoMatrix matrix = PANGO_MATRIX_INIT;
1323     PangoContext *context;
1324     PangoLayout *layout;
1325     PangoRectangle logical_rect, ink_rect;
1326     GtkAllocation allocation;
1327     GdkRGBA fg_color, bg_color;
1328 
1329     GtkBorder padding;
1330     gtk_style_context_get_padding (stylecontext, gtk_widget_get_state_flags (widget), &padding);
1331     xthickness=padding.left+padding.right;
1332     ythickness=padding.top+padding.bottom;
1333 
1334     if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR)
1335         if (ruler->priv->max_length==1)
1336             g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->linear_format, ruler->priv->max_length);
1337         else
1338             g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->linear_format, ruler->priv->max_length - 1);
1339     else if (ruler->priv->max_length==1)
1340         g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->log_format, ruler->priv->max_length);
1341     else
1342         g_snprintf (format_string, FORMAT_LENGTH, ruler->priv->log_format, ruler->priv->max_length - 1);
1343 
1344     if (!gtk_widget_is_drawable (GTK_WIDGET (ruler)))
1345         return;
1346 
1347     gtk_widget_get_allocation(widget, &allocation);
1348     stylecontext = gtk_widget_get_style_context(widget);
1349 
1350     layout = gtk_widget_create_pango_layout (widget, "E+-012456789");
1351 
1352     if ((ruler->priv->orientation == GTK_ORIENTATION_VERTICAL) && (ruler->priv->text_orientation == GTK_ORIENTATION_VERTICAL)) {
1353         /* vertical ruler with vertical text */
1354         context = gtk_widget_get_pango_context (widget);
1355         pango_context_set_base_gravity (context, PANGO_GRAVITY_WEST);
1356         pango_matrix_rotate (&matrix, 90.);
1357         pango_context_set_matrix (context, &matrix);
1358         pango_layout_context_changed(layout);
1359     }
1360 
1361     pango_layout_get_pixel_extents (layout, &ink_rect, &logical_rect);
1362 
1363     digit_width = ceil ((logical_rect.width) / 12);
1364 
1365     width = allocation.width;
1366     height = allocation.height;
1367 
1368     cr = cairo_create(ruler->priv->backing_surface);
1369     //gtk_style_context_get_background_color(stylecontext, GTK_STATE_FLAG_NORMAL, &bg_color);
1370     gdk_rgba_parse (&bg_color, "#fefefe");
1371     gdk_cairo_set_source_rgba (cr, &bg_color);
1372     cairo_paint(cr);
1373 
1374     gtk_style_context_get_color(stylecontext, GTK_STATE_FLAG_NORMAL, &fg_color);
1375     gdk_cairo_set_source_rgba (cr, &fg_color);
1376 
1377     gtk_render_frame(stylecontext, cr, 0.0, 0.0, width, height);
1378 
1379     /* only draw the bottom line IF we are drawing ticks */
1380     if (ruler->priv->draw_ticks) {
1381         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
1382             cairo_rectangle (cr, 0, height - ythickness, width, ythickness);
1383         }
1384         else {
1385             cairo_rectangle (cr, width-xthickness, 0, xthickness, height);
1386         }
1387     }
1388 
1389     if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR) {
1390         upper = ruler->priv->upper;
1391         lower = ruler->priv->lower;
1392     } else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2) {
1393         if (ruler->priv->upper <= 0 || ruler->priv->lower <= 0) {
1394             g_warning
1395             ("For logarithmic scaling, the visible limits must by larger than 0!");
1396         }
1397         upper = log2 (ruler->priv->upper);
1398         lower = log2 (ruler->priv->lower);
1399     } else {
1400         if (ruler->priv->upper <= 0 || ruler->priv->lower <= 0) {
1401             g_warning
1402             ("For logarithmic scaling, the visible limits must by larger than 0!");
1403         }
1404         upper = log10 (ruler->priv->upper);
1405         lower = log10 (ruler->priv->lower);
1406     }
1407 
1408     if ((upper - lower) == 0)
1409         goto out;
1410 
1411     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1412         increment = (gdouble) width / (upper - lower);
1413     else
1414         increment = (gdouble) height / (upper - lower);
1415 
1416 
1417     /* determine the scale, i.e. the distance between the most significant ticks
1418      *
1419      * the ticks have to be farther apart than the length of the displayed numbers
1420      */
1421     if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR) {
1422         text_width = (ruler->priv->max_length) * digit_width + 1;
1423 
1424         for (power = -20; power < 21; power++) {
1425             if ((digit = 1) * pow (10, power) * fabs (increment) > text_width)
1426                 break;
1427             if ((digit = 2.5) * pow (10, power) * fabs (increment) > text_width)
1428                 break;
1429             if ((digit = 5) * pow (10, power) * fabs (increment) > text_width)
1430                 break;
1431         }
1432 
1433 
1434         if (power == 21) {
1435             power = 20;
1436             digit = 5;
1437         }
1438         subd_incr = digit * pow (10, power);
1439     } else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2) {
1440         subd_incr = 1.;
1441     } else {
1442         subd_incr = 1.;
1443     }
1444 
1445     length = (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1446              ? height - 5 : width - 5;
1447 
1448     if (ruler->priv->manual_ticks==NULL)
1449         if (lower < upper) {
1450             start = floor (lower / subd_incr) * subd_incr;
1451             end = ceil (upper / subd_incr) * subd_incr;
1452         } else {
1453             start = floor (upper / subd_incr) * subd_incr;
1454             end = ceil (lower / subd_incr) * subd_incr;
1455         }
1456     else { /* we are manually setting the tick labels and marks. */
1457         start = 0.;
1458         end = (gfloat)ruler->priv->manual_tick_cnt-1;
1459         subd_incr=1.;
1460     }
1461 
1462 
1463     for (cur = start; cur <= end; cur += subd_incr) {
1464         if (ruler->priv->manual_ticks==NULL)
1465             pos = ROUND (((cur_text=cur) - lower) * increment);
1466         else {
1467             /* manual ticks must be positioned according to the scale */
1468             if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR)
1469                 cur_text=ruler->priv->manual_ticks[(int)cur];
1470             else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2)
1471                 cur_text=log2(ruler->priv->manual_ticks[(int)cur]);
1472             else
1473                 cur_text=log10(ruler->priv->manual_ticks[(int)cur]);
1474             pos = ROUND ((cur_text - lower) * increment);
1475             cur_text=ruler->priv->manual_ticks[(int)cur];
1476         }
1477         /*draw main ticks*/
1478         if (ruler->priv->draw_ticks) {
1479             if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1480                 cairo_rectangle (cr, pos, height + ythickness - length, 1, length);
1481             else
1482                 cairo_rectangle (cr, width + xthickness - length, pos, length, 1);
1483         }
1484 
1485 
1486         /* draw label */
1487         /* if manual tick labels are present, display them instead of calculated labels */
1488         if ((ruler->priv->manual_ticks!=NULL) && (ruler->priv->manual_tick_cnt!=0) && (ruler->priv->manual_tick_labels!=NULL))
1489             pango_layout_set_text (layout, ruler->priv->manual_tick_labels[(int)cur], -1);
1490         else {
1491             if ((ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR) || (ruler->priv->manual_ticks!=NULL)) {
1492                 if (ABS (cur_text) < 0.1 * subd_incr)	/* Rounding errors occur and might make "0" look funny without this check */
1493                     cur_text = 0;
1494 
1495                 g_snprintf (unit_str, ruler->priv->max_length + 1, format_string, cur_text);
1496             } else if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2)
1497                 g_snprintf (unit_str, ruler->priv->max_length + 1, format_string, pow (2, cur_text));
1498             else
1499                 g_snprintf (unit_str, ruler->priv->max_length + 1, format_string, pow (10, cur_text));
1500 
1501             pango_layout_set_text (layout, unit_str, -1);
1502         }
1503         pango_layout_get_pixel_extents (layout, &ink_rect, &logical_rect);
1504 
1505         /* remember the pixel extents for sizing later. */
1506         if ((ruler->priv->orientation == GTK_ORIENTATION_VERTICAL) & (ruler->priv->max_y_text_width<logical_rect.width)) {
1507             if (ruler->priv->text_orientation ==GTK_ORIENTATION_VERTICAL)
1508                 ruler->priv->max_y_text_width=logical_rect.height;
1509             else
1510                 ruler->priv->max_y_text_width=logical_rect.width;
1511             gtk_widget_set_size_request(GTK_WIDGET(ruler), ruler->priv->max_y_text_width, ruler->priv->max_x_text_height);
1512         } else if (ruler->priv->max_x_text_height<logical_rect.height) {
1513             ruler->priv->max_x_text_height=logical_rect.height;
1514             gtk_widget_set_size_request(GTK_WIDGET(ruler), ruler->priv->max_y_text_width, ruler->priv->max_x_text_height);
1515         }
1516 
1517 
1518 
1519         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL){
1520             if (!ruler->priv->draw_ticks) /* if ticks aren't present, draw a little lower */
1521                 pos=pos - logical_rect.width+2+ruler->priv->text_hoffset;
1522 			gtk_render_layout(stylecontext, cr, pos + 2, ythickness - 1, layout);
1523         } else {
1524             y_loc=pos - logical_rect.width - 2; /* standard vertical text y alignment */
1525             /*y_loc=pos-2;*/ /* standard vertical text y alignment */
1526             if (ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) /* if ticks are present, then draw a little higher */
1527                 y_loc=pos - logical_rect.width*2/3; /* horizontal text y alignment */
1528             if ((ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) & (!ruler->priv->draw_ticks)) /* if ticks aren't present, draw a little lower */
1529                 y_loc=pos - logical_rect.width/3;
1530 
1531             x_loc=xthickness-1+ruler->priv->text_hoffset;
1532             if ((ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) & (ruler->priv->text_alignment == PANGO_ALIGN_RIGHT)) /* set right adjusted text */
1533                 x_loc=width-ink_rect.width-2+ruler->priv->text_hoffset; /* shift 2 pixels left to give a better aesthetic */
1534             if ((ruler->priv->text_orientation == GTK_ORIENTATION_HORIZONTAL) & (ruler->priv->text_alignment == PANGO_ALIGN_CENTER)) /* set centrally adjusted text */
1535                 x_loc=(width-ink_rect.width)/2-2+ruler->priv->text_hoffset;
1536 			gtk_render_layout(stylecontext, cr, x_loc, y_loc, layout);
1537         }
1538 
1539         /* Draw sub-ticks */
1540         if (ruler->priv->draw_subticks & ruler->priv->draw_ticks) {
1541             if (!ruler->priv->invert_edge) /* sub-ticks on the bottom */
1542                 subtick_start=length / 2;
1543             else
1544                 subtick_start=length;
1545 
1546             if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LINEAR)
1547                 for (i = 1; i < 5; ++i) {
1548                     pos = ROUND ((cur - lower + subd_incr / 5 * i) * increment);
1549 
1550                     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1551                         cairo_rectangle (cr, pos, height + ythickness - subtick_start, 1, length / 2);
1552                     else
1553                         cairo_rectangle (cr, width + xthickness - subtick_start, pos, length / 2, 1);
1554                 }
1555             else  if (ruler->priv->scale_type == GTK_DATABOX_SCALE_LOG2)
1556                 for (i = 1; i < 8; ++i) {
1557                     pos = ROUND ((cur - lower + log2 (i)) * increment);
1558 
1559                     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1560                         cairo_rectangle (cr, pos, height + ythickness - subtick_start, 1, length / 2);
1561                     else
1562                         cairo_rectangle (cr, width + xthickness - subtick_start, pos, length / 2, 1);
1563                 }
1564             else
1565                 for (i = 2; i < 10; ++i) {
1566                     pos = ROUND ((cur - lower + log10 (i)) * increment);
1567 
1568                     if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1569                         cairo_rectangle (cr, pos, height + ythickness - subtick_start, 1, length / 2);
1570                     else
1571                         cairo_rectangle (cr, width + xthickness - subtick_start, pos, length / 2, 1);
1572                 }
1573         }
1574     }
1575 
1576     cairo_fill (cr);
1577 out:
1578     cairo_destroy (cr);
1579 
1580     g_object_unref (layout);
1581 }
1582 
1583 static void
gtk_databox_ruler_draw_pos(GtkDataboxRuler * ruler)1584 gtk_databox_ruler_draw_pos (GtkDataboxRuler * ruler) {
1585     GtkWidget *widget = GTK_WIDGET (ruler);
1586 	GtkStyleContext *stylecontext = gtk_widget_get_style_context(widget);
1587     gint x, y;
1588     gint width, height;
1589     gint bs_width, bs_height;
1590     gint ythickness;
1591     gdouble increment;
1592     GdkDrawingContext *drawc;
1593     cairo_region_t *crr;
1594     cairo_t *cr;
1595 	GtkAllocation allocation;
1596 	GdkRGBA fg_color;
1597 
1598     GtkStyleContext *context= gtk_widget_get_style_context (widget);
1599     GtkBorder padding;
1600     gint xthickness;
1601     gtk_style_context_get_padding (context, gtk_widget_get_state_flags (widget), &padding);
1602     xthickness=padding.left+padding.right;
1603     ythickness=padding.top+padding.bottom;
1604 
1605     if (gtk_widget_is_drawable (widget)) {
1606 		gtk_widget_get_allocation(widget, &allocation);
1607         width = allocation.width - xthickness * 2;
1608         height = allocation.height - ythickness * 2;
1609 
1610         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
1611             bs_width = height / 2 + 2;
1612             bs_width |= 1;		/* make sure it's odd */
1613             bs_height = bs_width / 2 + 1;
1614             if (ruler->priv->invert_edge)
1615                 bs_height=-bs_height;
1616         } else {
1617             bs_height = width / 2 + 2;
1618             bs_height |= 1;	/* make sure it's odd */
1619             bs_width = bs_height / 2 + 1;
1620             if (ruler->priv->invert_edge)
1621                 bs_width=-bs_width;
1622         }
1623 
1624         if (!ruler->priv->invert_edge && (bs_width < 0) && (bs_height < 0))
1625             return; /* return if negative values and not inverted */
1626 
1627         if (ruler->priv->invert_edge && (bs_width > 0) && (bs_height > 0))
1628             return; /* return if positive values and inverted */
1629 
1630         crr = gdk_window_get_visible_region (gtk_widget_get_window (widget));
1631         drawc = gdk_window_begin_draw_frame (gtk_widget_get_window (widget), crr);
1632         cr = gdk_drawing_context_get_cairo_context (drawc);
1633         /*cr = gdk_cairo_create (gtk_widget_get_window(widget));*/
1634 
1635         /*  If a backing store exists, restore the ruler  */
1636         if (ruler->priv->backing_surface)
1637 		{
1638 /* TODO: HERE WE SHOULD REALLY CLIP THIS TO THE RECTANGLE OF THE ARROW */
1639 			cairo_set_source_surface(cr, ruler->priv->backing_surface, 0, 0);
1640 			cairo_paint(cr);
1641 		}
1642 
1643 		gtk_style_context_get_color(stylecontext, gtk_style_context_get_state(stylecontext), &fg_color);
1644         if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL) {
1645             increment = (gdouble) width / (ruler->priv->upper - ruler->priv->lower);
1646 
1647             x = ROUND ((ruler->priv->position - ruler->priv->lower) * increment) +
1648                 (xthickness - bs_width) / 2 - 1;
1649             y = (height + bs_height) / 2 + ythickness;
1650 
1651 			gdk_cairo_set_source_rgba (cr, &fg_color);
1652 
1653             cairo_move_to (cr, x, y);
1654             cairo_line_to (cr, x + bs_width / 2., y + bs_height);
1655             cairo_line_to (cr, x + bs_width, y);
1656         } else {
1657             increment = (gdouble) height / (ruler->priv->upper - ruler->priv->lower);
1658 
1659             x = (width + bs_width) / 2 + xthickness;
1660             y = ROUND ((ruler->priv->position - ruler->priv->lower) * increment) +
1661                 (ythickness - bs_height) / 2 - 1;
1662 
1663 			gdk_cairo_set_source_rgba (cr, &fg_color);
1664 
1665             cairo_move_to (cr, x, y);
1666             cairo_line_to (cr, x + bs_width, y + bs_height / 2.);
1667             cairo_line_to (cr, x, y + bs_height);
1668         }
1669         cairo_fill (cr);
1670 
1671         gdk_window_end_draw_frame (gtk_widget_get_window (widget), drawc);
1672         cairo_region_destroy (crr);
1673 
1674         /* remember the rectangle of the arrow - so that it may be cleared on re-run */
1675         ruler->priv->xsrc = x;
1676         ruler->priv->ysrc = y;
1677         if (ruler->priv->invert_edge) { /* inverted edges need clearing in the negative direction */
1678             if (ruler->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1679                 ruler->priv->ysrc = y+bs_height; /* bs_height is negative */
1680             else
1681                 ruler->priv->xsrc = x+bs_width; /* bs_width is negative */
1682         }
1683     }
1684 }
1685 
1686 
1687 static void
gtk_databox_ruler_realize(GtkWidget * widget)1688 gtk_databox_ruler_realize (GtkWidget * widget) {
1689     GtkDataboxRuler *ruler;
1690     GdkWindowAttr attributes;
1691     gint attributes_mask;
1692 	GtkAllocation allocation;
1693 	GtkStyleContext *stylecontext;
1694 
1695     ruler = GTK_DATABOX_RULER (widget);
1696     gtk_widget_set_realized(GTK_WIDGET (ruler), TRUE);
1697 	gtk_widget_get_allocation(widget, &allocation);
1698 
1699     attributes.window_type = GDK_WINDOW_CHILD;
1700     attributes.x = allocation.x;
1701     attributes.y = allocation.y;
1702     attributes.width = allocation.width;
1703     attributes.height = allocation.height;
1704     attributes.wclass = GDK_INPUT_OUTPUT;
1705     attributes.visual = gtk_widget_get_visual (widget);
1706     attributes.event_mask = gtk_widget_get_events (widget);
1707     attributes.event_mask |= (GDK_EXPOSURE_MASK |
1708                               GDK_POINTER_MOTION_MASK |
1709                               GDK_POINTER_MOTION_HINT_MASK);
1710 
1711     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
1712 
1713     gtk_widget_set_window(widget,
1714         gdk_window_new (gtk_widget_get_parent_window (widget), &attributes,
1715                         attributes_mask));
1716     gdk_window_set_user_data (gtk_widget_get_window(widget), ruler);
1717 
1718     stylecontext = gtk_widget_get_style_context(widget);
1719 
1720     gtk_style_context_add_class(stylecontext, GTK_STYLE_CLASS_BACKGROUND);
1721 
1722     /*gtk_style_context_set_background(stylecontext, gtk_widget_get_window(widget));*/
1723 
1724     gtk_databox_ruler_create_backing_surface (ruler);
1725 }
1726 
1727 static void
gtk_databox_ruler_unrealize(GtkWidget * widget)1728 gtk_databox_ruler_unrealize (GtkWidget * widget) {
1729     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
1730     gtk_widget_set_realized(widget, FALSE);
1731 
1732     if (ruler->priv->backing_surface)
1733 		cairo_surface_destroy (ruler->priv->backing_surface);
1734     ruler->priv->backing_surface=NULL;
1735 
1736     if (GTK_WIDGET_CLASS (gtk_databox_ruler_parent_class)->unrealize)
1737         (*GTK_WIDGET_CLASS (gtk_databox_ruler_parent_class)->unrealize) (widget);
1738 }
1739 
1740 static void
gtk_databox_ruler_size_allocate(GtkWidget * widget,GtkAllocation * allocation)1741 gtk_databox_ruler_size_allocate (GtkWidget * widget,
1742                                  GtkAllocation * allocation) {
1743     GtkDataboxRuler *ruler = GTK_DATABOX_RULER (widget);
1744 
1745 	gtk_widget_set_allocation(widget, allocation);
1746 
1747     if (gtk_widget_get_realized (widget))
1748         if (gtk_widget_is_drawable(widget)) {
1749             gdk_window_move_resize (gtk_widget_get_window(widget),
1750                                     allocation->x, allocation->y,
1751                                     allocation->width, allocation->height);
1752 
1753             gtk_databox_ruler_create_backing_surface (ruler);
1754         }
1755 }
1756 
1757 static gint
gtk_databox_ruler_draw(GtkWidget * widget,cairo_t * cr)1758 gtk_databox_ruler_draw (GtkWidget * widget, cairo_t * cr){
1759     GtkDataboxRuler *ruler;
1760 	GtkAllocation allocation;
1761 
1762     if (gtk_widget_is_drawable (widget)) {
1763         ruler = GTK_DATABOX_RULER (widget);
1764 		gtk_widget_get_allocation(widget, &allocation);
1765 
1766         gtk_databox_ruler_draw_ticks (ruler);
1767 
1768 		if (ruler->priv->backing_surface)
1769 		{
1770 			cairo_set_source_surface(cr, ruler->priv->backing_surface, 0, 0);
1771 			cairo_paint(cr);
1772 		}
1773 
1774 /* TODO: draw_pos also blits the backing_surface to the window, should make it happen only once) */
1775         if (ruler->priv->draw_position)
1776             gtk_databox_ruler_draw_pos (ruler);
1777     }
1778 
1779     return FALSE;
1780 }
1781 
1782 static void
gtk_databox_ruler_create_backing_surface(GtkDataboxRuler * ruler)1783 gtk_databox_ruler_create_backing_surface (GtkDataboxRuler * ruler) {
1784     GtkWidget *widget;
1785     gint width;
1786     gint height;
1787     GtkAllocation allocation;
1788     GdkDrawingContext *drawc;
1789     cairo_region_t *crr;
1790     cairo_t *cr;
1791 
1792     widget = GTK_WIDGET (ruler);
1793     gtk_widget_get_allocation(widget, &allocation);
1794     width = allocation.width;
1795     height = allocation.height;
1796 
1797     if (ruler->priv->backing_surface) {
1798         if ((width == ruler->priv->old_width) &&
1799                 (height == ruler->priv->old_height))
1800             return;
1801 
1802 		cairo_surface_destroy(ruler->priv->backing_surface);
1803     }
1804 
1805 	ruler->priv->old_width = width;
1806 	ruler->priv->old_height = height;
1807 
1808     crr = gdk_window_get_visible_region (gtk_widget_get_window (widget));
1809     drawc = gdk_window_begin_draw_frame (gtk_widget_get_window (widget), crr);
1810     cr = gdk_drawing_context_get_cairo_context (drawc);
1811     /*cr = gdk_cairo_create(gtk_widget_get_window(widget));*/
1812 
1813     ruler->priv->backing_surface = cairo_surface_create_similar(
1814 		cairo_get_target(cr),
1815 		CAIRO_CONTENT_COLOR,
1816 		width, height);
1817 
1818     ruler->priv->xsrc = 0;
1819     ruler->priv->ysrc = 0;
1820 
1821     gdk_window_end_draw_frame (gtk_widget_get_window (widget), drawc);
1822     cairo_region_destroy (crr);
1823 }
1824 
1825 #define __GTK_DATABOX_RULER_C__
1826