gtkdatabox  1.0.0
About: GtkDatabox is a Gtk+-widget for live display of large amounts of fluctuating numerical data.
  Fossies Dox: gtkdatabox-1.0.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

gtkdatabox.c
Go to the documentation of this file.
1 /* $Id: gtkdatabox.c 4 2008-06-22 09:19:11Z rbock $ */
2 /* GtkDatabox - An extension to the gtk+ library
3  * Copyright (C) 1998 - 2008 Dr. Roland Bock
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1
8  * of the License, or (at your option) any later version.
9  *
10  * This program 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
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <gtkdatabox.h>
25 #include <gtkdatabox_marshal.h>
26 #include <gtkdatabox_ruler.h>
27 #include <gtk/gtk.h>
28 #include <math.h>
29 
30 #ifdef _MSC_VER
31 #ifndef _DATABOX_LOG2_
32 #define _DATABOX_LOG2_
33 /*< private >*/
34 #define log2(x) (log(x)/log(2))
35 #endif /*_DATABOX_LOG2_ */
36 #endif /*_MSC_VER */
37 
38 static gint gtk_databox_button_press (GtkWidget * widget,
39  GdkEventButton * event);
40 static gint gtk_databox_scroll_event (GtkWidget *widget,
41  GdkEventScroll *event);
42 static gint gtk_databox_button_release (GtkWidget * widget,
43  GdkEventButton * event);
44 static gint gtk_databox_motion_notify (GtkWidget * widget,
45  GdkEventMotion * event);
46 static void gtk_databox_realize (GtkWidget * widget);
47 static void gtk_databox_unrealize (GtkWidget * widget);
48 static void gtk_databox_size_allocate (GtkWidget * widget,
49  GtkAllocation * allocation);
50 static gint gtk_databox_draw (GtkWidget * widget,
51  cairo_t * cr);
52 static void gtk_databox_set_property (GObject * object,
53  guint prop_id,
54  const GValue * value,
55  GParamSpec * pspec);
56 static void gtk_databox_get_property (GObject * object,
57  guint prop_id,
58  GValue * value,
59  GParamSpec * pspec);
60 
61 static gfloat gtk_databox_get_offset_x (GtkDatabox* box);
62 static gfloat gtk_databox_get_page_size_x (GtkDatabox* box);
63 static gfloat gtk_databox_get_offset_y (GtkDatabox* box);
64 static gfloat gtk_databox_get_page_size_y (GtkDatabox* box);
68 static void gtk_databox_selection_cancel (GtkDatabox * box);
69 static void gtk_databox_zoomed (GtkDatabox * box);
70 static void gtk_databox_draw_selection (GtkDatabox * box, gboolean clear);
72 static void gtk_databox_ruler_update (GtkDatabox * box);
73 
74 /* IDs of signals */
75 enum {
82 };
83 
84 /* signals will be configured during class_init */
85 static gint gtk_databox_signals[LAST_SIGNAL] = { 0 };
86 
87 
88 /* IDs of properties */
89 enum {
100 };
101 
102 /*
103  * GtkDataboxPrivate
104  *
105  * A private data structure used by the #GtkDatabox. It shields all internal things
106  * from developers who are just using the widget.
107  *
108  */
110 
112  cairo_surface_t *backing_surface;
113  gint old_width;
115 
116  /* Total and visible limits (values, not pixels) */
117  gfloat total_left;
118  gfloat total_right;
119  gfloat total_top;
120  gfloat total_bottom;
121  gfloat visible_left;
123  gfloat visible_top;
125 
126  /* Translation information between values and pixels */
131 
132  /* Properties */
134  gboolean enable_zoom;
135  GtkAdjustment *adj_x;
136  GtkAdjustment *adj_y;
139 
140  /* Other private stuff */
141  GList *graphs;
142  GdkPoint marked;
143  GdkPoint select;
145  gfloat zoom_limit;
146 
147  /* flags */
150 
151  GtkShadowType box_shadow; /* The type of shadow drawn on the pixmap edge */
152  GtkCssProvider *cssp; /* Internal style sheet used for background-color */
153 };
154 
155 /**
156  * gtk_databox_get_type
157  *
158  * Determines the #GType of the GtkDatabox widget type.
159  *
160  * Return value: The #GType of the GtkDatabox widget type.
161  *
162  */
163 G_DEFINE_TYPE_WITH_PRIVATE(GtkDatabox, gtk_databox, GTK_TYPE_WIDGET)
164 
165 static void
167  GObjectClass *gobject_class;
168  GtkWidgetClass *widget_class;
169 
170  gobject_class = G_OBJECT_CLASS (class);
171  widget_class = (GtkWidgetClass *) class;
172 
173  gobject_class->set_property = gtk_databox_set_property;
174  gobject_class->get_property = gtk_databox_get_property;
175 
176  widget_class->realize = gtk_databox_realize;
177  widget_class->unrealize = gtk_databox_unrealize;
178  widget_class->size_allocate = gtk_databox_size_allocate;
179  widget_class->draw = gtk_databox_draw;
180  widget_class->motion_notify_event = gtk_databox_motion_notify;
181  widget_class->button_press_event = gtk_databox_button_press;
182  widget_class->button_release_event = gtk_databox_button_release;
183  widget_class->scroll_event = gtk_databox_scroll_event;
184 
185  /**
186  * GtkDatabox:enable-selection:
187  *
188  * Defines whether the user can select
189  * rectangular areas with the mouse (#TRUE) or not (#FALSE).
190  *
191  */
192  g_object_class_install_property (gobject_class,
194  g_param_spec_boolean ("enable-selection",
195  "Enable Selection",
196  "Enable selection of areas via mouse (TRUE/FALSE)",
197  TRUE, /* default value */
198  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
199 
200  /**
201  * GtkDatabox:enable-zoom:
202  *
203  * Defines whether the user can use the mouse to zoom in or out (#TRUE) or not (#FALSE).
204  *
205  */
206  g_object_class_install_property (gobject_class,
207  ENABLE_ZOOM,
208  g_param_spec_boolean ("enable-zoom",
209  "Enable Zoom",
210  "Enable zooming in or out via mouse click (TRUE/FALSE)",
211  TRUE, /* default value */
212  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
213 
214  /**
215  * GtkDatabox:adjustment_x:
216  *
217  * The #GtkAdjustment associated with the horizontal scrollbar. The #GtkDatabox widget
218  * creates a GtkAdjustment itself. Normally there is no need for you to create another
219  * GtkAdjustment. You could simply use the one you get via gtk_databox_get_adjustment_x().
220  *
221  */
222  g_object_class_install_property (gobject_class,
223  ADJUSTMENT_X,
224  g_param_spec_object ("adjustment-x",
225  "Horizontal Adjustment",
226  "GtkAdjustment for horizontal scrolling",
227  GTK_TYPE_ADJUSTMENT,
228  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
229 
230  /**
231  * GtkDatabox:adjustment_y:
232  *
233  * The #GtkAdjustment associated with the vertical scrollbar. The #GtkDatabox widget
234  * creates a GtkAdjustment itself. Normally there is no need for you to create another
235  * GtkAdjustment. You could simply use the one you get via gtk_databox_get_adjustment_y().
236  *
237  */
238  g_object_class_install_property (gobject_class,
239  ADJUSTMENT_Y,
240  g_param_spec_object ("adjustment-y",
241  "Vertical Adjustment",
242  "GtkAdjustment for vertical scrolling",
243  GTK_TYPE_ADJUSTMENT,
244  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
245 
246  /**
247  * GtkDatabox:ruler_x:
248  *
249  * The horizontal %GtkDataboxRuler (or NULL).
250  *
251  */
252  g_object_class_install_property (gobject_class,
253  RULER_X,
254  g_param_spec_object ("ruler-x",
255  "Horizontal Ruler",
256  "A horizontal GtkDataboxRuler or NULL",
258  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
259 
260  /**
261  * GtkDatabox:ruler_y:
262  *
263  * The vertical %GtkDataboxRuler (or NULL).
264  *
265  */
266  g_object_class_install_property (gobject_class,
267  RULER_Y,
268  g_param_spec_object ("ruler-y",
269  "Vertical Ruler",
270  "A vertical GtkDataboxRuler or NULL",
272  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
273 
274  /**
275  * GtkDatabox:scale_type_x:
276  *
277  * The horizontal scale type (linear or lograrithmic).
278  */
279  g_object_class_install_property (gobject_class,
280  SCALE_TYPE_X,
281  g_param_spec_enum ("scale-type-x",
282  "Horizontal scale type",
283  "Horizontal scale type (linear or logarithmic)",
286  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
287 
288  /**
289  * GtkDatabox:scale_type_y:
290  *
291  * The vertical scale type (linear or lograrithmic).
292  */
293  g_object_class_install_property (gobject_class,
294  SCALE_TYPE_Y,
295  g_param_spec_enum ("scale-type-y",
296  "Vertical scale type",
297  "Vertical scale type (linear or logarithmic)",
300  G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
301 
302 
303  g_object_class_install_property (gobject_class,
304  BOX_SHADOW,
305  g_param_spec_uint ("box-shadow",
306  "Box Shadow",
307  "Style of the box shadow: GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT",
308  GTK_SHADOW_NONE,
309  GTK_SHADOW_ETCHED_OUT,
310  GTK_SHADOW_NONE,
311  G_PARAM_READWRITE));
312 
313  /**
314  * GtkDatabox::zoomed:
315  * @box: The #GtkDatabox widget which zoomed in or out.
316  *
317  * This signal is emitted each time the zoom of the widget is changed, see for example
318  * gtk_databox_zoom_to_selection(), gtk_databox_set_visible_limits().
319  */
321  g_signal_new ("zoomed",
322  G_TYPE_FROM_CLASS (gobject_class),
323  G_SIGNAL_RUN_FIRST,
324  G_STRUCT_OFFSET (GtkDataboxClass, zoomed),
325  NULL, /* accumulator */
326  NULL, /* accumulator_data */
328  G_TYPE_NONE, 0);
329 
330  /**
331  * GtkDatabox::selection-started:
332  * @box: The #GtkDatabox widget in which the selection has been started.
333  * @selection_values: The corners of the selection rectangle.
334  *
335  * This signal is emitted when the mouse is firstmoved
336  * with the left button pressed after the mouse-down (and the #GtkDatabox:enable-selection property
337  * is set). The corners of the selection rectangle are stored in @selection_values.
338  *
339  * @see_also: #GtkDatabox::selection-changed
340  */
342  g_signal_new ("selection-started",
343  G_TYPE_FROM_CLASS (gobject_class),
344  G_SIGNAL_RUN_FIRST,
345  G_STRUCT_OFFSET (GtkDataboxClass, selection_started),
346  NULL, /* accumulator */
347  NULL, /* accumulator_data */
349  G_TYPE_NONE,
350  1,
351  G_TYPE_POINTER);
352 
353  /**
354  * GtkDatabox::selection-changed:
355  * @box: The #GtkDatabox widget in which the selection was changed.
356  * @selection_values: The corners of the selection rectangle.
357  *
358  * This signal is emitted when the mouse is moved
359  * with the left button pressed (and the #GtkDatabox:enable-selection property
360  * is set). The corners of the selection rectangle are stored in @selection_values.
361  */
363  g_signal_new ("selection-changed",
364  G_TYPE_FROM_CLASS (gobject_class),
365  G_SIGNAL_RUN_FIRST,
366  G_STRUCT_OFFSET (GtkDataboxClass, selection_changed),
367  NULL, /* accumulator */
368  NULL, /* accumulator_data */
370  G_TYPE_NONE,
371  1,
372  G_TYPE_POINTER);
373 
374  /**
375  * GtkDatabox::selection-finalized:
376  * @box: The #GtkDatabox widget in which the selection has been stopped.
377  * @selection_values: The corners of the selection rectangle.
378  *
379  * This signal is emitted when the left mouse button
380  * is released after a selection was started before.
381  *
382  * @see_also: #GtkDatabox::selection-changed
383  */
385  g_signal_new ("selection-finalized",
386  G_TYPE_FROM_CLASS (gobject_class),
387  G_SIGNAL_RUN_FIRST,
388  G_STRUCT_OFFSET (GtkDataboxClass, selection_finalized),
389  NULL, /* accumulator */
390  NULL, /* accumulator_data */
392  G_TYPE_NONE,
393  1,
394  G_TYPE_POINTER);
395 
396  /**
397  * GtkDatabox::selection-canceled:
398  * @box: The #GtkDatabox widget which zoomed in or out.
399  *
400  * This signal is emitted after a right click outside
401  * a selection rectangle.
402  */
404  g_signal_new ("selection-canceled",
405  G_TYPE_FROM_CLASS (gobject_class),
406  G_SIGNAL_RUN_FIRST,
407  G_STRUCT_OFFSET (GtkDataboxClass, selection_canceled),
408  NULL, /* accumulator */
409  NULL, /* accumulator_data */
411  G_TYPE_NONE,
412  0);
413 
414  class->zoomed = NULL;
415  class->selection_started = NULL;
416  class->selection_changed = NULL;
417  class->selection_finalized = NULL;
418  class->selection_canceled = NULL;
419 }
420 
421 static void
423  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
424 
425  priv->backing_surface = NULL;
428  priv->translation_factor_x = 0;
429  priv->translation_factor_y = 0;
430  priv->enable_selection = TRUE;
431  priv->enable_zoom = TRUE;
432  priv->ruler_x = NULL;
433  priv->ruler_y = NULL;
434  priv->graphs = NULL;
435  priv->zoom_limit = 0.01;
436  priv->selection_active = FALSE;
437  priv->selection_finalized = FALSE;
438  priv->box_shadow=GTK_SHADOW_NONE;
439  priv->cssp = gtk_css_provider_new ();
440 
441  /* gtk_databox_set_total_limits(box, -1., 1., 1., -1.); */
442  priv->visible_left = priv->total_left = -1.0;
443  priv->visible_right = priv->total_right = 1.0;
444  priv->visible_top = priv->total_top = 1.0;
445  priv->visible_bottom = priv->total_bottom = -1.0;
446  gtk_databox_set_adjustment_x (box, NULL);
447  gtk_databox_set_adjustment_y (box, NULL);
448  /*gtk_databox_set_total_limits(box, -1., 1., 1., -1.);*/
449  g_object_set(GTK_WIDGET(box), "expand", TRUE, NULL);
450 }
451 
452 /**
453  * gtk_databox_new
454  *
455  * Creates a new #GtkDatabox widget.
456  *
457  * Return value: The new #GtkDatabox widget.
458  *
459  */
460 GtkWidget *
462  return g_object_new (GTK_TYPE_DATABOX, NULL);
463 }
464 
465 /**
466  * gtk_databox_get_graphs
467  * @box: A #GtkDatabox widget
468  *
469  * Return a list of graphs that were previously added to @box.
470  *
471  * Return value: A #GList that contains all graphs
472  */
473 GList *
475 {
476  g_return_val_if_fail (GTK_IS_DATABOX (box), (GList*)-1);
477  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
478  return priv->graphs;
479 }
480 
481 static gint
482 gtk_databox_motion_notify (GtkWidget *widget, GdkEventMotion *event) {
483  GtkDatabox *box = GTK_DATABOX (widget);
484  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
485  GdkModifierType state;
486  gint x;
487  gint y;
488 
489  if (event->is_hint) {
490  gdk_window_get_device_position (gtk_widget_get_window(widget), event->device, &x, &y, &state);
491  } else {
492  state = event->state;
493  x = event->x;
494  y = event->y;
495  }
496 
497  if (state & GDK_BUTTON1_MASK
498  && priv->enable_selection && !priv->selection_finalized) {
499  GdkRectangle rect;
500  gint width;
501  gint height;
502 
503  width = gdk_window_get_width(gtk_widget_get_window(widget));
504  height = gdk_window_get_height(gtk_widget_get_window(widget));
505  x = MAX (0, MIN (width - 1, x));
506  y = MAX (0, MIN (height - 1, y));
507 
508  if (priv->selection_active) {
509  /* Clear current selection from backing_surface */
510  gtk_databox_draw_selection (box, TRUE);
511  } else {
512  priv->selection_active = TRUE;
513  priv->marked.x = x;
514  priv->marked.y = y;
515  priv->select.x = x;
516  priv->select.y = y;
518  g_signal_emit (G_OBJECT (box),
520  &priv->selectionValues);
521  }
522 
523  /* Determine the exposure rectangle (covering old selection and new) */
524  rect.x = MIN (MIN (priv->marked.x, priv->select.x), x);
525  rect.y = MIN (MIN (priv->marked.y, priv->select.y), y);
526  rect.width = MAX (MAX (priv->marked.x, priv->select.x), x)
527  - rect.x + 1;
528  rect.height = MAX (MAX (priv->marked.y, priv->select.y), y)
529  - rect.y + 1;
530 
531  priv->select.x = x;
532  priv->select.y = y;
533 
534  /* Draw new selection */
535  gtk_databox_draw_selection (box, FALSE);
536 
538  g_signal_emit (G_OBJECT (box),
540  0, &priv->selectionValues);
541  }
542 
543  return FALSE;
544 }
545 
546 static void
547 gtk_databox_set_property (GObject * object,
548  guint property_id,
549  const GValue * value, GParamSpec * pspec) {
550  GtkDatabox *box = GTK_DATABOX (object);
551  switch (property_id) {
552  case ENABLE_SELECTION:
553  gtk_databox_set_enable_selection (box, g_value_get_boolean (value));
554  break;
555  case ENABLE_ZOOM:
556  gtk_databox_set_enable_zoom (box, g_value_get_boolean (value));
557  break;
558  case ADJUSTMENT_X:
559  gtk_databox_set_adjustment_x (box, g_value_get_object (value));
560  break;
561  case ADJUSTMENT_Y:
562  gtk_databox_set_adjustment_y (box, g_value_get_object (value));
563  break;
564  case RULER_X:
565  gtk_databox_set_ruler_x (box, g_value_get_object (value));
566  break;
567  case RULER_Y:
568  gtk_databox_set_ruler_y (box, g_value_get_object (value));
569  break;
570  case SCALE_TYPE_X:
571  gtk_databox_set_scale_type_x (box, g_value_get_enum (value));
572  break;
573  case SCALE_TYPE_Y:
574  gtk_databox_set_scale_type_y (box, g_value_get_enum (value));
575  break;
576  case BOX_SHADOW:
577  gtk_databox_set_box_shadow (box, (GtkShadowType) g_value_get_uint (value));
578  break;
579  default:
580  /* We don't have any other property... */
581  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
582  break;
583  }
584 }
585 
586 static void
587 gtk_databox_get_property (GObject * object,
588  guint property_id,
589  GValue * value, GParamSpec * pspec) {
590  GtkDatabox *box = GTK_DATABOX (object);
591  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
592 
593  switch (property_id) {
594  case ENABLE_SELECTION:
595  g_value_set_boolean (value, gtk_databox_get_enable_selection (box));
596  break;
597  case ENABLE_ZOOM:
598  g_value_set_boolean (value, gtk_databox_get_enable_zoom (box));
599  break;
600  case ADJUSTMENT_X:
601  g_value_set_object (value, G_OBJECT (gtk_databox_get_adjustment_x (box)));
602  break;
603  case ADJUSTMENT_Y:
604  g_value_set_object (value, G_OBJECT (gtk_databox_get_adjustment_y (box)));
605  break;
606  case RULER_X:
607  g_value_set_object (value, G_OBJECT (gtk_databox_get_ruler_x (box)));
608  break;
609  case RULER_Y:
610  g_value_set_object (value, G_OBJECT (gtk_databox_get_ruler_y (box)));
611  break;
612  case SCALE_TYPE_X:
613  g_value_set_enum (value, gtk_databox_get_scale_type_x (box));
614  break;
615  case SCALE_TYPE_Y:
616  g_value_set_enum (value, gtk_databox_get_scale_type_y (box));
617  break;
618  case BOX_SHADOW:
619  g_value_set_uint (value, priv->box_shadow);
620  break;
621  default:
622  /* We don't have any other property... */
623  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
624  break;
625  }
626 }
627 
628 
629 static void
630 gtk_databox_realize (GtkWidget * widget) {
631  GtkDatabox *box;
632  GdkWindowAttr attributes;
633  gint attributes_mask;
634  GtkAllocation allocation;
635  GtkStyleContext *stylecontext;
636 
637  box = GTK_DATABOX (widget);
638  gtk_widget_set_realized(widget, TRUE);
639  gtk_widget_get_allocation(widget, &allocation);
640 
641  attributes.window_type = GDK_WINDOW_CHILD;
642  attributes.x = allocation.x;
643  attributes.y = allocation.y;
644  attributes.width = allocation.width;
645  attributes.height = allocation.height;
646  attributes.wclass = GDK_INPUT_OUTPUT;
647  attributes.visual = gtk_widget_get_visual (widget);
648  attributes.event_mask = gtk_widget_get_events (widget);
649  attributes.event_mask |= (GDK_EXPOSURE_MASK |
650  GDK_SCROLL_MASK |
651  GDK_TOUCH_MASK |
652  GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
653  GDK_POINTER_MOTION_MASK |
654  GDK_POINTER_MOTION_HINT_MASK);
655 
656  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
657 
658  gtk_widget_set_window(widget,
659  gdk_window_new (gtk_widget_get_parent_window (widget), &attributes,
660  attributes_mask));
661  gdk_window_set_user_data (gtk_widget_get_window(widget), box);
662 
663  stylecontext = gtk_widget_get_style_context(widget);
664  gtk_style_context_add_class(stylecontext, GTK_STYLE_CLASS_BACKGROUND);
665 
667 }
668 
669 static void
670 gtk_databox_unrealize (GtkWidget * widget) {
671  GtkDatabox *box = GTK_DATABOX (widget);
672  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
673  gtk_widget_set_realized(widget, FALSE);
674 
675  if (priv->backing_surface)
676  cairo_surface_destroy (priv->backing_surface);
677  priv->backing_surface=NULL;
678  if (priv->adj_x)
679  g_object_unref (priv->adj_x);
680  priv->adj_x=NULL;
681  if (priv->adj_y)
682  g_object_unref (priv->adj_y);
683 
684  g_list_free (priv->graphs);
685  priv->graphs=NULL;
686 
687  if (GTK_WIDGET_CLASS (gtk_databox_parent_class)->unrealize)
688  (*GTK_WIDGET_CLASS (gtk_databox_parent_class)->unrealize) (widget);
689 
690 }
691 
692 
693 /**
694  * gtk_databox_set_enable_selection
695  * @box: A #GtkDatabox widget
696  * @enable: Whether selection via mouse is enabled or not.
697  *
698  * Setter function for the #GtkDatabox:enable-selection property.
699  *
700  */
701 void
703  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
704  g_return_if_fail (GTK_IS_DATABOX (box));
705 
706  priv->enable_selection = enable;
707  if (priv->selection_active) {
709  }
710 
711  g_object_notify (G_OBJECT (box), "enable-selection");
712 }
713 
714 /**
715  * gtk_databox_set_enable_zoom
716  * @box: A #GtkDatabox widget
717  * @enable: Whether zoom via mouse is enabled or not.
718  *
719  * Setter function for the #GtkDatabox:enable-zoom property.
720  *
721  */
722 void
723 gtk_databox_set_enable_zoom (GtkDatabox * box, gboolean enable) {
724  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
725  g_return_if_fail (GTK_IS_DATABOX (box));
726 
727  priv->enable_zoom = enable;
728 
729  g_object_notify (G_OBJECT (box), "enable-zoom");
730 }
731 
732 /**
733  * gtk_databox_set_adjustment_x
734  * @box: A #GtkDatabox widget
735  * @adj: A #GtkAdjustment object
736  *
737  * Setter function for the #GtkDatabox:adjustment-x property. Normally, it should not be
738  * required to use this function, see property documentation.
739  *
740  */
741 void
742 gtk_databox_set_adjustment_x (GtkDatabox * box, GtkAdjustment * adj) {
743  gdouble page_size_x;
744  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
745 
746  g_return_if_fail (GTK_IS_DATABOX (box));
747 
748  if (!adj)
749  adj = GTK_ADJUSTMENT(gtk_adjustment_new (0, 0, 0, 0, 0, 0));
750 
751  g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
752 
753  if (priv->adj_x) {
754  /* @@@ Do we need to disconnect from the signals here? */
755  g_object_unref (priv->adj_x);
756  if (g_object_is_floating(G_OBJECT(priv->adj_x)))
757  g_object_ref_sink (priv->adj_x);
758  }
759 
760  priv->adj_x = adj;
761  g_object_ref (priv->adj_x);
762 
763  /* We always scroll from 0 to 1.0 */
764  if (priv->total_left != priv->total_right)
765  {
766  page_size_x = gtk_databox_get_page_size_x(box);
767  } else {
768  page_size_x = 1.0;
769  }
770 
771  gtk_adjustment_configure(priv->adj_x,
772  gtk_databox_get_offset_x (box), /* value */
773  0.0, /* lower */
774  1.0, /* upper */
775  page_size_x / 20, /* step_increment */
776  page_size_x * 0.9, /* page_increment */
777  page_size_x); /* page_size */
778 
779  g_signal_connect_swapped (G_OBJECT (priv->adj_x), "value_changed",
780  G_CALLBACK
782 
783  g_object_notify (G_OBJECT (box), "adjustment-x");
784 }
785 
786 /**
787  * gtk_databox_set_adjustment_y
788  * @box: A #GtkDatabox widget
789  * @adj: A #GtkAdjustment object
790  *
791  * Setter function for the #GtkDatabox:adjustment-y property. Normally, it should not be
792  * required to use this function, see property documentation.
793  *
794  */
795 void
796 gtk_databox_set_adjustment_y (GtkDatabox * box, GtkAdjustment * adj) {
797  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
798  gdouble page_size_y;
799 
800  g_return_if_fail (GTK_IS_DATABOX (box));
801  if (!adj)
802  adj = GTK_ADJUSTMENT(gtk_adjustment_new (0, 0, 0, 0, 0, 0));
803 
804  g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
805 
806  if (priv->adj_y) {
807  /* @@@ Do we need to disconnect from the signals here? */
808  g_object_unref (priv->adj_y);
809  if (g_object_is_floating(G_OBJECT(priv->adj_y)))
810  g_object_ref_sink (priv->adj_y);
811  }
812 
813  priv->adj_y = adj;
814  g_object_ref (priv->adj_y);
815 
816  /* We always scroll from 0 to 1.0 */
817  if (priv->total_top != priv->total_bottom)
818  {
819  page_size_y = gtk_databox_get_page_size_y(box);
820  } else {
821  page_size_y = 1.0;
822  }
823 
824  gtk_adjustment_configure(priv->adj_y,
825  gtk_databox_get_offset_y (box), /* value */
826  0.0, /* lower */
827  1.0, /* upper */
828  page_size_y / 20, /* step_increment */
829  page_size_y * 0.9, /* page_increment */
830  page_size_y); /* page_size */
831 
832  g_signal_connect_swapped (G_OBJECT (priv->adj_y), "value_changed",
833  G_CALLBACK
835 
836  g_object_notify (G_OBJECT (box), "adjustment-y");
837 }
838 
839 /**
840  * gtk_databox_set_ruler_x
841  * @box: A #GtkDatabox widget
842  * @ruler: A #GtkDataboxRuler object
843  *
844  * Setter function for the #GtkDatabox:ruler-x property.
845  *
846  */
847 void
849  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
850 
851  g_return_if_fail (GTK_IS_DATABOX (box));
852  g_return_if_fail (ruler == NULL || GTK_DATABOX_IS_RULER (ruler));
853  g_return_if_fail (ruler == NULL || gtk_databox_ruler_get_orientation(ruler) == GTK_ORIENTATION_HORIZONTAL);
854 
855  if (priv->ruler_x) {
856  /* @@@ Do we need to disconnect the signals here? */
857  /* @@@ Do we need to call object_ref and object_unref here and for adjustments? */
858  }
859 
860  priv->ruler_x = ruler;
861 
862  if (GTK_DATABOX_IS_RULER (ruler)) {
864 
866  g_signal_connect_swapped (box, "motion_notify_event",
867  G_CALLBACK (GTK_WIDGET_GET_CLASS
868  (priv->ruler_x)->
869  motion_notify_event),
870  G_OBJECT (priv->ruler_x));
871  }
872 
873  g_object_notify (G_OBJECT (box), "ruler-x");
874 }
875 
876 /**
877  * gtk_databox_set_ruler_y
878  * @box: A #GtkDatabox widget
879  * @ruler: An #GtkDataboxRuler object
880  *
881  * Setter function for the #GtkDatabox:ruler-y property.
882  *
883  */
884 void
886  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
887 
888  g_return_if_fail (GTK_IS_DATABOX (box));
889  g_return_if_fail (ruler == NULL || GTK_DATABOX_IS_RULER (ruler));
890  g_return_if_fail (ruler == NULL || gtk_databox_ruler_get_orientation(ruler) == GTK_ORIENTATION_VERTICAL);
891 
892  if (priv->ruler_y) {
893  /* @@@ Do we need to disconnect the signals here? */
894  /* @@@ Do we need to call object_ref and object_unref here and for adjustments? */
895  }
896 
897  priv->ruler_y = ruler;
898 
899  if (GTK_DATABOX_IS_RULER (ruler)) {
901  priv->scale_type_y);
902 
904  g_signal_connect_swapped (box, "motion_notify_event",
905  G_CALLBACK (GTK_WIDGET_GET_CLASS
906  (priv->ruler_y)->
907  motion_notify_event),
908  G_OBJECT (priv->ruler_y));
909  }
910 
911  g_object_notify (G_OBJECT (box), "ruler-y");
912 }
913 
914 /**
915  * gtk_databox_set_scale_type_x
916  * @box: A #GtkDatabox widget
917  * @scale_type: An #GtkDataboxScaleType (linear or logarithmic)
918  *
919  * Setter function for the #GtkDatabox:scale-type-x property.
920  *
921  */
922 void
924  GtkDataboxScaleType scale_type) {
925  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
926  priv->scale_type_x = scale_type;
927 
928  if (priv->ruler_x)
929  gtk_databox_ruler_set_scale_type (priv->ruler_x, scale_type);
930 
931  g_object_notify (G_OBJECT (box), "scale-type-x");
932 }
933 
934 /**
935  * gtk_databox_set_scale_type_y
936  * @box: A #GtkDatabox widget
937  * @scale_type: An #GtkDataboxScaleType (linear or logarithmic)
938  *
939  * Setter function for the #GtkDatabox:scale-type-y property.
940  *
941  */
942 void
944  GtkDataboxScaleType scale_type) {
945  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
946  priv->scale_type_y = scale_type;
947 
948  if (priv->ruler_y)
949  gtk_databox_ruler_set_scale_type (priv->ruler_y, scale_type);
950 
951  g_object_notify (G_OBJECT (box), "scale-type-y");
952 }
953 
954 /**
955  * gtk_databox_set_box_shadow:
956  * @box: a #GtkDatabox widget.
957  * @which_shadow: How to render the box shadow on the GtkDatabox edges.
958  *
959  * Sets the shadow type when using gtk_paint_box. This will draw the desired edge shadow.
960  **/
961 void
962 gtk_databox_set_box_shadow(GtkDatabox * box, GtkShadowType which_shadow) {
963  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
964 
965  g_return_if_fail (GTK_IS_DATABOX (box));
966  g_return_if_fail (which_shadow<=GTK_SHADOW_ETCHED_OUT);
967 
968  if (priv->box_shadow!=which_shadow) {
969  priv->box_shadow=which_shadow;
970  if (gtk_widget_is_drawable (GTK_WIDGET (box)))
971  gtk_widget_queue_draw (GTK_WIDGET (box));
972  }
973 }
974 
975 
976 /**
977  * gtk_databox_get_enable_selection
978  * @box: A #GtkDatabox widget.
979  *
980  * Getter function for the #GtkDatabox:enable-selection property.
981  *
982  * Return value: The #GtkDatabox:enable-selection property value.
983  *
984  */
985 gboolean
987  g_return_val_if_fail (GTK_IS_DATABOX (box), FALSE);
988  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
989  return priv->enable_selection;
990 }
991 
992 /**
993  * gtk_databox_get_enable_zoom
994  * @box: A #GtkDatabox widget.
995  *
996  * Getter function for the #GtkDatabox:enable-zoom property.
997  *
998  * Return value: The #GtkDatabox:enable-zoom property value.
999  *
1000  */
1001 gboolean
1003  g_return_val_if_fail (GTK_IS_DATABOX (box), FALSE);
1004  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1005  return priv->enable_zoom;
1006 }
1007 
1008 /**
1009  * gtk_databox_get_adjustment_x
1010  * @box: A #GtkDatabox widget.
1011  *
1012  * Getter function for the #GtkDatabox:adjustment-x property.
1013  *
1014  * Return value: The #GtkDatabox:adjustment-x property value.
1015  *
1016  */
1017 GtkAdjustment *
1019  g_return_val_if_fail (GTK_IS_DATABOX (box), NULL);
1020  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1021  return priv->adj_x;
1022 }
1023 
1024 /**
1025  * gtk_databox_get_adjustment_y
1026  * @box: A #GtkDatabox widget.
1027  *
1028  * Getter function for the #GtkDatabox:adjustment-y property.
1029  *
1030  * Return value: The #GtkDatabox:adjustment-y property value.
1031  *
1032  */
1033 GtkAdjustment *
1035  g_return_val_if_fail (GTK_IS_DATABOX (box), NULL);
1036  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1037  return priv->adj_y;
1038 }
1039 
1040 /**
1041  * gtk_databox_get_ruler_x
1042  * @box: A #GtkDatabox widget.
1043  *
1044  * Getter function for the #GtkDatabox:ruler-x property.
1045  *
1046  * Return value: The #GtkDatabox:ruler-x property value.
1047  *
1048  */
1051  g_return_val_if_fail (GTK_IS_DATABOX (box), NULL);
1052  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1053  return priv->ruler_x;
1054 }
1055 
1056 /**
1057  * gtk_databox_get_ruler_y
1058  * @box: A #GtkDatabox widget.
1059  *
1060  * Getter function for the #GtkDatabox:ruler-y property.
1061  *
1062  * Return value: The #GtkDatabox:ruler-y property value.
1063  *
1064  */
1067  g_return_val_if_fail (GTK_IS_DATABOX (box), NULL);
1068  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1069  return priv->ruler_y;
1070 }
1071 
1072 /**
1073  * gtk_databox_get_scale_type_x
1074  * @box: A #GtkDatabox widget.
1075  *
1076  * Getter function for the #GtkDatabox:scale-type-x property.
1077  *
1078  * Return value: The #GtkDatabox:scale-type-x property value.
1079  *
1080  */
1083  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1084  return priv->scale_type_x;
1085 }
1086 
1087 /**
1088  * gtk_databox_get_scale_type_y
1089  * @box: A #GtkDatabox widget.
1090  *
1091  * Getter function for the #GtkDatabox:scale-type-y property.
1092  *
1093  * Return value: The #GtkDatabox:scale-type-y property value.
1094  *
1095  */
1098  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1099  return priv->scale_type_y;
1100 }
1101 
1102 /**
1103  * gtk_databox_get_box_shadow:
1104  * @box: a #GtkDatabox widget
1105  *
1106  * Gets the type of shadow being rendered to the @box (GTK_SHADOW_NONE, GTK_SHADOW_IN, GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_ETCHED_OUT).
1107  *
1108  * Return value: The currently used shadow type of the @box, -1 on failure.
1109  **/
1110 GtkShadowType
1112 
1113  g_return_val_if_fail (GTK_IS_DATABOX (box), -1);
1114  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1115  return priv->box_shadow;
1116 }
1117 
1118 /**
1119  * gtk_databox_set_bg_color:
1120  * @box: a #GtkDatabox widget
1121  * @bg_color: a color name, as used in CSS (html color)
1122  *
1123  * Convenience function to override the background color of @box, acording to @bg_color.
1124  *
1125  **/
1126 void
1127 gtk_databox_set_bg_color (GtkDatabox * box, gchar *bg_color) {
1128  GtkWidget * widget;
1129  GtkDataboxPrivate *priv;
1130  GtkStyleContext *stylecontext;
1131  gchar *css_bg_color;
1132 
1133  g_return_if_fail (GTK_IS_DATABOX (box));
1134  widget = GTK_WIDGET (box);
1135  priv = gtk_databox_get_instance_private (box);
1136 
1137  stylecontext = gtk_widget_get_style_context (widget);
1138  gtk_style_context_remove_provider (stylecontext, GTK_STYLE_PROVIDER (priv->cssp));
1139  css_bg_color = g_strdup_printf (".%s {background-color: %s;}", GTK_STYLE_CLASS_BACKGROUND, bg_color);
1140  gtk_css_provider_load_from_data (priv->cssp, css_bg_color, -1, NULL);
1141  gtk_style_context_add_provider (stylecontext, GTK_STYLE_PROVIDER (priv->cssp), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1142  g_free (css_bg_color);
1143 }
1144 
1145 static void
1147  /* @@@ Check for all external functions, if type checks are implemented! */
1148  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1149  GtkWidget *widget = GTK_WIDGET(box);
1150  GtkAllocation allocation;
1151 
1152  gtk_widget_get_allocation(widget, &allocation);
1154  priv->translation_factor_x =
1155  (gfloat)allocation.width / (priv->visible_right -
1156  priv->visible_left);
1157  else if (priv->scale_type_x == GTK_DATABOX_SCALE_LOG2)
1158  priv->translation_factor_x =
1159  (gfloat)allocation.width / log2 (priv->visible_right /
1160  priv->visible_left);
1161  else
1162  priv->translation_factor_x =
1163  (gfloat)allocation.width / log10 (priv->visible_right /
1164  priv->visible_left);
1165 
1167  priv->translation_factor_y =
1168  (gfloat)allocation.height / (priv->visible_bottom -
1169  priv->visible_top);
1170  else if (priv->scale_type_y == GTK_DATABOX_SCALE_LOG2)
1171  priv->translation_factor_y =
1172  (gfloat)allocation.height / log2 (priv->visible_bottom /
1173  priv->visible_top);
1174  else
1175  priv->translation_factor_y =
1176  (gfloat)allocation.height / log10 (priv->visible_bottom /
1177  priv->visible_top);
1178 }
1179 
1180 static void
1182  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1183  GtkAllocation allocation;
1184  GtkWidget *widget;
1185  GdkDrawingContext *drawc;
1186  cairo_region_t *crr;
1187  cairo_t *cr;
1188  gint width;
1189  gint height;
1190 
1191  widget = GTK_WIDGET (box);
1192  gtk_widget_get_allocation(widget, &allocation);
1193  width = allocation.width;
1194  height = allocation.height;
1195  if (priv->backing_surface) {
1196  if ((width == priv->old_width) &&
1197  (height == priv->old_height))
1198  return;
1199  cairo_surface_destroy (priv->backing_surface);
1200  }
1201 
1202  priv->old_width = width;
1203  priv->old_height = height;
1204 
1205  crr = gdk_window_get_visible_region (gtk_widget_get_window (widget));
1206  drawc = gdk_window_begin_draw_frame (gtk_widget_get_window (widget), crr);
1207  cr = gdk_drawing_context_get_cairo_context (drawc);
1208 
1209  priv->backing_surface = cairo_surface_create_similar(
1210  cairo_get_target (cr),
1211  CAIRO_CONTENT_COLOR,
1212  width, height);
1213  gdk_window_end_draw_frame (gtk_widget_get_window (widget), drawc);
1214  cairo_region_destroy (crr);
1215 }
1216 
1217 /**
1218  * gtk_databox_get_backing_surface:
1219  * @box: A #GtkDatabox widget
1220  *
1221  * This function returns the surface which is used by @box and its #GtkDataboxGraph objects
1222  * for drawing operations before copying the result to the screen.
1223  *
1224  * The function is typically called by the #GtkDataboxGraph objects.
1225  *
1226  * Return value: Backing surface
1227  */
1228 cairo_surface_t *
1230  g_return_val_if_fail (GTK_IS_DATABOX (box), NULL);
1231  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1232  return priv->backing_surface;
1233 }
1234 
1235 static void
1236 gtk_databox_size_allocate (GtkWidget * widget, GtkAllocation * allocation) {
1237  GtkDatabox *box = GTK_DATABOX (widget);
1238  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1239 
1240  gtk_widget_set_allocation(widget, allocation);
1241 
1242  if (gtk_widget_get_window(widget)) /* don't move_resize an unrealized window */
1243  {
1244  gdk_window_move_resize (gtk_widget_get_window(widget),
1245  allocation->x, allocation->y,
1246  allocation->width, allocation->height);
1247  }
1248 
1249  if (priv->selection_active) {
1251  }
1252 
1254 }
1255 
1256 static gint
1257 gtk_databox_draw (GtkWidget * widget, cairo_t * cr) {
1258  GtkDatabox *box = GTK_DATABOX (widget);
1259  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1260  GList *list;
1261  cairo_t *cr2;
1262  GtkStyleContext *stylecontext = gtk_widget_get_style_context(widget);
1263  GtkAllocation allocation;
1264 
1266 
1267  cr2 = cairo_create(priv->backing_surface);
1268  gtk_widget_get_allocation (widget, &allocation);
1269  gtk_render_background (stylecontext, cr2, 0.0, 0.0, allocation.width, allocation.height);
1270  cairo_destroy(cr2);
1271 
1272  list = g_list_last (priv->graphs);
1273  while (list) {
1274  if (list->data)
1275  gtk_databox_graph_draw (GTK_DATABOX_GRAPH (list->data), box);
1276  list = g_list_previous (list);
1277  }
1278 
1279  if (priv->selection_active)
1280  gtk_databox_draw_selection (box, TRUE);
1281 
1282  cairo_set_source_surface (cr, priv->backing_surface, 0, 0);
1283  cairo_paint(cr);
1284  /* the following was removed - unsure if it creates problems
1285  gtk_databox_draw_selection (box, FALSE);
1286  */
1287 
1288  return FALSE;
1289 }
1290 
1291 static void
1293  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1294  priv->selectionValues.x1 =
1295  gtk_databox_pixel_to_value_x (box, priv->marked.x);
1296  priv->selectionValues.x2 =
1297  gtk_databox_pixel_to_value_x (box, priv->select.x);
1298  priv->selectionValues.y1 =
1299  gtk_databox_pixel_to_value_y (box, priv->marked.y);
1300  priv->selectionValues.y2 =
1301  gtk_databox_pixel_to_value_y (box, priv->select.y);
1302 }
1303 
1304 static gint
1305 gtk_databox_button_press (GtkWidget * widget, GdkEventButton * event) {
1306  GtkDatabox *box = GTK_DATABOX (widget);
1307  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1308 
1309  if (event->type != GDK_BUTTON_PRESS && event->type != GDK_2BUTTON_PRESS)
1310  return FALSE;
1311 
1312  priv->selection_finalized = FALSE;
1313  if ((event->button == 1 || event->button == 2) & !(event->type==GDK_2BUTTON_PRESS)) {
1314  if (priv->selection_active) {
1315  if (event->x > MIN (priv->marked.x, priv->select.x)
1316  && event->x < MAX (priv->marked.x, priv->select.x)
1317  && event->y > MIN (priv->marked.y, priv->select.y)
1318  && event->y < MAX (priv->marked.y, priv->select.y)) {
1320  } else {
1322  }
1323  priv->marked.x = priv->select.x = event->x;
1324  priv->marked.y = priv->select.y = event->y;
1326  }
1327  }
1328 
1329  if ((event->button == 3) || (event->button == 1 && event->type==GDK_2BUTTON_PRESS)) {
1330  if (event->state & GDK_SHIFT_MASK) {
1331  gtk_databox_zoom_home (box);
1332  } else {
1333  gtk_databox_zoom_out (box);
1334  }
1335  }
1336 
1337  return FALSE;
1338 }
1339 
1340 static gint
1341 gtk_databox_button_release (GtkWidget * widget, GdkEventButton * event) {
1342  GtkDatabox *box = GTK_DATABOX (widget);
1343  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1344 
1345  if (event->type != GDK_BUTTON_RELEASE)
1346  return FALSE;
1347 
1348  if (priv->selection_active) {
1349  priv->selection_finalized = TRUE;
1350 
1351  g_signal_emit (G_OBJECT (box),
1353  0, &priv->selectionValues);
1354  }
1355 
1356  return FALSE;
1357 }
1358 
1359 static gint
1360 gtk_databox_scroll_event (GtkWidget *widget, GdkEventScroll *event) {
1361  GtkDatabox *box = GTK_DATABOX (widget);
1362  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1363 
1364  if (event->state & GDK_CONTROL_MASK && priv->enable_zoom) {
1365  if (event->direction == GDK_SCROLL_DOWN) {
1366  gtk_databox_zoom_out(box);
1367  } else if (event->direction == GDK_SCROLL_UP &&
1368  (gtk_adjustment_get_page_size(priv->adj_x) / 2) >= priv->zoom_limit &&
1369  (gtk_adjustment_get_page_size(priv->adj_y) / 2) >= priv->zoom_limit) {
1370  gdouble x_val, y_val;
1371  gdouble x_proportion, y_proportion;
1372 
1373  x_val = gtk_databox_pixel_to_value_x(box, event->x);
1374  y_val = gtk_databox_pixel_to_value_y(box, event->y);
1375 
1376  if (priv->scale_type_x == GTK_DATABOX_SCALE_LINEAR) {
1377  x_proportion = (x_val - priv->total_left) /
1378  (priv->total_right - priv->total_left);
1379  } else {
1380  x_proportion = log(x_val/priv->total_left) /
1381  log(priv->total_right / priv->total_left);
1382  }
1383 
1384  if (priv->scale_type_y == GTK_DATABOX_SCALE_LINEAR) {
1385  y_proportion = (y_val - priv->total_top) /
1386  (priv->total_bottom - priv->total_top);
1387  } else {
1388  y_proportion = log(y_val/priv->total_top) /
1389  log(priv->total_bottom / priv->total_top);
1390  }
1391 
1392  g_object_freeze_notify(G_OBJECT(priv->adj_x));
1393  gtk_adjustment_set_page_size(priv->adj_x, gtk_adjustment_get_page_size(priv->adj_x) / 2);
1394  gtk_adjustment_set_value(priv->adj_x, (x_proportion +
1395  gtk_adjustment_get_value(priv->adj_x)) / 2);
1396  g_object_thaw_notify(G_OBJECT(priv->adj_x));
1397 
1398  g_object_freeze_notify(G_OBJECT(priv->adj_y));
1399  gtk_adjustment_set_page_size(priv->adj_y, gtk_adjustment_get_page_size(priv->adj_y) / 2);
1400  gtk_adjustment_set_value(priv->adj_y, (y_proportion +
1401  gtk_adjustment_get_value(priv->adj_y)) / 2);
1402  g_object_thaw_notify(G_OBJECT(priv->adj_y));
1403 
1405  gtk_databox_zoomed (box);
1406  }
1407  } else {
1408  GtkAdjustment *adj;
1409  gdouble delta = 0.0, new_value;
1410 
1411  if ((event->direction == GDK_SCROLL_UP ||
1412  event->direction == GDK_SCROLL_DOWN) &&
1413  !(event->state & GDK_SHIFT_MASK)) {
1414  adj = priv->adj_y;
1415  } else {
1416  adj = priv->adj_x;
1417  }
1418 
1419  switch (event->direction) {
1420  case GDK_SCROLL_UP:
1421  case GDK_SCROLL_SMOOTH:
1422  case GDK_SCROLL_LEFT:
1423  delta = 0 - gtk_adjustment_get_step_increment(adj);
1424  break;
1425  case GDK_SCROLL_DOWN:
1426  case GDK_SCROLL_RIGHT:
1427  delta = gtk_adjustment_get_step_increment(adj);
1428  break;
1429  }
1430 
1431  new_value = CLAMP (gtk_adjustment_get_value(adj) + delta, gtk_adjustment_get_lower(adj),
1432  gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
1433  gtk_adjustment_set_value(adj, new_value);
1434  }
1435 
1436  return FALSE;
1437 }
1438 
1439 static void
1441  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1442 
1443  /* There is no active selection after cancellation */
1444  priv->selection_active = FALSE;
1445 
1446  /* Only active selections can be stopped */
1447  priv->selection_finalized = FALSE;
1448 
1449  /* Remove selection box */
1450  gtk_databox_draw_selection (box, TRUE);
1451 
1452  /* Let everyone know that the selection has been canceled */
1453  g_signal_emit (G_OBJECT (box),
1455 }
1456 
1457 
1458 static void
1460  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1461 
1462  g_return_if_fail(GTK_IS_DATABOX(box));
1463  g_return_if_fail(GTK_IS_ADJUSTMENT(priv->adj_x));
1464  g_return_if_fail(GTK_IS_ADJUSTMENT(priv->adj_y));
1465 
1466  priv->selection_active = FALSE;
1467  priv->selection_finalized = FALSE;
1468 
1469 #ifndef GTK3_18
1470  gtk_adjustment_changed (priv->adj_x);
1471  gtk_adjustment_changed (priv->adj_y);
1472 #endif
1473 
1474  gtk_widget_queue_draw (GTK_WIDGET(box));
1475 
1476  g_signal_emit (G_OBJECT (box),
1478 }
1479 
1480 /**
1481  * gtk_databox_zoom_to_selection:
1482  * @box: A #GtkDatabox widget
1483  *
1484  * This is equivalent to left-clicking into the selected area.
1485  *
1486  * This function works, if the attribute #enable-zoom is set to #TRUE. Calling the function
1487  * then zooms to the area selected with the mouse.
1488  *
1489  * Side effect: The @box emits #GtkDatabox::zoomed.
1490  */
1491 void
1493  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1494  GtkWidget *widget;
1495  GtkAllocation allocation;
1496  gdouble temp_value, temp_page_size;
1497 
1498  g_return_if_fail(GTK_IS_DATABOX(box));
1499 
1500  widget = GTK_WIDGET (box);
1501  gtk_widget_get_allocation(widget, &allocation);
1502 
1503  if (!priv->enable_zoom) {
1505  return;
1506  }
1507 
1508  g_object_freeze_notify(G_OBJECT(priv->adj_x));
1509  g_object_freeze_notify(G_OBJECT(priv->adj_y));
1510 
1511  temp_value = gtk_adjustment_get_value(priv->adj_x);
1512  temp_value += (gdouble) (MIN (priv->marked.x, priv->select.x))
1513  * gtk_adjustment_get_page_size(priv->adj_x)
1514  / allocation.width;
1515  temp_page_size = gtk_adjustment_get_page_size(priv->adj_x);
1516  temp_page_size *=
1517  (gdouble) (ABS (priv->marked.x - priv->select.x) + 1)
1518  / allocation.width;
1519 
1520  gtk_adjustment_set_page_size(priv->adj_x, temp_page_size);
1521  gtk_adjustment_set_value(priv->adj_x, temp_value);
1522 
1523  temp_value = gtk_adjustment_get_value(priv->adj_y);
1524  temp_value += (gdouble) (MIN (priv->marked.y, priv->select.y))
1525  * gtk_adjustment_get_page_size(priv->adj_y)
1526  / allocation.height;
1527  temp_page_size = gtk_adjustment_get_page_size(priv->adj_y);
1528  temp_page_size *=
1529  (gfloat) (ABS (priv->marked.y - priv->select.y) + 1)
1530  / allocation.height;
1531 
1532  gtk_adjustment_set_page_size(priv->adj_y, temp_page_size);
1533  gtk_adjustment_set_value(priv->adj_y, temp_value);
1534 
1535  /* If we zoom too far into the data, we will get funny results, because
1536  * of overflow effects. Therefore zooming is limited to zoom_limit.
1537  */
1538  if (gtk_adjustment_get_page_size(priv->adj_x) < priv->zoom_limit) {
1539  temp_value = (gfloat) MAX (0, gtk_adjustment_get_value(priv->adj_x)
1540  - (priv->zoom_limit -
1541  gtk_adjustment_get_page_size(priv->adj_x)) /
1542  2.0);
1543  gtk_adjustment_set_page_size(priv->adj_x, priv->zoom_limit);
1544  gtk_adjustment_set_value(priv->adj_x, temp_value);
1545  }
1546 
1547  if (gtk_adjustment_get_page_size(priv->adj_y) < priv->zoom_limit) {
1548  temp_value = (gfloat) MAX (0, gtk_adjustment_get_value(priv->adj_y)
1549  - (priv->zoom_limit -
1550  gtk_adjustment_get_page_size(priv->adj_y)) /
1551  2.0);
1552  gtk_adjustment_set_page_size(priv->adj_y, priv->zoom_limit);
1553  gtk_adjustment_set_value(priv->adj_y, temp_value);
1554  }
1555  g_object_thaw_notify(G_OBJECT(priv->adj_y));
1556  g_object_thaw_notify(G_OBJECT(priv->adj_x));
1557 
1559  gtk_databox_zoomed (box);
1560 }
1561 
1562 /**
1563  * gtk_databox_zoom_out:
1564  * @box: A #GtkDatabox widget
1565  *
1566  * This is equivalent to right-clicking into the @box.
1567  *
1568  * This function works, if the attribute #enable-zoom is set to #TRUE. Calling the function
1569  * then zooms out by a factor of 2 in both dimensions (the maximum is defined by the total
1570  * limits, see gtk_databox_set_total_limits()).
1571  *
1572  * Side effect: The @box emits #GtkDatabox::zoomed.
1573  */
1574 void
1576  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1577  if (!priv->enable_zoom) {
1578  return;
1579  }
1580 
1581  g_object_freeze_notify(G_OBJECT(priv->adj_x));
1582  g_object_freeze_notify(G_OBJECT(priv->adj_y));
1583  gtk_adjustment_set_page_size(priv->adj_x, MIN (1.0, gtk_adjustment_get_page_size(priv->adj_x) * 2));
1584  gtk_adjustment_set_page_size(priv->adj_y, MIN (1.0, gtk_adjustment_get_page_size(priv->adj_y) * 2));
1585  gtk_adjustment_set_value(priv->adj_x,
1586  (gtk_adjustment_get_page_size(priv->adj_x) == 1.0)
1587  ? 0
1588  : MAX (0, MIN (gtk_adjustment_get_value(priv->adj_x) - gtk_adjustment_get_page_size(priv->adj_x) / 4,
1589  1.0 - gtk_adjustment_get_page_size(priv->adj_x))));
1590  gtk_adjustment_set_value(priv->adj_y,
1591  (gtk_adjustment_get_page_size(priv->adj_y) == 1.0)
1592  ? 0
1593  : MAX (0, MIN (gtk_adjustment_get_value(priv->adj_y) - gtk_adjustment_get_page_size(priv->adj_y) / 4,
1594  1.0 - gtk_adjustment_get_page_size(priv->adj_y))));
1595  g_object_thaw_notify(G_OBJECT(priv->adj_y));
1596  g_object_thaw_notify(G_OBJECT(priv->adj_x));
1597 
1599  gtk_databox_zoomed (box);
1600 }
1601 
1602 /**
1603  * gtk_databox_zoom_home:
1604  * @box: A #GtkDatabox widget
1605  *
1606  * This is equivalent to shift right-clicking into the @box.
1607  *
1608  * This function works, if the attribute #enable-zoom is set to #TRUE. It is equivalent to
1609  * calling the gtk_databox_set_visible_limits() with the total limits.
1610  *
1611  */
1612 void
1614  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1615  if (!priv->enable_zoom) {
1616  return;
1617  }
1618 
1620  priv->total_left, priv->total_right,
1621  priv->total_top, priv->total_bottom);
1622 }
1623 
1624 static void
1625 gtk_databox_draw_selection (GtkDatabox * box, gboolean clear) {
1626  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1627  GtkWidget *widget = GTK_WIDGET (box);
1628  GdkDrawingContext *drawc;
1629  cairo_region_t *crr;
1630  cairo_t *cr;
1631 
1632  crr = gdk_window_get_visible_region (gtk_widget_get_window (widget));
1633  drawc = gdk_window_begin_draw_frame (gtk_widget_get_window (widget), crr);
1634  cr = gdk_drawing_context_get_cairo_context (drawc);
1635  cairo_rectangle (cr,
1636  MIN (priv->marked.x, priv->select.x) - 0.5,
1637  MIN (priv->marked.y, priv->select.y) - 0.5,
1638  ABS (priv->marked.x - priv->select.x) + 1.0,
1639  ABS (priv->marked.y - priv->select.y) + 1.0);
1640 
1641  if (clear) {
1642  cairo_set_source_surface (cr, priv->backing_surface, 0, 0);
1643  cairo_paint(cr);
1644  cairo_set_line_width (cr, 2.0);
1645  } else {
1646  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
1647  cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
1648  cairo_set_line_width (cr, 1.0);
1649  }
1650  cairo_stroke(cr);
1651  gdk_window_end_draw_frame (gtk_widget_get_window (widget), drawc);
1652  cairo_region_destroy (crr);
1653 }
1654 
1655 static void
1658 
1659  gtk_widget_queue_draw (GTK_WIDGET(box));
1660 }
1661 
1662 static void
1664  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1665  if (priv->ruler_x) {
1667  GTK_DATABOX_RULER (priv->ruler_x),
1668  priv->visible_left,
1669  priv->visible_right,
1670  0.5 * (priv->visible_left + priv->visible_right));
1671  }
1672 
1673  if (priv->ruler_y) {
1675  GTK_DATABOX_RULER (priv->ruler_y),
1676  priv->visible_top,
1677  priv->visible_bottom,
1678  0.5 * (priv->visible_top + priv->visible_bottom));
1679  }
1680 }
1681 
1682 /**
1683  * gtk_databox_auto_rescale:
1684  * @box: A #GtkDatabox widget
1685  * @border: Relative border width (e.g. 0.1 means that the border on each side is 10% of the data area).
1686  *
1687  * This function is similar to gtk_databox_set_total_limits(). It sets the total limits
1688  * to match the data extrema (see gtk_databox_calculate_extrema()). If you do not like data pixels exactly at the
1689  * widget's border, you can add modify the limits using the border parameter: The limits are extended by
1690  * @border*(max-min) if max!=min. If max==min, they are extended by @border*max (otherwise the data could not be
1691  * scaled to the pixel realm).
1692  *
1693  * After calling this function, x values grow from left to right, y values grow from bottom to top.
1694  *
1695  * Return value: 0 on success,
1696  * -1 if @box is no GtkDatabox widget,
1697  * -2 if no datasets are available
1698  */
1699 gint
1700 gtk_databox_auto_rescale (GtkDatabox * box, gfloat border) {
1701  gfloat min_x;
1702  gfloat max_x;
1703  gfloat min_y;
1704  gfloat max_y;
1705  gint extrema_success = gtk_databox_calculate_extrema (box, &min_x, &max_x,
1706  &min_y, &max_y);
1707  if (extrema_success)
1708  return extrema_success;
1709  else {
1710  gfloat width = max_x - min_x;
1711  gfloat height = max_y - min_y;
1712 
1713  if (width == 0) width = max_x;
1714  if (height == 0) height = max_y;
1715 
1716  min_x -= border * width;
1717  max_x += border * width;
1718  min_y -= border * height;
1719  max_y += border * height;
1720  }
1721 
1722  gtk_databox_set_total_limits (GTK_DATABOX (box), min_x, max_x, max_y,
1723  min_y);
1724 
1725  return 0;
1726 }
1727 
1728 
1729 /**
1730  * gtk_databox_calculate_extrema:
1731  * @box: A #GtkDatabox widget
1732  * @min_x: Will be filled with the lowest x value of all datasets
1733  * @max_x: Will be filled with the highest x value of all datasets
1734  * @min_y: Will be filled with the lowest y value of all datasets
1735  * @max_y: Will be filled with the highest y value of all datasets
1736  *
1737  * Determines the minimum and maximum x and y values of all
1738  * #GtkDataboxGraph objects which have been added to the #GtkDatabox widget via gtk_databox_graph_add().
1739  *
1740  * Return value: 0 on success,
1741  * -1 if @box is no GtkDatabox widget,
1742  * -2 if no datasets are available
1743  */
1744 gint
1746  gfloat * min_x, gfloat * max_x, gfloat * min_y,
1747  gfloat * max_y) {
1748  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1749  GList *list;
1750  gint return_val = -2;
1751  gboolean first = TRUE;
1752 
1753  g_return_val_if_fail (GTK_IS_DATABOX (box), -1);
1754 
1755  list = g_list_last (priv->graphs);
1756  while (list) {
1757  gfloat graph_min_x;
1758  gfloat graph_max_x;
1759  gfloat graph_min_y;
1760  gfloat graph_max_y;
1761  gint value = -1;
1762 
1763  if (list->data) {
1764  value =
1766  (list->data), &graph_min_x,
1767  &graph_max_x, &graph_min_y,
1768  &graph_max_y);
1769  } else {
1770  /* Do nothing if data == NULL */
1771  }
1772 
1773  if (value >= 0) {
1774  return_val = 0;
1775 
1776  if (first) {
1777  /* The min and max values need to be initialized with the
1778  * first valid values from the graph
1779  */
1780  *min_x = graph_min_x;
1781  *max_x = graph_max_x;
1782  *min_y = graph_min_y;
1783  *max_y = graph_max_y;
1784 
1785  first = FALSE;
1786  } else {
1787  *min_x = MIN (*min_x, graph_min_x);
1788  *min_y = MIN (*min_y, graph_min_y);
1789  *max_x = MAX (*max_x, graph_max_x);
1790  *max_y = MAX (*max_y, graph_max_y);
1791  }
1792  }
1793 
1794  list = g_list_previous (list);
1795  }
1796  return return_val;
1797 }
1798 
1799 static gfloat
1801  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1802 
1804  return (priv->visible_left - priv->total_left)
1805  / (priv->total_right - priv->total_left);
1806  else if (priv->scale_type_x == GTK_DATABOX_SCALE_LOG2)
1807  return log2 (priv->visible_left / priv->total_left)
1808  / log2 (priv->total_right / priv->total_left);
1809  else
1810  return log10 (priv->visible_left / priv->total_left)
1811  / log10 (priv->total_right / priv->total_left);
1812 }
1813 
1814 static gfloat
1816  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1817 
1819  return (priv->visible_left - priv->visible_right)
1820  / (priv->total_left - priv->total_right);
1821  else if (priv->scale_type_x == GTK_DATABOX_SCALE_LOG2)
1822  return log2 (priv->visible_left / priv->visible_right)
1823  / log2 (priv->total_left / priv->total_right);
1824  else
1825  return log10 (priv->visible_left / priv->visible_right)
1826  / log10 (priv->total_left / priv->total_right);
1827 }
1828 
1829 static gfloat
1831  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1832 
1834  return (priv->visible_top - priv->total_top)
1835  / (priv->total_bottom - priv->total_top);
1836  else if (priv->scale_type_y == GTK_DATABOX_SCALE_LOG2)
1837  return log2 (priv->visible_top / priv->total_top)
1838  / log2 (priv->total_bottom / priv->total_top);
1839  else
1840  return log10 (priv->visible_top / priv->total_top)
1841  / log10 (priv->total_bottom / priv->total_top);
1842 }
1843 
1844 static gfloat
1846  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1847 
1849  return (priv->visible_top - priv->visible_bottom)
1850  / (priv->total_top - priv->total_bottom);
1851  else if (priv->scale_type_y == GTK_DATABOX_SCALE_LOG2)
1852  return log2 (priv->visible_top / priv->visible_bottom)
1853  / log2 (priv->total_top / priv->total_bottom);
1854  else
1855  return log10 (priv->visible_top / priv->visible_bottom)
1856  / log10 (priv->total_top / priv->total_bottom);
1857 }
1858 
1859 /**
1860  * gtk_databox_set_total_limits:
1861  * @box: A #GtkDatabox widget
1862  * @left: Left total limit
1863  * @right: Right total limit
1864  * @top: Top total limit
1865  * @bottom: Bottom total limit
1866  *
1867  * This function is used to set the limits of the total
1868  * display area of @box.
1869  * This function can be used to invert the orientation of the displayed graphs,
1870  * e.g. @top=-1000 and @bottom=0.
1871  *
1872  * Side effect: The @box also internally calls gtk_databox_set_visible_limits() with the same values.
1873  *
1874  */
1875 void
1877  gfloat left, gfloat right,
1878  gfloat top, gfloat bottom) {
1879  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1880  g_return_if_fail (GTK_IS_DATABOX (box));
1881  g_return_if_fail (left != right);
1882  g_return_if_fail (top != bottom);
1883 
1884  priv->total_left = left;
1885  priv->total_right = right;
1886  priv->total_top = top;
1887  priv->total_bottom = bottom;
1888 
1889  gtk_databox_set_visible_limits(box, left, right, top, bottom);
1890 }
1891 
1892 /**
1893  * gtk_databox_set_visible_limits:
1894  * @box: A #GtkDatabox widget
1895  * @left: Left visible limit
1896  * @right: Right visible limit
1897  * @top: Top visible limit
1898  * @bottom: Bottom visible limit
1899  *
1900  * This function is used to set the limits of the visible
1901  * display area of @box. The visible display area can be section of the total
1902  * area, i.e. the @box zooms in, showing only a part of the complete picture.
1903  *
1904  * The orientation of the values have to be the same as in gtk_databox_set_total_limits() and
1905  * the visible limits have to be within the total limits. The
1906  * values will not be used otherwise.
1907  *
1908  * Side effect: The @box emits #GtkDatabox::zoomed.
1909  *
1910  */
1911 void
1913  gfloat left, gfloat right,
1914  gfloat top, gfloat bottom) {
1915  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1916  gboolean visible_inside_total = FALSE;
1917 
1918  g_return_if_fail (GTK_IS_DATABOX (box));
1919 
1920  visible_inside_total =
1921  ((priv->total_left <= left && left < right
1922  && right <= priv->total_right)
1923  || (priv->total_left >= left && left > right
1924  && right >= priv->total_right))
1925  &&
1926  ((priv->total_bottom <= bottom && bottom < top
1927  && top <= priv->total_top)
1928  || (priv->total_bottom >= bottom && bottom > top
1929  && top >= priv->total_top));
1930 
1931  g_return_if_fail (visible_inside_total);
1932 
1933  priv->visible_left = left;
1934  priv->visible_right = right;
1935  priv->visible_top = top;
1936  priv->visible_bottom = bottom;
1937 
1939 
1940  g_object_freeze_notify(G_OBJECT(priv->adj_x));
1941  g_object_freeze_notify(G_OBJECT(priv->adj_y));
1942 
1943  gtk_adjustment_set_value(priv->adj_x, gtk_databox_get_offset_x (box));
1944  gtk_adjustment_set_page_size(priv->adj_x, gtk_databox_get_page_size_x (box));
1945  gtk_adjustment_set_value(priv->adj_y, gtk_databox_get_offset_y (box));
1946  gtk_adjustment_set_page_size(priv->adj_y, gtk_databox_get_page_size_y (box));
1947 
1948  g_object_thaw_notify(G_OBJECT(priv->adj_y));
1949  g_object_thaw_notify(G_OBJECT(priv->adj_x));
1950 
1951  /* Update rulers */
1953 
1955 
1956  gtk_databox_zoomed (box);
1957 }
1958 
1959 /**
1960  * gtk_databox_calculate_visible_limits:
1961  * @box: A #GtkDatabox widget
1962  *
1963  * Calculates the visible limits based on the adjustment values and page sizes
1964  * and calls gtk_databox_set_visible_limits();
1965  */
1966 static void
1968  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
1969  if (!gtk_widget_get_visible (GTK_WIDGET(box)))
1970  return;
1971 
1972  if (priv->scale_type_x == GTK_DATABOX_SCALE_LINEAR) {
1973  priv->visible_left =
1974  priv->total_left
1975  + (priv->total_right - priv->total_left)
1976  * gtk_adjustment_get_value(priv->adj_x);
1977  priv->visible_right =
1978  priv->total_left
1979  + (priv->total_right - priv->total_left)
1980  * (gtk_adjustment_get_value(priv->adj_x) + gtk_adjustment_get_page_size(priv->adj_x));
1981  } else {
1982  priv->visible_left =
1983  priv->total_left
1984  * pow (priv->total_right / priv->total_left,
1985  gtk_adjustment_get_value(priv->adj_x));
1986  priv->visible_right =
1987  priv->total_left
1988  * pow (priv->total_right / priv->total_left,
1989  gtk_adjustment_get_value(priv->adj_x) + gtk_adjustment_get_page_size(priv->adj_x));
1990  }
1991 
1992  if (priv->scale_type_y == GTK_DATABOX_SCALE_LINEAR) {
1993  priv->visible_top =
1994  priv->total_top
1995  + (priv->total_bottom - priv->total_top)
1996  * gtk_adjustment_get_value(priv->adj_y);
1997  priv->visible_bottom =
1998  priv->total_top
1999  + (priv->total_bottom - priv->total_top)
2000  * (gtk_adjustment_get_value(priv->adj_y) + gtk_adjustment_get_page_size(priv->adj_y));
2001  } else {
2002  priv->visible_top =
2003  priv->total_top
2004  * pow (priv->total_bottom / priv->total_top,
2005  gtk_adjustment_get_value(priv->adj_y)),
2006  priv->visible_bottom =
2007  priv->total_top
2008  * pow (priv->total_bottom / priv->total_top,
2009  gtk_adjustment_get_value(priv->adj_y) + gtk_adjustment_get_page_size(priv->adj_y));
2010  }
2011 
2012  /* Adjustments are the basis for the calculations in this function
2013  * so they do not need to be updated
2014  */
2015 
2016  /* Update rulers */
2018 
2020 }
2021 
2022 /**
2023  * gtk_databox_get_total_limits:
2024  * @box: A #GtkDatabox widget
2025  * @left: Space for total left value or #NULL
2026  * @right: Space for total right value or #NULL
2027  * @top: Space for total top value or #NULL
2028  * @bottom: Space for total bottom value or #NULL
2029  *
2030  * Gives the total limits (as set by gtk_databox_auto_rescale() or gtk_databox_set_total_limits()).
2031  */
2032 void
2034  gfloat * left, gfloat * right,
2035  gfloat * top, gfloat * bottom) {
2036  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2037  g_return_if_fail (GTK_IS_DATABOX (box));
2038 
2039  if (left)
2040  *left = priv->total_left;
2041  if (right)
2042  *right = priv->total_right;
2043  if (top)
2044  *top = priv->total_top;
2045  if (bottom)
2046  *bottom = priv->total_bottom;
2047 }
2048 
2049 /**
2050  * gtk_databox_get_visible_limits:
2051  * @box: A #GtkDatabox widget
2052  * @left: Space for visible left value or #NULL
2053  * @right: Space for visible right value or #NULL
2054  * @top: Space for visible top value or #NULL
2055  * @bottom: Space for visible bottom value or #NULL
2056  *
2057  * Gives the current visible limits. These differ from those given by gtk_databox_get_total_limits() if
2058  * you zoomed into the data for instance by gtk_databox_zoom_to_selection() or gtk_databox_set_visible_limits() (these values
2059  * can be changed by scrolling, of course).
2060  */
2061 void
2063  gfloat * left, gfloat * right,
2064  gfloat * top, gfloat * bottom) {
2065  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2066  g_return_if_fail (GTK_IS_DATABOX (box));
2067 
2068  if (left)
2069  *left = priv->visible_left;
2070  if (right)
2071  *right = priv->visible_right;
2072  if (top)
2073  *top = priv->visible_top;
2074  if (bottom)
2075  *bottom = priv->visible_bottom;
2076 }
2077 
2078 
2079 /**
2080  * gtk_databox_graph_add:
2081  * @box: A #GtkDatabox widget
2082  * @graph: A graph, e.g. a #GtkDataboxPoints or a #GtkDataboxGrid object
2083  *
2084  * Adds the @graph to the @box. The next time the @box is re-drawn, the graph will be shown.
2085  *
2086  * It might be becessary to modify the total_limits in order for the graph to be displayed properly (see gtk_databox_set_total_limits()).
2087  *
2088  * Return value: 0 on success, -1 otherwise
2089  */
2090 gint
2092  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2093  g_return_val_if_fail (GTK_IS_DATABOX (box), -1);
2094  g_return_val_if_fail (GTK_DATABOX_IS_GRAPH (graph), -1);
2095 
2096  priv->graphs = g_list_append (priv->graphs, graph);
2097 
2098  return (priv->graphs == NULL) ? -1 : 0;
2099 }
2100 
2101 /**
2102  * gtk_databox_graph_add_front:
2103  * @box: A #GtkDatabox widget
2104  * @graph: A graph, e.g. a #GtkDataboxPoints or a #GtkDataboxGrid object
2105  *
2106  * Adds the @graph to the @box and will be plotted on top. The next time the @box is re-drawn, the graph will be shown.
2107  *
2108  * It might be becessary to modify the total_limits in order for the graph to be displayed properly (see gtk_databox_set_total_limits()).
2109  *
2110  * Return value: 0 on success, -1 otherwise
2111  */
2112 gint
2114 
2115  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2116  g_return_val_if_fail (GTK_IS_DATABOX (box), -1);
2117  g_return_val_if_fail (GTK_DATABOX_IS_GRAPH (graph), -1);
2118 
2119  priv->graphs = g_list_prepend (priv->graphs, graph);
2120 
2121  return (priv->graphs == NULL) ? -1 : 0;
2122 }
2123 
2124 /**
2125  * gtk_databox_graph_remove:
2126  * @box: A #GtkDatabox widget
2127  * @graph: A graph, e.g. a #GtkDataboxPoints or a #GtkDataboxGrid object
2128  *
2129  * Removes the @graph from the @box once. The next time the @box is re-drawn, the graph will not be shown (unless it was added more
2130  * than once).
2131  *
2132  * Return value: 0 on success, -1 otherwise
2133  */
2134 gint
2136  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2137  GList *list;
2138 
2139  g_return_val_if_fail (GTK_IS_DATABOX (box), -1);
2140  g_return_val_if_fail (GTK_DATABOX_IS_GRAPH (graph), -1);
2141 
2142  list = g_list_find (priv->graphs, graph);
2143  g_return_val_if_fail (list, -1);
2144 
2145  priv->graphs = g_list_delete_link (priv->graphs, list);
2146  return 0;
2147 }
2148 
2149 /**
2150  * gtk_databox_graph_remove_all:
2151  * @box: A #GtkDatabox widget
2152  *
2153  * Removes all graphs from the @box. The next time the @box is re-drawn, no graphs will be shown.
2154  *
2155  * Return value: 0 on success, -1 otherwise
2156  */
2157 gint
2159  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2160  g_return_val_if_fail (GTK_IS_DATABOX (box), -1);
2161 
2162  g_list_free (priv->graphs);
2163  priv->graphs = NULL;
2164 
2165  return 0;
2166 }
2167 
2168 /**
2169  * gtk_databox_value_to_pixel_x:
2170  * @box: A #GtkDatabox widget
2171  * @value: An x value
2172  *
2173  * Calculates the horizontal pixel coordinate which represents the x @value.
2174  * Pixel coordinates are relative to the top-left corner of the @box which is equivalent to (0,0).
2175  *
2176  * Return value: Pixel coordinate
2177  */
2178 gint16
2180  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2181 
2183  return (value -
2184  priv->visible_left) *
2185  priv->translation_factor_x;
2186  else if (priv->scale_type_x == GTK_DATABOX_SCALE_LOG2)
2187  return log2 (value / priv->visible_left) *
2188  priv->translation_factor_x;
2189  else
2190  return log10 (value / priv->visible_left) *
2191  priv->translation_factor_x;
2192 }
2193 
2194 /**
2195  * gtk_databox_value_to_pixel_y:
2196  * @box: A #GtkDatabox widget
2197  * @value: A y value
2198  *
2199  * Calculates the vertical pixel coordinate which represents the y @value.
2200  * Pixel coordinates are relative to the top-left corner of the @box which is equivalent to (0,0).
2201  *
2202  * Return value: Pixel coordinate
2203  */
2204 gint16
2206  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2207 
2209  return (value -
2210  priv->visible_top) * priv->translation_factor_y;
2211  else if (priv->scale_type_y == GTK_DATABOX_SCALE_LOG2)
2212  return log2 (value / priv->visible_top) *
2213  priv->translation_factor_y;
2214  else
2215  return log10 (value / priv->visible_top) *
2216  priv->translation_factor_y;
2217 }
2218 
2219 /**
2220  * gtk_databox_values_to_xpixels:
2221  * @box: A #GtkDatabox widget.
2222  * @pixels: address to return pixel x coordinates.
2223  * @values: An x values array.
2224  * @vtype: GType of @values.
2225  * @maxlen: maximum length of the arrays.
2226  * @start: first value to compute.
2227  * @stride: bytes per row of plotting.
2228  * @len: how many values to compute.
2229  *
2230  * Calculates the horizontal coordinates for @pixels which represents the x @values.
2231  * Pixel coordinates are relative to the left corner of the @box which is equivalent to (0).
2232  *
2233  * Return value: Pixel coordinates
2234  */
2235 void
2237  void *values, GType vtype, guint maxlen, guint start, guint stride, guint len)
2238 {
2239  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2240  guint i, indx;
2241  gfloat fval = 0.0;
2242  GtkDataboxScaleType scale_type;
2243  gfloat tf, minvis;
2244 
2245  scale_type = priv->scale_type_x;
2246  tf = priv->translation_factor_x;
2247  minvis = priv->visible_left;
2248 
2249  indx = start * stride;
2250  i = 0;
2251  do {
2252  /* This may be excessive, but it handles every conceivable type */
2253  if (vtype == G_TYPE_FLOAT)
2254  fval = ((gfloat *)values)[indx];
2255  else if (vtype == G_TYPE_DOUBLE)
2256  fval = ((gdouble *)values)[indx];
2257  else if (vtype == G_TYPE_INT)
2258  fval = ((gint *)values)[indx];
2259  else if (vtype == G_TYPE_UINT)
2260  fval = ((guint *)values)[indx];
2261  else if (vtype == G_TYPE_LONG)
2262  fval = ((glong *)values)[indx];
2263  else if (vtype == G_TYPE_ULONG)
2264  fval = ((gulong *)values)[indx];
2265  else if (vtype == G_TYPE_INT64)
2266  fval = ((gint64 *)values)[indx];
2267  else if (vtype == G_TYPE_UINT64)
2268  fval = ((guint64 *)values)[indx];
2269  else if (vtype == G_TYPE_CHAR)
2270  fval = ((gchar *)values)[indx];
2271  else if (vtype == G_TYPE_UCHAR)
2272  fval = ((guchar *)values)[indx];
2273 
2274  if (scale_type == GTK_DATABOX_SCALE_LINEAR)
2275  pixels[i] = tf * (fval - minvis);
2276  else if (scale_type == GTK_DATABOX_SCALE_LOG2)
2277  pixels[i] = tf * log2(fval / minvis);
2278  else
2279  pixels[i] = tf * log10(fval / minvis);
2280 
2281  /* handle the wrap-around (ring buffer) issue using modulus. for efficiency, don't do this for non-wraparound cases. */
2282  /* note this allows multiple wrap-arounds. One could hold a single cycle of a sine wave, and plot a continuous wave */
2283  /* This can be optimized using pointers later */
2284  if (i + start > maxlen)
2285  indx = ((i + start) % maxlen) * stride;
2286  else
2287  indx += stride;
2288  } while (++i < len);
2289 }
2290 
2291 /**
2292  * gtk_databox_values_to_ypixels:
2293  * @box: A #GtkDatabox widget
2294  * @pixels: address to return pixel y coordinates.
2295  * @values: an y values array.
2296  * @vtype: GType of @values.
2297  * @maxlen: maximum length of the arrays.
2298  * @start: first value to compute.
2299  * @stride: bytes per row of plotting.
2300  * @len: how many values to compute.
2301  *
2302  * Calculates the vertical coordinates for @pixels which represents the y @values.
2303  * Pixel coordinates are relative to the top corner of the @box which is equivalent to (0).
2304  *
2305  * Return value: Pixel coordinates
2306  */
2307 void
2309  void *values, GType vtype, guint maxlen, guint start, guint stride, guint len)
2310 {
2311  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2312  guint i, indx;
2313  gfloat fval = 0.0;
2314  GtkDataboxScaleType scale_type;
2315  gfloat tf, minvis;
2316 
2317  scale_type = priv->scale_type_y;
2318  tf = priv->translation_factor_y;
2319  minvis = priv->visible_top;
2320 
2321  indx = start * stride;
2322  i = 0;
2323  do {
2324  /* This may be excessive, but it handles every conceivable type */
2325  if (vtype == G_TYPE_FLOAT)
2326  fval = ((gfloat *)values)[indx];
2327  else if (vtype == G_TYPE_DOUBLE)
2328  fval = ((gdouble *)values)[indx];
2329  else if (vtype == G_TYPE_INT)
2330  fval = ((gint *)values)[indx];
2331  else if (vtype == G_TYPE_UINT)
2332  fval = ((guint *)values)[indx];
2333  else if (vtype == G_TYPE_LONG)
2334  fval = ((glong *)values)[indx];
2335  else if (vtype == G_TYPE_ULONG)
2336  fval = ((gulong *)values)[indx];
2337  else if (vtype == G_TYPE_INT64)
2338  fval = ((gint64 *)values)[indx];
2339  else if (vtype == G_TYPE_UINT64)
2340  fval = ((guint64 *)values)[indx];
2341  else if (vtype == G_TYPE_CHAR)
2342  fval = ((gchar *)values)[indx];
2343  else if (vtype == G_TYPE_UCHAR)
2344  fval = ((guchar *)values)[indx];
2345 
2346  if (scale_type == GTK_DATABOX_SCALE_LINEAR)
2347  pixels[i] = tf * (fval - minvis);
2348  else if (scale_type == GTK_DATABOX_SCALE_LOG2)
2349  pixels[i] = tf * log2(fval / minvis);
2350  else
2351  pixels[i] = tf * log10(fval / minvis);
2352 
2353  /* handle the wrap-around (ring buffer) issue using modulus. for efficiency, don't do this for non-wraparound cases. */
2354  /* note this allows multiple wrap-arounds. One could hold a single cycle of a sine wave, and plot a continuous wave */
2355  /* This can be optimized using pointers later */
2356  if (i + start > maxlen)
2357  indx = ((i + start) % maxlen) * stride;
2358  else
2359  indx += stride;
2360  } while (++i < len);
2361 }
2362 
2363 /**
2364  * gtk_databox_pixel_to_value_x:
2365  * @box: A #GtkDatabox widget
2366  * @pixel: A horizontal pixel coordinate
2367  *
2368  * Calculates the x value which is represented by the horizontal @pixel coordinate.
2369  * Pixel coordinates are relative to the top-left corner of the @box which is equivalent to (0,0).
2370  *
2371  * Return value: x value
2372  */
2373 gfloat
2375  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2376 
2378  return priv->visible_left +
2379  pixel / priv->translation_factor_x;
2380  else if (priv->scale_type_x == GTK_DATABOX_SCALE_LOG2)
2381  return priv->visible_left * pow (2,
2382  pixel /
2383  priv->
2384  translation_factor_x);
2385  else
2386  return priv->visible_left * pow (10,
2387  pixel /
2388  priv->
2389  translation_factor_x);
2390 }
2391 
2392 /**
2393  * gtk_databox_pixel_to_value_y:
2394  * @box: A #GtkDatabox widget
2395  * @pixel: A vertical pixel coordinate
2396  *
2397  * Calculates the y value which is represented by the vertical @pixel coordinate.
2398  * Pixel coordinates are relative to the top-left corner of the @box which is equivalent to (0,0).
2399  *
2400  * Return value: y value
2401  */
2402 gfloat
2404  GtkDataboxPrivate *priv = gtk_databox_get_instance_private(box);
2405 
2407  return priv->visible_top +
2408  pixel / priv->translation_factor_y;
2409  else if (priv->scale_type_y == GTK_DATABOX_SCALE_LOG2)
2410  return priv->visible_top * pow (2,
2411  pixel /
2412  priv->
2413  translation_factor_y);
2414  else
2415  return priv->visible_top * pow (10,
2416  pixel /
2417  priv->
2418  translation_factor_y);
2419 }
2420 
2421 /**
2422  * gtk_databox_create_box_with_scrollbars_and_rulers:
2423  * @p_box: Will contain a pointer to a #GtkDatabox widget
2424  * @p_grid: Will contain a pointer to a #GtkGrid widget
2425  * @scrollbar_x: Whether to attach a horizontal scrollbar
2426  * @scrollbar_y: Whether to attach a vertical scrollbar
2427  * @ruler_x: Whether to attach a horizontal ruler
2428  * @ruler_y: Whether to attach a vertical ruler
2429  *
2430  * This is a convenience function which creates a #GtkDatabox widget in a
2431  * GtkGrid widget optionally accompanied by scrollbars and rulers. You only
2432  * have to fill in the data (gtk_databox_graph_add()) and adjust the limits
2433  * (gtk_databox_set_total_limits() or gtk_databox_auto_rescale()).
2434  *
2435  * This function produces the default databox with rulers at the top left and
2436  * scroll bars at the bottom right.
2437  *
2438  * Return value: #GtkGrid in the @p_grid object pointer.
2439  *
2440  * @see_also: gtk_databox_new(), gtk_databox_set_adjustment_x(), gtk_databox_set_adjustment_y(), gtk_databox_set_ruler_x(), gtk_databox_set_ruler_y()
2441  */
2442 void
2444  GtkWidget ** p_grid,
2445  gboolean scrollbar_x,
2446  gboolean scrollbar_y,
2447  gboolean ruler_x,
2448  gboolean ruler_y) {
2449  /* create with rulers top left by default */
2450  gtk_databox_create_box_with_scrollbars_and_rulers_positioned (p_box, p_grid, scrollbar_x, scrollbar_y, ruler_x, ruler_y, TRUE, TRUE);
2451 }
2452 
2453 /**
2454  * gtk_databox_create_box_with_scrollbars_and_rulers_positioned:
2455  * @p_box: Will contain a pointer to a #GtkDatabox widget
2456  * @p_grid: Will contain a pointer to a #GtkGrid widget
2457  * @scrollbar_x: Whether to attach a horizontal scrollbar
2458  * @scrollbar_y: Whether to attach a vertical scrollbar
2459  * @ruler_x: Whether to attach a horizontal ruler
2460  * @ruler_y: Whether to attach a vertical ruler
2461  * @ruler_x_top: Whether to put the ruler_x up the top
2462  * @ruler_y_left: Whether to put the ruler_y on the left
2463  *
2464  * This is a convenience function which creates a #GtkDatabox widget in a
2465  * GtkGrid widget optionally accompanied by scrollbars and rulers. You only
2466  * have to fill in the data (gtk_databox_graph_add()) and adjust the limits
2467  * (gtk_databox_set_total_limits() or gtk_databox_auto_rescale()).
2468  *
2469  * This function produces the default databox with rulers at the top left and
2470  * scroll bars at the bottom right.
2471  *
2472  * Return value: #GtkGrid in the @p_grid object pointer.
2473  *
2474  * @see_also: gtk_databox_new(), gtk_databox_set_adjustment_x(), gtk_databox_set_adjustment_y(), gtk_databox_set_ruler_x(), gtk_databox_set_ruler_y(), gtk_databox_create_box_with_scrollbars_and_rulers()
2475  */
2476 void
2478  GtkWidget ** p_grid,
2479  gboolean scrollbar_x,
2480  gboolean scrollbar_y,
2481  gboolean ruler_x,
2482  gboolean ruler_y,
2483  gboolean ruler_x_top,
2484  gboolean ruler_y_left) {
2485  GtkGrid *grid;
2486  GtkDatabox *box;
2487  GtkWidget *scrollbar;
2488  GtkWidget *ruler;
2489  gint left_col, top_row;
2490  GtkDataboxPrivate *priv;
2491 
2492  *p_grid = gtk_grid_new ();
2493  *p_box = gtk_databox_new ();
2494  box = GTK_DATABOX (*p_box);
2495  grid = GTK_GRID (*p_grid);
2496  priv = gtk_databox_get_instance_private(box);
2497 
2498  left_col=1;
2499  top_row=1;
2500  gtk_grid_attach (grid, GTK_WIDGET (box), left_col, top_row, 1, 1);
2501 
2502  if (scrollbar_x) {
2503  scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, NULL);
2505  gtk_range_get_adjustment (GTK_RANGE
2506  (scrollbar)));
2507  if (ruler_x_top) {
2508  left_col=1;
2509  top_row=2;
2510  } else {
2511  left_col=1;
2512  top_row=0;
2513  }
2514  gtk_grid_attach (grid, scrollbar, left_col, top_row, 1, 1);
2515  }
2516 
2517  if (scrollbar_y) {
2518  scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, NULL);
2520  gtk_range_get_adjustment (GTK_RANGE
2521  (scrollbar)));
2522  if (ruler_y_left) {
2523  left_col=2;
2524  top_row=1;
2525  } else {
2526  left_col=0;
2527  top_row=1;
2528  }
2529  gtk_grid_attach (grid, scrollbar, left_col, top_row, 1, 1);
2530  }
2531 
2532  if (ruler_x) {
2533  ruler = gtk_databox_ruler_new (GTK_ORIENTATION_HORIZONTAL);
2535  priv->scale_type_x);
2536  if (ruler_x_top) {
2537  left_col=1;
2538  top_row=0;
2539  } else {
2540  gtk_databox_ruler_set_invert_edge(GTK_DATABOX_RULER(ruler), TRUE); /* set the ruler to reverse its edge */
2541  left_col=1;
2542  top_row=2;
2543  }
2544  gtk_grid_attach (grid, ruler, left_col, top_row, 1, 1);
2546  }
2547 
2548  if (ruler_y) {
2549  ruler = gtk_databox_ruler_new (GTK_ORIENTATION_VERTICAL);
2551  priv->scale_type_y);
2552  if (ruler_y_left) {
2553  left_col=0;
2554  top_row=1;
2555  } else {
2556  gtk_databox_ruler_set_invert_edge(GTK_DATABOX_RULER(ruler), TRUE); /* set the ruler to reverse its edge */
2557  left_col=2;
2558  top_row=1;
2559  }
2560  gtk_grid_attach (grid, ruler, left_col, top_row, 1, 1);
2562  }
2563 }
gint gtk_databox_graph_add(GtkDatabox *box, GtkDataboxGraph *graph)
Definition: gtkdatabox.c:2091
void gtk_databox_set_ruler_x(GtkDatabox *box, GtkDataboxRuler *ruler)
Definition: gtkdatabox.c:848
static void gtk_databox_draw_selection(GtkDatabox *box, gboolean clear)
Definition: gtkdatabox.c:1625
gfloat gtk_databox_pixel_to_value_x(GtkDatabox *box, gint16 pixel)
Definition: gtkdatabox.c:2374
void gtk_databox_set_adjustment_x(GtkDatabox *box, GtkAdjustment *adj)
Definition: gtkdatabox.c:742
static void gtk_databox_realize(GtkWidget *widget)
Definition: gtkdatabox.c:630
void gtk_databox_set_enable_selection(GtkDatabox *box, gboolean enable)
Definition: gtkdatabox.c:702
void gtk_databox_set_scale_type_y(GtkDatabox *box, GtkDataboxScaleType scale_type)
Definition: gtkdatabox.c:943
void gtk_databox_get_total_limits(GtkDatabox *box, gfloat *left, gfloat *right, gfloat *top, gfloat *bottom)
Definition: gtkdatabox.c:2033
GtkDataboxRuler * gtk_databox_get_ruler_x(GtkDatabox *box)
Definition: gtkdatabox.c:1050
static void gtk_databox_zoomed(GtkDatabox *box)
Definition: gtkdatabox.c:1459
static gint gtk_databox_scroll_event(GtkWidget *widget, GdkEventScroll *event)
Definition: gtkdatabox.c:1360
static gfloat gtk_databox_get_offset_y(GtkDatabox *box)
Definition: gtkdatabox.c:1830
void gtk_databox_zoom_home(GtkDatabox *box)
Definition: gtkdatabox.c:1613
static void gtk_databox_init(GtkDatabox *box)
Definition: gtkdatabox.c:422
GtkDataboxRuler * gtk_databox_get_ruler_y(GtkDatabox *box)
Definition: gtkdatabox.c:1066
void gtk_databox_get_visible_limits(GtkDatabox *box, gfloat *left, gfloat *right, gfloat *top, gfloat *bottom)
Definition: gtkdatabox.c:2062
static void gtk_databox_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
Definition: gtkdatabox.c:1236
gfloat gtk_databox_pixel_to_value_y(GtkDatabox *box, gint16 pixel)
Definition: gtkdatabox.c:2403
void gtk_databox_zoom_out(GtkDatabox *box)
Definition: gtkdatabox.c:1575
static gint gtk_databox_button_release(GtkWidget *widget, GdkEventButton *event)
Definition: gtkdatabox.c:1341
static void gtk_databox_calculate_selection_values(GtkDatabox *box)
Definition: gtkdatabox.c:1292
GtkShadowType gtk_databox_get_box_shadow(GtkDatabox *box)
Definition: gtkdatabox.c:1111
gint16 gtk_databox_value_to_pixel_x(GtkDatabox *box, gfloat value)
Definition: gtkdatabox.c:2179
GtkAdjustment * gtk_databox_get_adjustment_y(GtkDatabox *box)
Definition: gtkdatabox.c:1034
GtkDataboxScaleType gtk_databox_get_scale_type_y(GtkDatabox *box)
Definition: gtkdatabox.c:1097
static void gtk_databox_ruler_update(GtkDatabox *box)
Definition: gtkdatabox.c:1663
gint gtk_databox_auto_rescale(GtkDatabox *box, gfloat border)
Definition: gtkdatabox.c:1700
void gtk_databox_values_to_xpixels(GtkDatabox *box, gint16 *pixels, void *values, GType vtype, guint maxlen, guint start, guint stride, guint len)
Definition: gtkdatabox.c:2236
static void gtk_databox_selection_cancel(GtkDatabox *box)
Definition: gtkdatabox.c:1440
void gtk_databox_set_ruler_y(GtkDatabox *box, GtkDataboxRuler *ruler)
Definition: gtkdatabox.c:885
cairo_surface_t * gtk_databox_get_backing_surface(GtkDatabox *box)
Definition: gtkdatabox.c:1229
static void gtk_databox_create_backing_surface(GtkDatabox *box)
Definition: gtkdatabox.c:1181
static void gtk_databox_unrealize(GtkWidget *widget)
Definition: gtkdatabox.c:670
static void gtk_databox_class_init(GtkDataboxClass *class)
Definition: gtkdatabox.c:166
static void gtk_databox_calculate_translation_factors(GtkDatabox *box)
Definition: gtkdatabox.c:1146
void gtk_databox_create_box_with_scrollbars_and_rulers_positioned(GtkWidget **p_box, GtkWidget **p_grid, gboolean scrollbar_x, gboolean scrollbar_y, gboolean ruler_x, gboolean ruler_y, gboolean ruler_x_top, gboolean ruler_y_left)
Definition: gtkdatabox.c:2477
static void gtk_databox_adjustment_value_changed(GtkDatabox *box)
Definition: gtkdatabox.c:1656
GList * gtk_databox_get_graphs(GtkDatabox *box)
Definition: gtkdatabox.c:474
GtkAdjustment * gtk_databox_get_adjustment_x(GtkDatabox *box)
Definition: gtkdatabox.c:1018
static gfloat gtk_databox_get_page_size_x(GtkDatabox *box)
Definition: gtkdatabox.c:1815
static gint gtk_databox_button_press(GtkWidget *widget, GdkEventButton *event)
Definition: gtkdatabox.c:1305
@ LAST_SIGNAL
Definition: gtkdatabox.c:81
@ SELECTION_CHANGED_SIGNAL
Definition: gtkdatabox.c:78
@ SELECTION_FINALIZED_SIGNAL
Definition: gtkdatabox.c:79
@ ZOOMED_SIGNAL
Definition: gtkdatabox.c:76
@ SELECTION_STARTED_SIGNAL
Definition: gtkdatabox.c:77
@ SELECTION_CANCELED_SIGNAL
Definition: gtkdatabox.c:80
static gint gtk_databox_draw(GtkWidget *widget, cairo_t *cr)
Definition: gtkdatabox.c:1257
static void gtk_databox_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Definition: gtkdatabox.c:547
static gint gtk_databox_motion_notify(GtkWidget *widget, GdkEventMotion *event)
Definition: gtkdatabox.c:482
static gfloat gtk_databox_get_page_size_y(GtkDatabox *box)
Definition: gtkdatabox.c:1845
void gtk_databox_set_bg_color(GtkDatabox *box, gchar *bg_color)
Definition: gtkdatabox.c:1127
static gfloat gtk_databox_get_offset_x(GtkDatabox *box)
Definition: gtkdatabox.c:1800
void gtk_databox_set_total_limits(GtkDatabox *box, gfloat left, gfloat right, gfloat top, gfloat bottom)
Definition: gtkdatabox.c:1876
void gtk_databox_set_scale_type_x(GtkDatabox *box, GtkDataboxScaleType scale_type)
Definition: gtkdatabox.c:923
@ SCALE_TYPE_X
Definition: gtkdatabox.c:96
@ RULER_X
Definition: gtkdatabox.c:94
@ RULER_Y
Definition: gtkdatabox.c:95
@ ADJUSTMENT_Y
Definition: gtkdatabox.c:93
@ SCALE_TYPE_Y
Definition: gtkdatabox.c:97
@ ADJUSTMENT_X
Definition: gtkdatabox.c:92
@ LAST_PROPERTY
Definition: gtkdatabox.c:99
@ ENABLE_SELECTION
Definition: gtkdatabox.c:90
@ BOX_SHADOW
Definition: gtkdatabox.c:98
@ ENABLE_ZOOM
Definition: gtkdatabox.c:91
static void gtk_databox_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
Definition: gtkdatabox.c:587
gint gtk_databox_graph_add_front(GtkDatabox *box, GtkDataboxGraph *graph)
Definition: gtkdatabox.c:2113
static gint gtk_databox_signals[LAST_SIGNAL]
Definition: gtkdatabox.c:85
void gtk_databox_set_box_shadow(GtkDatabox *box, GtkShadowType which_shadow)
Definition: gtkdatabox.c:962
void gtk_databox_set_adjustment_y(GtkDatabox *box, GtkAdjustment *adj)
Definition: gtkdatabox.c:796
gboolean gtk_databox_get_enable_selection(GtkDatabox *box)
Definition: gtkdatabox.c:986
void gtk_databox_set_enable_zoom(GtkDatabox *box, gboolean enable)
Definition: gtkdatabox.c:723
GtkDataboxScaleType gtk_databox_get_scale_type_x(GtkDatabox *box)
Definition: gtkdatabox.c:1082
gint gtk_databox_graph_remove(GtkDatabox *box, GtkDataboxGraph *graph)
Definition: gtkdatabox.c:2135
gint gtk_databox_calculate_extrema(GtkDatabox *box, gfloat *min_x, gfloat *max_x, gfloat *min_y, gfloat *max_y)
Definition: gtkdatabox.c:1745
GtkWidget * gtk_databox_new(void)
Definition: gtkdatabox.c:461
static void gtk_databox_calculate_visible_limits(GtkDatabox *box)
Definition: gtkdatabox.c:1967
void gtk_databox_create_box_with_scrollbars_and_rulers(GtkWidget **p_box, GtkWidget **p_grid, gboolean scrollbar_x, gboolean scrollbar_y, gboolean ruler_x, gboolean ruler_y)
Definition: gtkdatabox.c:2443
gint gtk_databox_graph_remove_all(GtkDatabox *box)
Definition: gtkdatabox.c:2158
void gtk_databox_values_to_ypixels(GtkDatabox *box, gint16 *pixels, void *values, GType vtype, guint maxlen, guint start, guint stride, guint len)
Definition: gtkdatabox.c:2308
gint16 gtk_databox_value_to_pixel_y(GtkDatabox *box, gfloat value)
Definition: gtkdatabox.c:2205
gboolean gtk_databox_get_enable_zoom(GtkDatabox *box)
Definition: gtkdatabox.c:1002
void gtk_databox_set_visible_limits(GtkDatabox *box, gfloat left, gfloat right, gfloat top, gfloat bottom)
Definition: gtkdatabox.c:1912
void gtk_databox_zoom_to_selection(GtkDatabox *box)
Definition: gtkdatabox.c:1492
#define GTK_IS_DATABOX(obj)
Definition: gtkdatabox.h:62
#define GTK_DATABOX(obj)
Definition: gtkdatabox.h:56
#define GTK_TYPE_DATABOX
Definition: gtkdatabox.h:55
#define GTK_DATABOX_GRAPH(obj)
void gtk_databox_graph_draw(GtkDataboxGraph *graph, GtkDatabox *box)
gint gtk_databox_graph_calculate_extrema(GtkDataboxGraph *graph, gfloat *min_x, gfloat *max_x, gfloat *min_y, gfloat *max_y)
#define GTK_DATABOX_IS_GRAPH(obj)
G_DEFINE_TYPE_WITH_PRIVATE(GtkDataboxMarkers, gtk_databox_markers, GTK_DATABOX_TYPE_XYC_GRAPH)
#define gtk_databox_marshal_VOID__POINTER
#define gtk_databox_marshal_VOID__VOID
#define GTK_DATABOX_IS_RULER(obj)
void gtk_databox_ruler_set_scale_type(GtkDataboxRuler *ruler, guint scale_type)
#define GTK_DATABOX_TYPE_RULER
GtkOrientation gtk_databox_ruler_get_orientation(GtkDataboxRuler *ruler)
void gtk_databox_ruler_set_invert_edge(GtkDataboxRuler *ruler, gboolean invert)
#define GTK_DATABOX_RULER(obj)
GtkWidget * gtk_databox_ruler_new(GtkOrientation orientation)
void gtk_databox_ruler_set_range(GtkDataboxRuler *ruler, gdouble lower, gdouble upper, gdouble position)
GType gtk_databox_scale_type_get_type(void)
GtkDataboxScaleType
@ GTK_DATABOX_SCALE_LINEAR
@ GTK_DATABOX_SCALE_LOG2
typedefG_BEGIN_DECLS struct _GtkDatabox GtkDatabox
gfloat translation_factor_x
Definition: gtkdatabox.c:129
GtkShadowType box_shadow
Definition: gtkdatabox.c:151
cairo_surface_t * backing_surface
Definition: gtkdatabox.c:112
GtkDataboxRuler * ruler_x
Definition: gtkdatabox.c:137
gboolean selection_active
Definition: gtkdatabox.c:148
GtkCssProvider * cssp
Definition: gtkdatabox.c:152
GtkAdjustment * adj_x
Definition: gtkdatabox.c:135
gboolean enable_zoom
Definition: gtkdatabox.c:134
gfloat translation_factor_y
Definition: gtkdatabox.c:130
gboolean enable_selection
Definition: gtkdatabox.c:133
gboolean selection_finalized
Definition: gtkdatabox.c:149
GtkDataboxScaleType scale_type_y
Definition: gtkdatabox.c:128
GtkDataboxRuler * ruler_y
Definition: gtkdatabox.c:138
GtkAdjustment * adj_y
Definition: gtkdatabox.c:136
GtkDataboxScaleType scale_type_x
Definition: gtkdatabox.c:127
GtkDataboxValueRectangle selectionValues
Definition: gtkdatabox.c:144