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