1 /* $Id: gtkdatabox_xyc_graph.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 #include <gtkdatabox_xyc_graph.h>
21 
22 G_DEFINE_TYPE(GtkDataboxXYCGraph, gtk_databox_xyc_graph,
23 	GTK_DATABOX_TYPE_GRAPH)
24 
25 static gint gtk_databox_xyc_graph_real_calculate_extrema (GtkDataboxGraph *
26 							  xyc_graph,
27 							  gfloat * min_x,
28 							  gfloat * max_x,
29 							  gfloat * min_y,
30 							  gfloat * max_y);
31 
32 /* IDs of properties */
33 enum
34 {
35    PROP_X = 1,
36    PROP_Y,
37    PROP_LEN,
38    PROP_MAXLEN,
39    PROP_XSTART,
40    PROP_YSTART,
41    PROP_XSTRIDE,
42    PROP_YSTRIDE,
43    PROP_XTYPE,
44    PROP_YTYPE
45 };
46 
47 /**
48  * GtkDataboxXYCGraphPrivate
49  *
50  * A private data structure used by the #GtkDataboxXYCGraph. It shields all internal things
51  * from developers who are just using the object.
52  *
53  **/
54 typedef struct _GtkDataboxXYCGraphPrivate GtkDataboxXYCGraphPrivate;
55 
56 struct _GtkDataboxXYCGraphPrivate
57 {
58    gfloat *X;
59    gfloat *Y;
60    guint len;
61    guint maxlen;
62    guint xstart;
63    guint ystart;
64    guint xstride;
65    guint ystride;
66    GType xtype;
67    GType ytype;
68 };
69 
70 //static gpointer parent_class = NULL;
71 
72 void
gtk_databox_xyc_graph_set_X_Y_length(GtkDataboxXYCGraph * xyc_graph,gfloat * X,gfloat * Y,guint len)73 gtk_databox_xyc_graph_set_X_Y_length(GtkDataboxXYCGraph * xyc_graph, gfloat * X, gfloat * Y, guint len)
74 {
75    GtkDataboxXYCGraphPrivate *priv = GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph);
76    priv->Y = Y;
77    priv->X = X;
78    priv->len = len;
79 }
80 
81 static void
gtk_databox_xyc_graph_set_X(GtkDataboxXYCGraph * xyc_graph,gfloat * X)82 gtk_databox_xyc_graph_set_X (GtkDataboxXYCGraph * xyc_graph, gfloat * X)
83 {
84    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
85    g_return_if_fail (X);
86 
87    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->X = X;
88 
89    g_object_notify (G_OBJECT (xyc_graph), "X-Values");
90 }
91 
92 static void
gtk_databox_xyc_graph_set_Y(GtkDataboxXYCGraph * xyc_graph,gfloat * Y)93 gtk_databox_xyc_graph_set_Y (GtkDataboxXYCGraph * xyc_graph, gfloat * Y)
94 {
95    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
96    g_return_if_fail (Y);
97 
98    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->Y = Y;
99 
100    g_object_notify (G_OBJECT (xyc_graph), "Y-Values");
101 }
102 
103 static void
gtk_databox_xyc_graph_set_length(GtkDataboxXYCGraph * xyc_graph,guint len)104 gtk_databox_xyc_graph_set_length (GtkDataboxXYCGraph * xyc_graph, guint len)
105 {
106    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
107    g_return_if_fail (len > 0);
108 
109    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->len = len;
110 
111    g_object_notify (G_OBJECT (xyc_graph), "length");
112 }
113 
114 static void
gtk_databox_xyc_graph_set_maxlen(GtkDataboxXYCGraph * xyc_graph,guint maxlen)115 gtk_databox_xyc_graph_set_maxlen (GtkDataboxXYCGraph * xyc_graph, guint maxlen)
116 {
117    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
118    g_return_if_fail (maxlen > 0);
119 
120    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->maxlen = maxlen;
121 
122    g_object_notify (G_OBJECT (xyc_graph), "maxlen");
123 }
124 
125 static void
gtk_databox_xyc_graph_set_xstart(GtkDataboxXYCGraph * xyc_graph,guint xstart)126 gtk_databox_xyc_graph_set_xstart (GtkDataboxXYCGraph * xyc_graph, guint xstart)
127 {
128    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
129 
130    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->xstart = xstart;
131 
132    g_object_notify (G_OBJECT (xyc_graph), "X-Values");
133 }
134 
135 static void
gtk_databox_xyc_graph_set_ystart(GtkDataboxXYCGraph * xyc_graph,guint ystart)136 gtk_databox_xyc_graph_set_ystart (GtkDataboxXYCGraph * xyc_graph, guint ystart)
137 {
138    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
139 
140    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->ystart = ystart;
141 
142    g_object_notify (G_OBJECT (xyc_graph), "Y-Values");
143 }
144 
145 static void
gtk_databox_xyc_graph_set_xstride(GtkDataboxXYCGraph * xyc_graph,guint xstride)146 gtk_databox_xyc_graph_set_xstride (GtkDataboxXYCGraph * xyc_graph, guint xstride)
147 {
148    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
149 
150    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->xstride = xstride;
151 
152    g_object_notify (G_OBJECT (xyc_graph), "X-Values");
153 }
154 
155 static void
gtk_databox_xyc_graph_set_ystride(GtkDataboxXYCGraph * xyc_graph,guint ystride)156 gtk_databox_xyc_graph_set_ystride (GtkDataboxXYCGraph * xyc_graph, guint ystride)
157 {
158    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
159 
160    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->ystride = ystride;
161 
162    g_object_notify (G_OBJECT (xyc_graph), "Y-Values");
163 }
164 
165 static void
gtk_databox_xyc_graph_set_xtype(GtkDataboxXYCGraph * xyc_graph,GType xtype)166 gtk_databox_xyc_graph_set_xtype (GtkDataboxXYCGraph * xyc_graph, GType xtype)
167 {
168    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
169 
170    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->xtype = xtype;
171 
172    g_object_notify (G_OBJECT (xyc_graph), "X-Values");
173 }
174 
175 static void
gtk_databox_xyc_graph_set_ytype(GtkDataboxXYCGraph * xyc_graph,GType ytype)176 gtk_databox_xyc_graph_set_ytype (GtkDataboxXYCGraph * xyc_graph, GType ytype)
177 {
178    g_return_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph));
179 
180    GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->ytype = ytype;
181 
182    g_object_notify (G_OBJECT (xyc_graph), "Y-Values");
183 }
184 
185 static void
gtk_databox_xyc_graph_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)186 gtk_databox_xyc_graph_set_property (GObject * object,
187 				    guint property_id,
188 				    const GValue * value, GParamSpec * pspec)
189 {
190    GtkDataboxXYCGraph *xyc_graph = GTK_DATABOX_XYC_GRAPH (object);
191 
192    switch (property_id)
193    {
194    case PROP_X:
195       gtk_databox_xyc_graph_set_X (xyc_graph, (gfloat *) g_value_get_pointer (value));
196       break;
197    case PROP_Y:
198       gtk_databox_xyc_graph_set_Y (xyc_graph, (gfloat *) g_value_get_pointer (value));
199       break;
200    case PROP_LEN:
201       gtk_databox_xyc_graph_set_length (xyc_graph, g_value_get_int (value));
202       break;
203    case PROP_MAXLEN:
204       gtk_databox_xyc_graph_set_maxlen (xyc_graph, g_value_get_int (value));
205       break;
206    case PROP_XSTART:
207       gtk_databox_xyc_graph_set_xstart (xyc_graph, g_value_get_int (value));
208       break;
209    case PROP_YSTART:
210       gtk_databox_xyc_graph_set_ystart (xyc_graph, g_value_get_int (value));
211       break;
212    case PROP_XSTRIDE:
213       gtk_databox_xyc_graph_set_xstride (xyc_graph, g_value_get_int (value));
214       break;
215    case PROP_YSTRIDE:
216       gtk_databox_xyc_graph_set_ystride (xyc_graph, g_value_get_int (value));
217       break;
218    case PROP_XTYPE:
219       gtk_databox_xyc_graph_set_xtype (xyc_graph, g_value_get_gtype (value));
220       break;
221    case PROP_YTYPE:
222       gtk_databox_xyc_graph_set_ytype (xyc_graph, g_value_get_gtype (value));
223       break;
224    default:
225       /* We don't have any other property... */
226       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
227       break;
228    }
229 }
230 
231 /**
232  * gtk_databox_xyc_graph_get_X:
233  * @xyc_graph: A #GtkDataboxXYCGraph object
234  *
235  * Gets the X values of the @xzc_graph.
236  *
237  * Return value: Pointer to X values
238  */
239 gfloat *
gtk_databox_xyc_graph_get_X(GtkDataboxXYCGraph * xyc_graph)240 gtk_databox_xyc_graph_get_X (GtkDataboxXYCGraph * xyc_graph)
241 {
242    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), NULL);
243 
244    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->X;
245 }
246 
247 /**
248  * gtk_databox_xyc_graph_get_Y:
249  * @xyc_graph: A #GtkDataboxXYCGraph object
250  *
251  * Gets the Y values of the @xzc_graph.
252  *
253  * Return value: Pointer to Y values
254  */
255 gfloat *
gtk_databox_xyc_graph_get_Y(GtkDataboxXYCGraph * xyc_graph)256 gtk_databox_xyc_graph_get_Y (GtkDataboxXYCGraph * xyc_graph)
257 {
258    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), NULL);
259 
260    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->Y;
261 }
262 
263 /**
264  * gtk_databox_xyc_graph_get_length:
265  * @xyc_graph: A #GtkDataboxXYCGraph object
266  *
267  * Gets the the length of the X and Y values arrays.
268  *
269  * Return value: Length of X/Y arrays.
270  */
271 guint
gtk_databox_xyc_graph_get_length(GtkDataboxXYCGraph * xyc_graph)272 gtk_databox_xyc_graph_get_length (GtkDataboxXYCGraph * xyc_graph)
273 {
274    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
275    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->len;
276 }
277 
278 /**
279  * gtk_databox_xyc_graph_get_maxlen:
280  * @xyc_graph: A #GtkDataboxXYCGraph object
281  *
282  * Gets the the maxlen of the X and Y values arrays.
283  *
284  * Return value: Size of X/Y arrays.
285  */
286 guint
gtk_databox_xyc_graph_get_maxlen(GtkDataboxXYCGraph * xyc_graph)287 gtk_databox_xyc_graph_get_maxlen (GtkDataboxXYCGraph * xyc_graph)
288 {
289    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
290    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->maxlen;
291 }
292 
293 /**
294  * gtk_databox_xyc_graph_get_xstart:
295  * @xyc_graph: A #GtkDataboxXYCGraph object
296  *
297  * Gets the the start offset of the X values array.  This is the element in the array pointed to by X that will be the first element plotted.
298  * If X is a pointer to a gfloat array, and xstart is 5, then x[5] will be the first data element.  If Xstride is 1, then x[6] will be the
299  * second element.  x[5 + len - 1] will be last element.
300  * Usually, xstart will be 0.  It can be nonzero to allow for interleaved X/Y samples, or if the data is stored as a matrix, then X can point
301  * to the start of the matrix, xstart can be the column number, and xstride the number of columns.
302  *
303  * Return value: The xstart value.
304  */
305 guint
gtk_databox_xyc_graph_get_xstart(GtkDataboxXYCGraph * xyc_graph)306 gtk_databox_xyc_graph_get_xstart (GtkDataboxXYCGraph * xyc_graph)
307 {
308    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
309    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->xstart;
310 }
311 
312 /**
313  * gtk_databox_xyc_graph_get_ystart:
314  * @xyc_graph: A #GtkDataboxXYCGraph object
315  *
316  * Gets the the start offset of the Y values array.  This is the element in the array pointed to by Y that will be the first element plotted.
317  * If Y is a pointer to a gfloat array, and ystart is 5, then y[5] will be the first data element.  If Ystride is 1, then y[6] will be the
318  * second element.  y[5 + len - 1] will be last element.
319  * Usually, ystart will be 0.  It can be nonzero to allow for interleaved X/Y samples, or if the data is stored as a matrix, then Y can point
320  * to the start of the matrix, ystart can be the column number, and ystride the number of columns.
321  *
322  * Return value: The ystart value.
323  */
324 guint
gtk_databox_xyc_graph_get_ystart(GtkDataboxXYCGraph * xyc_graph)325 gtk_databox_xyc_graph_get_ystart (GtkDataboxXYCGraph * xyc_graph)
326 {
327    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
328    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->ystart;
329 }
330 
331 /**
332  * gtk_databox_xyc_graph_get_xstride:
333  * @xyc_graph: A #GtkDataboxXYCGraph object
334  *
335  * Gets the the stride offset of the X values array.  This is the element in the array pointed to by X that will be the first element plotted.
336  * If X is a pointer to a gfloat array, and xstart is 5, then x[5] will be the first data element.  If Xstride is 1, then x[6] will be the
337  * second element.  x[5 + len - 1] will be last element.
338  * Usually, xstride will be 1.  It can be nonzero to allow for interleaved X/Y samples, or if the data is stored as a matrix, then X can point
339  * to the start of the matrix, xstart can be the column number, and xstride the number of columns.
340  *
341  * Return value: The xstride value.
342  */
343 guint
gtk_databox_xyc_graph_get_xstride(GtkDataboxXYCGraph * xyc_graph)344 gtk_databox_xyc_graph_get_xstride (GtkDataboxXYCGraph * xyc_graph)
345 {
346    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
347    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->xstride;
348 }
349 
350 /**
351  * gtk_databox_xyc_graph_get_ystride:
352  * @xyc_graph: A #GtkDataboxXYCGraph object
353  *
354  * Gets the the stride offset of the Y values array.  This is the element in the array pointed to by Y that will be the first element plotted.
355  * If Y is a pointer to a gfloat array, and ystart is 5, then y[5] will be the first data element.  If Ystride is 1, then y[6] will be the
356  * second element.  y[5 + len - 1] will be last element.
357  * Usually, ystride will be 1.  It can be nonzero to allow for interleaved X/Y samples, or if the data is stored as a matrix, then Y can point
358  * to the start of the matrix, ystart can be the column number, and ystride the number of columns.
359  *
360  * Return value: The ystride value.
361  */
362 guint
gtk_databox_xyc_graph_get_ystride(GtkDataboxXYCGraph * xyc_graph)363 gtk_databox_xyc_graph_get_ystride (GtkDataboxXYCGraph * xyc_graph)
364 {
365    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
366    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->ystride;
367 }
368 
369 /**
370  * gtk_databox_xyc_graph_get_xtype:
371  * @xyc_graph: A #GtkDataboxXYCGraph object
372  *
373  * Gets the the GType of the X array elements.  This may be G_TYPE_FLOAT, G_TYPE_DOUBLE, or similar.
374  *
375  * Return value: A GType, usually this is G_TYPE_FLOAT.
376  */
377 GType
gtk_databox_xyc_graph_get_xtype(GtkDataboxXYCGraph * xyc_graph)378 gtk_databox_xyc_graph_get_xtype (GtkDataboxXYCGraph * xyc_graph)
379 {
380    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
381    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->xtype;
382 }
383 
384 /**
385  * gtk_databox_xyc_graph_get_ytype:
386  * @xyc_graph: A #GtkDataboxXYCGraph object
387  *
388  * Gets the the GType of the Y array elements.  This may be G_TYPE_FLOAT, G_TYPE_DOUBLE, or similar.
389  *
390  * Return value: A GType, usually this is G_TYPE_FLOAT.
391  */
392 GType
gtk_databox_xyc_graph_get_ytype(GtkDataboxXYCGraph * xyc_graph)393 gtk_databox_xyc_graph_get_ytype (GtkDataboxXYCGraph * xyc_graph)
394 {
395    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (xyc_graph), 0);
396    return GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph)->ytype;
397 }
398 
399 static void
gtk_databox_xyc_graph_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)400 gtk_databox_xyc_graph_get_property (GObject * object,
401 				    guint property_id,
402 				    GValue * value, GParamSpec * pspec)
403 {
404    GtkDataboxXYCGraph *xyc_graph = GTK_DATABOX_XYC_GRAPH (object);
405 
406    switch (property_id)
407    {
408    case PROP_X:
409       g_value_set_pointer (value, gtk_databox_xyc_graph_get_X (xyc_graph));
410       break;
411    case PROP_Y:
412       g_value_set_pointer (value, gtk_databox_xyc_graph_get_Y (xyc_graph));
413       break;
414    case PROP_LEN:
415       g_value_set_int (value, gtk_databox_xyc_graph_get_length (xyc_graph));
416       break;
417    case PROP_MAXLEN:
418       g_value_set_int (value, gtk_databox_xyc_graph_get_maxlen (xyc_graph));
419       break;
420    case PROP_XSTART:
421       g_value_set_int (value, gtk_databox_xyc_graph_get_xstart (xyc_graph));
422       break;
423    case PROP_YSTART:
424       g_value_set_int (value, gtk_databox_xyc_graph_get_ystart (xyc_graph));
425       break;
426    case PROP_XSTRIDE:
427       g_value_set_int (value, gtk_databox_xyc_graph_get_xstride (xyc_graph));
428       break;
429    case PROP_YSTRIDE:
430       g_value_set_int (value, gtk_databox_xyc_graph_get_ystride (xyc_graph));
431       break;
432    case PROP_XTYPE:
433       g_value_set_gtype (value, gtk_databox_xyc_graph_get_xtype (xyc_graph));
434       break;
435    case PROP_YTYPE:
436       g_value_set_gtype (value, gtk_databox_xyc_graph_get_ytype (xyc_graph));
437       break;
438    default:
439       /* We don't have any other property... */
440       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
441       break;
442    }
443 }
444 
445 static void
gtk_databox_xyc_graph_class_init(GtkDataboxXYCGraphClass * klass)446 gtk_databox_xyc_graph_class_init (GtkDataboxXYCGraphClass *klass)
447 {
448    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
449    GtkDataboxGraphClass *graph_class = GTK_DATABOX_GRAPH_CLASS (klass);
450    GParamSpec *xyc_graph_param_spec;
451 
452    gobject_class->set_property = gtk_databox_xyc_graph_set_property;
453    gobject_class->get_property = gtk_databox_xyc_graph_get_property;
454 
455    xyc_graph_param_spec = g_param_spec_pointer ("X-Values",
456 						"X coordinates",
457 						"X values of data",
458 						G_PARAM_CONSTRUCT_ONLY |
459 						G_PARAM_READWRITE);
460 
461    g_object_class_install_property (gobject_class,
462 				    PROP_X, xyc_graph_param_spec);
463 
464    xyc_graph_param_spec = g_param_spec_pointer ("Y-Values",
465 						"Y coordinates",
466 						"Y values of data",
467 						G_PARAM_CONSTRUCT_ONLY |
468 						G_PARAM_READWRITE);
469 
470    g_object_class_install_property (gobject_class,
471 				    PROP_Y, xyc_graph_param_spec);
472 
473    xyc_graph_param_spec = g_param_spec_int ("length", "length of X and Y", "number of data points", G_MININT, G_MAXINT, 0,	/* default value */
474 					    G_PARAM_CONSTRUCT_ONLY |
475 					    G_PARAM_READWRITE);
476 
477    g_object_class_install_property (gobject_class,
478 				    PROP_LEN, xyc_graph_param_spec);
479 
480    xyc_graph_param_spec = g_param_spec_int ("maxlen", "maxlen of X and Y", "maximal number of data points", G_MININT, G_MAXINT, 0,	/* default value */
481 					    G_PARAM_CONSTRUCT_ONLY |
482 					    G_PARAM_READWRITE);
483    g_object_class_install_property (gobject_class,
484 				    PROP_MAXLEN, xyc_graph_param_spec);
485 
486    xyc_graph_param_spec = g_param_spec_int ("xstart", "array index of first X", "array index of first X", G_MININT, G_MAXINT, 0,	/* default value */
487 					    G_PARAM_CONSTRUCT_ONLY |
488 					    G_PARAM_READWRITE);
489    g_object_class_install_property (gobject_class,
490 				    PROP_XSTART, xyc_graph_param_spec);
491 
492    xyc_graph_param_spec = g_param_spec_int ("ystart", "array index of first Y", "array index of first Y", G_MININT, G_MAXINT, 0,	/* default value */
493 					    G_PARAM_CONSTRUCT_ONLY |
494 					    G_PARAM_READWRITE);
495    g_object_class_install_property (gobject_class,
496 				    PROP_YSTART, xyc_graph_param_spec);
497 
498    xyc_graph_param_spec = g_param_spec_int ("xstride", "stride of X values", "stride of X values", G_MININT, G_MAXINT, 1,	/* default value */
499 					    G_PARAM_CONSTRUCT_ONLY |
500 					    G_PARAM_READWRITE);
501    g_object_class_install_property (gobject_class,
502 				    PROP_XSTRIDE, xyc_graph_param_spec);
503 
504    xyc_graph_param_spec = g_param_spec_int ("ystride", "stride of Y values", "stride of Y values", G_MININT, G_MAXINT, 1,	/* default value */
505 					    G_PARAM_CONSTRUCT_ONLY |
506 					    G_PARAM_READWRITE);
507    g_object_class_install_property (gobject_class,
508 				    PROP_YSTRIDE, xyc_graph_param_spec);
509 
510    xyc_graph_param_spec = g_param_spec_gtype ("xtype", "GType of X elements", "GType of X elements", G_TYPE_NONE,
511 					    G_PARAM_CONSTRUCT_ONLY |
512 					    G_PARAM_READWRITE);
513    g_object_class_install_property (gobject_class,
514 				    PROP_XTYPE, xyc_graph_param_spec);
515 
516    xyc_graph_param_spec = g_param_spec_gtype ("ytype", "GType of Y elements", "GType of Y elements", G_TYPE_NONE,
517 					    G_PARAM_CONSTRUCT_ONLY |
518 					    G_PARAM_READWRITE);
519    g_object_class_install_property (gobject_class,
520 				    PROP_YTYPE, xyc_graph_param_spec);
521 
522    graph_class->calculate_extrema =
523       gtk_databox_xyc_graph_real_calculate_extrema;
524 
525    g_type_class_add_private (klass, sizeof (GtkDataboxXYCGraphPrivate));
526 }
527 
gtk_databox_xyc_graph_init(GtkDataboxXYCGraph * xyc_graph)528 static void gtk_databox_xyc_graph_init (GtkDataboxXYCGraph *xyc_graph) {xyc_graph = xyc_graph;}
529 
530 static gint
gtk_databox_xyc_graph_real_calculate_extrema(GtkDataboxGraph * graph,gfloat * min_x,gfloat * max_x,gfloat * min_y,gfloat * max_y)531 gtk_databox_xyc_graph_real_calculate_extrema (GtkDataboxGraph * graph,
532 					      gfloat * min_x, gfloat * max_x,
533 					      gfloat * min_y, gfloat * max_y)
534 {
535    GtkDataboxXYCGraph *xyc_graph = GTK_DATABOX_XYC_GRAPH (graph);
536    GtkDataboxXYCGraphPrivate *priv = GTK_DATABOX_XYC_GRAPH_GET_PRIVATE(xyc_graph);
537    guint i, indx, len, maxlen, start, stride;
538    void *values;
539    GType vtype;
540    gfloat fval = 0.0, minval = 0.0, maxval = 0.0;
541 
542    g_return_val_if_fail (GTK_DATABOX_IS_XYC_GRAPH (graph), -1);
543    g_return_val_if_fail (min_x, -1);
544    g_return_val_if_fail (max_x, -1);
545    g_return_val_if_fail (min_y, -1);
546    g_return_val_if_fail (max_y, -1);
547    g_return_val_if_fail (priv->len, -1);
548 
549    len = priv->len;
550    maxlen = priv->maxlen;
551    values = priv->X;
552    vtype = priv->xtype;
553    start = priv->xstart;
554    stride = priv->xstride;
555 
556    indx = start * stride;
557    i = 0;
558    do {
559 		if (vtype == G_TYPE_FLOAT)
560 			fval = ((gfloat *)values)[indx];
561 		else if (vtype == G_TYPE_DOUBLE)
562 			fval = ((gdouble *)values)[indx];
563 		else if (vtype == G_TYPE_INT)
564 			fval = ((gint *)values)[indx];
565 		else if (vtype == G_TYPE_UINT)
566 			fval = ((guint *)values)[indx];
567 		else if (vtype == G_TYPE_LONG)
568 			fval = ((glong *)values)[indx];
569 		else if (vtype == G_TYPE_ULONG)
570 			fval = ((gulong *)values)[indx];
571 		else if (vtype == G_TYPE_INT64)
572 			fval = ((gint64 *)values)[indx];
573 		else if (vtype == G_TYPE_UINT64)
574 			fval = ((guint64 *)values)[indx];
575 		else if (vtype == G_TYPE_CHAR)
576 			fval = ((gchar *)values)[indx];
577 		else if (vtype == G_TYPE_UCHAR)
578 			fval = ((guchar *)values)[indx];
579 
580 		if (i==0)
581 		{
582 			minval = maxval = fval;
583 		}
584 		else
585 		{
586 			if (fval < minval) minval = fval;
587 			if (fval > maxval) maxval = fval;
588 		}
589 
590 		/* handle the wrap-around (ring buffer) issue using modulus.  for efficiency, don't do this for non-wraparound cases. */
591 		/* note this allows multiple wrap-arounds.  One could hold a single cycle of a sine wave, and plot a continuous wave */
592 		/* This can be optimized using pointers later */
593 		if (i + start > maxlen)
594 			indx = ((i + start) % maxlen) * stride;
595 		else
596 			indx += stride;
597    } while (++i < len);
598 
599    *min_x = minval;
600    *max_x = maxval;
601 
602    values = priv->Y;
603    vtype = priv->ytype;
604    start = priv->ystart;
605    stride = priv->ystride;
606 
607    indx = start * stride;
608    i = 0;
609    do {
610 		if (vtype == G_TYPE_FLOAT)
611 			fval = ((gfloat *)values)[indx];
612 		else if (vtype == G_TYPE_DOUBLE)
613 			fval = ((gdouble *)values)[indx];
614 		else if (vtype == G_TYPE_INT)
615 			fval = ((gint *)values)[indx];
616 		else if (vtype == G_TYPE_UINT)
617 			fval = ((guint *)values)[indx];
618 		else if (vtype == G_TYPE_LONG)
619 			fval = ((glong *)values)[indx];
620 		else if (vtype == G_TYPE_ULONG)
621 			fval = ((gulong *)values)[indx];
622 		else if (vtype == G_TYPE_INT64)
623 			fval = ((gint64 *)values)[indx];
624 		else if (vtype == G_TYPE_UINT64)
625 			fval = ((guint64 *)values)[indx];
626 		else if (vtype == G_TYPE_CHAR)
627 			fval = ((gchar *)values)[indx];
628 		else if (vtype == G_TYPE_UCHAR)
629 			fval = ((guchar *)values)[indx];
630 
631 		if (i==0) /* yes putting this check inside the loop is inefficient, but it makes the code simpler */
632 		{
633 			minval = maxval = fval;
634 		}
635 		else
636 		{
637 			if (fval < minval) minval = fval;
638 			if (fval > maxval) maxval = fval;
639 		}
640 
641 		/* handle the wrap-around (ring buffer) issue using modulus.  for efficiency, don't do this for non-wraparound cases. */
642 		/* note this allows multiple wrap-arounds.  One could hold a single cycle of a sine wave, and plot a continuous wave */
643 		/* This can be optimized using pointers later */
644 		if (i + start > maxlen)
645 			indx = ((i + start) % maxlen) * stride;
646 		else
647 			indx += stride;
648    } while (++i < len);
649 
650    *min_y = minval;
651    *max_y = maxval;
652 
653    return 0;
654 }
655