1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2018 Maxime DOYEN
4 * This file is part of HomeBank.
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.
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.
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/>.
27 #include "gtk-chart-colors.h"
28 #include "gtk-chart.h"
42 #define DBGDRAW_RECT 0
43 #define DBGDRAW_TEXT 0
44 #define DBGDRAW_ITEM 0
47 static void gtk_chart_class_intern_init (gpointer
);
48 static void gtk_chart_class_init (GtkChartClass
*klass
);
49 static void gtk_chart_init (GtkChart
*chart
);
50 static void gtk_chart_dispose (GObject
* object
);
51 static void gtk_chart_finalize (GObject
* object
);
53 static gboolean
drawarea_configure_event_callback(GtkWidget
*widget
, GdkEventConfigure
*event
, gpointer user_data
);
54 static void drawarea_realize_callback(GtkWidget
*widget
, gpointer user_data
);
55 static gboolean
drawarea_draw_callback(GtkWidget
*widget
, cairo_t
*wcr
, gpointer user_data
);
56 static gboolean
drawarea_motionnotifyevent_callback(GtkWidget
*widget
, GdkEventMotion
*event
, gpointer user_data
);
57 static gboolean
drawarea_querytooltip_callback(GtkWidget
*widget
, gint x
, gint y
, gboolean keyboard_mode
, GtkTooltip
*tooltip
, gpointer user_data
);
59 static gboolean
drawarea_full_redraw(GtkWidget
*widget
, gpointer user_data
);
61 static void chart_calculation(GtkChart
*chart
);
62 static void chart_clear(GtkChart
*chart
);
64 static void colchart_first_changed( GtkAdjustment
*adj
, gpointer user_data
);
65 static void colchart_compute_range(GtkChart
*chart
);
66 static void colchart_calculation(GtkChart
*chart
);
67 static void colchart_scrollbar_setvalues(GtkChart
*chart
);
69 static void piechart_calculation(GtkChart
*chart
);
74 static GtkBoxClass
*gtk_chart_parent_class
= NULL
;
76 static const double dashed3
[] = {3.0};
81 static GType chart_type
= 0;
85 static const GTypeInfo chart_info
=
87 sizeof (GtkChartClass
),
89 NULL
, /* base_finalize */
90 (GClassInitFunc
) gtk_chart_class_intern_init
,
91 NULL
, /* class_finalize */
92 NULL
, /* class_data */
95 (GInstanceInitFunc
) gtk_chart_init
,
99 chart_type
= g_type_register_static (GTK_TYPE_BOX
, "GtkChart",
107 gtk_chart_class_intern_init (gpointer klass
)
109 gtk_chart_parent_class
= g_type_class_peek_parent (klass
);
110 gtk_chart_class_init ((GtkChartClass
*) klass
);
114 gtk_chart_class_init (GtkChartClass
* class)
116 GObjectClass
*gobject_class
= G_OBJECT_CLASS (class);
117 //GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
119 DB( g_print("\n[gtkchart] class init\n") );
121 //gobject_class->get_property = gtk_chart_get_property;
122 //gobject_class->set_property = gtk_chart_set_property;
123 gobject_class
->dispose
= gtk_chart_dispose
;
124 gobject_class
->finalize
= gtk_chart_finalize
;
126 //widget_class->size_allocate = gtk_chart_size_allocate;
132 gtk_chart_init (GtkChart
* chart
)
134 GtkWidget
*widget
, *vbox
, *frame
;
136 DB( g_print("\n[gtkchart] init\n") );
139 chart
->surface
= NULL
;
147 chart
->usrbarw
= 0.0;
148 chart
->barw
= GTK_CHART_BARW
;
150 chart
->show_legend
= TRUE
;
151 chart
->show_legend_wide
= FALSE
;
152 chart
->show_mono
= FALSE
;
154 chart
->lastactive
= -1;
156 chart
->minor_rate
= 1.0;
157 chart
->timer_tag
= 0;
159 gtk_chart_set_color_scheme(chart
, CHART_COLMAP_HOMEBANK
);
161 widget
=GTK_WIDGET(chart
);
163 gtk_box_set_homogeneous(GTK_BOX(widget
), FALSE
);
165 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
166 gtk_box_pack_start (GTK_BOX (widget
), vbox
, TRUE
, TRUE
, 0);
169 frame
= gtk_frame_new(NULL
);
170 gtk_frame_set_shadow_type (GTK_FRAME(frame
), GTK_SHADOW_ETCHED_IN
);
171 gtk_box_pack_start (GTK_BOX (vbox
), frame
, TRUE
, TRUE
, 0);
173 chart
->drawarea
= gtk_drawing_area_new();
174 //gtk_widget_set_double_buffered (GTK_WIDGET(widget), FALSE);
176 gtk_container_add( GTK_CONTAINER(frame
), chart
->drawarea
);
177 gtk_widget_set_size_request(chart
->drawarea
, 100, 100 );
179 gtk_widget_set_has_tooltip(chart
->drawarea
, TRUE
);
181 gtk_widget_show(chart
->drawarea
);
185 PangoFontDescription *font_desc;
187 g_print("draw_area font\n");
189 style = gtk_widget_get_style(GTK_WIDGET(chart->drawarea));
190 font_desc = style->font_desc;
192 g_print("family: %s\n", pango_font_description_get_family(font_desc) );
193 g_print("size: %d (%d)\n", pango_font_description_get_size (font_desc), pango_font_description_get_size (font_desc )/PANGO_SCALE );
198 chart
->adjustment
= GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 1.0, 1.0, 1.0, 1.0));
199 chart
->scrollbar
= gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL
, GTK_ADJUSTMENT (chart
->adjustment
));
200 gtk_box_pack_start (GTK_BOX (vbox
), chart
->scrollbar
, FALSE
, TRUE
, 0);
201 gtk_widget_show(chart
->scrollbar
);
203 g_signal_connect( G_OBJECT(chart
->drawarea
), "configure-event", G_CALLBACK (drawarea_configure_event_callback
), chart
);
204 g_signal_connect( G_OBJECT(chart
->drawarea
), "realize", G_CALLBACK(drawarea_realize_callback
), chart
) ;
205 g_signal_connect( G_OBJECT(chart
->drawarea
), "draw", G_CALLBACK(drawarea_draw_callback
), chart
) ;
208 gtk_widget_add_events(GTK_WIDGET(chart
->drawarea
),
210 //GDK_POINTER_MOTION_MASK |
211 GDK_POINTER_MOTION_HINT_MASK
212 //GDK_BUTTON_PRESS_MASK |
213 //GDK_BUTTON_RELEASE_MASK
216 g_signal_connect( G_OBJECT(chart
->drawarea
), "query-tooltip", G_CALLBACK(drawarea_querytooltip_callback
), chart
);
217 g_signal_connect( G_OBJECT(chart
->drawarea
), "motion-notify-event", G_CALLBACK(drawarea_motionnotifyevent_callback
), chart
);
219 g_signal_connect (G_OBJECT(chart
->adjustment
), "value-changed", G_CALLBACK (colchart_first_changed
), chart
);
221 //g_signal_connect( G_OBJECT(chart->drawarea), "map-event", G_CALLBACK(chart_map), chart ) ;
222 //g_signal_connect( G_OBJECT(chart->drawarea), "button-press-event", G_CALLBACK(chart_button_press), chart );
223 //g_signal_connect( G_OBJECT(chart->drawarea), "button-release-event", G_CALLBACK(chart_button_release), chart );
230 gtk_chart_new (gint type
)
234 DB( g_print("\n======================================================\n") );
235 DB( g_print("\n[gtkchart] new\n") );
237 chart
= g_object_new (GTK_TYPE_CHART
, NULL
);
240 return GTK_WIDGET(chart
);
245 gtk_chart_dispose (GObject
*gobject
)
247 //GtkChart *chart = GTK_CHART (object);
249 DB( g_print("\n[gtkchart] dispose\n") );
251 /* In dispose(), you are supposed to free all types referenced from this
252 * object which might themselves hold a reference to self. Generally,
253 * the most simple solution is to unref all members on which you own a
257 /* dispose() might be called multiple times, so we must guard against
258 * calling g_object_unref() on an invalid GObject by setting the member
259 * NULL; g_clear_object() does this for us, atomically.
261 //g_clear_object (&self->priv->an_object);
263 /* Always chain up to the parent class; there is no need to check if
264 * the parent class implements the dispose() virtual function: it is
265 * always guaranteed to do so
267 G_OBJECT_CLASS (gtk_chart_parent_class
)->dispose (gobject
);
272 gtk_chart_finalize (GObject
* object
)
274 GtkChart
*chart
= GTK_CHART (object
);
276 DB( g_print("\n[gtkchart] finalize\n") );
282 pango_font_description_free (chart
->pfd
);
288 cairo_surface_destroy (chart
->surface
);
289 chart
->surface
= NULL
;
292 G_OBJECT_CLASS (gtk_chart_parent_class
)->finalize (object
);
297 ** print a integer number
299 static gchar
*chart_print_int(GtkChart
*chart
, gint value
)
301 hb_strfmon_int(chart
->buffer1
, CHART_BUFFER_LENGTH
-1, (gdouble
)value
, chart
->kcur
, chart
->minor
);
302 return chart
->buffer1
;
307 ** print a rate number
309 static gchar
*chart_print_rate(GtkChart
*chart
, gdouble value
)
311 g_snprintf (chart
->buffer1
, CHART_BUFFER_LENGTH
-1, "%.2f%%", value
);
312 return chart
->buffer1
;
317 ** print a double number
319 static gchar
*chart_print_double(GtkChart
*chart
, gchar
*buffer
, gdouble value
)
321 hb_strfmon(buffer
, CHART_BUFFER_LENGTH
-1, value
, chart
->kcur
, chart
->minor
);
327 ** clear any allocated memory
329 static void chart_clear(GtkChart
*chart
)
333 DB( g_print("\n[gtkchart] clear\n") );
335 //free & clear any previous allocated datas
336 if(chart
->title
!= NULL
)
338 g_free(chart
->title
);
342 if(chart
->subtitle
!= NULL
)
344 g_free(chart
->subtitle
);
345 chart
->subtitle
= NULL
;
348 if(chart
->items
!= NULL
)
350 for(i
=0;i
<chart
->nb_items
;i
++)
352 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
354 g_free(item
->label
); //we free label as it comes from a model_get into setup_with_model
355 g_free(item
->legend
);
357 g_array_free(chart
->items
, TRUE
);
367 chart
->every_xval
= 7;
370 chart
->lastactive
= -1;
376 ** setup our chart with a model and column
378 static void chart_setup_with_model(GtkChart
*chart
, GtkTreeModel
*list_store
, guint column1
, guint column2
)
384 DB( g_print("\n[chart] setup with model\n") );
388 chart
->nb_items
= gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store
), NULL
);
390 chart
->items
= g_array_sized_new(FALSE
, FALSE
, sizeof(ChartItem
), chart
->nb_items
);
392 DB( g_print(" nb=%d, struct=%d\n", chart
->nb_items
, sizeof(ChartItem
)) );
394 chart
->dual
= (column1
== column2
) ? FALSE
: TRUE
;
396 /* Get the first iter in the list */
397 valid
= gtk_tree_model_get_iter_first (GTK_TREE_MODEL(list_store
), &iter
);
403 gdouble value1
, value2
;
406 /* column 0: pos (gint) */
407 /* column 1: key (gint) */
408 /* column 2: label (gchar) */
409 /* column x: values (double) */
411 gtk_tree_model_get (GTK_TREE_MODEL(list_store
), &iter
,
418 if(chart
->dual
|| chart
->abs
)
420 value1
= ABS(value1
);
421 value2
= ABS(value2
);
424 DB( g_print("%d: '%s' %.2f %2f\n", i
, label
, value1
, value2
) );
426 /* data1 value storage & min, max compute */
427 chart
->rawmin
= MIN(chart
->rawmin
, value1
);
428 chart
->rawmax
= MAX(chart
->rawmax
, value1
);
432 /* data2 value storage & min, max compute */
433 chart
->rawmin
= MIN(chart
->rawmin
, value2
);
434 chart
->rawmax
= MAX(chart
->rawmax
, value2
);
438 item
.serie1
= value1
;
439 item
.serie2
= value2
;
440 g_array_append_vals(chart
->items
, &item
, 1);
442 /* ensure rawmin rawmax not equal */
443 if(chart
->rawmin
== chart
->rawmax
)
449 /* pie chart total sum */
450 chart
->total
+= ABS(value1
);
453 //don't g_free(label); here done into chart_clear
455 valid
= gtk_tree_model_iter_next (list_store
, &iter
);
459 // compute rate for legend for bar/pie
460 for(i
=0;i
<chart
->nb_items
;i
++)
462 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
465 strval
= chart_print_double(chart
, chart
->buffer1
, item
->serie1
);
466 item
->rate
= ABS(item
->serie1
*100/chart
->total
);
467 item
->legend
= g_markup_printf_escaped("%s\n%s (%.f%%)", item
->label
, strval
, item
->rate
);
470 //g_print("total is %.2f\n", total);
471 //ensure the widget is mapped
472 //gtk_widget_map(chart);
477 static void chart_set_font_size(GtkChart
*chart
, PangoLayout
*layout
, gint font_size
)
481 //TODO: use PANGO_SCALE INSTEAD
483 //DB( g_print("\n[chart] set font size\n") );
487 case CHART_FONT_SIZE_TITLE
:
488 size
= chart
->pfd_size
+ 3;
490 case CHART_FONT_SIZE_SUBTITLE
:
491 size
= chart
->pfd_size
+ 1;
493 case CHART_FONT_SIZE_NORMAL
:
494 size
= chart
->pfd_size
- 1;
496 case CHART_FONT_SIZE_SMALL
:
497 size
= chart
->pfd_size
- 2;
501 //DB( g_print(" size=%d\n", size) );
503 pango_font_description_set_size(chart
->pfd
, size
* PANGO_SCALE
);
505 pango_layout_set_font_description (layout
, chart
->pfd
);
511 ** recompute according to type
513 static void chart_recompute(GtkChart
*chart
)
516 DB( g_print("\n[gtkchart] recompute\n") );
519 if( !gtk_widget_get_realized(chart
->drawarea
) || chart
->surface
== NULL
)
522 chart_calculation (chart
);
526 case CHART_TYPE_LINE
:
528 colchart_calculation(chart
);
529 gtk_adjustment_set_value(chart
->adjustment
, 0);
530 colchart_scrollbar_setvalues(chart
);
531 gtk_widget_show(chart
->scrollbar
);
534 piechart_calculation(chart
);
535 gtk_widget_hide(chart
->scrollbar
);
546 static float CalculateStepSize(float range
, float targetSteps
)
548 // calculate an initial guess at step size
549 float tempStep
= range
/targetSteps
;
551 // get the magnitude of the step size
552 float mag
= (float)floor(log10(tempStep
));
553 float magPow
= (float)pow(10, mag
);
555 // calculate most significant digit of the new step size
556 float magMsd
= (int)(tempStep
/magPow
+ 0.5);
558 // promote the MSD to either 1, 2, or 5
561 else if (magMsd
> 2.0)
563 else if (magMsd
>= 1.0)
566 return magMsd
*magPow
;
570 static void colchart_compute_range(GtkChart
*chart
)
572 double lobound
=chart
->rawmin
, hibound
=chart
->rawmax
;
574 DB( g_print("\n[column] compute range\n") );
576 /* comptute max ticks */
577 chart
->range
= chart
->rawmax
- chart
->rawmin
;
578 gint maxticks
= MIN(10,floor(chart
->graph
.height
/ (chart
->font_h
* 2)));
580 DB( g_print(" raw :: [%.2f - %.2f] range=%.2f\n", chart
->rawmin
, chart
->rawmax
, chart
->range
) );
581 DB( g_print(" raw :: maxticks=%d (%g / (%g*2))\n", maxticks
, chart
->graph
.height
, chart
->font_h
) );
584 chart
->unit
= CalculateStepSize((hibound
-lobound
), maxticks
);
585 chart
->min
= -chart
->unit
* ceil(-lobound
/chart
->unit
);
586 chart
->max
= chart
->unit
* ceil(hibound
/chart
->unit
);
587 chart
->range
= chart
->max
- chart
->min
;
588 chart
->div
= chart
->range
/ chart
->unit
;
590 DB( g_print(" end :: interval=%.2f, ticks=%d\n", chart
->unit
, chart
->div
) );
591 DB( g_print(" end :: [%.2f - %.2f], range=%.2f\n", chart
->min
, chart
->max
, chart
->range
) );
596 static void chart_calculation(GtkChart
*chart
)
598 GtkWidget
*drawarea
= chart
->drawarea
;
599 GdkWindow
*gdkwindow
;
600 cairo_surface_t
*surf
= NULL
;
603 GtkAllocation allocation
;
609 DB( g_print("\n[gtkchart] calculation\n") );
611 gtk_widget_get_allocation(drawarea
, &allocation
);
613 chart
->l
= CHART_MARGIN
;
614 chart
->t
= CHART_MARGIN
;
615 chart
->r
= allocation
.width
- CHART_MARGIN
;
616 chart
->b
= allocation
.height
- CHART_MARGIN
;
617 chart
->w
= allocation
.width
- (CHART_MARGIN
*2);
618 chart
->h
= allocation
.height
- (CHART_MARGIN
*2);
620 gdkwindow
= gtk_widget_get_window(chart
->drawarea
);
623 surf
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, allocation
.width
, allocation
.height
);
624 cr
= cairo_create (surf
);
627 cr
= gdk_cairo_create (gdkwindow
);
629 /* Create a PangoLayout, set the font and text */
630 layout
= pango_cairo_create_layout (cr
);
635 if(chart
->title
!= NULL
)
637 chart_set_font_size(chart
, layout
, CHART_FONT_SIZE_TITLE
);
638 pango_layout_set_text (layout
, chart
->title
, -1);
639 pango_layout_get_size (layout
, &tw
, &th
);
640 chart
->title_zh
= (th
/ PANGO_SCALE
);
641 DB( g_print(" - title: %s w=%d h=%d\n", chart
->title
, tw
, th
) );
645 chart
->subtitle_zh
= 0;
646 if(chart
->subtitle
!= NULL
)
648 chart_set_font_size(chart
, layout
, CHART_FONT_SIZE_SUBTITLE
);
649 pango_layout_set_text (layout
, chart
->subtitle
, -1);
650 pango_layout_get_size (layout
, &tw
, &th
);
651 chart
->subtitle_zh
= (th
/ PANGO_SCALE
);
652 DB( g_print(" - title: %s w=%d h=%d\n", chart
->subtitle
, tw
, th
) );
654 chart
->subtitle_y
= chart
->t
+ chart
->title_zh
;
657 chart
->graph
.y
= chart
->t
+ chart
->title_zh
+ chart
->subtitle_zh
;
658 chart
->graph
.height
= chart
->h
- chart
->title_zh
- chart
->subtitle_zh
;
660 if(chart
->title_zh
> 0 || chart
->subtitle_zh
> 0)
662 chart
->graph
.y
+= CHART_MARGIN
;
663 chart
->graph
.height
-= CHART_MARGIN
;
667 // compute other text
668 chart_set_font_size(chart
, layout
, CHART_FONT_SIZE_NORMAL
);
670 // y-axis labels (amounts)
672 colchart_compute_range(chart
);
674 valstr
= chart_print_int(chart
, (gint
)chart
->min
);
675 pango_layout_set_text (layout
, valstr
, -1);
676 pango_layout_get_size (layout
, &tw
, &th
);
677 chart
->scale_w
= (tw
/ PANGO_SCALE
);
679 valstr
= chart_print_int(chart
, (gint
)chart
->max
);
680 pango_layout_set_text (layout
, valstr
, -1);
681 pango_layout_get_size (layout
, &tw
, &th
);
682 chart
->scale_w
= MAX(chart
->scale_w
, (tw
/ PANGO_SCALE
));
684 DB( g_print(" - scale: %d,%d %g,%g\n", chart
->l
, 0, chart
->scale_w
, 0.0) );
686 // todo: compute maxwidth of item labels
688 for(i
=0;i
<chart
->nb_items
;i
++)
690 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
693 pango_layout_set_text (layout
, item
->label
, -1);
694 pango_layout_get_size (layout
, &tw
, &th
);
695 label_w
= MAX(label_w
, (tw
/ PANGO_SCALE
));
697 chart
->label_w
= label_w
;
699 // compute font height
700 chart
->font_h
= (th
/ PANGO_SCALE
);
702 // compute graph region
705 case CHART_TYPE_LINE
:
707 chart
->graph
.x
= chart
->l
+ chart
->scale_w
+ 2;
708 chart
->graph
.width
= chart
->w
- chart
->scale_w
- 2;
711 chart
->graph
.x
= chart
->l
;
712 chart
->graph
.width
= chart
->w
;
716 DB( g_print(" - graph : %g,%g %g,%g\n", chart
->graph
.x
, chart
->graph
.y
, chart
->graph
.width
, chart
->graph
.height
) );
719 if( ((chart
->type
== CHART_TYPE_LINE
) || (chart
->type
== CHART_TYPE_COL
)) && chart
->show_xval
)
720 chart
->graph
.height
-= (chart
->font_h
+ CHART_SPACING
);
722 // compute: each legend column width, and legend width
723 if(chart
->show_legend
)
725 chart_set_font_size(chart
, layout
, CHART_FONT_SIZE_SMALL
);
727 //we compute the rate text here to get the font height
728 pango_layout_set_text (layout
, "00.00 %", -1);
729 pango_layout_get_size (layout
, &tw
, &th
);
731 chart
->legend_font_h
= (th
/ PANGO_SCALE
);
733 // labels not much than 1/4 of graph
734 gdouble lw
= floor(chart
->graph
.width
/ 4);
735 chart
->legend_label_w
= MIN(chart
->label_w
, lw
);
737 chart
->legend
.width
= chart
->legend_font_h
+ CHART_SPACING
+ chart
->legend_label_w
;
738 chart
->legend
.height
= MIN(floor(chart
->nb_items
* chart
->legend_font_h
* CHART_LINE_SPACING
), chart
->graph
.height
);
740 if(chart
->show_legend_wide
)
742 chart
->legend_value_w
= chart
->scale_w
;
743 chart
->legend_rate_w
= (tw
/ PANGO_SCALE
);
744 chart
->legend
.width
+= CHART_SPACING
+ chart
->legend_value_w
+ CHART_SPACING
+ chart
->legend_rate_w
;
747 //if legend visible, substract
748 chart
->graph
.width
-= (chart
->legend
.width
+ CHART_MARGIN
);
750 chart
->legend
.x
= chart
->graph
.x
+ chart
->graph
.width
+ CHART_MARGIN
;
751 chart
->legend
.y
= chart
->graph
.y
;
753 DB( g_print(" - graph : %g %g %g %g\n", chart
->graph
.x
, chart
->graph
.y
, chart
->graph
.width
, chart
->graph
.height
) );
754 DB( g_print(" - legend: %g %g %g %g\n", chart
->legend
.x
, chart
->legend
.y
, chart
->legend
.width
, chart
->legend
.height
) );
757 g_object_unref (layout
);
760 cairo_surface_destroy(surf
);
764 static void colchart_calculation(GtkChart
*chart
)
768 DB( g_print("\n[column] calculation\n") );
771 the bar has a default width of 41
772 min space is 3 and min barw is 8
776 if( chart
->usrbarw
> 0.0 )
778 blkw
= chart
->usrbarw
;
779 chart
->barw
= blkw
- 3;
783 //minvisi = floor(chart->graph.width / (GTK_CHART_MINBARW+3) );
784 maxvisi
= floor(chart
->graph
.width
/ (GTK_CHART_MAXBARW
+3) );
786 DB( g_print(" width=%.2f, nb=%d, minvisi=%d, maxvisi=%d\n", chart
->graph
.width
, chart
->nb_items
, minvisi
, maxvisi
) );
788 if( chart
->nb_items
<= maxvisi
)
790 chart
->barw
= GTK_CHART_MAXBARW
;
791 blkw
= GTK_CHART_MAXBARW
+ ( chart
->graph
.width
- (chart
->nb_items
*GTK_CHART_MAXBARW
) ) / chart
->nb_items
;
795 blkw
= MAX(GTK_CHART_MINBARW
, floor(chart
->graph
.width
/ chart
->nb_items
));
796 chart
->barw
= blkw
- 3;
801 chart
->barw
= chart
->barw
/ 2;
803 DB( g_print(" blkw=%d, barw=%2.f\n", blkw
, chart
->barw
) );
807 chart
->visible
= chart
->graph
.width
/ blkw
;
808 chart
->visible
= MIN(chart
->visible
, chart
->nb_items
);
810 chart
->ox
= chart
->l
;
811 chart
->oy
= chart
->b
;
813 chart
->oy
= floor(chart
->graph
.y
+ (chart
->max
/chart
->range
) * chart
->graph
.height
);
815 DB( g_print(" + ox=%f oy=%f\n", chart
->ox
, chart
->oy
) );
817 /* todo: hack on every xval */
818 if(chart
->label_w
> 0 && chart
->visible
> 0)
820 if( chart
->label_w
<= chart
->blkw
)
821 chart
->every_xval
= 1;
823 chart
->every_xval
= floor( 0.5 + (chart
->label_w
+ CHART_SPACING
) / chart
->blkw
);
825 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
) );
833 static void colchart_draw_scale(GtkWidget
*widget
, gpointer user_data
)
835 GtkChart
*chart
= GTK_CHART(user_data
);
845 DB( g_print("\n[column] draw scale\n") );
847 cr
= cairo_create (chart
->surface
);
848 layout
= pango_cairo_create_layout (cr
);
849 chart_set_font_size(chart
, layout
, CHART_FONT_SIZE_NORMAL
);
850 cairo_set_line_width (cr
, 1);
853 //cairo_rectangle(cr, CHART_MARGIN, 0, chart->w, chart->h + CHART_MARGIN);
856 // Y-scale lines + labels (amounts)
857 curxval
= chart
->max
;
858 cairo_set_dash(cr
, 0, 0, 0);
859 for(i
=0 ; i
<=chart
->div
; i
++)
861 y
= 0.5 + floor (chart
->graph
.y
+ ((i
* chart
->unit
) / chart
->range
) * chart
->graph
.height
);
862 //DB( g_print(" + i=%d :: y=%f (%f / %f) * %f\n", i, y, i*chart->unit, chart->range, chart->graph.height) );
864 // curxval = 0.0 is x-axis
865 cairo_user_set_rgbacol (cr
, &global_colors
[THTEXT
], ( curxval
== 0.0 ) ? 0.8 : 0.1);
866 cairo_move_to (cr
, chart
->graph
.x
, y
);
867 cairo_line_to (cr
, chart
->graph
.x
+ chart
->graph
.width
, y
);
870 cairo_user_set_rgbacol (cr
, &global_colors
[THTEXT
], 0.78);
871 valstr
= chart_print_int(chart
, (gint
)curxval
);
872 pango_layout_set_text (layout
, valstr
, -1);
873 pango_layout_get_size (layout
, &tw
, &th
);
874 cairo_move_to (cr
, chart
->graph
.x
- (tw
/ PANGO_SCALE
) - 2, y
- ((th
/ PANGO_SCALE
)*0.8) );
875 pango_cairo_show_layout (cr
, layout
);
877 curxval
-= chart
->unit
;
880 // X-scale lines + labels (items)
881 if(chart
->show_xval
&& chart
->every_xval
> 0 )
883 x
= chart
->graph
.x
+ (chart
->blkw
/2);
884 y
= chart
->b
- chart
->font_h
;
885 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
887 cairo_set_dash(cr
, dashed3
, 1, 0);
889 for(i
=first
; i
<(first
+chart
->visible
) ; i
++)
891 if( !(i
% chart
->every_xval
) )
893 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
895 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.1);
896 cairo_move_to(cr
, x
, chart
->graph
.y
);
897 cairo_line_to(cr
, x
, chart
->b
- chart
->font_h
);
900 valstr
= item
->label
;
901 pango_layout_set_text (layout
, valstr
, -1);
902 pango_layout_get_size (layout
, &tw
, &th
);
903 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.78);
904 cairo_move_to(cr
, x
- ((tw
/ PANGO_SCALE
)/2), y
);
905 pango_cairo_show_layout (cr
, layout
);
911 g_object_unref (layout
);
917 ** draw all visible bars
919 static void colchart_draw_bars(GtkWidget
*widget
, gpointer user_data
)
921 GtkChart
*chart
= GTK_CHART(user_data
);
926 DB( g_print("\n[column] draw bars\n") );
929 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
931 cr
= gdk_cairo_create (gtk_widget_get_window(widget
));
932 //cr = cairo_create (chart->surface);
934 DB( g_print(" x=%.2f first=%d, blkw=%.2f, barw=%.2f\n", x
, first
, chart
->blkw
, chart
->barw
) );
936 #if DBGDRAW_ITEM == 1
938 cairo_set_line_width(cr
, 1.0);
941 cairo_set_dash (cr
, &dashlength
, 1, 0);
942 cairo_set_source_rgb(cr
, 1.0, 0.0, 1.0); // violet
943 for(i
=first
; i
<=(first
+chart
->visible
) ;i
++)
945 cairo_move_to(cr
, x2
, chart
->graph
.y
);
946 cairo_line_to(cr
, x2
, chart
->graph
.x
+ chart
->graph
.height
);
950 cairo_set_dash (cr
, &dashlength
, 0, 0);
953 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
955 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
957 gint barw
= chart
->barw
;
959 //if(!chart->datas1[i]) goto nextbar;
961 if(!chart
->show_mono
)
962 color
= i
% chart
->color_scheme
.nb_cols
;
964 color
= chart
->color_scheme
.cs_green
;
966 cairo_user_set_rgbcol_over(cr
, &chart
->color_scheme
.colors
[color
], i
== chart
->active
);
968 x2
= x
+ (chart
->blkw
/2) - 1;
969 x2
= !chart
->dual
? x2
- (barw
/2) : x2
- barw
- 1;
973 h
= floor((item
->serie1
/ chart
->range
) * chart
->graph
.height
);
975 if(item
->serie1
< 0.0)
980 color
= chart
->color_scheme
.cs_red
;
981 cairo_user_set_rgbcol_over(cr
, &chart
->color_scheme
.colors
[color
], i
== chart
->active
);
984 //DB( g_print(" + i=%d :: y2=%f h=%f (%f / %f) * %f\n", i, y2, h, chart->datas1[i], chart->range, chart->graph.height ) );
986 cairo_rectangle(cr
, x2
+2, y2
, barw
, h
);
991 if( chart
->dual
&& item
->serie2
)
994 h
= floor((item
->serie2
/ chart
->range
) * chart
->graph
.height
);
997 cairo_rectangle(cr
, x2
+2, y2
, barw
, h
);
1005 //gdk_draw_line (widget->window, widget->style->fg_gc[widget->state], x, chart->oy-chart->posbarh, x, chart->oy+chart->negbarh);
1014 ** get the bar under the mouse pointer
1016 static gint
colchart_get_active(GtkWidget
*widget
, gint x
, gint y
, gpointer user_data
)
1018 GtkChart
*chart
= GTK_CHART(user_data
);
1020 gint index
, first
, px
;
1024 if( x
<= chart
->r
&& x
>= chart
->graph
.x
&& y
>= chart
->graph
.y
&& y
<= chart
->b
)
1026 px
= (x
- chart
->graph
.x
);
1027 //py = (y - chart->oy);
1028 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1029 index
= first
+ (px
/ chart
->blkw
);
1031 if(index
< chart
->nb_items
)
1038 static void colchart_first_changed( GtkAdjustment
*adj
, gpointer user_data
)
1040 GtkChart
*chart
= GTK_CHART(user_data
);
1043 DB( g_print("\n[column] first changed\n") );
1045 //first = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj));
1047 //DB( g_print(" first=%d\n", first) );
1050 DB( g_print("scrollbar\n adj=%8x, low=%.2f upp=%.2f val=%.2f step=%.2f page=%.2f size=%.2f\n", adj,
1051 adj->lower, adj->upper, adj->value, adj->step_increment, adj->page_increment, adj->page_size) );
1053 /* Set the number of decimal places to which adj->value is rounded */
1054 //gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
1055 //gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
1057 drawarea_full_redraw (chart
->drawarea
, chart
);
1059 DB( g_print("gtk_widget_queue_draw\n") );
1060 gtk_widget_queue_draw(chart
->drawarea
);
1065 ** scrollbar set values for upper, page size, and also show/hide
1067 static void colchart_scrollbar_setvalues(GtkChart
*chart
)
1069 GtkAdjustment
*adj
= chart
->adjustment
;
1072 g_return_if_fail (GTK_IS_ADJUSTMENT (adj
));
1074 DB( g_print("\n[column] sb_set_values\n") );
1076 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(adj
));
1078 DB( g_print(" entries=%d, visible=%d\n", chart
->nb_items
, chart
->visible
) );
1079 DB( g_print(" first=%d, upper=%d, pagesize=%d\n", first
, chart
->nb_items
, chart
->visible
) );
1081 gtk_adjustment_set_upper(adj
, (gdouble
)chart
->nb_items
);
1082 gtk_adjustment_set_page_size(adj
, (gdouble
)chart
->visible
);
1083 gtk_adjustment_set_page_increment(adj
, (gdouble
)chart
->visible
);
1085 if(first
+chart
->visible
> chart
->nb_items
)
1087 gtk_adjustment_set_value(adj
, (gdouble
)chart
->nb_items
- chart
->visible
);
1089 gtk_adjustment_changed (adj
);
1091 if( chart
->visible
< chart
->nb_items
)
1092 gtk_widget_hide(GTK_WIDGET(chart
->scrollbar
));
1094 gtk_widget_show(GTK_WIDGET(chart
->scrollbar
));
1101 ** draw all visible lines
1103 static void linechart_draw_plot(cairo_t
*cr
, double x
, double y
, double r
, GtkChart
*chart
)
1105 cairo_set_line_width(cr
, r
/ 2);
1107 cairo_user_set_rgbcol(cr
, &global_colors
[THBASE
]);
1108 cairo_arc(cr
, x
, y
, r
, 0, 2*M_PI
);
1109 cairo_stroke_preserve(cr
);
1111 //cairo_set_source_rgb(cr, COLTOCAIRO(0), COLTOCAIRO(119), COLTOCAIRO(204));
1112 cairo_user_set_rgbcol(cr
, &chart
->color_scheme
.colors
[chart
->color_scheme
.cs_blue
]);
1117 static void linechart_draw_lines(GtkWidget
*widget
, gpointer user_data
)
1119 GtkChart
*chart
= GTK_CHART(user_data
);
1121 double x
, y
, x2
, y2
, firstx
, lastx
, linew
;
1125 DB( g_print("\n[line] draw lines\n") );
1129 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1131 cr
= gdk_cairo_create (gtk_widget_get_window(widget
));
1132 //cr = cairo_create (chart->surface);
1135 //cairo_rectangle(cr, CHART_MARGIN, 0, chart->w, chart->h + CHART_MARGIN);
1139 #if DBGDRAW_ITEM == 1
1141 cairo_set_line_width(cr
, 1.0);
1142 double dashlength
= 4;
1143 cairo_set_dash (cr
, &dashlength
, 1, 0);
1144 cairo_set_source_rgb(cr
, 1.0, 0.0, 1.0); // violet
1145 for(i
=first
; i
<=(first
+chart
->visible
) ;i
++)
1147 cairo_move_to(cr
, x2
, chart
->graph
.y
);
1148 cairo_line_to(cr
, x2
, chart
->graph
.x
+ chart
->graph
.height
);
1153 cairo_set_dash (cr
, &dashlength
, 0, 0);
1156 //todo: it should be possible to draw line & plot together using surface and composite fill, or sub path ??
1160 if(chart
->barw
< 24)
1162 linew
= 1 + (chart
->barw
/ 8.0);
1165 cairo_set_line_join(cr
, CAIRO_LINE_JOIN_BEVEL
);
1166 cairo_set_line_width(cr
, linew
);
1168 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
1170 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
1172 x2
= x
+ (chart
->blkw
)/2;
1173 y2
= chart
->oy
- (item
->serie1
/ chart
->range
) * chart
->graph
.height
;
1177 cairo_move_to(cr
, x2
, y2
);
1181 if( i
< (chart
->nb_items
) )
1183 cairo_line_to(cr
, x2
, y2
);
1187 lastx
= x2
- chart
->barw
;
1193 cairo_user_set_rgbcol(cr
, &chart
->color_scheme
.colors
[chart
->color_scheme
.cs_blue
]);
1194 cairo_stroke_preserve(cr
);
1196 cairo_line_to(cr
, lastx
, y
);
1197 cairo_line_to(cr
, firstx
, y
);
1198 cairo_close_path(cr
);
1200 cairo_user_set_rgbacol(cr
, &chart
->color_scheme
.colors
[chart
->color_scheme
.cs_blue
], AREA_ALPHA
);
1205 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1208 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
1210 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
1212 x2
= x
+ (chart
->blkw
)/2;
1213 y2
= chart
->oy
- (item
->serie1
/ chart
->range
) * chart
->graph
.height
;
1215 //test draw vertical selection line
1216 if( i
== chart
->active
)
1218 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.1);
1220 //cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); //blue
1221 cairo_set_line_width(cr
, 1.0);
1222 cairo_move_to(cr
, x2
, chart
->graph
.y
);
1223 cairo_line_to(cr
, x2
, chart
->b
- chart
->font_h
);
1228 linechart_draw_plot(cr
, x2
, y2
, i
== chart
->active
? linew
+1 : linew
, chart
);
1236 DB( g_print(" min=%.2f range=%.2f\n", chart
->min
, chart
->range
) );
1239 if( chart
->show_over
)
1241 //if(chart->minimum != 0 && chart->minimum >= chart->min)
1242 if(chart
->minimum
>= chart
->min
)
1244 if( chart
->minimum
< 0 )
1246 y
= 0.5 + chart
->oy
+ (ABS(chart
->minimum
)/chart
->range
) * chart
->graph
.height
;
1250 y
= 0.5 + chart
->oy
- (ABS(chart
->minimum
)/chart
->range
) * chart
->graph
.height
;
1253 y2
= (ABS(chart
->min
)/chart
->range
) * chart
->graph
.height
- (y
- chart
->oy
) + 1;
1255 cairo_set_source_rgba(cr
, COLTOCAIRO(255), COLTOCAIRO(0), COLTOCAIRO(0), AREA_ALPHA
/ 2);
1257 DB( g_print(" draw over: x%d, y%f, w%d, h%f\n", chart
->l
, y
, chart
->w
, y2
) );
1259 cairo_rectangle(cr
, chart
->graph
.x
, y
, chart
->graph
.width
, y2
);
1262 cairo_set_line_width(cr
, 1.0);
1263 cairo_set_source_rgb(cr
, COLTOCAIRO(255), COLTOCAIRO(0), COLTOCAIRO(0));
1265 cairo_set_dash (cr
, dashed3
, 1, 0);
1266 cairo_move_to(cr
, chart
->graph
.x
, y
);
1267 cairo_line_to (cr
, chart
->graph
.x
+ chart
->graph
.width
, y
);
1281 ** get the point under the mouse pointer
1283 static gint
linechart_get_active(GtkWidget
*widget
, gint x
, gint y
, gpointer user_data
)
1285 GtkChart
*chart
= GTK_CHART(user_data
);
1287 gint first
, index
, px
;
1289 DB( g_print("\n[line] get active\n") );
1293 if( x
<= chart
->r
&& x
>= chart
->graph
.x
&& y
>= chart
->graph
.y
&& y
<= chart
->b
)
1295 px
= (x
- chart
->graph
.x
);
1296 //py = (y - chart->oy);
1297 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1298 index
= first
+ (px
/ (chart
->blkw
));
1300 if(index
< chart
->nb_items
)
1310 static void piechart_calculation(GtkChart
*chart
)
1312 //GtkWidget *drawarea = chart->drawarea;
1315 DB( g_print("\n[pie] calculation\n") );
1317 w
= chart
->graph
.width
;
1318 h
= chart
->graph
.height
;
1320 chart
->rayon
= MIN(w
, h
);
1323 #if CHART_PARAM_PIE_MARK == TRUE
1324 gint m
= floor(chart
->rayon
/ 100);
1326 chart
->rayon
-= (m
* 2);
1330 chart
->ox
= chart
->graph
.x
+ (w
/ 2);
1331 chart
->oy
= chart
->graph
.y
+ (chart
->rayon
/ 2);
1333 DB( g_print(" center: %g, %g - R=%d, mark=%d\n", chart
->ox
, chart
->oy
, chart
->rayon
, chart
->mark
) );
1338 static void piechart_draw_slices(GtkWidget
*widget
, gpointer user_data
)
1340 GtkChart
*chart
= GTK_CHART(user_data
);
1343 if(chart
->nb_items
<= 0)
1346 DB( g_print("\n[pie] draw slices\n") );
1351 double a1
= 0 * (M_PI
/ 180);
1352 double a2
= 360 * (M_PI
/ 180);
1354 //g_print("angle1=%.2f angle2=%.2f\n", a1, a2);
1356 double cx
= chart
->ox
;
1357 double cy
= chart
->oy
;
1358 double radius
= chart
->rayon
/2;
1364 cr
= gdk_cairo_create (gtk_widget_get_window(widget
));
1365 //cr = cairo_create (chart->surface);
1367 DB( g_print("rayon=%d\n", chart
->rayon
) );
1369 for(i
=0; i
< chart
->nb_items
;i
++)
1371 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
1373 a1
= ((360 * (sum
/ chart
->total
)) - 90) * (M_PI
/ 180);
1374 sum
+= ABS(item
->serie1
);
1375 a2
= ((360 * (sum
/ chart
->total
)) - 90) * (M_PI
/ 180);
1376 //if(i < chart->nb_items-1) a2 += 0.0175;
1381 cairo_move_to(cr
, dx
, dy
);
1382 cairo_arc(cr
, dx
, dy
, radius
, a1
, a2
);
1384 #if CHART_PARAM_PIE_LINE == TRUE
1385 cairo_set_line_width(cr
, 2.0);
1386 cairo_set_source_rgb(cr
, 1.0, 1.0, 1.0);
1387 cairo_line_to(cr
, cx
, cy
);
1388 cairo_stroke_preserve(cr
);
1391 DB( g_print("- s%2d: %.2f%% a1=%.2f a2=%.2f\n", i
, sum
/ chart
->total
, a1
, a2
) );
1393 //g_print("color : %f %f %f\n", COLTOCAIRO(colors[i].r), COLTOCAIRO(colors[i].g), COLTOCAIRO(colors[i].b));
1395 color
= i
% chart
->color_scheme
.nb_cols
;
1396 cairo_user_set_rgbcol_over(cr
, &chart
->color_scheme
.colors
[color
], i
== chart
->active
);
1402 #if CHART_PARAM_PIE_DONUT == TRUE
1407 //radius = (gint)((chart->rayon/3) * (1 / PHI));
1409 //radius = (gint)((chart->rayon/2) * 2 / 3);
1411 //piehole value from 0.4 to 0.6 will look best on most charts
1412 radius
= (gint
)(chart
->rayon
/2) * CHART_PARAM_PIE_HOLEVALUE
;
1414 cairo_arc(cr
, cx
, cy
, radius
, a1
, a2
);
1415 cairo_user_set_rgbcol(cr
, &global_colors
[THBASE
]);
1424 static gint
piechart_get_active(GtkWidget
*widget
, gint x
, gint y
, gpointer user_data
)
1426 GtkChart
*chart
= GTK_CHART(user_data
);
1427 gint retval
, px
, py
;
1431 DB( g_print("\n[pie] get active\n") );
1437 h
= sqrt( pow(px
,2) + pow(py
,2) );
1438 radius
= chart
->rayon
/ 2;
1440 if(h
<= radius
&& h
>= (radius
* CHART_PARAM_PIE_HOLEVALUE
) )
1444 b
= (acos(px
/ h
) * 180) / M_PI
;
1445 angle
= py
> 0 ? b
: 360 - b
;
1447 if(angle
> 360) angle
-= 360;
1448 //angle = 360 - angle;
1452 for(index
=0; index
< chart
->nb_items
;index
++)
1454 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, index
);
1456 cumul
+= ABS(item
->serie1
/chart
->total
)*360;
1464 //DB( g_print(" inside: x=%d, y=%d\n", x, y) );
1465 //DB( g_print(" inside: b=%f angle=%f, slice is %d\n", b, angle, index) );
1471 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1472 static gboolean
drawarea_full_redraw(GtkWidget
*widget
, gpointer user_data
)
1474 GtkChart
*chart
= GTK_CHART(user_data
);
1476 PangoLayout
*layout
;
1479 DB( g_print("------\n[gtkchart] drawarea full redraw\n") );
1481 cr
= cairo_create (chart
->surface
);
1484 cairo_font_face_t
*ff
;
1485 cairo_scaled_font_t
*sf
;
1487 ff
= cairo_get_font_face(cr
);
1488 sf
= cairo_get_scaled_font(cr
);
1490 g_print("cairo ff = '%s'\n", cairo_toy_font_face_get_family(ff
) );
1492 ff
= cairo_scaled_font_get_font_face(sf
);
1493 g_print("cairo sf = '%s'\n", cairo_toy_font_face_get_family(ff
) );
1495 //cairo_set_font_face(cr, ff);
1498 /* fillin the back in white */
1499 //cairo_user_set_rgbcol(cr, &global_colors[WHITE]);
1500 cairo_user_set_rgbcol(cr
, &global_colors
[THBASE
]);
1504 if(chart
->nb_items
== 0)
1510 /*debug help draws */
1511 #if DBGDRAW_RECT == 1
1513 cairo_set_line_width(cr
, 1.0);
1514 cairo_set_source_rgb(cr
, 0.0, 1.0, 0.0); //green
1515 cairo_rectangle(cr
, chart
->l
+0.5, chart
->t
+0.5, chart
->w
, chart
->h
);
1519 cairo_set_source_rgb(cr
, 1.0, 0.5, 0.0); //orange
1520 cairo_rectangle(cr
, chart
->graph
.x
+0.5, chart
->graph
.y
+0.5, chart
->graph
.width
, chart
->graph
.height
);
1527 layout
= pango_cairo_create_layout (cr
);
1529 chart_set_font_size(chart
, layout
, CHART_FONT_SIZE_TITLE
);
1530 pango_layout_set_text (layout
, chart
->title
, -1);
1531 pango_layout_get_size (layout
, &tw
, &th
);
1533 cairo_user_set_rgbcol(cr
, &global_colors
[THTEXT
]);
1534 cairo_move_to(cr
, chart
->l
, chart
->t
);
1535 pango_cairo_show_layout (cr
, layout
);
1537 #if DBGDRAW_TEXT == 1
1539 cairo_set_source_rgb(cr
, 0.0, 0.0, 1.0); //blue
1541 cairo_set_dash (cr
, &dashlength
, 1, 0);
1542 //cairo_move_to(cr, chart->l, chart->t);
1543 cairo_rectangle(cr
, chart
->l
+0.5, chart
->t
+0.5, (tw
/ PANGO_SCALE
), (th
/ PANGO_SCALE
));
1547 g_object_unref (layout
);
1552 case CHART_TYPE_COL
:
1553 colchart_draw_scale(widget
, chart
);
1554 //colchart_draw_bars(widget, chart);
1556 case CHART_TYPE_LINE
:
1557 colchart_draw_scale(widget
, chart
);
1558 //linechart_draw_lines(widget, chart);
1560 case CHART_TYPE_PIE
:
1561 //piechart_draw_slices(widget, chart);
1567 if(chart
->show_legend
)
1575 DB( g_print("\n[chart] draw legend\n") );
1577 layout
= pango_cairo_create_layout (cr
);
1578 chart_set_font_size(chart
, layout
, CHART_FONT_SIZE_SMALL
);
1579 pango_layout_set_ellipsize(layout
, PANGO_ELLIPSIZE_END
);
1581 x
= chart
->legend
.x
;
1582 y
= chart
->legend
.y
;
1583 radius
= chart
->legend_font_h
;
1585 #if DBGDRAW_RECT == 1
1587 cairo_set_source_rgb(cr
, 1.0, 0.5, 0.0); //orange
1589 cairo_set_dash (cr
, &dashlength
, 1, 0);
1590 //cairo_move_to(cr, x, y);
1591 cairo_rectangle(cr
, chart
->legend
.x
+0.5, chart
->legend
.y
+0.5, chart
->legend
.width
, chart
->legend
.height
);
1595 for(i
=0; i
< chart
->nb_items
;i
++)
1597 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
1601 //DB( g_print(" draw %2d '%s' y=%g\n", i, item->label, y) );
1603 #if DBGDRAW_TEXT == 1
1605 cairo_set_source_rgb(cr
, 0.0, 0.0, 1.0); //blue
1607 cairo_set_dash (cr
, &dashlength
, 1, 0);
1608 //cairo_move_to(cr, x, y);
1609 cairo_rectangle(cr
, x
+0.5, y
+0.5, chart
->legend_font_h
+ CHART_SPACING
+ chart
->legend_label_w
, chart
->legend_font_h
);
1613 // check if enought height to draw
1614 if( chart
->nb_items
- i
> 1 )
1616 if( (y
+ floor(2 * radius
* CHART_LINE_SPACING
)) > chart
->b
)
1618 DB( g_print(" print ...\n\n") );
1619 pango_layout_set_text (layout
, "...", -1);
1620 cairo_move_to(cr
, x
+ radius
+ CHART_SPACING
, y
);
1621 pango_cairo_show_layout (cr
, layout
);
1627 cairo_arc(cr
, x
+ (radius
/2), y
+ (radius
/2), (radius
/2), 0, 2 * M_PI
);
1628 color
= i
% chart
->color_scheme
.nb_cols
;
1629 cairo_user_set_rgbcol(cr
, &chart
->color_scheme
.colors
[color
]);
1632 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.78);
1635 valstr
= item
->label
;
1636 pango_layout_set_text (layout
, valstr
, -1);
1637 pango_layout_set_width(layout
, chart
->legend_label_w
* PANGO_SCALE
);
1638 cairo_move_to(cr
, x
+ chart
->legend_font_h
+ CHART_SPACING
, y
);
1639 pango_cairo_show_layout (cr
, layout
);
1641 if( chart
->show_legend_wide
)
1643 pango_layout_set_width(layout
, -1);
1646 valstr
= chart_print_double(chart
, chart
->buffer1
, item
->serie1
);
1647 pango_layout_set_text (layout
, valstr
, -1);
1648 pango_layout_get_size (layout
, &tw
, &th
);
1649 cairo_move_to(cr
, x
+ chart
->legend_font_h
+ chart
->legend_label_w
+ (CHART_SPACING
*3) + chart
->legend_value_w
- (tw
/PANGO_SCALE
), y
);
1650 pango_cairo_show_layout (cr
, layout
);
1653 valstr
= chart_print_rate(chart
, item
->rate
);
1654 pango_layout_set_text (layout
, valstr
, -1);
1655 pango_layout_get_size (layout
, &tw
, &th
);
1656 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
);
1657 pango_cairo_show_layout (cr
, layout
);
1660 //the radius contains the font height here
1661 //y += floor(chart->font_h * CHART_LINE_SPACING);
1662 y
+= floor(radius
* CHART_LINE_SPACING
);
1666 g_object_unref (layout
);
1677 drawarea_configure_event_callback (GtkWidget
*widget
,
1678 GdkEventConfigure
*event
,
1681 GtkChart
*chart
= GTK_CHART(user_data
);
1682 GtkAllocation allocation
;
1683 GtkStyleContext
*context
;
1684 PangoFontDescription
*desc
;
1688 DB( g_print("\n[gtkchart] drawarea configure \n") );
1690 gtk_widget_get_allocation (widget
, &allocation
);
1692 DB( g_print("w=%d h=%d\n", allocation
.width
, allocation
.height
) );
1696 cairo_surface_destroy (chart
->surface
);
1698 chart
->surface
= gdk_window_create_similar_surface (gtk_widget_get_window (widget
),
1699 CAIRO_CONTENT_COLOR
,
1703 context
= gtk_widget_get_style_context (widget
);
1705 chart_color_global_default();
1708 colfound
= gtk_style_context_lookup_color(context
, "theme_base_color", &color
);
1710 colfound
= gtk_style_context_lookup_color(context
, "base_color", &color
);
1714 struct rgbcol
*tcol
= &global_colors
[THBASE
];
1715 tcol
->r
= color
.red
* 255;
1716 tcol
->g
= color
.green
* 255;
1717 tcol
->b
= color
.blue
* 255;
1718 DB( g_print(" - theme base col: %x %x %x\n", tcol
->r
, tcol
->g
, tcol
->b
) );
1722 colfound
= gtk_style_context_lookup_color(context
, "theme_text_color", &color
);
1724 gtk_style_context_lookup_color(context
, "text_color", &color
);
1729 struct rgbcol
*tcol
= &global_colors
[THTEXT
];
1730 tcol
->r
= color
.red
* 255;
1731 tcol
->g
= color
.green
* 255;
1732 tcol
->b
= color
.blue
* 255;
1733 DB( g_print(" - theme text (bg) col: %x %x %x\n", tcol
->r
, tcol
->g
, tcol
->b
) );
1737 //drawarea_full_redraw(widget, user_data);
1739 /* get and copy the font */
1740 gtk_style_context_get(context
, GTK_STATE_FLAG_NORMAL
, "font", &desc
, NULL
);
1743 pango_font_description_free (chart
->pfd
);
1746 chart
->pfd
= pango_font_description_copy(desc
);
1747 chart
->pfd_size
= pango_font_description_get_size (desc
) / PANGO_SCALE
;
1748 //chart->barw = (6 + chart->pfd_size) * PHI;
1750 //leak: we should free desc here ?
1751 //or no need to copy above ?
1752 //pango_font_description_free(desc);
1754 DB( g_print("family: %s\n", pango_font_description_get_family(chart
->pfd
) ) );
1755 DB( g_print("size : %d (%d)\n", chart
->pfd_size
, chart
->pfd_size
/PANGO_SCALE
) );
1756 DB( g_print("isabs : %d\n", pango_font_description_get_size_is_absolute (chart
->pfd
) ) );
1759 if( gtk_widget_get_realized(widget
))
1761 chart_recompute(chart
);
1762 drawarea_full_redraw(widget
, chart
);
1765 /* We've handled the configure event, no need for further processing. */
1770 static void drawarea_realize_callback(GtkWidget
*widget
, gpointer user_data
)
1772 //GtkChart *chart = GTK_CHART(user_data);
1774 DB( g_print("\n[gtkchart] drawarea realize\n") );
1776 //chart_recompute(chart);
1781 static gboolean
drawarea_draw_callback(GtkWidget
*widget
, cairo_t
*cr
, gpointer user_data
)
1783 GtkChart
*chart
= GTK_CHART(user_data
);
1785 if( !gtk_widget_get_realized(widget
) || chart
->surface
== NULL
)
1788 DB( g_print("\n[gtkchart] drawarea draw callback\n") );
1790 cairo_set_source_surface (cr
, chart
->surface
, 0, 0);
1795 case CHART_TYPE_COL
:
1796 colchart_draw_bars(widget
, chart
);
1798 case CHART_TYPE_LINE
:
1799 linechart_draw_lines(widget
, chart
);
1801 case CHART_TYPE_PIE
:
1802 piechart_draw_slices(widget
, chart
);
1810 static gboolean
drawarea_querytooltip_callback(GtkWidget
*widget
, gint x
, gint y
, gboolean keyboard_mode
, GtkTooltip
*tooltip
, gpointer user_data
)
1812 GtkChart
*chart
= GTK_CHART(user_data
);
1813 gchar
*strval
, *strval2
, *buffer
;
1814 gboolean retval
= FALSE
;
1816 if(chart
->surface
== NULL
)
1819 DB( g_print("\n[gtkchart] drawarea querytooltip\n") );
1821 DB( g_print(" x=%d, y=%d kbm=%d\n", x
, y
, keyboard_mode
) );
1822 if(chart
->lastactive
!= chart
->active
)
1827 if(chart
->active
>= 0)
1829 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, chart
->active
);
1831 strval
= chart_print_double(chart
, chart
->buffer1
, item
->serie1
);
1834 //#1420495 don't use g_markup_printf_escaped
1835 if( chart
->type
== CHART_TYPE_PIE
)
1836 buffer
= g_strdup_printf("%s\n%s\n%.2f%%", item
->label
, strval
, item
->rate
);
1838 buffer
= g_strdup_printf("%s\n%s", item
->label
, strval
);
1843 strval2
= chart_print_double(chart
, chart
->buffer2
, item
->serie2
);
1844 buffer
= g_strdup_printf("%s\n+%s\n%s", item
->label
, strval2
, strval
);
1847 gtk_tooltip_set_text(tooltip
, buffer
);
1848 //gtk_label_set_markup(GTK_LABEL(chart->ttlabel), buffer);
1853 chart
->lastactive
= chart
->active
;
1859 static gboolean
drawarea_motionnotifyevent_callback(GtkWidget
*widget
, GdkEventMotion
*event
, gpointer user_data
)
1861 GtkChart
*chart
= GTK_CHART(user_data
);
1862 gboolean retval
= TRUE
;
1865 if(chart
->surface
== NULL
|| chart
->nb_items
== 0)
1868 DB( g_print("\n[gtkchart] drawarea motion\n") );
1875 DB( g_print(" is hint\n") );
1877 gdk_window_get_device_position(event
->window
, event
->device
, &x
, &y
, NULL
);
1878 //gdk_window_get_pointer(event->window, &x, &y, NULL);
1884 case CHART_TYPE_COL
:
1885 chart
->active
= colchart_get_active(widget
, x
, y
, chart
);
1887 case CHART_TYPE_LINE
:
1888 chart
->active
= linechart_get_active(widget
, x
, y
, chart
);
1890 case CHART_TYPE_PIE
:
1891 chart
->active
= piechart_get_active(widget
, x
, y
, chart
);
1896 if( chart
->show_legend
&& chart
->active
== - 1)
1898 if( x
>= chart
->legend
.x
&& (x
<= (chart
->legend
.x
+chart
->legend
.width
))
1899 && y
>= chart
->legend
.y
&& (y
<= (chart
->legend
.y
+chart
->legend
.height
))
1902 //use the radius a font height here
1903 chart
->active
= (y
- chart
->legend
.y
) / floor(chart
->legend_font_h
* CHART_LINE_SPACING
);
1906 if( chart
->active
> chart
->nb_items
- 1)
1912 // rollover redraw ?
1913 DB( g_print(" active: last=%d, curr=%d\n", chart
->lastactive
, chart
->active
) );
1915 if(chart
->lastactive
!= chart
->active
)
1917 GdkRectangle update_rect
;
1920 DB( g_print(" motion rollover redraw :: active=%d\n", chart
->active
) );
1922 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1924 /* pie : always invalidate all graph area */
1925 if( chart
->type
== CHART_TYPE_PIE
)
1927 update_rect
.x
= chart
->graph
.x
;
1928 update_rect
.y
= chart
->graph
.y
;
1929 update_rect
.width
= chart
->graph
.width
;
1930 update_rect
.height
= chart
->graph
.height
;
1932 /* Now invalidate the affected region of the drawing area. */
1933 gdk_window_invalidate_rect (gtk_widget_get_window (widget
),
1938 if(chart
->lastactive
!= -1)
1940 /* column/line : invalidate rollover */
1941 if( chart
->type
== CHART_TYPE_COL
|| chart
->type
== CHART_TYPE_LINE
)
1943 update_rect
.x
= chart
->graph
.x
+ (chart
->lastactive
- first
) * chart
->blkw
;
1944 update_rect
.y
= chart
->graph
.y
- 6;
1945 update_rect
.width
= chart
->blkw
;
1946 update_rect
.height
= chart
->graph
.height
+ 12;
1949 /* Now invalidate the affected region of the drawing area. */
1950 gdk_window_invalidate_rect (gtk_widget_get_window (widget
),
1955 /* column/line : invalidate current item */
1956 if( chart
->type
== CHART_TYPE_COL
|| chart
->type
== CHART_TYPE_LINE
)
1958 update_rect
.x
= chart
->graph
.x
+ (chart
->active
- first
) * chart
->blkw
;
1959 update_rect
.y
= chart
->graph
.y
- 6;
1960 update_rect
.width
= chart
->blkw
;
1961 update_rect
.height
= chart
->graph
.height
+ 12;
1963 /* Now invalidate the affected region of the drawing area. */
1964 gdk_window_invalidate_rect (gtk_widget_get_window (widget
),
1969 //gtk_widget_queue_draw( widget );
1973 DB( g_print(" x=%d, y=%d, time=%d\n", x
, y
, event
->time
) );
1975 //if(inlegend != TRUE)
1976 // gtk_tooltip_trigger_tooltip_query(gtk_widget_get_display(chart->drawarea));
1982 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1983 /* public functions */
1984 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1986 void gtk_chart_queue_redraw(GtkChart
*chart
)
1988 DB( g_print("\n[gtkchart] queue redraw\n") );
1990 if( gtk_widget_get_realized(chart
->drawarea
) )
1992 chart_recompute(chart
);
1993 drawarea_full_redraw(chart
->drawarea
, chart
);
1994 DB( g_print("gtk_widget_queue_draw\n") );
1995 gtk_widget_queue_draw( chart
->drawarea
);
2001 ** change the model and/or column
2003 void gtk_chart_set_datas(GtkChart
*chart
, GtkTreeModel
*model
, guint column
, gchar
*title
, gchar
*subtitle
)
2005 g_return_if_fail (GTK_IS_CHART (chart
));
2007 DB( g_print("\n[gtkchart] set datas\n") );
2009 if( GTK_IS_TREE_MODEL(model
) )
2011 chart_setup_with_model(chart
, model
, column
, column
);
2013 chart
->title
= g_strdup(title
);
2014 if(subtitle
!= NULL
)
2015 chart
->subtitle
= g_strdup(subtitle
);
2017 gtk_chart_queue_redraw(chart
);
2022 if( GTK_IS_LIST_STORE(chart
->model
) )
2023 gtk_list_store_clear (GTK_LIST_STORE(chart
->model
));
2029 ** change the model and/or column
2031 void gtk_chart_set_dualdatas(GtkChart
*chart
, GtkTreeModel
*model
, guint column1
, guint column2
, gchar
*title
, gchar
*subtitle
)
2033 g_return_if_fail (GTK_IS_CHART (chart
));
2035 DB( g_print("\n[gtkchart] set dualdatas\n") );
2037 if( GTK_IS_TREE_MODEL(model
) )
2039 chart_setup_with_model(chart
, model
, column1
, column2
);
2041 chart
->title
= g_strdup(title
);
2042 if(subtitle
!= NULL
)
2043 chart
->subtitle
= g_strdup(subtitle
);
2045 gtk_chart_queue_redraw(chart
);
2050 if( GTK_IS_LIST_STORE(chart
->model
) )
2051 gtk_list_store_clear (GTK_LIST_STORE(chart
->model
));
2057 ** change the type dynamically
2059 void gtk_chart_set_type(GtkChart
* chart
, gint type
)
2061 g_return_if_fail (GTK_IS_CHART (chart
));
2062 //g_return_if_fail (type < CHART_TYPE_MAX);
2064 DB( g_print("\n[gtkchart] set type %d\n", type
) );
2067 chart
->dual
= FALSE
;
2069 gtk_chart_queue_redraw(chart
);
2072 /* = = = = = = = = = = parameters = = = = = = = = = = */
2074 void gtk_chart_set_color_scheme(GtkChart
* chart
, gint index
)
2076 colorscheme_init(&chart
->color_scheme
, index
);
2082 ** set the minor parameters
2084 void gtk_chart_set_minor_prefs(GtkChart
* chart
, gdouble rate
, gchar
*symbol
)
2086 g_return_if_fail (GTK_IS_CHART (chart
));
2088 DB( g_print("\n[gtkchart] set minor prefs\n") );
2090 chart
->minor_rate
= rate
;
2091 chart
->minor_symbol
= symbol
;
2095 void gtk_chart_set_absolute(GtkChart
* chart
, gboolean abs
)
2097 g_return_if_fail (GTK_IS_CHART (chart
));
2099 DB( g_print("\n[gtkchart] set absolute\n") );
2105 void gtk_chart_set_currency(GtkChart
* chart
, guint32 kcur
)
2107 g_return_if_fail (GTK_IS_CHART (chart
));
2114 ** set the overdrawn minimum
2116 void gtk_chart_set_overdrawn(GtkChart
* chart
, gdouble minimum
)
2118 g_return_if_fail (GTK_IS_CHART (chart
));
2120 DB( g_print("\n[gtkchart] set overdrawn\n") );
2122 chart
->minimum
= minimum
;
2124 //if(chart->type == CHART_TYPE_LINE)
2125 // chart_recompute(chart);
2130 ** obsolete: set the every_xval
2132 /*void gtk_chart_set_every_xval(GtkChart * chart, gint gap)
2134 g_return_if_fail (GTK_IS_CHART (chart));
2136 DB( g_print("\n[gtkchart] set every_xval\n") );
2138 chart->every_xval = gap;
2140 //if(chart->type != CHART_TYPE_PIE)
2141 // chart_recompute(chart);
2148 void gtk_chart_set_barw(GtkChart
* chart
, gdouble barw
)
2150 g_return_if_fail (GTK_IS_CHART (chart
));
2152 DB( g_print("\n[gtkchart] set barw\n") );
2154 if( barw
>= GTK_CHART_MINBARW
&& barw
<= GTK_CHART_MAXBARW
)
2155 chart
->usrbarw
= barw
;
2160 if(chart
->type
!= CHART_TYPE_PIE
)
2161 gtk_chart_queue_redraw(chart
);
2165 ** set the show mono (colors)
2167 void gtk_chart_set_showmono(GtkChart
* chart
, gboolean mono
)
2169 g_return_if_fail (GTK_IS_CHART (chart
));
2171 chart
->show_mono
= mono
;
2173 if(chart
->type
!= CHART_TYPE_PIE
)
2174 gtk_chart_queue_redraw(chart
);
2178 /* = = = = = = = = = = visibility = = = = = = = = = = */
2181 ** change the legend visibility
2183 void gtk_chart_show_legend(GtkChart
* chart
, gboolean visible
, gboolean showextracol
)
2185 g_return_if_fail (GTK_IS_CHART (chart
));
2187 chart
->show_legend
= visible
;
2188 chart
->show_legend_wide
= showextracol
;
2189 gtk_chart_queue_redraw(chart
);
2193 ** change the x-value visibility
2195 void gtk_chart_show_xval(GtkChart
* chart
, gboolean visible
)
2197 g_return_if_fail (GTK_IS_CHART (chart
));
2199 DB( g_print("\n[gtkchart] set show xval\n") );
2201 chart
->show_xval
= visible
;
2203 //if(chart->type != CHART_TYPE_PIE)
2204 // chart_recompute(chart);
2208 ** chnage the overdrawn visibility
2210 void gtk_chart_show_overdrawn(GtkChart
* chart
, gboolean visible
)
2212 g_return_if_fail (GTK_IS_CHART (chart
));
2214 DB( g_print("\n[gtkchart] set show overdrawn\n") );
2216 chart
->show_over
= visible
;
2218 //if(chart->type == CHART_TYPE_LINE)
2219 // chart_recompute(chart);
2224 ** change the minor visibility
2226 void gtk_chart_show_minor(GtkChart
* chart
, gboolean minor
)
2228 g_return_if_fail (GTK_IS_CHART (chart
));
2230 DB( g_print("\n[gtkchart] set show minor\n") );
2232 chart
->minor
= minor
;
2234 if(chart
->type
!= CHART_TYPE_PIE
)
2235 gtk_chart_queue_redraw(chart
);