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