]> Dogcows Code - chaz/homebank/blob - src/gtk-chart.c
Merge branch 'upstream'
[chaz/homebank] / src / gtk-chart.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 #include <math.h>
22 #include <string.h>
23
24 #include <gtk/gtk.h>
25
26 #include "homebank.h"
27 #include "gtk-chart-colors.h"
28 #include "gtk-chart.h"
29
30
31 #define MYDEBUG 0
32
33
34 #if MYDEBUG
35 #define DB(x) (x);
36 #else
37 #define DB(x);
38 #endif
39
40
41 #define DYNAMICS 1
42
43 #define DBGDRAW_RECT 0
44 #define DBGDRAW_TEXT 0
45 #define DBGDRAW_ITEM 0
46
47
48 static void gtk_chart_class_intern_init (gpointer);
49 static void gtk_chart_class_init (GtkChartClass *klass);
50 static void gtk_chart_init (GtkChart *chart);
51 static void gtk_chart_dispose (GObject * object);
52 static void gtk_chart_finalize (GObject * object);
53
54 static gboolean drawarea_configure_event_callback(GtkWidget *widget, GdkEventConfigure *event, gpointer user_data);
55 static void drawarea_realize_callback(GtkWidget *widget, gpointer user_data);
56 static gboolean drawarea_draw_callback(GtkWidget *widget, cairo_t *wcr, gpointer user_data);
57 static gboolean drawarea_motionnotifyevent_callback(GtkWidget *widget, GdkEventMotion *event, gpointer user_data);
58 static gboolean drawarea_querytooltip_callback(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data);
59
60 static gboolean drawarea_full_redraw(GtkWidget *widget, gpointer user_data);
61
62 static void chart_calculation(GtkChart *chart);
63 static void chart_clear(GtkChart *chart);
64
65 static void colchart_first_changed( GtkAdjustment *adj, gpointer user_data);
66 static void colchart_compute_range(GtkChart *chart);
67 static void colchart_calculation(GtkChart *chart);
68 static void colchart_scrollbar_setvalues(GtkChart *chart);
69
70 static void piechart_calculation(GtkChart *chart);
71
72
73
74
75 static GtkBoxClass *gtk_chart_parent_class = NULL;
76
77 static const double dashed3[] = {3.0};
78
79 GType
80 gtk_chart_get_type ()
81 {
82 static GType chart_type = 0;
83
84 if (!chart_type)
85 {
86 static const GTypeInfo chart_info =
87 {
88 sizeof (GtkChartClass),
89 NULL, /* base_init */
90 NULL, /* base_finalize */
91 (GClassInitFunc) gtk_chart_class_intern_init,
92 NULL, /* class_finalize */
93 NULL, /* class_data */
94 sizeof (GtkChart),
95 0, /* n_preallocs */
96 (GInstanceInitFunc) gtk_chart_init,
97 NULL
98 };
99
100 chart_type = g_type_register_static (GTK_TYPE_BOX, "GtkChart",
101 &chart_info, 0);
102
103 }
104 return chart_type;
105 }
106
107 static void
108 gtk_chart_class_intern_init (gpointer klass)
109 {
110 gtk_chart_parent_class = g_type_class_peek_parent (klass);
111 gtk_chart_class_init ((GtkChartClass *) klass);
112 }
113
114 static void
115 gtk_chart_class_init (GtkChartClass * class)
116 {
117 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
118 //GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
119
120 DB( g_print("\n[gtkchart] class init\n") );
121
122 //gobject_class->get_property = gtk_chart_get_property;
123 //gobject_class->set_property = gtk_chart_set_property;
124 gobject_class->dispose = gtk_chart_dispose;
125 gobject_class->finalize = gtk_chart_finalize;
126
127 //widget_class->size_allocate = gtk_chart_size_allocate;
128
129 }
130
131
132 static void
133 gtk_chart_init (GtkChart * chart)
134 {
135 GtkWidget *widget, *vbox, *frame;
136
137 DB( g_print("\n[gtkchart] init\n") );
138
139
140 chart->surface = NULL;
141 chart->nb_items = 0;
142 chart->items = NULL;
143 chart->title = NULL;
144
145 chart->pfd = NULL;
146 chart->abs = FALSE;
147 chart->dual = FALSE;
148 chart->usrbarw = 0.0;
149 chart->barw = GTK_CHART_BARW;
150
151 chart->show_legend = TRUE;
152 chart->show_legend_wide = FALSE;
153 chart->show_mono = FALSE;
154 chart->active = -1;
155 chart->lastactive = -1;
156
157 chart->minor_rate = 1.0;
158 chart->timer_tag = 0;
159
160 gtk_chart_set_color_scheme(chart, CHART_COLMAP_HOMEBANK);
161
162 widget=GTK_WIDGET(chart);
163
164 gtk_box_set_homogeneous(GTK_BOX(widget), FALSE);
165
166 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
167 gtk_box_pack_start (GTK_BOX (widget), vbox, TRUE, TRUE, 0);
168
169 /* drawing area */
170 frame = gtk_frame_new(NULL);
171 gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
172 gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
173
174 chart->drawarea = gtk_drawing_area_new();
175 //gtk_widget_set_double_buffered (GTK_WIDGET(widget), FALSE);
176
177 gtk_container_add( GTK_CONTAINER(frame), chart->drawarea );
178 gtk_widget_set_size_request(chart->drawarea, 100, 100 );
179 #if DYNAMICS == 1
180 gtk_widget_set_has_tooltip(chart->drawarea, TRUE);
181 #endif
182 gtk_widget_show(chart->drawarea);
183
184 #if MYDEBUG == 1
185 /*GtkStyle *style;
186 PangoFontDescription *font_desc;
187
188 g_print("draw_area font\n");
189
190 style = gtk_widget_get_style(GTK_WIDGET(chart->drawarea));
191 font_desc = style->font_desc;
192
193 g_print("family: %s\n", pango_font_description_get_family(font_desc) );
194 g_print("size: %d (%d)\n", pango_font_description_get_size (font_desc), pango_font_description_get_size (font_desc )/PANGO_SCALE );
195 */
196 #endif
197
198 /* scrollbar */
199 chart->adjustment = GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 1.0, 1.0, 1.0, 1.0));
200 chart->scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (chart->adjustment));
201 gtk_box_pack_start (GTK_BOX (vbox), chart->scrollbar, FALSE, TRUE, 0);
202 gtk_widget_show(chart->scrollbar);
203
204 g_signal_connect( G_OBJECT(chart->drawarea), "configure-event", G_CALLBACK (drawarea_configure_event_callback), chart);
205 g_signal_connect( G_OBJECT(chart->drawarea), "realize", G_CALLBACK(drawarea_realize_callback), chart ) ;
206 g_signal_connect( G_OBJECT(chart->drawarea), "draw", G_CALLBACK(drawarea_draw_callback), chart ) ;
207
208 #if DYNAMICS == 1
209 gtk_widget_add_events(GTK_WIDGET(chart->drawarea),
210 GDK_EXPOSURE_MASK |
211 //GDK_POINTER_MOTION_MASK |
212 GDK_POINTER_MOTION_HINT_MASK
213 //GDK_BUTTON_PRESS_MASK |
214 //GDK_BUTTON_RELEASE_MASK
215 );
216
217 g_signal_connect( G_OBJECT(chart->drawarea), "query-tooltip", G_CALLBACK(drawarea_querytooltip_callback), chart );
218 g_signal_connect( G_OBJECT(chart->drawarea), "motion-notify-event", G_CALLBACK(drawarea_motionnotifyevent_callback), chart );
219 #endif
220 g_signal_connect (G_OBJECT(chart->adjustment), "value-changed", G_CALLBACK (colchart_first_changed), chart);
221
222 //g_signal_connect( G_OBJECT(chart->drawarea), "map-event", G_CALLBACK(chart_map), chart ) ;
223 //g_signal_connect( G_OBJECT(chart->drawarea), "button-press-event", G_CALLBACK(chart_button_press), chart );
224 //g_signal_connect( G_OBJECT(chart->drawarea), "button-release-event", G_CALLBACK(chart_button_release), chart );
225 }
226
227
228 /* --- */
229
230 GtkWidget *
231 gtk_chart_new (gint type)
232 {
233 GtkChart *chart;
234
235 DB( g_print("\n======================================================\n") );
236 DB( g_print("\n[gtkchart] new\n") );
237
238 chart = g_object_new (GTK_TYPE_CHART, NULL);
239 chart->type = type;
240
241 return GTK_WIDGET(chart);
242 }
243
244
245 static void
246 gtk_chart_dispose (GObject *gobject)
247 {
248 //GtkChart *chart = GTK_CHART (object);
249
250 DB( g_print("\n[gtkchart] dispose\n") );
251
252 /* In dispose(), you are supposed to free all types referenced from this
253 * object which might themselves hold a reference to self. Generally,
254 * the most simple solution is to unref all members on which you own a
255 * reference.
256 */
257
258 /* dispose() might be called multiple times, so we must guard against
259 * calling g_object_unref() on an invalid GObject by setting the member
260 * NULL; g_clear_object() does this for us, atomically.
261 */
262 //g_clear_object (&self->priv->an_object);
263
264 /* Always chain up to the parent class; there is no need to check if
265 * the parent class implements the dispose() virtual function: it is
266 * always guaranteed to do so
267 */
268 G_OBJECT_CLASS (gtk_chart_parent_class)->dispose (gobject);
269 }
270
271
272 static void
273 gtk_chart_finalize (GObject * object)
274 {
275 GtkChart *chart = GTK_CHART (object);
276
277 DB( g_print("\n[gtkchart] finalize\n") );
278
279 chart_clear(chart);
280
281 if(chart->pfd)
282 {
283 pango_font_description_free (chart->pfd);
284 chart->pfd = NULL;
285 }
286
287 if (chart->surface)
288 {
289 cairo_surface_destroy (chart->surface);
290 chart->surface = NULL;
291 }
292
293 G_OBJECT_CLASS (gtk_chart_parent_class)->finalize (object);
294 }
295
296
297 /*
298 ** print a integer number
299 */
300 static gchar *chart_print_int(GtkChart *chart, gint value)
301 {
302 hb_strfmon_int(chart->buffer1, CHART_BUFFER_LENGTH-1, (gdouble)value, chart->kcur, chart->minor);
303 return chart->buffer1;
304 }
305
306
307 /*
308 ** print a rate number
309 */
310 static gchar *chart_print_rate(GtkChart *chart, gdouble value)
311 {
312 g_snprintf (chart->buffer1, CHART_BUFFER_LENGTH-1, "%.2f%%", value);
313 return chart->buffer1;
314 }
315
316
317 /*
318 ** print a double number
319 */
320 static gchar *chart_print_double(GtkChart *chart, gchar *buffer, gdouble value)
321 {
322 hb_strfmon(buffer, CHART_BUFFER_LENGTH-1, value, chart->kcur, chart->minor);
323 return buffer;
324 }
325
326
327 /*
328 ** clear any allocated memory
329 */
330 static void chart_clear(GtkChart *chart)
331 {
332 gint i;
333
334 DB( g_print("\n[gtkchart] clear\n") );
335
336 //free & clear any previous allocated datas
337 if(chart->title != NULL)
338 {
339 g_free(chart->title);
340 chart->title = NULL;
341 }
342
343 if(chart->subtitle != NULL)
344 {
345 g_free(chart->subtitle);
346 chart->subtitle = NULL;
347 }
348
349 if(chart->items != NULL)
350 {
351 for(i=0;i<chart->nb_items;i++)
352 {
353 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
354
355 g_free(item->label); //we free label as it comes from a model_get into setup_with_model
356 g_free(item->legend);
357 }
358 g_array_free(chart->items, TRUE);
359 chart->items = NULL;
360 }
361
362 chart->nb_items = 0;
363
364 chart->total = 0;
365 chart->range = 0;
366 chart->rawmin = 0;
367 chart->rawmax = 0;
368 chart->every_xval = 7;
369
370 chart->active = -1;
371 chart->lastactive = -1;
372
373 }
374
375
376 /*
377 ** setup our chart with a model and column
378 */
379 static void chart_setup_with_model(GtkChart *chart, GtkTreeModel *list_store, guint column1, guint column2)
380 {
381 gint i;
382 gboolean valid;
383 GtkTreeIter iter;
384
385 DB( g_print("\n[chart] setup with model\n") );
386
387 chart_clear(chart);
388
389 chart->nb_items = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store), NULL);
390
391 chart->items = g_array_sized_new(FALSE, FALSE, sizeof(ChartItem), chart->nb_items);
392
393 DB( g_print(" nb=%d, struct=%d\n", chart->nb_items, sizeof(ChartItem)) );
394
395 chart->dual = (column1 == column2) ? FALSE : TRUE;
396
397 /* Get the first iter in the list */
398 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(list_store), &iter);
399 i = 0;
400 while (valid)
401 {
402 gint id;
403 gchar *label;
404 gdouble value1, value2;
405 ChartItem item;
406
407 /* column 0: pos (gint) */
408 /* column 1: key (gint) */
409 /* column 2: label (gchar) */
410 /* column x: values (double) */
411
412 gtk_tree_model_get (GTK_TREE_MODEL(list_store), &iter,
413 0, &id,
414 2, &label,
415 column1, &value1,
416 column2, &value2,
417 -1);
418
419 if(chart->dual || chart->abs)
420 {
421 value1 = ABS(value1);
422 value2 = ABS(value2);
423 }
424
425 DB( g_print("%d: '%s' %.2f %2f\n", i, label, value1, value2) );
426
427 /* data1 value storage & min, max compute */
428 chart->rawmin = MIN(chart->rawmin, value1);
429 chart->rawmax = MAX(chart->rawmax, value1);
430
431 if( chart->dual )
432 {
433 /* data2 value storage & min, max compute */
434 chart->rawmin = MIN(chart->rawmin, value2);
435 chart->rawmax = MAX(chart->rawmax, value2);
436 }
437
438 item.label = label;
439 item.serie1 = value1;
440 item.serie2 = value2;
441 g_array_append_vals(chart->items, &item, 1);
442
443 /* ensure rawmin rawmax not equal */
444 if(chart->rawmin == chart->rawmax)
445 {
446 chart->rawmin = 0;
447 chart->rawmax = 100;
448 }
449
450 /* pie chart total sum */
451 chart->total += ABS(value1);
452
453 //leak
454 //don't g_free(label); here done into chart_clear
455
456 valid = gtk_tree_model_iter_next (list_store, &iter);
457 i++;
458 }
459
460 // compute rate for legend for bar/pie
461 for(i=0;i<chart->nb_items;i++)
462 {
463 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
464 gchar *strval;
465
466 strval = chart_print_double(chart, chart->buffer1, item->serie1);
467 item->rate = ABS(item->serie1*100/chart->total);
468 item->legend = g_markup_printf_escaped("%s\n%s (%.f%%)", item->label, strval, item->rate);
469 }
470
471 //g_print("total is %.2f\n", total);
472 //ensure the widget is mapped
473 //gtk_widget_map(chart);
474
475 }
476
477
478 static void chart_set_font_size(GtkChart *chart, PangoLayout *layout, gint font_size)
479 {
480 gint size = 10;
481
482 //TODO: use PANGO_SCALE INSTEAD
483
484 //DB( g_print("\n[chart] set font size\n") );
485
486 switch(font_size)
487 {
488 case CHART_FONT_SIZE_TITLE:
489 size = chart->pfd_size + 3;
490 break;
491 case CHART_FONT_SIZE_SUBTITLE:
492 size = chart->pfd_size + 1;
493 break;
494 case CHART_FONT_SIZE_NORMAL:
495 size = chart->pfd_size - 1;
496 break;
497 case CHART_FONT_SIZE_SMALL:
498 size = chart->pfd_size - 2;
499 break;
500 }
501
502 //DB( g_print(" size=%d\n", size) );
503
504 pango_font_description_set_size(chart->pfd, size * PANGO_SCALE);
505
506 pango_layout_set_font_description (layout, chart->pfd);
507
508 }
509
510
511 /*
512 ** recompute according to type
513 */
514 static void chart_recompute(GtkChart *chart)
515 {
516
517 DB( g_print("\n[gtkchart] recompute\n") );
518
519
520 if( !gtk_widget_get_realized(chart->drawarea) || chart->surface == NULL )
521 return;
522
523 chart_calculation (chart);
524
525 switch(chart->type)
526 {
527 case CHART_TYPE_LINE:
528 case CHART_TYPE_COL:
529 colchart_calculation(chart);
530 gtk_adjustment_set_value(chart->adjustment, 0);
531 colchart_scrollbar_setvalues(chart);
532 gtk_widget_show(chart->scrollbar);
533 break;
534 case CHART_TYPE_PIE:
535 piechart_calculation(chart);
536 gtk_widget_hide(chart->scrollbar);
537 break;
538 }
539 }
540
541
542
543
544 /* bar section */
545
546
547 static float CalculateStepSize(float range, float targetSteps)
548 {
549 // calculate an initial guess at step size
550 float tempStep = range/targetSteps;
551
552 // get the magnitude of the step size
553 float mag = (float)floor(log10(tempStep));
554 float magPow = (float)pow(10, mag);
555
556 // calculate most significant digit of the new step size
557 float magMsd = (int)(tempStep/magPow + 0.5);
558
559 // promote the MSD to either 1, 2, or 5
560 if (magMsd > 5.0)
561 magMsd = 10.0f;
562 else if (magMsd > 2.0)
563 magMsd = 5.0f;
564 else if (magMsd >= 1.0)
565 magMsd = 2.0f;
566
567 return magMsd*magPow;
568 }
569
570
571 static void colchart_compute_range(GtkChart *chart)
572 {
573 double lobound=chart->rawmin, hibound=chart->rawmax;
574
575 DB( g_print("\n[column] compute range\n") );
576
577 /* comptute max ticks */
578 chart->range = chart->rawmax - chart->rawmin;
579 gint maxticks = MIN(10,floor(chart->graph.height / (chart->font_h * 2)));
580
581 DB( g_print(" raw :: [%.2f - %.2f] range=%.2f\n", chart->rawmin, chart->rawmax, chart->range) );
582 DB( g_print(" raw :: maxticks=%d (%g / (%g*2))\n", maxticks, chart->graph.height, chart->font_h) );
583
584 DB( g_print("\n") );
585 chart->unit = CalculateStepSize((hibound-lobound), maxticks);
586 chart->min = -chart->unit * ceil(-lobound/chart->unit);
587 chart->max = chart->unit * ceil(hibound/chart->unit);
588 chart->range = chart->max - chart->min;
589 chart->div = chart->range / chart->unit;
590
591 DB( g_print(" end :: interval=%.2f, ticks=%d\n", chart->unit, chart->div) );
592 DB( g_print(" end :: [%.2f - %.2f], range=%.2f\n", chart->min, chart->max, chart->range) );
593
594 }
595
596
597 static void chart_calculation(GtkChart *chart)
598 {
599 GtkWidget *drawarea = chart->drawarea;
600 GdkWindow *gdkwindow;
601 cairo_surface_t *surf = NULL;
602 cairo_t *cr;
603 int tw, th;
604 GtkAllocation allocation;
605 PangoLayout *layout;
606 gchar *valstr;
607 gint i;
608
609
610 DB( g_print("\n[gtkchart] calculation\n") );
611
612 gtk_widget_get_allocation(drawarea, &allocation);
613
614 chart->l = CHART_MARGIN;
615 chart->t = CHART_MARGIN;
616 chart->r = allocation.width - CHART_MARGIN;
617 chart->b = allocation.height - CHART_MARGIN;
618 chart->w = allocation.width - (CHART_MARGIN*2);
619 chart->h = allocation.height - (CHART_MARGIN*2);
620
621 gdkwindow = gtk_widget_get_window(chart->drawarea);
622 if(!gdkwindow)
623 {
624 surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
625 cr = cairo_create (surf);
626 }
627 else
628 cr = gdk_cairo_create (gdkwindow);
629
630 /* Create a PangoLayout, set the font and text */
631 layout = pango_cairo_create_layout (cr);
632
633
634 // compute title
635 chart->title_zh = 0;
636 if(chart->title != NULL)
637 {
638 chart_set_font_size(chart, layout, CHART_FONT_SIZE_TITLE);
639 pango_layout_set_text (layout, chart->title, -1);
640 pango_layout_get_size (layout, &tw, &th);
641 chart->title_zh = (th / PANGO_SCALE);
642 DB( g_print(" - title: %s w=%d h=%d\n", chart->title, tw, th) );
643 }
644
645 // compute subtitle
646 chart->subtitle_zh = 0;
647 if(chart->subtitle != NULL)
648 {
649 chart_set_font_size(chart, layout, CHART_FONT_SIZE_SUBTITLE);
650 pango_layout_set_text (layout, chart->subtitle, -1);
651 pango_layout_get_size (layout, &tw, &th);
652 chart->subtitle_zh = (th / PANGO_SCALE);
653 DB( g_print(" - title: %s w=%d h=%d\n", chart->subtitle, tw, th) );
654 }
655 chart->subtitle_y = chart->t + chart->title_zh;
656
657
658 chart->graph.y = chart->t + chart->title_zh + chart->subtitle_zh;
659 chart->graph.height = chart->h - chart->title_zh - chart->subtitle_zh;
660
661 if(chart->title_zh > 0 || chart->subtitle_zh > 0)
662 {
663 chart->graph.y += CHART_MARGIN;
664 chart->graph.height -= CHART_MARGIN;
665 }
666
667
668 // compute other text
669 chart_set_font_size(chart, layout, CHART_FONT_SIZE_NORMAL);
670
671 // y-axis labels (amounts)
672 chart->scale_w = 0;
673 colchart_compute_range(chart);
674
675 valstr = chart_print_int(chart, (gint)chart->min);
676 pango_layout_set_text (layout, valstr, -1);
677 pango_layout_get_size (layout, &tw, &th);
678 chart->scale_w = (tw / PANGO_SCALE);
679
680 valstr = chart_print_int(chart, (gint)chart->max);
681 pango_layout_set_text (layout, valstr, -1);
682 pango_layout_get_size (layout, &tw, &th);
683 chart->scale_w = MAX(chart->scale_w, (tw / PANGO_SCALE));
684
685 DB( g_print(" - scale: %d,%d %g,%g\n", chart->l, 0, chart->scale_w, 0.0) );
686
687 // todo: compute maxwidth of item labels
688 double label_w = 0;
689 for(i=0;i<chart->nb_items;i++)
690 {
691 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
692
693 // label width
694 pango_layout_set_text (layout, item->label, -1);
695 pango_layout_get_size (layout, &tw, &th);
696 label_w = MAX(label_w, (tw / PANGO_SCALE));
697 }
698 chart->label_w = label_w;
699
700 // compute font height
701 chart->font_h = (th / PANGO_SCALE);
702
703 // compute graph region
704 switch(chart->type)
705 {
706 case CHART_TYPE_LINE:
707 case CHART_TYPE_COL:
708 chart->graph.x = chart->l + chart->scale_w + 2;
709 chart->graph.width = chart->w - chart->scale_w - 2;
710 break;
711 case CHART_TYPE_PIE:
712 chart->graph.x = chart->l;
713 chart->graph.width = chart->w;
714 break;
715 }
716
717 DB( g_print(" - graph : %g,%g %g,%g\n", chart->graph.x, chart->graph.y, chart->graph.width, chart->graph.height) );
718
719
720 if( ((chart->type == CHART_TYPE_LINE) || (chart->type == CHART_TYPE_COL)) && chart->show_xval)
721 chart->graph.height -= (chart->font_h + CHART_SPACING);
722
723 // compute: each legend column width, and legend width
724 if(chart->show_legend)
725 {
726 chart_set_font_size(chart, layout, CHART_FONT_SIZE_SMALL);
727
728 //we compute the rate text here to get the font height
729 pango_layout_set_text (layout, "00.00 %", -1);
730 pango_layout_get_size (layout, &tw, &th);
731
732 chart->legend_font_h = (th / PANGO_SCALE);
733
734 // labels not much than 1/4 of graph
735 gdouble lw = floor(chart->graph.width / 4);
736 chart->legend_label_w = MIN(chart->label_w, lw);
737
738 chart->legend.width = chart->legend_font_h + CHART_SPACING + chart->legend_label_w;
739 chart->legend.height = MIN(floor(chart->nb_items * chart->legend_font_h * CHART_LINE_SPACING), chart->graph.height);
740
741 if(chart->show_legend_wide )
742 {
743 chart->legend_value_w = chart->scale_w;
744 chart->legend_rate_w = (tw / PANGO_SCALE);
745 chart->legend.width += CHART_SPACING + chart->legend_value_w + CHART_SPACING + chart->legend_rate_w;
746 }
747
748 //if legend visible, substract
749 chart->graph.width -= (chart->legend.width + CHART_MARGIN);
750
751 chart->legend.x = chart->graph.x + chart->graph.width + CHART_MARGIN;
752 chart->legend.y = chart->graph.y;
753
754 DB( g_print(" - graph : %g %g %g %g\n", chart->graph.x, chart->graph.y, chart->graph.width, chart->graph.height ) );
755 DB( g_print(" - legend: %g %g %g %g\n", chart->legend.x, chart->legend.y, chart->legend.width, chart->legend.height ) );
756 }
757
758 g_object_unref (layout);
759
760 cairo_destroy(cr);
761 cairo_surface_destroy(surf);
762 }
763
764
765 static void colchart_calculation(GtkChart *chart)
766 {
767 gint blkw, maxvisi;
768
769 DB( g_print("\n[column] calculation\n") );
770
771 /* from fusionchart
772 the bar has a default width of 41
773 min space is 3 and min barw is 8
774 */
775
776 // new computing
777 if( chart->usrbarw > 0.0 )
778 {
779 blkw = chart->usrbarw;
780 chart->barw = blkw - 3;
781 }
782 else
783 {
784 //minvisi = floor(chart->graph.width / (GTK_CHART_MINBARW+3) );
785 maxvisi = floor(chart->graph.width / (GTK_CHART_MAXBARW+3) );
786
787 DB( g_print(" width=%.2f, nb=%d, minvisi=%d, maxvisi=%d\n", chart->graph.width, chart->nb_items, minvisi, maxvisi) );
788
789 if( chart->nb_items <= maxvisi )
790 {
791 chart->barw = GTK_CHART_MAXBARW;
792 blkw = GTK_CHART_MAXBARW + ( chart->graph.width - (chart->nb_items*GTK_CHART_MAXBARW) ) / chart->nb_items;
793 }
794 else
795 {
796 blkw = MAX(GTK_CHART_MINBARW, floor(chart->graph.width / chart->nb_items));
797 chart->barw = blkw - 3;
798 }
799 }
800
801 if(chart->dual)
802 chart->barw = chart->barw / 2;
803
804 DB( g_print(" blkw=%d, barw=%2.f\n", blkw, chart->barw) );
805
806
807 chart->blkw = blkw;
808 chart->visible = chart->graph.width / blkw;
809 chart->visible = MIN(chart->visible, chart->nb_items);
810
811 chart->ox = chart->l;
812 chart->oy = chart->b;
813 if(chart->range > 0)
814 chart->oy = floor(chart->graph.y + (chart->max/chart->range) * chart->graph.height);
815
816 DB( g_print(" + ox=%f oy=%f\n", chart->ox, chart->oy) );
817
818 /* todo: hack on every xval */
819 if(chart->label_w > 0 && chart->visible > 0)
820 {
821 if( chart->label_w <= chart->blkw )
822 chart->every_xval = 1;
823 else
824 chart->every_xval = floor( 0.5 + (chart->label_w + CHART_SPACING) / chart->blkw);
825
826 DB( g_print(" vis=%3d/%3d, xlabel_w=%g, blk_w=%g :: everyxval=%d\n", chart->visible, chart->nb_items, chart->label_w, chart->blkw, chart->every_xval) );
827 }
828 }
829
830
831 /*
832 ** draw the scale
833 */
834 static void colchart_draw_scale(GtkWidget *widget, gpointer user_data)
835 {
836 GtkChart *chart = GTK_CHART(user_data);
837 cairo_t *cr;
838 double x, y;
839 gdouble curxval;
840 gint i, first;
841 PangoLayout *layout;
842 gchar *valstr;
843 int tw, th;
844
845
846 DB( g_print("\n[column] draw scale\n") );
847
848 cr = cairo_create (chart->surface);
849 layout = pango_cairo_create_layout (cr);
850 chart_set_font_size(chart, layout, CHART_FONT_SIZE_NORMAL);
851 cairo_set_line_width (cr, 1);
852
853 /* clip */
854 //cairo_rectangle(cr, CHART_MARGIN, 0, chart->w, chart->h + CHART_MARGIN);
855 //cairo_clip(cr);
856
857 // Y-scale lines + labels (amounts)
858 curxval = chart->max;
859 cairo_set_dash(cr, 0, 0, 0);
860 for(i=0 ; i<=chart->div ; i++)
861 {
862 y = 0.5 + floor (chart->graph.y + ((i * chart->unit) / chart->range) * chart->graph.height);
863 //DB( g_print(" + i=%d :: y=%f (%f / %f) * %f\n", i, y, i*chart->unit, chart->range, chart->graph.height) );
864
865 // curxval = 0.0 is x-axis
866 cairo_user_set_rgbacol (cr, &global_colors[THTEXT], ( curxval == 0.0 ) ? 0.8 : 0.1);
867 cairo_move_to (cr, chart->graph.x, y);
868 cairo_line_to (cr, chart->graph.x + chart->graph.width, y);
869 cairo_stroke (cr);
870
871 cairo_user_set_rgbacol (cr, &global_colors[THTEXT], 0.78);
872 valstr = chart_print_int(chart, (gint)curxval);
873 pango_layout_set_text (layout, valstr, -1);
874 pango_layout_get_size (layout, &tw, &th);
875 cairo_move_to (cr, chart->graph.x - (tw / PANGO_SCALE) - 2, y - ((th / PANGO_SCALE)*0.8) );
876 pango_cairo_show_layout (cr, layout);
877
878 curxval -= chart->unit;
879 }
880
881 // X-scale lines + labels (items)
882 if(chart->show_xval && chart->every_xval > 0 )
883 {
884 x = chart->graph.x + (chart->blkw/2);
885 y = chart->b - chart->font_h;
886 first = gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
887
888 cairo_set_dash(cr, dashed3, 1, 0);
889
890 for(i=first ; i<(first+chart->visible) ; i++)
891 {
892 if( !(i % chart->every_xval) )
893 {
894 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
895
896 cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 0.1);
897 cairo_move_to(cr, x, chart->graph.y);
898 cairo_line_to(cr, x, chart->b - chart->font_h);
899 cairo_stroke(cr);
900
901 valstr = item->label;
902 pango_layout_set_text (layout, valstr, -1);
903 pango_layout_get_size (layout, &tw, &th);
904 cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 0.78);
905 cairo_move_to(cr, x - ((tw / PANGO_SCALE)/2), y);
906 pango_cairo_show_layout (cr, layout);
907 }
908 x += chart->blkw;
909 }
910 }
911
912 /* average */
913 if( chart->show_average )
914 {
915 if( chart->average < 0 )
916 {
917 y = 0.5 + chart->oy + (ABS(chart->average)/chart->range) * chart->graph.height;
918 }
919 else
920 {
921 y = 0.5 + chart->oy - (ABS(chart->average)/chart->range) * chart->graph.height;
922 }
923
924 DB( g_print(" draw average: x%d, y%f, w%d\n", chart->l, y, chart->w) );
925
926 cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 1.0);
927 cairo_set_line_width(cr, 1.0);
928 cairo_set_dash (cr, dashed3, 1, 0);
929 cairo_move_to(cr, chart->graph.x, y);
930 cairo_line_to (cr, chart->graph.x + chart->graph.width, y);
931 cairo_stroke(cr);
932 }
933
934 g_object_unref (layout);
935 cairo_destroy(cr);
936 }
937
938
939 /*
940 ** draw all visible bars
941 */
942 static void colchart_draw_bars(GtkWidget *widget, gpointer user_data)
943 {
944 GtkChart *chart = GTK_CHART(user_data);
945 cairo_t *cr;
946 double x, x2, y2, h;
947 gint i, first;
948
949 DB( g_print("\n[column] draw bars\n") );
950
951 x = chart->graph.x;
952 first = (gint)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
953
954 cr = gdk_cairo_create (gtk_widget_get_window(widget));
955 //cr = cairo_create (chart->surface);
956
957 DB( g_print(" x=%.2f first=%d, blkw=%.2f, barw=%.2f\n", x, first, chart->blkw, chart->barw ) );
958
959 #if DBGDRAW_ITEM == 1
960 x2 = x + 0.5;
961 cairo_set_line_width(cr, 1.0);
962 double dashlength;
963 dashlength = 4;
964 cairo_set_dash (cr, &dashlength, 1, 0);
965 cairo_set_source_rgb(cr, 1.0, 0.0, 1.0); // violet
966 for(i=first; i<=(first+chart->visible) ;i++)
967 {
968 cairo_move_to(cr, x2, chart->graph.y);
969 cairo_line_to(cr, x2, chart->graph.x + chart->graph.height);
970 x2 += chart->blkw;
971 }
972 cairo_stroke(cr);
973 cairo_set_dash (cr, &dashlength, 0, 0);
974 #endif
975
976 for(i=first; i<(first+chart->visible) ;i++)
977 {
978 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
979 gint color;
980 gint barw = chart->barw;
981
982 //if(!chart->datas1[i]) goto nextbar;
983
984 if(!chart->show_mono)
985 color = i % chart->color_scheme.nb_cols;
986 else
987 color = chart->color_scheme.cs_green;
988
989 cairo_user_set_rgbcol_over(cr, &chart->color_scheme.colors[color], i == chart->active);
990
991 x2 = x + (chart->blkw/2) - 1;
992 x2 = !chart->dual ? x2 - (barw/2) : x2 - barw - 1;
993
994 if(item->serie1)
995 {
996 h = floor((item->serie1 / chart->range) * chart->graph.height);
997 y2 = chart->oy - h;
998 if(item->serie1 < 0.0)
999 {
1000 y2 += 1;
1001 if(chart->show_mono)
1002 {
1003 color = chart->color_scheme.cs_red;
1004 cairo_user_set_rgbcol_over(cr, &chart->color_scheme.colors[color], i == chart->active);
1005 }
1006 }
1007 //DB( g_print(" + i=%d :: y2=%f h=%f (%f / %f) * %f\n", i, y2, h, chart->datas1[i], chart->range, chart->graph.height ) );
1008
1009 cairo_rectangle(cr, x2+2, y2, barw, h);
1010 cairo_fill(cr);
1011
1012 }
1013
1014 if( chart->dual && item->serie2)
1015 {
1016 x2 = x2 + barw + 1;
1017 h = floor((item->serie2 / chart->range) * chart->graph.height);
1018 y2 = chart->oy - h;
1019
1020 cairo_rectangle(cr, x2+2, y2, barw, h);
1021 cairo_fill(cr);
1022
1023 }
1024
1025 x += chart->blkw;
1026
1027 //debug
1028 //gdk_draw_line (widget->window, widget->style->fg_gc[widget->state], x, chart->oy-chart->posbarh, x, chart->oy+chart->negbarh);
1029
1030 }
1031
1032 cairo_destroy(cr);
1033
1034 }
1035
1036 /*
1037 ** get the bar under the mouse pointer
1038 */
1039 static gint colchart_get_active(GtkWidget *widget, gint x, gint y, gpointer user_data)
1040 {
1041 GtkChart *chart = GTK_CHART(user_data);
1042 gint retval;
1043 gint index, first, px;
1044
1045 retval = -1;
1046
1047 if( x <= chart->r && x >= chart->graph.x && y >= chart->graph.y && y <= chart->b )
1048 {
1049 px = (x - chart->graph.x);
1050 //py = (y - chart->oy);
1051 first = gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
1052 index = first + (px / chart->blkw);
1053
1054 if(index < chart->nb_items)
1055 retval = index;
1056 }
1057
1058 return(retval);
1059 }
1060
1061 static void colchart_first_changed( GtkAdjustment *adj, gpointer user_data)
1062 {
1063 GtkChart *chart = GTK_CHART(user_data);
1064 //gint first;
1065
1066 DB( g_print("\n[column] first changed\n") );
1067
1068 //first = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj));
1069
1070 //DB( g_print(" first=%d\n", first) );
1071
1072 /*
1073 DB( g_print("scrollbar\n adj=%8x, low=%.2f upp=%.2f val=%.2f step=%.2f page=%.2f size=%.2f\n", adj,
1074 adj->lower, adj->upper, adj->value, adj->step_increment, adj->page_increment, adj->page_size) );
1075 */
1076 /* Set the number of decimal places to which adj->value is rounded */
1077 //gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
1078 //gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
1079
1080 drawarea_full_redraw (chart->drawarea, chart);
1081
1082 DB( g_print("gtk_widget_queue_draw\n") );
1083 gtk_widget_queue_draw(chart->drawarea);
1084
1085 }
1086
1087 /*
1088 ** scrollbar set values for upper, page size, and also show/hide
1089 */
1090 static void colchart_scrollbar_setvalues(GtkChart *chart)
1091 {
1092 GtkAdjustment *adj = chart->adjustment;
1093 gint first;
1094
1095 g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
1096
1097 DB( g_print("\n[column] sb_set_values\n") );
1098
1099 first = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj));
1100
1101 DB( g_print(" entries=%d, visible=%d\n", chart->nb_items, chart->visible) );
1102 DB( g_print(" first=%d, upper=%d, pagesize=%d\n", first, chart->nb_items, chart->visible) );
1103
1104 gtk_adjustment_set_upper(adj, (gdouble)chart->nb_items);
1105 gtk_adjustment_set_page_size(adj, (gdouble)chart->visible);
1106 gtk_adjustment_set_page_increment(adj, (gdouble)chart->visible);
1107
1108 if(first+chart->visible > chart->nb_items)
1109 {
1110 gtk_adjustment_set_value(adj, (gdouble)chart->nb_items - chart->visible);
1111 }
1112 gtk_adjustment_changed (adj);
1113
1114 if( chart->visible < chart->nb_items )
1115 gtk_widget_hide(GTK_WIDGET(chart->scrollbar));
1116 else
1117 gtk_widget_show(GTK_WIDGET(chart->scrollbar));
1118
1119 }
1120
1121 /* line section */
1122
1123 /*
1124 ** draw all visible lines
1125 */
1126 static void linechart_draw_plot(cairo_t *cr, double x, double y, double r, GtkChart *chart)
1127 {
1128 cairo_set_line_width(cr, r / 2);
1129
1130 cairo_user_set_rgbcol(cr, &global_colors[THBASE]);
1131 cairo_arc(cr, x, y, r, 0, 2*M_PI);
1132 cairo_stroke_preserve(cr);
1133
1134 //cairo_set_source_rgb(cr, COLTOCAIRO(0), COLTOCAIRO(119), COLTOCAIRO(204));
1135 cairo_user_set_rgbcol(cr, &chart->color_scheme.colors[chart->color_scheme.cs_blue]);
1136 cairo_fill(cr);
1137 }
1138
1139
1140 static void linechart_draw_lines(GtkWidget *widget, gpointer user_data)
1141 {
1142 GtkChart *chart = GTK_CHART(user_data);
1143 cairo_t *cr;
1144 double x, y, x2, y2, firstx, lastx, linew;
1145 gint first, i;
1146
1147
1148 DB( g_print("\n[line] draw lines\n") );
1149
1150 x = chart->graph.x;
1151 y = chart->oy;
1152 first = (gint)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
1153
1154 cr = gdk_cairo_create (gtk_widget_get_window(widget));
1155 //cr = cairo_create (chart->surface);
1156
1157 /* clip */
1158 //cairo_rectangle(cr, CHART_MARGIN, 0, chart->w, chart->h + CHART_MARGIN);
1159 //cairo_clip(cr);
1160
1161
1162 #if DBGDRAW_ITEM == 1
1163 x2 = x + 0.5;
1164 cairo_set_line_width(cr, 1.0);
1165 double dashlength = 4;
1166 cairo_set_dash (cr, &dashlength, 1, 0);
1167 cairo_set_source_rgb(cr, 1.0, 0.0, 1.0); // violet
1168 for(i=first; i<=(first+chart->visible) ;i++)
1169 {
1170 cairo_move_to(cr, x2, chart->graph.y);
1171 cairo_line_to(cr, x2, chart->graph.x + chart->graph.height);
1172 x2 += chart->blkw;
1173 }
1174 cairo_stroke(cr);
1175
1176 cairo_set_dash (cr, &dashlength, 0, 0);
1177 #endif
1178
1179 //todo: it should be possible to draw line & plot together using surface and composite fill, or sub path ??
1180 lastx = x;
1181 firstx = x;
1182 linew = 4.0;
1183 if(chart->barw < 24)
1184 {
1185 linew = 1 + (chart->barw / 8.0);
1186 }
1187
1188 cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL);
1189 cairo_set_line_width(cr, linew);
1190
1191 for(i=first; i<(first+chart->visible) ;i++)
1192 {
1193 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
1194
1195 x2 = x + (chart->blkw)/2;
1196 y2 = chart->oy - (item->serie1 / chart->range) * chart->graph.height;
1197 if( i == first)
1198 {
1199 firstx = x2;
1200 cairo_move_to(cr, x2, y2);
1201 }
1202 else
1203 {
1204 if( i < (chart->nb_items) )
1205 {
1206 cairo_line_to(cr, x2, y2);
1207 lastx = x2;
1208 }
1209 else
1210 lastx = x2 - chart->barw;
1211 }
1212
1213 x += chart->blkw;
1214 }
1215
1216 cairo_user_set_rgbcol(cr, &chart->color_scheme.colors[chart->color_scheme.cs_blue]);
1217 cairo_stroke_preserve(cr);
1218
1219 cairo_line_to(cr, lastx, y);
1220 cairo_line_to(cr, firstx, y);
1221 cairo_close_path(cr);
1222
1223 cairo_user_set_rgbacol(cr, &chart->color_scheme.colors[chart->color_scheme.cs_blue], AREA_ALPHA);
1224 cairo_fill(cr);
1225
1226 x = chart->graph.x;
1227 y = chart->oy;
1228 first = (gint)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
1229
1230 // draw plots
1231 for(i=first; i<(first+chart->visible) ;i++)
1232 {
1233 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
1234
1235 x2 = x + (chart->blkw)/2;
1236 y2 = chart->oy - (item->serie1 / chart->range) * chart->graph.height;
1237
1238 //test draw vertical selection line
1239 if( i == chart->active )
1240 {
1241 cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 0.1);
1242
1243 //cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); //blue
1244 cairo_set_line_width(cr, 1.0);
1245 cairo_move_to(cr, x2, chart->graph.y);
1246 cairo_line_to(cr, x2, chart->b - chart->font_h);
1247 cairo_stroke(cr);
1248 }
1249
1250
1251 linechart_draw_plot(cr, x2, y2, i == chart->active ? linew+1 : linew, chart);
1252
1253
1254 x += chart->blkw;
1255 }
1256
1257 /* average */
1258
1259 if( chart->show_average )
1260 {
1261 if( chart->average < 0 )
1262 {
1263 y = 0.5 + chart->oy + (ABS(chart->average)/chart->range) * chart->graph.height;
1264 }
1265 else
1266 {
1267 y = 0.5 + chart->oy - (ABS(chart->average)/chart->range) * chart->graph.height;
1268 }
1269
1270 y2 = (ABS(chart->min)/chart->range) * chart->graph.height - (y - chart->oy) + 1;
1271
1272 DB( g_print(" draw average: x%d, y%f, w%d, h%f\n", chart->l, y, chart->w, y2) );
1273
1274 cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 1.0);
1275 cairo_set_line_width(cr, 1.0);
1276 cairo_set_dash (cr, dashed3, 1, 0);
1277 cairo_move_to(cr, chart->graph.x, y);
1278 cairo_line_to (cr, chart->graph.x + chart->graph.width, y);
1279 cairo_stroke(cr);
1280 }
1281
1282
1283
1284 /* overdrawn */
1285 DB( g_print(" min=%.2f range=%.2f\n", chart->min, chart->range) );
1286
1287 if( chart->show_over )
1288 {
1289 //if(chart->minimum != 0 && chart->minimum >= chart->min)
1290 if(chart->minimum >= chart->min)
1291 {
1292 if( chart->minimum < 0 )
1293 {
1294 y = 0.5 + chart->oy + (ABS(chart->minimum)/chart->range) * chart->graph.height;
1295 }
1296 else
1297 {
1298 y = 0.5 + chart->oy - (ABS(chart->minimum)/chart->range) * chart->graph.height;
1299 }
1300
1301 y2 = (ABS(chart->min)/chart->range) * chart->graph.height - (y - chart->oy) + 1;
1302
1303 cairo_set_source_rgba(cr, COLTOCAIRO(255), COLTOCAIRO(0), COLTOCAIRO(0), AREA_ALPHA / 2);
1304
1305 DB( g_print(" draw over: x%d, y%f, w%d, h%f\n", chart->l, y, chart->w, y2) );
1306
1307 cairo_rectangle(cr, chart->graph.x, y, chart->graph.width, y2 );
1308 cairo_fill(cr);
1309
1310 cairo_set_line_width(cr, 1.0);
1311 cairo_set_source_rgb(cr, COLTOCAIRO(255), COLTOCAIRO(0), COLTOCAIRO(0));
1312
1313 cairo_set_dash (cr, dashed3, 1, 0);
1314 cairo_move_to(cr, chart->graph.x, y);
1315 cairo_line_to (cr, chart->graph.x + chart->graph.width, y);
1316 cairo_stroke(cr);
1317 }
1318 }
1319
1320 cairo_destroy(cr);
1321
1322
1323 }
1324
1325
1326
1327
1328 /*
1329 ** get the point under the mouse pointer
1330 */
1331 static gint linechart_get_active(GtkWidget *widget, gint x, gint y, gpointer user_data)
1332 {
1333 GtkChart *chart = GTK_CHART(user_data);
1334 gint retval;
1335 gint first, index, px;
1336
1337 DB( g_print("\n[line] get active\n") );
1338
1339 retval = -1;
1340
1341 if( x <= chart->r && x >= chart->graph.x && y >= chart->graph.y && y <= chart->b )
1342 {
1343 px = (x - chart->graph.x);
1344 //py = (y - chart->oy);
1345 first = gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
1346 index = first + (px / (chart->blkw));
1347
1348 if(index < chart->nb_items)
1349 retval = index;
1350 }
1351
1352 return(retval);
1353 }
1354
1355
1356 /* pie section */
1357
1358 static void piechart_calculation(GtkChart *chart)
1359 {
1360 //GtkWidget *drawarea = chart->drawarea;
1361 gint w, h;
1362
1363 DB( g_print("\n[pie] calculation\n") );
1364
1365 w = chart->graph.width;
1366 h = chart->graph.height;
1367
1368 chart->rayon = MIN(w, h);
1369 chart->mark = 0;
1370
1371 #if CHART_PARAM_PIE_MARK == TRUE
1372 gint m = floor(chart->rayon / 100);
1373 m = MAX(2, m);
1374 chart->rayon -= (m * 2);
1375 chart->mark = m;
1376 #endif
1377
1378 chart->ox = chart->graph.x + (w / 2);
1379 chart->oy = chart->graph.y + (chart->rayon / 2);
1380
1381 DB( g_print(" center: %g, %g - R=%d, mark=%d\n", chart->ox, chart->oy, chart->rayon, chart->mark) );
1382
1383 }
1384
1385
1386 static void piechart_draw_slices(GtkWidget *widget, gpointer user_data)
1387 {
1388 GtkChart *chart = GTK_CHART(user_data);
1389 cairo_t *cr;
1390
1391 if(chart->nb_items <= 0 || chart->total == 0.0)
1392 return;
1393
1394 DB( g_print("\n[pie] draw slices\n") );
1395
1396
1397 //cairo drawing
1398
1399 double a1 = 0 * (M_PI / 180);
1400 double a2 = 360 * (M_PI / 180);
1401
1402 //g_print("angle1=%.2f angle2=%.2f\n", a1, a2);
1403
1404 double cx = chart->ox;
1405 double cy = chart->oy;
1406 double radius = chart->rayon/2;
1407 gint i;
1408 double dx, dy;
1409 double sum = 0.0;
1410 gint color;
1411
1412 cr = gdk_cairo_create (gtk_widget_get_window(widget));
1413 //cr = cairo_create (chart->surface);
1414
1415 DB( g_print("rayon=%d\n", chart->rayon) );
1416 DB( g_print("total=%.f\n", chart->total) );
1417
1418 for(i=0; i< chart->nb_items ;i++)
1419 {
1420 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
1421
1422 a1 = ((360 * (sum / chart->total)) - 90) * (M_PI / 180);
1423 sum += ABS(item->serie1);
1424 a2 = ((360 * (sum / chart->total)) - 90) * (M_PI / 180);
1425 //if(i < chart->nb_items-1) a2 += 0.0175;
1426
1427 dx = cx;
1428 dy = cy;
1429
1430 DB( g_print("- s%2d: %.2f%% a1=%.2f a2=%.2f | %s %.f\n", i, sum / chart->total, a1, a2, item->label, item->serie1) );
1431
1432
1433 cairo_move_to(cr, dx, dy);
1434 cairo_arc(cr, dx, dy, radius, a1, a2);
1435
1436 #if CHART_PARAM_PIE_LINE == TRUE
1437 cairo_set_line_width(cr, 2.0);
1438 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1439 cairo_line_to(cr, cx, cy);
1440 cairo_stroke_preserve(cr);
1441 #endif
1442
1443 //g_print("color : %f %f %f\n", COLTOCAIRO(colors[i].r), COLTOCAIRO(colors[i].g), COLTOCAIRO(colors[i].b));
1444
1445 color = i % chart->color_scheme.nb_cols;
1446 cairo_user_set_rgbcol_over(cr, &chart->color_scheme.colors[color], i == chart->active);
1447 cairo_fill(cr);
1448 }
1449
1450
1451
1452 #if CHART_PARAM_PIE_DONUT == TRUE
1453 a1 = 0;
1454 a2 = 2 * M_PI;
1455
1456 //original
1457 //radius = (gint)((chart->rayon/3) * (1 / PHI));
1458 //5.1
1459 //radius = (gint)((chart->rayon/2) * 2 / 3);
1460 //ynab
1461 //piehole value from 0.4 to 0.6 will look best on most charts
1462 radius = (gint)(chart->rayon/2) * CHART_PARAM_PIE_HOLEVALUE;
1463
1464 cairo_arc(cr, cx, cy, radius, a1, a2);
1465 cairo_user_set_rgbcol(cr, &global_colors[THBASE]);
1466 cairo_fill(cr);
1467 #endif
1468
1469 cairo_destroy(cr);
1470
1471 }
1472
1473
1474 static gint piechart_get_active(GtkWidget *widget, gint x, gint y, gpointer user_data)
1475 {
1476 GtkChart *chart = GTK_CHART(user_data);
1477 gint retval, px, py;
1478 gint index;
1479 double radius, h;
1480
1481 DB( g_print("\n[pie] get active\n") );
1482
1483 retval = -1;
1484
1485 px = x - chart->ox;
1486 py = y - chart->oy;
1487 h = sqrt( pow(px,2) + pow(py,2) );
1488 radius = chart->rayon / 2;
1489
1490 if(h <= radius && h >= (radius * CHART_PARAM_PIE_HOLEVALUE) )
1491 {
1492 double angle, b;
1493
1494 b = (acos(px / h) * 180) / M_PI;
1495 angle = py > 0 ? b : 360 - b;
1496 angle += 90;
1497 if(angle > 360) angle -= 360;
1498 //angle = 360 - angle;
1499
1500 //todo optimize
1501 gdouble cumul = 0;
1502 for(index=0; index< chart->nb_items ;index++)
1503 {
1504 ChartItem *item = &g_array_index(chart->items, ChartItem, index);
1505
1506 cumul += ABS(item->serie1/chart->total)*360;
1507 if( cumul > angle )
1508 {
1509 retval = index;
1510 break;
1511 }
1512 }
1513
1514 //DB( g_print(" inside: x=%d, y=%d\n", x, y) );
1515 //DB( g_print(" inside: b=%f angle=%f, slice is %d\n", b, angle, index) );
1516 }
1517 return(retval);
1518 }
1519
1520
1521 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1522 static gboolean drawarea_full_redraw(GtkWidget *widget, gpointer user_data)
1523 {
1524 GtkChart *chart = GTK_CHART(user_data);
1525 cairo_t *cr;
1526 PangoLayout *layout;
1527 int tw, th;
1528
1529 DB( g_print("------\n[gtkchart] drawarea full redraw\n") );
1530
1531 cr = cairo_create (chart->surface);
1532
1533 #if MYDEBUG == 1
1534 cairo_font_face_t *ff;
1535 cairo_scaled_font_t *sf;
1536
1537 ff = cairo_get_font_face(cr);
1538 sf = cairo_get_scaled_font(cr);
1539
1540 g_print("cairo ff = '%s'\n", cairo_toy_font_face_get_family(ff) );
1541
1542 ff = cairo_scaled_font_get_font_face(sf);
1543 g_print("cairo sf = '%s'\n", cairo_toy_font_face_get_family(ff) );
1544
1545 //cairo_set_font_face(cr, ff);
1546 #endif
1547
1548 /* fillin the back in white */
1549 //cairo_user_set_rgbcol(cr, &global_colors[WHITE]);
1550 cairo_user_set_rgbcol(cr, &global_colors[THBASE]);
1551
1552 cairo_paint(cr);
1553
1554 if(chart->nb_items == 0)
1555 {
1556 cairo_destroy(cr);
1557 return FALSE;
1558 }
1559
1560 /*debug help draws */
1561 #if DBGDRAW_RECT == 1
1562 //clip area
1563 cairo_set_line_width(cr, 1.0);
1564 cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); //green
1565 cairo_rectangle(cr, chart->l+0.5, chart->t+0.5, chart->w, chart->h);
1566 cairo_stroke(cr);
1567
1568 //graph area
1569 cairo_set_source_rgb(cr, 1.0, 0.5, 0.0); //orange
1570 cairo_rectangle(cr, chart->graph.x+0.5, chart->graph.y+0.5, chart->graph.width, chart->graph.height);
1571 cairo_stroke(cr);
1572 #endif
1573
1574 // draw title
1575 if(chart->title)
1576 {
1577 layout = pango_cairo_create_layout (cr);
1578
1579 chart_set_font_size(chart, layout, CHART_FONT_SIZE_TITLE);
1580 pango_layout_set_text (layout, chart->title, -1);
1581 pango_layout_get_size (layout, &tw, &th);
1582
1583 cairo_user_set_rgbcol(cr, &global_colors[THTEXT]);
1584 cairo_move_to(cr, chart->l, chart->t);
1585 pango_cairo_show_layout (cr, layout);
1586
1587 #if DBGDRAW_TEXT == 1
1588 double dashlength;
1589 cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); //blue
1590 dashlength = 3;
1591 cairo_set_dash (cr, &dashlength, 1, 0);
1592 //cairo_move_to(cr, chart->l, chart->t);
1593 cairo_rectangle(cr, chart->l+0.5, chart->t+0.5, (tw / PANGO_SCALE), (th / PANGO_SCALE));
1594 cairo_stroke(cr);
1595 #endif
1596
1597 g_object_unref (layout);
1598 }
1599
1600 switch(chart->type)
1601 {
1602 case CHART_TYPE_COL:
1603 colchart_draw_scale(widget, chart);
1604 //colchart_draw_bars(widget, chart);
1605 break;
1606 case CHART_TYPE_LINE:
1607 colchart_draw_scale(widget, chart);
1608 //linechart_draw_lines(widget, chart);
1609 break;
1610 case CHART_TYPE_PIE:
1611 //piechart_draw_slices(widget, chart);
1612 break;
1613 }
1614
1615
1616 //test legend
1617 if(chart->show_legend)
1618 {
1619 gint i;
1620 gchar *valstr;
1621 gint x, y;
1622 gint radius;
1623 gint color;
1624
1625 DB( g_print("\n[chart] draw legend\n") );
1626
1627 layout = pango_cairo_create_layout (cr);
1628 chart_set_font_size(chart, layout, CHART_FONT_SIZE_SMALL);
1629 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
1630
1631 x = chart->legend.x;
1632 y = chart->legend.y;
1633 radius = chart->legend_font_h;
1634
1635 #if DBGDRAW_RECT == 1
1636 double dashlength;
1637 cairo_set_source_rgb(cr, 1.0, 0.5, 0.0); //orange
1638 dashlength = 3;
1639 cairo_set_dash (cr, &dashlength, 1, 0);
1640 //cairo_move_to(cr, x, y);
1641 cairo_rectangle(cr, chart->legend.x+0.5, chart->legend.y+0.5, chart->legend.width, chart->legend.height);
1642 cairo_stroke(cr);
1643 #endif
1644
1645 for(i=0; i< chart->nb_items ;i++)
1646 {
1647 ChartItem *item = &g_array_index(chart->items, ChartItem, i);
1648
1649 if(item)
1650 {
1651 //DB( g_print(" draw %2d '%s' y=%g\n", i, item->label, y) );
1652
1653 #if DBGDRAW_TEXT == 1
1654 double dashlength;
1655 cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); //blue
1656 dashlength = 3;
1657 cairo_set_dash (cr, &dashlength, 1, 0);
1658 //cairo_move_to(cr, x, y);
1659 cairo_rectangle(cr, x+0.5, y+0.5, chart->legend_font_h + CHART_SPACING + chart->legend_label_w, chart->legend_font_h);
1660 cairo_stroke(cr);
1661 #endif
1662
1663 // check if enought height to draw
1664 if( chart->nb_items - i > 1 )
1665 {
1666 if( (y + floor(2 * radius * CHART_LINE_SPACING)) > chart->b )
1667 {
1668 DB( g_print(" print ...\n\n") );
1669 pango_layout_set_text (layout, "...", -1);
1670 cairo_move_to(cr, x + radius + CHART_SPACING, y);
1671 pango_cairo_show_layout (cr, layout);
1672 break;
1673 }
1674 }
1675
1676 // 1: palette
1677 cairo_arc(cr, x + (radius/2), y + (radius/2), (radius/2), 0, 2 * M_PI);
1678 color = i % chart->color_scheme.nb_cols;
1679 cairo_user_set_rgbcol(cr, &chart->color_scheme.colors[color]);
1680 cairo_fill(cr);
1681
1682 cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 0.78);
1683
1684 // 2: label
1685 valstr = item->label;
1686 pango_layout_set_text (layout, valstr, -1);
1687 pango_layout_set_width(layout, chart->legend_label_w * PANGO_SCALE);
1688 cairo_move_to(cr, x + chart->legend_font_h + CHART_SPACING, y);
1689 pango_cairo_show_layout (cr, layout);
1690
1691 if( chart->show_legend_wide )
1692 {
1693 pango_layout_set_width(layout, -1);
1694
1695 // 3: value
1696 valstr = chart_print_double(chart, chart->buffer1, item->serie1);
1697 pango_layout_set_text (layout, valstr, -1);
1698 pango_layout_get_size (layout, &tw, &th);
1699 cairo_move_to(cr, x + chart->legend_font_h + chart->legend_label_w + (CHART_SPACING*3) + chart->legend_value_w - (tw/PANGO_SCALE), y);
1700 pango_cairo_show_layout (cr, layout);
1701
1702 // 4: rate
1703 valstr = chart_print_rate(chart, item->rate);
1704 pango_layout_set_text (layout, valstr, -1);
1705 pango_layout_get_size (layout, &tw, &th);
1706 cairo_move_to(cr, x + chart->legend_font_h + chart->legend_label_w + chart->legend_value_w + chart->legend_rate_w + (CHART_SPACING*3) - (tw/PANGO_SCALE), y);
1707 pango_cairo_show_layout (cr, layout);
1708 }
1709
1710 //the radius contains the font height here
1711 //y += floor(chart->font_h * CHART_LINE_SPACING);
1712 y += floor(radius * CHART_LINE_SPACING);
1713 }
1714 }
1715
1716 g_object_unref (layout);
1717
1718 }
1719
1720 cairo_destroy(cr);
1721
1722 return TRUE;
1723 }
1724
1725
1726 static gboolean
1727 drawarea_configure_event_callback (GtkWidget *widget,
1728 GdkEventConfigure *event,
1729 gpointer user_data)
1730 {
1731 GtkChart *chart = GTK_CHART(user_data);
1732 GtkAllocation allocation;
1733 GtkStyleContext *context;
1734 PangoFontDescription *desc;
1735 gboolean colfound;
1736 GdkRGBA color;
1737
1738 DB( g_print("\n[gtkchart] drawarea configure \n") );
1739
1740 gtk_widget_get_allocation (widget, &allocation);
1741
1742 DB( g_print("w=%d h=%d\n", allocation.width, allocation.height) );
1743
1744
1745 if (chart->surface)
1746 cairo_surface_destroy (chart->surface);
1747
1748 chart->surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
1749 CAIRO_CONTENT_COLOR,
1750 allocation.width,
1751 allocation.height);
1752
1753 context = gtk_widget_get_style_context (widget);
1754
1755 chart_color_global_default();
1756
1757 // get base color
1758 colfound = gtk_style_context_lookup_color(context, "theme_base_color", &color);
1759 if(!colfound)
1760 colfound = gtk_style_context_lookup_color(context, "base_color", &color);
1761
1762 if( colfound )
1763 {
1764 struct rgbcol *tcol = &global_colors[THBASE];
1765 tcol->r = color.red * 255;
1766 tcol->g = color.green * 255;
1767 tcol->b = color.blue * 255;
1768 DB( g_print(" - theme base col: %x %x %x\n", tcol->r, tcol->g, tcol->b) );
1769 }
1770
1771 //get text color
1772 colfound = gtk_style_context_lookup_color(context, "theme_text_color", &color);
1773 if(!colfound)
1774 gtk_style_context_lookup_color(context, "text_color", &color);
1775
1776
1777 if( colfound )
1778 {
1779 struct rgbcol *tcol = &global_colors[THTEXT];
1780 tcol->r = color.red * 255;
1781 tcol->g = color.green * 255;
1782 tcol->b = color.blue * 255;
1783 DB( g_print(" - theme text (bg) col: %x %x %x\n", tcol->r, tcol->g, tcol->b) );
1784 }
1785
1786 //commented 5.1.5
1787 //drawarea_full_redraw(widget, user_data);
1788
1789 /* get and copy the font */
1790 gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL, "font", &desc, NULL);
1791 if(chart->pfd)
1792 {
1793 pango_font_description_free (chart->pfd);
1794 chart->pfd = NULL;
1795 }
1796 chart->pfd = pango_font_description_copy(desc);
1797 chart->pfd_size = pango_font_description_get_size (desc) / PANGO_SCALE;
1798 //chart->barw = (6 + chart->pfd_size) * PHI;
1799
1800 //leak: we should free desc here ?
1801 //or no need to copy above ?
1802 //pango_font_description_free(desc);
1803
1804 DB( g_print("family: %s\n", pango_font_description_get_family(chart->pfd) ) );
1805 DB( g_print("size : %d (%d)\n", chart->pfd_size, chart->pfd_size/PANGO_SCALE ) );
1806 DB( g_print("isabs : %d\n", pango_font_description_get_size_is_absolute (chart->pfd) ) );
1807
1808
1809 if( gtk_widget_get_realized(widget))
1810 {
1811 chart_recompute(chart);
1812 drawarea_full_redraw(widget, chart);
1813 }
1814
1815 /* We've handled the configure event, no need for further processing. */
1816 return TRUE;
1817 }
1818
1819
1820 static void drawarea_realize_callback(GtkWidget *widget, gpointer user_data)
1821 {
1822 //GtkChart *chart = GTK_CHART(user_data);
1823
1824 DB( g_print("\n[gtkchart] drawarea realize\n") );
1825
1826 //chart_recompute(chart);
1827
1828 }
1829
1830
1831 static gboolean drawarea_draw_callback(GtkWidget *widget, cairo_t *cr, gpointer user_data)
1832 {
1833 GtkChart *chart = GTK_CHART(user_data);
1834
1835 if( !gtk_widget_get_realized(widget) || chart->surface == NULL )
1836 return FALSE;
1837
1838 DB( g_print("\n[gtkchart] drawarea draw callback\n") );
1839
1840 cairo_set_source_surface (cr, chart->surface, 0, 0);
1841 cairo_paint (cr);
1842
1843 switch(chart->type)
1844 {
1845 case CHART_TYPE_COL:
1846 colchart_draw_bars(widget, chart);
1847 break;
1848 case CHART_TYPE_LINE:
1849 linechart_draw_lines(widget, chart);
1850 break;
1851 case CHART_TYPE_PIE:
1852 piechart_draw_slices(widget, chart);
1853 break;
1854 }
1855
1856 return FALSE;
1857 }
1858
1859
1860 static gboolean drawarea_querytooltip_callback(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data)
1861 {
1862 GtkChart *chart = GTK_CHART(user_data);
1863 gchar *strval, *strval2, *buffer;
1864 gboolean retval = FALSE;
1865
1866 if(chart->surface == NULL)
1867 return FALSE;
1868
1869 DB( g_print("\n[gtkchart] drawarea querytooltip\n") );
1870
1871 DB( g_print(" x=%d, y=%d kbm=%d\n", x, y, keyboard_mode) );
1872 if(chart->lastactive != chart->active)
1873 {
1874 goto end;
1875 }
1876
1877 if(chart->active >= 0)
1878 {
1879 ChartItem *item = &g_array_index(chart->items, ChartItem, chart->active);
1880
1881 strval = chart_print_double(chart, chart->buffer1, item->serie1);
1882 if( !chart->dual )
1883 {
1884 //#1420495 don't use g_markup_printf_escaped
1885 if( chart->type == CHART_TYPE_PIE )
1886 buffer = g_strdup_printf("%s\n%s\n%.2f%%", item->label, strval, item->rate);
1887 else
1888 buffer = g_strdup_printf("%s\n%s", item->label, strval);
1889
1890 }
1891 else
1892 {
1893 strval2 = chart_print_double(chart, chart->buffer2, item->serie2);
1894 buffer = g_strdup_printf("%s\n+%s\n%s", item->label, strval2, strval);
1895 }
1896
1897 gtk_tooltip_set_text(tooltip, buffer);
1898 //gtk_label_set_markup(GTK_LABEL(chart->ttlabel), buffer);
1899 g_free(buffer);
1900 retval = TRUE;
1901 }
1902 end:
1903 chart->lastactive = chart->active;
1904
1905 return retval;
1906 }
1907
1908
1909 static gboolean drawarea_motionnotifyevent_callback(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
1910 {
1911 GtkChart *chart = GTK_CHART(user_data);
1912 gboolean retval = TRUE;
1913 gint x, y;
1914
1915 if(chart->surface == NULL || chart->nb_items == 0)
1916 return FALSE;
1917
1918 DB( g_print("\n[gtkchart] drawarea motion\n") );
1919 x = event->x;
1920 y = event->y;
1921
1922 //todo see this
1923 if(event->is_hint)
1924 {
1925 DB( g_print(" is hint\n") );
1926
1927 gdk_window_get_device_position(event->window, event->device, &x, &y, NULL);
1928 //gdk_window_get_pointer(event->window, &x, &y, NULL);
1929 //return FALSE;
1930 }
1931
1932 switch(chart->type)
1933 {
1934 case CHART_TYPE_COL:
1935 chart->active = colchart_get_active(widget, x, y, chart);
1936 break;
1937 case CHART_TYPE_LINE:
1938 chart->active = linechart_get_active(widget, x, y, chart);
1939 break;
1940 case CHART_TYPE_PIE:
1941 chart->active = piechart_get_active(widget, x, y, chart);
1942 break;
1943 }
1944
1945 //test: eval legend
1946 if( chart->show_legend && chart->active == - 1)
1947 {
1948 if( x >= chart->legend.x && (x <= (chart->legend.x+chart->legend.width ))
1949 && y >= chart->legend.y && (y <= (chart->legend.y+chart->legend.height ))
1950 )
1951 {
1952 //use the radius a font height here
1953 chart->active = (y - chart->legend.y) / floor(chart->legend_font_h * CHART_LINE_SPACING);
1954 }
1955
1956 if( chart->active > chart->nb_items - 1)
1957 {
1958 chart->active = -1;
1959 }
1960 }
1961
1962 // rollover redraw ?
1963 DB( g_print(" active: last=%d, curr=%d\n", chart->lastactive, chart->active) );
1964
1965 if(chart->lastactive != chart->active)
1966 {
1967 GdkRectangle update_rect;
1968 gint first;
1969
1970 DB( g_print(" motion rollover redraw :: active=%d\n", chart->active) );
1971
1972 first = (gint)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
1973
1974 /* pie : always invalidate all graph area */
1975 if( chart->type == CHART_TYPE_PIE )
1976 {
1977 update_rect.x = chart->graph.x;
1978 update_rect.y = chart->graph.y;
1979 update_rect.width = chart->graph.width;
1980 update_rect.height = chart->graph.height;
1981
1982 /* Now invalidate the affected region of the drawing area. */
1983 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
1984 &update_rect,
1985 FALSE);
1986 }
1987
1988 if(chart->lastactive != -1)
1989 {
1990 /* column/line : invalidate rollover */
1991 if( chart->type == CHART_TYPE_COL || chart->type == CHART_TYPE_LINE )
1992 {
1993 update_rect.x = chart->graph.x + (chart->lastactive - first) * chart->blkw;
1994 update_rect.y = chart->graph.y - 6;
1995 update_rect.width = chart->blkw;
1996 update_rect.height = chart->graph.height + 12;
1997 }
1998
1999 /* Now invalidate the affected region of the drawing area. */
2000 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
2001 &update_rect,
2002 FALSE);
2003 }
2004
2005 /* column/line : invalidate current item */
2006 if( chart->type == CHART_TYPE_COL || chart->type == CHART_TYPE_LINE )
2007 {
2008 update_rect.x = chart->graph.x + (chart->active - first) * chart->blkw;
2009 update_rect.y = chart->graph.y - 6;
2010 update_rect.width = chart->blkw;
2011 update_rect.height = chart->graph.height + 12;
2012
2013 /* Now invalidate the affected region of the drawing area. */
2014 gdk_window_invalidate_rect (gtk_widget_get_window (widget),
2015 &update_rect,
2016 FALSE);
2017 }
2018
2019 //gtk_widget_queue_draw( widget );
2020 //retval = FALSE;
2021 }
2022
2023 DB( g_print(" x=%d, y=%d, time=%d\n", x, y, event->time) );
2024
2025 //if(inlegend != TRUE)
2026 // gtk_tooltip_trigger_tooltip_query(gtk_widget_get_display(chart->drawarea));
2027
2028 return retval;
2029 }
2030
2031
2032 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2033 /* public functions */
2034 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2035
2036 void gtk_chart_queue_redraw(GtkChart *chart)
2037 {
2038 DB( g_print("\n[gtkchart] queue redraw\n") );
2039
2040 if( gtk_widget_get_realized(chart->drawarea) )
2041 {
2042 chart_recompute(chart);
2043 drawarea_full_redraw(chart->drawarea, chart);
2044 DB( g_print("gtk_widget_queue_draw\n") );
2045 gtk_widget_queue_draw( chart->drawarea );
2046 }
2047 }
2048
2049
2050 /*
2051 ** change the model and/or column
2052 */
2053 void gtk_chart_set_datas(GtkChart *chart, GtkTreeModel *model, guint column, gchar *title, gchar *subtitle)
2054 {
2055 g_return_if_fail (GTK_IS_CHART (chart));
2056
2057 DB( g_print("\n[gtkchart] set datas\n") );
2058
2059 if( GTK_IS_TREE_MODEL(model) )
2060 {
2061 chart_setup_with_model(chart, model, column, column);
2062 if(title != NULL)
2063 chart->title = g_strdup(title);
2064 if(subtitle != NULL)
2065 chart->subtitle = g_strdup(subtitle);
2066
2067 gtk_chart_queue_redraw(chart);
2068 }
2069 else
2070 {
2071 chart_clear(chart);
2072 if( GTK_IS_LIST_STORE(chart->model) )
2073 gtk_list_store_clear (GTK_LIST_STORE(chart->model));
2074
2075 }
2076 }
2077
2078 /*
2079 ** change the model and/or column
2080 */
2081 void gtk_chart_set_dualdatas(GtkChart *chart, GtkTreeModel *model, guint column1, guint column2, gchar *title, gchar *subtitle)
2082 {
2083 g_return_if_fail (GTK_IS_CHART (chart));
2084
2085 DB( g_print("\n[gtkchart] set dualdatas\n") );
2086
2087 if( GTK_IS_TREE_MODEL(model) )
2088 {
2089 chart_setup_with_model(chart, model, column1, column2 );
2090 if(title != NULL)
2091 chart->title = g_strdup(title);
2092 if(subtitle != NULL)
2093 chart->subtitle = g_strdup(subtitle);
2094
2095 gtk_chart_queue_redraw(chart);
2096 }
2097 else
2098 {
2099 chart_clear(chart);
2100 if( GTK_IS_LIST_STORE(chart->model) )
2101 gtk_list_store_clear (GTK_LIST_STORE(chart->model));
2102 }
2103 }
2104
2105
2106 /*
2107 ** change the type dynamically
2108 */
2109 void gtk_chart_set_type(GtkChart * chart, gint type)
2110 {
2111 g_return_if_fail (GTK_IS_CHART (chart));
2112 //g_return_if_fail (type < CHART_TYPE_MAX);
2113
2114 DB( g_print("\n[gtkchart] set type %d\n", type) );
2115
2116 chart->type = type;
2117 chart->dual = FALSE;
2118
2119 gtk_chart_queue_redraw(chart);
2120 }
2121
2122 /* = = = = = = = = = = parameters = = = = = = = = = = */
2123
2124 void gtk_chart_set_color_scheme(GtkChart * chart, gint index)
2125 {
2126 colorscheme_init(&chart->color_scheme, index);
2127 }
2128
2129
2130
2131 /*
2132 ** set the minor parameters
2133 */
2134 void gtk_chart_set_minor_prefs(GtkChart * chart, gdouble rate, gchar *symbol)
2135 {
2136 g_return_if_fail (GTK_IS_CHART (chart));
2137
2138 DB( g_print("\n[gtkchart] set minor prefs\n") );
2139
2140 chart->minor_rate = rate;
2141 chart->minor_symbol = symbol;
2142 }
2143
2144
2145 void gtk_chart_set_absolute(GtkChart * chart, gboolean abs)
2146 {
2147 g_return_if_fail (GTK_IS_CHART (chart));
2148
2149 DB( g_print("\n[gtkchart] set absolute\n") );
2150
2151 chart->abs = abs;
2152 }
2153
2154
2155 void gtk_chart_set_currency(GtkChart * chart, guint32 kcur)
2156 {
2157 g_return_if_fail (GTK_IS_CHART (chart));
2158
2159 chart->kcur = kcur;
2160 }
2161
2162
2163 /*
2164 ** set the overdrawn minimum
2165 */
2166 void gtk_chart_set_overdrawn(GtkChart * chart, gdouble minimum)
2167 {
2168 g_return_if_fail (GTK_IS_CHART (chart));
2169
2170 DB( g_print("\n[gtkchart] set overdrawn\n") );
2171
2172 chart->minimum = minimum;
2173
2174 //if(chart->type == CHART_TYPE_LINE)
2175 // chart_recompute(chart);
2176 }
2177
2178
2179 /*
2180 ** obsolete: set the every_xval
2181 */
2182 /*void gtk_chart_set_every_xval(GtkChart * chart, gint gap)
2183 {
2184 g_return_if_fail (GTK_IS_CHART (chart));
2185
2186 DB( g_print("\n[gtkchart] set every_xval\n") );
2187
2188 chart->every_xval = gap;
2189
2190 //if(chart->type != CHART_TYPE_PIE)
2191 // chart_recompute(chart);
2192 }*/
2193
2194
2195 /*
2196 ** set the barw
2197 */
2198 void gtk_chart_set_barw(GtkChart * chart, gdouble barw)
2199 {
2200 g_return_if_fail (GTK_IS_CHART (chart));
2201
2202 DB( g_print("\n[gtkchart] set barw\n") );
2203
2204 if( barw >= GTK_CHART_MINBARW && barw <= GTK_CHART_MAXBARW )
2205 chart->usrbarw = barw;
2206 else
2207 chart->usrbarw = 0;
2208
2209
2210 if(chart->type != CHART_TYPE_PIE)
2211 gtk_chart_queue_redraw(chart);
2212 }
2213
2214 /*
2215 ** set the show mono (colors)
2216 */
2217 void gtk_chart_set_showmono(GtkChart * chart, gboolean mono)
2218 {
2219 g_return_if_fail (GTK_IS_CHART (chart));
2220
2221 chart->show_mono = mono;
2222
2223 if(chart->type != CHART_TYPE_PIE)
2224 gtk_chart_queue_redraw(chart);
2225 }
2226
2227
2228 /* = = = = = = = = = = visibility = = = = = = = = = = */
2229
2230 /*
2231 ** change the legend visibility
2232 */
2233 void gtk_chart_show_legend(GtkChart * chart, gboolean visible, gboolean showextracol)
2234 {
2235 g_return_if_fail (GTK_IS_CHART (chart));
2236
2237 chart->show_legend = visible;
2238 chart->show_legend_wide = showextracol;
2239 gtk_chart_queue_redraw(chart);
2240 }
2241
2242 /*
2243 ** change the x-value visibility
2244 */
2245 void gtk_chart_show_xval(GtkChart * chart, gboolean visible)
2246 {
2247 g_return_if_fail (GTK_IS_CHART (chart));
2248
2249 DB( g_print("\n[gtkchart] set show xval\n") );
2250
2251 chart->show_xval = visible;
2252
2253 //if(chart->type != CHART_TYPE_PIE)
2254 // chart_recompute(chart);
2255 }
2256
2257
2258 void gtk_chart_show_average(GtkChart * chart, gdouble value, gboolean visible)
2259 {
2260 g_return_if_fail (GTK_IS_CHART (chart));
2261
2262 DB( g_print("\n[gtkchart] set show average %f\n", value) );
2263
2264 chart->average = value;
2265 chart->show_average = visible;
2266
2267 //if(chart->type == CHART_TYPE_LINE)
2268 // chart_recompute(chart);
2269 }
2270
2271
2272
2273 /*
2274 ** chnage the overdrawn visibility
2275 */
2276 void gtk_chart_show_overdrawn(GtkChart * chart, gboolean visible)
2277 {
2278 g_return_if_fail (GTK_IS_CHART (chart));
2279
2280 DB( g_print("\n[gtkchart] set show overdrawn\n") );
2281
2282 chart->show_over = visible;
2283
2284 //if(chart->type == CHART_TYPE_LINE)
2285 // chart_recompute(chart);
2286 }
2287
2288
2289 /*
2290 ** change the minor visibility
2291 */
2292 void gtk_chart_show_minor(GtkChart * chart, gboolean minor)
2293 {
2294 g_return_if_fail (GTK_IS_CHART (chart));
2295
2296 DB( g_print("\n[gtkchart] set show minor\n") );
2297
2298 chart->minor = minor;
2299
2300 if(chart->type != CHART_TYPE_PIE)
2301 gtk_chart_queue_redraw(chart);
2302
2303 }
2304
This page took 0.129459 seconds and 4 git commands to generate.