1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 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/>.
26 #include "gtk-chart-colors.h"
27 #include "gtk-chart.h"
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_destroy (GtkObject
*chart
);
47 drawarea_configure_event (GtkWidget
*widget
,
48 GdkEventConfigure
*event
,
50 static void drawarea_sizeallocate_callback(GtkWidget
*widget
, GtkAllocation
*allocation
, gpointer user_data
);
51 static void drawarea_realize_callback(GtkWidget
*widget
, gpointer user_data
);
52 static gboolean
drawarea_draw_callback( GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
);
53 static gboolean
drawarea_motionnotifyevent_callback(GtkWidget
*widget
, GdkEventMotion
*event
, gpointer user_data
);
54 static gboolean
drawarea_querytooltip_callback(GtkWidget
*widget
, gint x
, gint y
, gboolean keyboard_mode
, GtkTooltip
*tooltip
, gpointer user_data
);
56 static gboolean
drawarea_full_redraw(GtkWidget
*widget
, gpointer user_data
);
58 static void chart_calculation(GtkChart
*chart
);
59 static void chart_clear(GtkChart
*chart
, gboolean store
);
61 static void colchart_first_changed( GtkAdjustment
*adj
, gpointer user_data
);
62 static void colchart_compute_range(GtkChart
*chart
);
63 static void colchart_calculation(GtkChart
*chart
);
64 static void colchart_scrollbar_setvalues(GtkChart
*chart
);
66 static void piechart_calculation(GtkChart
*chart
);
68 static GdkPixbuf
*create_color_pixbuf (GdkColor
*col
);
69 static GtkWidget
*legend_list_new(GtkChart
*chart
);
72 static GtkHBoxClass
*gtk_chart_parent_class
= NULL
;
78 static GType chart_type
= 0;
82 static const GTypeInfo chart_info
=
84 sizeof (GtkChartClass
),
86 NULL
, /* base_finalize */
87 (GClassInitFunc
) gtk_chart_class_intern_init
,
88 NULL
, /* class_finalize */
89 NULL
, /* class_data */
92 (GInstanceInitFunc
) gtk_chart_init
,
96 chart_type
= g_type_register_static (GTK_TYPE_HBOX
, "GtkChart",
104 gtk_chart_class_intern_init (gpointer klass
)
106 gtk_chart_parent_class
= g_type_class_peek_parent (klass
);
107 gtk_chart_class_init ((GtkChartClass
*) klass
);
111 gtk_chart_class_init (GtkChartClass
* klass
)
113 //GObjectClass *gobject_class;
114 GtkObjectClass
*object_class
;
115 //GtkWidgetClass *widget_class;
117 //gobject_class = (GObjectClass*) klass;
118 object_class
= (GtkObjectClass
*) klass
;
119 //widget_class = (GtkWidgetClass*) klass;
121 gtk_chart_parent_class
= g_type_class_peek_parent (klass
);
123 DB( g_print("\n[gtkchart] class_init\n") );
125 object_class
->destroy
= gtk_chart_destroy
;
130 gtk_chart_init (GtkChart
* chart
)
132 GtkWidget
*widget
, *vbox
, *frame
;
133 GtkWidget
*scrollwin
, *treeview
;
135 chart
->surface
= NULL
;
141 chart
->barw
= GTK_CHART_BARW
;
144 chart
->lastactive
= -1;
146 chart
->minor_rate
= 1.0;
147 chart
->timer_tag
= 0;
149 gtk_chart_set_color_scheme(chart
, CHART_COLMAP_HOMEBANK
);
151 widget
=GTK_WIDGET(chart
);
153 gtk_box_set_homogeneous(GTK_BOX(widget
), FALSE
);
155 vbox
= gtk_vbox_new (FALSE
, 0);
156 gtk_box_pack_start (GTK_BOX (widget
), vbox
, TRUE
, TRUE
, 0);
159 frame
= gtk_frame_new(NULL
);
160 gtk_box_pack_start (GTK_BOX (vbox
), frame
, TRUE
, TRUE
, 0);
161 gtk_frame_set_shadow_type (GTK_FRAME(frame
), GTK_SHADOW_ETCHED_IN
);
163 chart
->drawarea
= gtk_drawing_area_new();
164 //gtk_widget_set_double_buffered (GTK_WIDGET(widget), FALSE);
166 gtk_container_add( GTK_CONTAINER(frame
), chart
->drawarea
);
167 gtk_widget_set_size_request(chart
->drawarea
, 150, 150 );
168 gtk_widget_set_has_tooltip(chart
->drawarea
, TRUE
);
169 gtk_widget_show(chart
->drawarea
);
173 PangoFontDescription
*font_desc
;
175 g_print("draw_area font\n");
177 style
= gtk_widget_get_style(GTK_WIDGET(chart
->drawarea
));
178 font_desc
= style
->font_desc
;
180 g_print("family: %s\n", pango_font_description_get_family(font_desc
) );
181 g_print("size: %d (%d)\n", pango_font_description_get_size (font_desc
), pango_font_description_get_size (font_desc
)/PANGO_SCALE
);
186 chart
->adjustment
= GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 1.0, 1.0, 1.0, 1.0));
187 chart
->scrollbar
= gtk_hscrollbar_new (GTK_ADJUSTMENT (chart
->adjustment
));
188 gtk_box_pack_start (GTK_BOX (vbox
), chart
->scrollbar
, FALSE
, TRUE
, 0);
191 /* legend treeview */
192 scrollwin
= gtk_scrolled_window_new(NULL
,NULL
);
193 chart
->scrollwin
= scrollwin
;
194 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin
), GTK_SHADOW_ETCHED_IN
);
195 //gtk_container_set_border_width (GTK_CONTAINER(scrollwin), 5);
196 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin
), GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
197 treeview
= legend_list_new(chart
);
198 chart
->treeview
= treeview
;
199 chart
->legend
= gtk_tree_view_get_model(GTK_TREE_VIEW(treeview
));
200 gtk_container_add(GTK_CONTAINER(scrollwin
), treeview
);
201 gtk_box_pack_start (GTK_BOX (widget
), scrollwin
, FALSE
, FALSE
, 0);
203 gtk_widget_add_events(GTK_WIDGET(chart
->drawarea
),
205 //GDK_POINTER_MOTION_MASK |
206 GDK_POINTER_MOTION_HINT_MASK
207 //GDK_BUTTON_PRESS_MASK |
208 //GDK_BUTTON_RELEASE_MASK
211 g_signal_connect( G_OBJECT(chart
->drawarea
),"configure-event", G_CALLBACK (drawarea_configure_event
), chart
);
212 g_signal_connect( G_OBJECT(chart
->drawarea
), "size-allocate", G_CALLBACK(drawarea_sizeallocate_callback
), chart
) ;
213 g_signal_connect( G_OBJECT(chart
->drawarea
), "realize", G_CALLBACK(drawarea_realize_callback
), chart
) ;
214 g_signal_connect( G_OBJECT(chart
->drawarea
), "expose-event", G_CALLBACK(drawarea_draw_callback
), chart
) ;
215 g_signal_connect( G_OBJECT(chart
->drawarea
), "query-tooltip", G_CALLBACK(drawarea_querytooltip_callback
), chart
);
216 g_signal_connect( G_OBJECT(chart
->drawarea
), "motion-notify-event", G_CALLBACK(drawarea_motionnotifyevent_callback
), chart
);
218 g_signal_connect (G_OBJECT(chart
->adjustment
), "value_changed", G_CALLBACK (colchart_first_changed
), chart
);
220 //g_signal_connect( G_OBJECT(chart->drawarea), "map-event", G_CALLBACK(chart_map), chart ) ;
221 //g_signal_connect( G_OBJECT(chart->drawarea), "button-press-event", G_CALLBACK(chart_button_press), chart );
222 //g_signal_connect( G_OBJECT(chart->drawarea), "button-release-event", G_CALLBACK(chart_button_release), chart );
229 gtk_chart_new (gint type
)
233 DB( g_print("\n[gtkchart] new\n") );
235 chart
= g_object_new (GTK_TYPE_CHART
, NULL
);
238 return GTK_WIDGET(chart
);
243 gtk_chart_destroy (GtkObject
* object
)
247 DB( g_print("\n[gtkchart] destroy\n") );
249 g_return_if_fail (GTK_IS_CHART (object
));
251 chart
= GTK_CHART (object
);
253 chart_clear(chart
, FALSE
);
257 cairo_surface_destroy (chart
->surface
);
258 chart
->surface
= NULL
;
260 GTK_OBJECT_CLASS (gtk_chart_parent_class
)->destroy (object
);
267 ** print a integer number
269 static gchar
*chart_print_int(GtkChart
*chart
, gint value
)
272 //mystrfmon(chart->buffer, CHART_BUFFER_LENGTH-1, (gdouble)value, chart->minor);
273 mystrfmon_int(chart
->buffer1
, CHART_BUFFER_LENGTH
-1, (gdouble
)value
, chart
->minor
);
278 value *= chart->minor_rate;
279 strfmon(chart->buffer, CHART_BUFFER_LENGTH-1, "%!.0n ", (gdouble)value);
280 strcat(chart->buffer, chart->minor_symbol);
283 strfmon(chart->buffer, CHART_BUFFER_LENGTH-1, "%.0n", (gdouble)value);
286 return chart
->buffer1
;
290 ** print a double number
292 static gchar
*chart_print_double(GtkChart
*chart
, gchar
*buffer
, gdouble value
)
295 mystrfmon(buffer
, CHART_BUFFER_LENGTH
-1, value
, chart
->minor
);
300 value *= chart->minor_rate;
301 strfmon(chart->buffer, CHART_BUFFER_LENGTH-1, "%!n ", (gdouble)value);
302 strcat(chart->buffer, chart->minor_symbol);
305 strfmon(chart->buffer, CHART_BUFFER_LENGTH-1, "%n", (gdouble)value);
313 ** clear any allocated memory
315 static void chart_clear(GtkChart
*chart
, gboolean store
)
319 DB( g_print("\n[gtkchart] clear\n") );
321 //free & clear any previous allocated datas
322 if(chart
->title
!= NULL
)
324 g_free(chart
->title
);
328 if(chart
->items
!= NULL
)
330 for(i
=0;i
<chart
->nb_items
;i
++)
332 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
334 g_free(item
->legend
);
336 g_array_free(chart
->items
, TRUE
);
342 gtk_list_store_clear (GTK_LIST_STORE(chart
->legend
));
351 chart
->every_xval
= 7;
354 chart
->lastactive
= -1;
360 ** setup our chart with a model and column
362 static void chart_setup_with_model(GtkChart
*chart
, GtkTreeModel
*list_store
, guint column1
, guint column2
)
366 GtkTreeIter iter
, l_iter
;
370 DB( g_print("\n[gtkchart] setup with model\n") );
372 chart_clear(chart
, TRUE
);
373 chart
->nb_items
= gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store
), NULL
);
375 chart
->items
= g_array_sized_new(FALSE
, FALSE
, sizeof(ChartItem
), chart
->nb_items
);
377 DB( g_print(" nb=%d, struct=%d\n", chart
->nb_items
, sizeof(ChartItem
)) );
379 chart
->dual
= (column1
== column2
) ? FALSE
: TRUE
;
381 /* Get the first iter in the list */
382 valid
= gtk_tree_model_get_iter_first (GTK_TREE_MODEL(list_store
), &iter
);
388 gdouble value1
, value2
;
391 /* column 0: pos (gint) */
392 /* column 1: key (gint) */
393 /* column 2: label (gchar) */
394 /* column x: values (double) */
396 gtk_tree_model_get (GTK_TREE_MODEL(list_store
), &iter
,
403 if(chart
->dual
|| chart
->abs
)
405 value1
= ABS(value1
);
406 value2
= ABS(value2
);
409 DB( g_print("%d: '%s' %.2f %2f\n", i
, label
, value1
, value2
) );
411 /* data1 value storage & min, max compute */
412 chart
->rawmin
= MIN(chart
->rawmin
, value1
);
413 chart
->rawmax
= MAX(chart
->rawmax
, value1
);
417 /* data2 value storage & min, max compute */
418 chart
->rawmin
= MIN(chart
->rawmin
, value2
);
419 chart
->rawmax
= MAX(chart
->rawmax
, value2
);
423 item
.serie1
= value1
;
424 item
.serie2
= value2
;
425 g_array_append_vals(chart
->items
, &item
, 1);
427 /* populate our legend list */
429 color
= i
% chart
->nb_cols
;
430 //color = id % chart->nb_cols;
432 //DB( g_print ("Row %d: (%s, %2.f) color %d\n", id, title, value, color) );
434 colour
.red
= COLTO16(chart
->colors
[color
].r
);
435 colour
.green
= COLTO16(chart
->colors
[color
].g
);
436 colour
.blue
= COLTO16(chart
->colors
[color
].b
);
438 gtk_list_store_append (GTK_LIST_STORE(chart
->legend
), &l_iter
);
439 gtk_list_store_set (GTK_LIST_STORE(chart
->legend
), &l_iter
,
440 LST_LEGEND_COLOR
, create_color_pixbuf (&colour
),
441 LST_LEGEND_TITLE
, label
,
442 LST_LEGEND_AMOUNT
, value1
,
446 /* pie chart total sum */
447 chart
->total
+= ABS(value1
);
449 valid
= gtk_tree_model_iter_next (list_store
, &iter
);
453 // compute rate for legend for bar/pie
454 for(i
=0;i
<chart
->nb_items
;i
++)
456 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
458 item
->rate
= ABS(item
->serie1
*100/chart
->total
);
459 item
->legend
= g_markup_printf_escaped("%s (%.2f%%)", item
->label
, item
->rate
);
462 if( chart
->type
!= CHART_TYPE_LINE
)
465 valid
= gtk_tree_model_get_iter_first (GTK_TREE_MODEL(chart
->legend
), &iter
);
468 gdouble amount
, rate
;
470 gtk_tree_model_get(GTK_TREE_MODEL(chart
->legend
), &iter
,
471 LST_LEGEND_AMOUNT
, &amount
,
474 rate
= ABS( amount
*100/chart
->total
);
476 gtk_list_store_set(GTK_LIST_STORE(chart
->legend
), &iter
,
477 LST_LEGEND_RATE
, rate
,
480 valid
= gtk_tree_model_iter_next (GTK_TREE_MODEL(chart
->legend
), &iter
);
486 //g_print("total is %.2f\n", total);
487 //ensure the widget is mapped
488 //gtk_widget_map(chart);
495 ** recompute according to type
497 static void chart_recompute(GtkChart
*chart
)
500 DB( g_print("\n[gtkchart] recompute\n") );
502 chart_calculation (chart
);
506 case CHART_TYPE_LINE
:
508 colchart_compute_range(chart
);
510 colchart_calculation(chart
);
511 gtk_adjustment_set_value(chart
->adjustment
, 0);
512 colchart_scrollbar_setvalues(chart
);
513 gtk_widget_show(chart
->scrollbar
);
516 piechart_calculation(chart
);
517 gtk_widget_hide(chart
->scrollbar
);
529 static float CalculateStepSize(float range
, float targetSteps
)
531 // calculate an initial guess at step size
532 float tempStep
= range
/targetSteps
;
534 // get the magnitude of the step size
535 float mag
= (float)floor(log10(tempStep
));
536 float magPow
= (float)pow(10, mag
);
538 // calculate most significant digit of the new step size
539 float magMsd
= (int)(tempStep
/magPow
+ 0.5);
541 // promote the MSD to either 1, 2, or 5
544 else if (magMsd
> 2.0)
546 else if (magMsd
>= 1.0)
549 return magMsd
*magPow
;
553 static void colchart_compute_range(GtkChart
*chart
)
555 double lobound
=chart
->rawmin
, hibound
=chart
->rawmax
;
557 DB( g_print("\n[gtkchart] bar compute range\n") );
559 /* comptute max ticks */
560 chart
->range
= chart
->rawmax
- chart
->rawmin
;
561 gint maxticks
= MIN(10,floor(chart
->graph_height
/ (chart
->font_h
* 2)));
563 DB( g_print(" raw :: [%.2f - %.2f] range=%.2f\n", chart
->rawmin
, chart
->rawmax
, chart
->range
) );
564 DB( g_print(" raw :: maxticks=%d (%g / (%g*2))\n", maxticks
, chart
->graph_height
, chart
->font_h
) );
567 chart
->unit
= CalculateStepSize((hibound
-lobound
), maxticks
);
568 chart
->min
= -chart
->unit
* ceil(-lobound
/chart
->unit
);
569 chart
->max
= chart
->unit
* ceil(hibound
/chart
->unit
);
570 chart
->range
= chart
->max
- chart
->min
;
571 chart
->div
= chart
->range
/ chart
->unit
;
573 DB( g_print(" end :: interval=%.2f, ticks=%d\n", chart
->unit
, chart
->div
) );
574 DB( g_print(" end :: [%.2f - %.2f], range=%.2f\n", chart
->min
, chart
->max
, chart
->range
) );
579 static void chart_calculation(GtkChart
*chart
)
581 GtkWidget
*drawarea
= chart
->drawarea
;
582 GdkWindow
*gdkwindow
;
583 cairo_surface_t
*surf
= NULL
;
585 cairo_text_extents_t te
;
586 cairo_font_extents_t fe
;
587 GtkAllocation allocation
;
591 DB( g_print("\n[gtkchart] calculation\n") );
593 gtk_widget_get_allocation(drawarea
, &allocation
);
595 chart
->l
= CHART_MARGIN
;
596 chart
->t
= CHART_MARGIN
;
597 chart
->r
= allocation
.width
- CHART_MARGIN
;
598 chart
->b
= allocation
.height
- CHART_MARGIN
;
599 chart
->w
= allocation
.width
- (CHART_MARGIN
*2);
600 chart
->h
= allocation
.height
- (CHART_MARGIN
*2);
603 gdkwindow
= gtk_widget_get_window(chart
->drawarea
);
606 surf
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, allocation
.width
, allocation
.height
);
607 cr
= cairo_create (surf
);
610 cr
= gdk_cairo_create (gdkwindow
);
614 if(chart
->title
!= NULL
)
616 cairo_set_font_size(cr
, CHART_FONT_SIZE_TITLE
);
617 cairo_font_extents(cr
, &fe
);
618 chart
->title_zh
= fe
.height
;
622 chart
->subtitle_zh
= 0;
623 if(chart
->subtitle
!= NULL
)
625 cairo_set_font_size(cr
, CHART_FONT_SIZE_PERIOD
);
626 cairo_font_extents(cr
, &fe
);
627 chart
->subtitle_zh
= fe
.height
;
630 chart
->subtitle_y
= chart
->t
+ chart
->title_zh
;
632 cairo_set_font_size(cr
, CHART_FONT_SIZE_NORMAL
);
634 // compute amount scale
635 valstr
= chart_print_int(chart
, (gint
)chart
->min
);
636 cairo_text_extents(cr
, valstr
, &te
);
637 chart
->scale_w
= te
.width
;
638 valstr
= chart_print_int(chart
, (gint
)chart
->max
);
639 cairo_text_extents(cr
, valstr
, &te
);
640 chart
->scale_w
= MAX(chart
->scale_w
, te
.width
);
641 DB( g_print(" - scale: %g,%g %g,%g\n", chart
->l
, 0.0, chart
->scale_w
, 0.0) );
643 // compute font height
644 cairo_font_extents(cr
, &fe
);
645 chart
->font_h
= fe
.height
;
647 // compute graph region
650 case CHART_TYPE_LINE
:
652 chart
->graph_x
= chart
->l
+ chart
->scale_w
+ 2;
653 chart
->graph_y
= chart
->t
+ chart
->title_zh
+ chart
->subtitle_zh
;
654 chart
->graph_width
= chart
->w
- chart
->scale_w
- 2;
655 chart
->graph_height
= chart
->h
- chart
->title_zh
- chart
->subtitle_zh
;
658 chart
->graph_x
= chart
->l
;
659 chart
->graph_y
= chart
->t
+ chart
->title_zh
+ chart
->subtitle_zh
;
660 chart
->graph_width
= chart
->w
;
661 chart
->graph_height
= chart
->h
- chart
->title_zh
- chart
->subtitle_zh
;
665 if(chart
->title_zh
> 0 || chart
->subtitle_zh
> 0)
667 chart
->graph_y
+= CHART_MARGIN
;
668 chart
->graph_height
-= CHART_MARGIN
;
671 if(chart
->type
!= CHART_TYPE_PIE
&& chart
->show_xval
)
672 chart
->graph_height
-= (chart
->font_h
+ CHART_SPACING
);
675 cairo_surface_destroy(surf
);
680 static void colchart_calculation(GtkChart
*chart
)
684 DB( g_print("\n[gtkchart] bar calculation\n") );
687 //if expand : we compute available space
688 //chart->barw = MAX(32, (chart->graph_width)/chart->nb_items);
689 //chart->barw = 32; // usr setted or defaut to BARW
692 blkw
= chart
->barw
+ 3;
694 blkw
= (chart
->barw
* 2) + 3;
697 chart
->visible
= chart
->graph_width
/ blkw
;
698 chart
->visible
= MIN(chart
->visible
, chart
->nb_items
);
700 chart
->ox
= chart
->l
;
701 chart
->oy
= floor(chart
->graph_y
+ (chart
->max
/chart
->range
) * chart
->graph_height
);
703 DB( g_print(" + ox=%f oy=%f\n", chart
->ox
, chart
->oy
) );
711 static void colchart_draw_scale(GtkWidget
*widget
, gpointer user_data
)
713 GtkChart
*chart
= GTK_CHART(user_data
);
718 DB( g_print("\n(gtkline) draw scale\n") );
721 //static const double dashed3[] = {2.0};
723 //gdkwindow = gtk_widget_get_window(widget);
724 //cr = gdk_cairo_create (gdkwindow);
725 //cr = gdk_cairo_create (widget->window);
726 cr
= cairo_create (chart
->surface
);
728 cairo_set_line_width(cr
, 1);
731 //cairo_rectangle(cr, CHART_MARGIN, 0, chart->w, chart->h + CHART_MARGIN);
734 /* draw vertical lines + legend */
737 x
= chart
->graph_x
+ 1.5 + (chart
->barw
/2);
739 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
741 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
743 if( !(i
% chart
->every_xval
) )
745 //cairo_user_set_rgbcol(cr, &global_colors[GREY1]);
746 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.05);
748 cairo_move_to(cr
, x
, chart
->graph_y
);
749 cairo_line_to(cr
, x
, chart
->b
);
757 /* horizontal lines */
759 curxval
= chart
->max
;
760 for(i
=0;i
<=chart
->div
;i
++)
763 //if(i == 0 || i == chart->div) /* top/bottom line */
765 //cairo_set_dash(cr, 0, 0, 0);
766 //cairo_user_set_rgbcol(cr, &global_colors[GREY1]);
767 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.1);
769 //else /* intermediate line (dotted) */
771 //cairo_set_dash(cr, dashed3, 1, 0);
772 //cairo_user_set_rgbcol(cr, &global_colors[GREY1]);
778 //cairo_set_dash(cr, 0, 0, 0);
779 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.8);
782 y
= 0.5 + floor(chart
->graph_y
+ ((i
* chart
->unit
) / chart
->range
) * chart
->graph_height
);
784 DB( g_print(" + i=%d :: y=%f (%f / %f) * %f\n", i
, y
, i
*chart
->unit
, chart
->range
, chart
->graph_height
) );
786 cairo_move_to(cr
, chart
->graph_x
, y
);
787 cairo_line_to(cr
, chart
->graph_x
+ chart
->graph_width
, y
);
790 curxval
-= chart
->unit
;
798 static void colchart_draw_scale_text(GtkWidget
*widget
, gpointer user_data
)
800 GtkChart
*chart
= GTK_CHART(user_data
);
806 DB( g_print("----------------------\n(gtkline) draw scale text\n") );
809 cairo_text_extents_t te
;
811 //GdkWindow *gdkwindow;
812 //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
);
818 cairo_set_line_width(cr
, 1);
821 //cairo_rectangle(cr, CHART_MARGIN, 0, chart->w, chart->h + CHART_MARGIN);
824 //cairo_set_operator(cr, CAIRO_OPERATOR_SATURATE);
826 /* draw x-legend (items) */
829 x
= chart
->graph_x
+ 1.5 + (chart
->barw
/2);
830 y
= chart
->b
- chart
->font_h
;
831 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
833 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
835 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
837 if( !(i
% chart
->every_xval
) )
839 valstr
= item
->label
;
840 cairo_text_extents(cr
, valstr
, &te
);
842 DB( g_print("%s w=%f h=%f\n", valstr
, te
.width
, te
.height
) );
844 cairo_user_set_rgbacol(cr
, &global_colors
[THTEXT
], 0.78);
845 //cairo_move_to(cr, x - (te.width/2), y - te.y_bearing);
846 cairo_move_to(cr
, x
, y
- te
.y_bearing
);
847 cairo_show_text(cr
, valstr
);
849 /*cairo_user_set_rgbcol(cr, &global_colors[TEXT]);
850 cairo_move_to(cr, x, y);
851 cairo_line_to(cr, x, y + te.height);
859 /* draw y-legend (amount) */
861 curxval
= chart
->max
;
862 for(i
=0;i
<=chart
->div
;i
++)
864 y
= 0.5 + floor(chart
->graph_y
+ ((i
* chart
->unit
) / chart
->range
) * chart
->graph_height
);
866 DB( g_print(" + i=%d :: y=%f (%f / %f) * %f\n", i
, y
, i
*chart
->unit
, chart
->range
, chart
->graph_height
) );
870 valstr
= chart_print_int(chart
, (gint
)curxval
);
871 cairo_text_extents(cr
, valstr
, &te
);
873 //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) );
876 cairo_move_to(cr
, chart
->graph_x
- te
.x_bearing
- te
.width
- 2, y
+ (( te
.height
)/2));
877 cairo_user_set_rgbacol (cr
, &global_colors
[THTEXT
], 0.78);
878 cairo_show_text(cr
, valstr
);
882 curxval
-= chart
->unit
;
889 ** draw all visible bars
891 static void colchart_draw_bars(GtkWidget
*widget
, gpointer user_data
)
893 GtkChart
*chart
= GTK_CHART(user_data
);
898 DB( g_print("\n[gtkchart] bar draw bars\n") );
901 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
903 cr
= gdk_cairo_create (gtk_widget_get_window(widget
));
904 //cr = cairo_create (chart->surface);
908 cairo_set_line_width(cr
, 1.0);
909 cairo_set_source_rgb(cr
, 1.0, 0.0, 1.0); // violet
910 for(i
=first
; i
<=(first
+chart
->visible
) ;i
++)
912 cairo_move_to(cr
, x2
, chart
->graph_y
);
913 cairo_line_to(cr
, x2
, chart
->graph_x
+ chart
->graph_height
);
920 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
922 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
924 gint barw
= chart
->barw
;
926 //if(!chart->datas1[i]) goto nextbar;
928 color
= i
% chart
->nb_cols
;
930 cairo_user_set_rgbcol_over(cr
, &chart
->colors
[color
], i
== chart
->active
);
935 h
= floor((item
->serie1
/ chart
->range
) * chart
->graph_height
);
937 if(item
->serie1
< 0.0)
940 //DB( g_print(" + i=%d :: y2=%f h=%f (%f / %f) * %f\n", i, y2, h, chart->datas1[i], chart->range, chart->graph_height ) );
943 cairo_rectangle(cr
, x2
+2, y2
, barw
, h
);
948 if( chart
->dual
&& item
->serie2
)
952 h
= floor((item
->serie2
/ chart
->range
) * chart
->graph_height
);
955 cairo_rectangle(cr
, x2
+2, y2
, barw
, h
);
963 //gdk_draw_line (widget->window, widget->style->fg_gc[widget->state], x, chart->oy-chart->posbarh, x, chart->oy+chart->negbarh);
972 ** get the bar under the mouse pointer
974 static gint
colchart_get_active(GtkWidget
*widget
, gint x
, gint y
, gpointer user_data
)
976 GtkChart
*chart
= GTK_CHART(user_data
);
978 gint index
, first
, px
;
982 if( x
<= chart
->r
&& x
>= chart
->graph_x
&& y
>= chart
->graph_y
&& y
<= chart
->b
)
984 px
= (x
- chart
->graph_x
);
985 //py = (y - chart->oy);
986 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
987 index
= first
+ (px
/ chart
->blkw
);
989 if(index
< chart
->nb_items
)
996 static void colchart_first_changed( GtkAdjustment
*adj
, gpointer user_data
)
998 GtkChart
*chart
= GTK_CHART(user_data
);
1001 DB( g_print("\n[gtkchart] bar first changed\n") );
1003 //first = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj));
1005 //DB( g_print(" first=%d\n", first) );
1008 DB( g_print("scrollbar\n adj=%8x, low=%.2f upp=%.2f val=%.2f step=%.2f page=%.2f size=%.2f\n", adj,
1009 adj->lower, adj->upper, adj->value, adj->step_increment, adj->page_increment, adj->page_size) );
1011 /* Set the number of decimal places to which adj->value is rounded */
1012 //gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
1013 //gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
1015 drawarea_full_redraw (chart
->drawarea
, chart
);
1016 gtk_widget_queue_draw(chart
->drawarea
);
1021 ** scrollbar set values for upper, page size, and also show/hide
1023 static void colchart_scrollbar_setvalues(GtkChart
*chart
)
1025 GtkAdjustment
*adj
= chart
->adjustment
;
1028 g_return_if_fail (GTK_IS_ADJUSTMENT (adj
));
1030 DB( g_print("\n[gtkchart] sb_set_values\n") );
1032 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(adj
));
1034 DB( g_print(" entries=%d, visible=%d\n", chart
->nb_items
, chart
->visible
) );
1035 DB( g_print(" first=%d, upper=%d, pagesize=%d\n", first
, chart
->nb_items
, chart
->visible
) );
1037 gtk_adjustment_set_upper(adj
, (gdouble
)chart
->nb_items
);
1038 gtk_adjustment_set_page_size(adj
, (gdouble
)chart
->visible
);
1039 gtk_adjustment_set_page_increment(adj
, (gdouble
)chart
->visible
);
1041 if(first
+chart
->visible
> chart
->nb_items
)
1043 gtk_adjustment_set_value(adj
, (gdouble
)chart
->nb_items
- chart
->visible
);
1045 gtk_adjustment_changed (adj
);
1047 if( chart
->visible
< chart
->nb_items
)
1048 gtk_widget_hide(GTK_WIDGET(chart
->scrollbar
));
1050 gtk_widget_show(GTK_WIDGET(chart
->scrollbar
));
1057 ** draw all visible lines
1059 static void linechart_draw_plot(cairo_t
*cr
, double x
, double y
, double r
, GtkChart
*chart
)
1061 cairo_set_line_width(cr
, r
/ 2);
1063 cairo_user_set_rgbcol(cr
, &global_colors
[THBASE
]);
1064 cairo_arc(cr
, x
, y
, r
, 0, 2*M_PI
);
1065 cairo_stroke_preserve(cr
);
1067 //cairo_set_source_rgb(cr, COLTOCAIRO(0), COLTOCAIRO(119), COLTOCAIRO(204));
1068 cairo_user_set_rgbcol(cr
, &chart
->colors
[chart
->cs_blue
]);
1073 static void linechart_draw_lines(GtkWidget
*widget
, gpointer user_data
)
1075 GtkChart
*chart
= GTK_CHART(user_data
);
1077 double x
, y
, x2
, y2
, firstx
, lastx
, linew
;
1081 DB( g_print("\n(gtkline) line draw lines\n") );
1085 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1087 cr
= gdk_cairo_create (gtk_widget_get_window(widget
));
1088 //cr = cairo_create (chart->surface);
1091 //cairo_rectangle(cr, CHART_MARGIN, 0, chart->w, chart->h + CHART_MARGIN);
1097 cairo_set_line_width(cr
, 1.0);
1098 cairo_set_source_rgb(cr
, 1.0, 0.0, 1.0); // violet
1099 for(i
=first
; i
<=(first
+chart
->visible
) ;i
++)
1101 cairo_move_to(cr
, x2
, chart
->graph_y
);
1102 cairo_line_to(cr
, x2
, chart
->graph_x
+ chart
->graph_height
);
1108 //todo: it should be possible to draw line & plot together using surface and composite fill, or sub path ??
1112 if(chart
->barw
< 24)
1114 linew
= 1 + (chart
->barw
/ 8.0);
1117 cairo_set_line_join(cr
, CAIRO_LINE_JOIN_BEVEL
);
1118 cairo_set_line_width(cr
, linew
);
1120 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
1122 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
1124 x2
= x
+ (chart
->blkw
)/2;
1125 y2
= chart
->oy
- (item
->serie1
/ chart
->range
) * chart
->graph_height
;
1129 cairo_move_to(cr
, x2
, y2
);
1133 if( i
< (chart
->nb_items
) )
1135 cairo_line_to(cr
, x2
, y2
);
1139 lastx
= x2
- chart
->barw
;
1145 cairo_user_set_rgbcol(cr
, &chart
->colors
[chart
->cs_blue
]);
1146 cairo_stroke_preserve(cr
);
1148 cairo_line_to(cr
, lastx
, y
);
1149 cairo_line_to(cr
, firstx
, y
);
1150 cairo_close_path(cr
);
1152 cairo_user_set_rgbacol(cr
, &chart
->colors
[chart
->cs_blue
], 0.15);
1157 first
= (gint
)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1160 for(i
=first
; i
<(first
+chart
->visible
) ;i
++)
1162 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
1164 x2
= x
+ (chart
->blkw
)/2;
1165 y2
= chart
->oy
- (item
->serie1
/ chart
->range
) * chart
->graph_height
;
1166 linechart_draw_plot(cr
, x2
, y2
, i
== chart
->active
? linew
+1 : linew
, chart
);
1171 if( chart
->show_over
)
1173 if(chart
->minimum
!= 0 && chart
->minimum
>= chart
->min
)
1175 y
= chart
->oy
- (chart
->minimum
/chart
->range
) * chart
->graph_height
;
1176 cairo_set_source_rgba(cr
, COLTOCAIRO(255), COLTOCAIRO(0), COLTOCAIRO(0), .15);
1178 DB( g_print(" draw over: %f, %f, %f, %f\n", chart
->l
, y
, chart
->w
, chart
->b
- y
) );
1180 cairo_rectangle(cr
, chart
->graph_x
, y
, chart
->graph_width
, chart
->b
- y
);
1194 ** get the point under the mouse pointer
1196 static gint
linechart_get_active(GtkWidget
*widget
, gint x
, gint y
, gpointer user_data
)
1198 GtkChart
*chart
= GTK_CHART(user_data
);
1200 gint first
, index
, px
;
1204 if( x
<= chart
->r
&& x
>= chart
->l
)
1206 px
= (x
- chart
->graph_x
);
1207 //py = (y - chart->oy);
1208 first
= gtk_adjustment_get_value(GTK_ADJUSTMENT(chart
->adjustment
));
1209 index
= first
+ (px
/ (chart
->blkw
));
1211 if(index
< chart
->nb_items
)
1222 static void piechart_calculation(GtkChart
*chart
)
1224 GtkWidget
*drawarea
= chart
->drawarea
;
1225 GtkAllocation allocation
;
1228 w
= chart
->graph_width
;
1229 h
= chart
->graph_height
;
1231 chart
->rayon
= MIN(w
, h
);
1233 gtk_widget_get_allocation(drawarea
, &allocation
);
1235 chart
->ox
= chart
->graph_x
+ (chart
->graph_width
/ 2);
1236 chart
->oy
= chart
->graph_y
+ (chart
->rayon
/ 2);
1241 static void piechart_draw_slices(GtkWidget
*widget
, gpointer user_data
)
1243 GtkChart
*chart
= GTK_CHART(user_data
);
1246 if(chart
->nb_items
<= 0)
1252 double a1
= 0 * (M_PI
/ 180);
1253 double a2
= 360 * (M_PI
/ 180);
1255 //g_print("angle1=%.2f angle2=%.2f\n", a1, a2);
1257 double cx
= chart
->ox
;
1258 double cy
= chart
->oy
;
1259 double radius
= chart
->rayon
/2;
1265 cr
= gdk_cairo_create (gtk_widget_get_window(widget
));
1266 //cr = cairo_create (chart->surface);
1268 for(i
=0; i
< chart
->nb_items
;i
++)
1270 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, i
);
1272 a1
= ((360 * (sum
/ chart
->total
)) - 90) * (M_PI
/ 180);
1273 sum
+= ABS(item
->serie1
);
1274 a2
= ((360 * (sum
/ chart
->total
)) - 90) * (M_PI
/ 180);
1275 if(i
< chart
->nb_items
-1) a2
+= 0.0175;
1280 cairo_move_to(cr
, dx
, dy
);
1281 cairo_arc(cr
, dx
, dy
, radius
, a1
, a2
);
1283 #if PIE_LINE_SLICE == 1
1284 cairo_set_line_width(cr
, 1.0);
1285 cairo_set_source_rgb(cr
, 1.0, 1.0, 1.0);
1286 cairo_line_to(cr
, cx
, cy
);
1287 cairo_stroke_preserve(cr
);
1290 DB( g_print("%d: %.2f%% %.2f %.2f\n", i
, sum
/ chart
->total
, a1
, a2
) );
1292 //g_print("color : %f %f %f\n", COLTOCAIRO(colors[i].r), COLTOCAIRO(colors[i].g), COLTOCAIRO(colors[i].b));
1294 color
= i
% chart
->nb_cols
;
1295 cairo_user_set_rgbcol_over(cr
, &chart
->colors
[color
], i
== chart
->active
);
1300 cairo_pattern_t
*pat1
;
1305 pat1
= cairo_pattern_create_radial( cx
, cy
, 0, cx
, cy
, radius
);
1306 cairo_pattern_add_color_stop_rgba(pat1
, 0.0, 1.0, 1.0, 1.0, .50);
1307 cairo_pattern_add_color_stop_rgba(pat1
, 0.9, 1.0, 1.0, 1.0, 0.1);
1309 cairo_arc(cr
, cx
, cy
, radius
, a1
, a2
);
1310 cairo_set_source(cr
, pat1
);
1315 cairo_pattern_t
*pat1
;
1319 double gradius
= radius
- 8;
1321 // start point, end point
1322 pat1
= cairo_pattern_create_linear(cx
, cy
-gradius
, cx
, cy
+gradius
);
1324 cairo_pattern_add_color_stop_rgba(pat1
, 0.0, 1.0, 1.0, 1.0, .15);
1325 cairo_pattern_add_color_stop_rgba(pat1
, 1.0, 1.0, 1.0, 1.0, 0.0);
1328 //cairo_rectangle(cr, cx-radius, cy-radius, radius*2, radius*2);
1330 cairo_arc(cr
, cx
, cy
, gradius
, a1
, a2
);
1331 cairo_set_source(cr
, pat1
);
1336 #if CHART_PIE_DONUT == 1
1339 radius
= (gint
)((chart
->rayon
/3) * (1 / PHI
));
1341 cairo_arc(cr
, cx
, cy
, radius
, a1
, a2
);
1342 cairo_user_set_rgbcol(cr
, &global_colors
[THBASE
]);
1357 static gint
piechart_get_active(GtkWidget
*widget
, gint x
, gint y
, gpointer user_data
)
1359 GtkChart
*chart
= GTK_CHART(user_data
);
1360 gint retval
, px
, py
;
1366 h
= sqrt( pow(px
,2) + pow(py
,2) );
1369 if(h
< (chart
->rayon
/2))
1373 b
= (acos(px
/ h
) * 180) / M_PI
;
1374 angle
= py
> 0 ? b
: 360 - b
;
1376 if(angle
> 360) angle
-= 360;
1377 //angle = 360 - angle;
1381 for(index
=0; index
< chart
->nb_items
;index
++)
1383 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, index
);
1385 cumul
+= ABS(item
->serie1
/chart
->total
)*360;
1393 //DB( g_print(" inside: x=%d, y=%d\n", x, y) );
1394 //DB( g_print(" inside: b=%f angle=%f, slice is %d\n", b, angle, index) );
1400 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1401 static gboolean
drawarea_full_redraw(GtkWidget
*widget
, gpointer user_data
)
1403 GtkChart
*chart
= GTK_CHART(user_data
);
1404 cairo_text_extents_t te
;
1405 cairo_font_extents_t fe
;
1408 DB( g_print("\n[gtkchart] drawarea full redraw\n") );
1412 cr
= cairo_create (chart
->surface
);
1415 cairo_font_face_t
*ff
;
1416 cairo_scaled_font_t
*sf
;
1418 ff
= cairo_get_font_face(cr
);
1419 sf
= cairo_get_scaled_font(cr
);
1421 g_print("cairo ff = '%s'\n", cairo_toy_font_face_get_family(ff
) );
1423 ff
= cairo_scaled_font_get_font_face(sf
);
1424 g_print("cairo sf = '%s'\n", cairo_toy_font_face_get_family(ff
) );
1427 //cairo_set_font_face(cr, ff);
1436 /* fillin the back in white */
1437 //cairo_user_set_rgbcol(cr, &global_colors[WHITE]);
1438 cairo_user_set_rgbcol(cr
, &global_colors
[THBASE
]);
1442 /* taken from scrolled window
1443 gtk_paint_shadow (widget->style, widget->window,
1444 GTK_STATE_NORMAL, scrolled_window->shadow_type,
1445 area, widget, "scrolled_window",
1446 widget->allocation.x + relative_allocation.x,
1447 widget->allocation.y + relative_allocation.y,
1448 relative_allocation.width,
1449 relative_allocation.height);
1453 /*debug help draws */
1455 cairo_set_line_width(cr
, 1.0);
1456 cairo_set_source_rgb(cr
, 0.0, 1.0, 0.0); //green
1457 cairo_rectangle(cr
, chart
->l
+0.5, chart
->t
+0.5, chart
->w
, chart
->h
);
1460 cairo_set_source_rgb(cr
, 1.0, 0.5, 0.0); //orange
1461 cairo_rectangle(cr
, chart
->graph_x
+0.5, chart
->graph_y
+0.5, chart
->graph_width
, chart
->graph_height
);
1466 cairo_set_font_size(cr
, CHART_FONT_SIZE_TITLE
);
1467 cairo_font_extents(cr
, &fe
);
1468 cairo_text_extents(cr
, chart
->title
, &te
);
1472 cairo_set_source_rgb(cr
, 0.0, 0.0, 1.0); //blue
1474 cairo_set_dash (cr
, &dashlength
, 1, 0);
1475 cairo_move_to(cr
, chart
->l
, chart
->t
);
1476 cairo_rectangle(cr
, chart
->l
+ te
.x_bearing
, chart
->t
, te
.width
, fe
.height
);
1481 //cairo_move_to(cr, chart->l + (chart->w/2) - ((te.width - te.x_bearing) / 2), chart->t - te.y_bearing);
1482 cairo_move_to(cr
, chart
->l
, chart
->t
- te
.y_bearing
);
1483 //cairo_user_set_rgbcol(cr, &global_colors[BLACK]);
1484 cairo_user_set_rgbcol(cr
, &global_colors
[THTEXT
]);
1485 cairo_show_text(cr
, chart
->title
);
1489 if(chart
->nb_items
== 0)
1494 case CHART_TYPE_COL
:
1495 colchart_draw_scale(widget
, chart
);
1496 //colchart_draw_bars(widget, chart);
1497 colchart_draw_scale_text(widget
, chart
);
1499 case CHART_TYPE_LINE
:
1500 colchart_draw_scale(widget
, chart
);
1501 //linechart_draw_lines(widget, chart);
1502 colchart_draw_scale_text(widget
, chart
);
1504 case CHART_TYPE_PIE
:
1505 //piechart_draw_slices(widget, chart);
1514 drawarea_configure_event (GtkWidget
*widget
,
1515 GdkEventConfigure
*event
,
1518 GtkChart
*chart
= GTK_CHART(user_data
);
1519 GtkAllocation allocation
;
1523 DB( g_print("\n[gtkchart] drawarea configure \n") );
1525 DB( g_print("w=%d h=%d\n", allocation
.width
, allocation
.height
) );
1527 gtk_widget_get_allocation (widget
, &allocation
);
1529 chart_recompute(chart
);
1532 cairo_surface_destroy (chart
->surface
);
1534 chart
->surface
= gdk_window_create_similar_surface (gtk_widget_get_window (widget
),
1535 CAIRO_CONTENT_COLOR
,
1541 style
= gtk_widget_get_style (widget
);
1542 //style = gtk_widget_get_style (chart->treeview);
1543 //style = gtk_widget_get_default_style();
1546 color
= &style
->text
[GTK_STATE_NORMAL
];
1547 struct rgbcol
*tcol
= &global_colors
[THTEXT
];
1548 tcol
->r
= color
->red
;
1549 tcol
->g
= color
->green
;
1550 tcol
->b
= color
->blue
;
1551 DB( g_print(" - theme text col: %x %x %x\n", tcol
->r
, tcol
->g
, tcol
->b
) );
1554 color
= &style
->base
[GTK_STATE_NORMAL
];
1555 tcol
= &global_colors
[THBASE
];
1556 tcol
->r
= color
->red
;
1557 tcol
->g
= color
->green
;
1558 tcol
->b
= color
->blue
;
1559 DB( g_print(" - theme base col: %x %x %x\n", tcol
->r
, tcol
->g
, tcol
->b
) );
1562 drawarea_full_redraw(widget
, user_data
);
1565 /* We've handled the configure event, no need for further processing. */
1570 static void drawarea_sizeallocate_callback(GtkWidget
*widget
, GtkAllocation
*allocation
, gpointer user_data
)
1572 GtkChart
*chart
= GTK_CHART(user_data
);
1574 DB( g_print("\n[gtkchart] drawarea sizeallocate\n") );
1575 DB( g_print("w=%d h=%d\n", allocation
->width
, allocation
->height
) );
1577 //g_print("\n[gtkchart] drawarea sizeallocate\n") ;
1578 //g_print("w=%d h=%d\n", allocation->width, allocation->height) ;
1581 if( gtk_widget_get_realized(widget
))
1583 chart_recompute(chart
);
1589 static void drawarea_realize_callback(GtkWidget
*widget
, gpointer user_data
)
1591 //GtkChart *chart = GTK_CHART(user_data);
1593 DB( g_print("\n[gtkchart] drawarea realize\n") );
1595 //chart_recompute(chart);
1601 static gboolean
drawarea_draw_callback( GtkWidget
*widget
, GdkEventExpose
*event
, gpointer user_data
)
1603 GtkChart
*chart
= GTK_CHART(user_data
);
1606 DB( g_print("\n[gtkchart] drawarea expose\n") );
1608 DB( g_print(" type=%d regionempty=%d\n", event
->type
, cairo_region_is_empty(event
->region
)) );
1612 cr
= gdk_cairo_create (gtk_widget_get_window (widget
));
1614 cairo_set_source_surface (cr
, chart
->surface
, 0, 0);
1615 //gdk_cairo_rectangle (cr, &event->area);
1618 /* here draw only line, bar, slices */
1619 if(chart
->nb_items
== 0)
1624 case CHART_TYPE_COL
:
1625 colchart_draw_bars(widget
, chart
);
1627 case CHART_TYPE_LINE
:
1628 linechart_draw_lines(widget
, chart
);
1630 case CHART_TYPE_PIE
:
1631 piechart_draw_slices(widget
, chart
);
1643 static gboolean
drawarea_querytooltip_callback(GtkWidget
*widget
, gint x
, gint y
, gboolean keyboard_mode
, GtkTooltip
*tooltip
, gpointer user_data
)
1645 GtkChart
*chart
= GTK_CHART(user_data
);
1646 gchar
*strval
, *strval2
, *buffer
;
1647 gboolean retval
= FALSE
;
1649 DB( g_print("\n[gtkchart] drawarea querytooltip\n") );
1651 DB( g_print(" x=%d, y=%d kbm=%d\n", x
, y
, keyboard_mode
) );
1652 if(chart
->lastactive
!= chart
->active
)
1657 if(chart
->active
>= 0)
1659 ChartItem
*item
= &g_array_index(chart
->items
, ChartItem
, chart
->active
);
1661 strval
= chart_print_double(chart
, chart
->buffer1
, item
->serie1
);
1665 if( chart
->type
== CHART_TYPE_PIE
)
1666 buffer
= g_markup_printf_escaped("%s\n%s\n%.2f%%", item
->label
, strval
, item
->rate
);
1668 buffer
= g_markup_printf_escaped("%s\n%s", item
->label
, strval
);
1673 strval2
= chart_print_double(chart
, chart
->buffer2
, item
->serie2
);
1674 buffer
= g_markup_printf_escaped("%s\n+%s\n%s", item
->label
, strval2
, strval
);
1677 gtk_tooltip_set_text(tooltip
, buffer
);
1678 //gtk_label_set_markup(GTK_LABEL(chart->ttlabel), buffer);
1683 chart
->lastactive
= chart
->active
;
1689 static gboolean
drawarea_motionnotifyevent_callback(GtkWidget
*widget
, GdkEventMotion
*event
, gpointer user_data
)
1691 GtkChart
*chart
= GTK_CHART(user_data
);
1692 gboolean retval
= TRUE
;
1695 if(chart
->nb_items
== 0)
1698 DB( g_print("\n[gtkchart] drawarea motion\n") );
1705 DB( g_print(" is hint\n") );
1707 //gdk_window_get_device_position(event->window, event->device, &x, &y, NULL);
1708 gdk_window_get_pointer(event
->window
, &x
, &y
, NULL
);
1714 case CHART_TYPE_COL
:
1715 chart
->active
= colchart_get_active(widget
, x
, y
, chart
);
1717 case CHART_TYPE_LINE
:
1718 chart
->active
= linechart_get_active(widget
, x
, y
, chart
);
1720 case CHART_TYPE_PIE
:
1721 chart
->active
= piechart_get_active(widget
, x
, y
, chart
);
1725 // rollover redraw ?
1726 DB( g_print(" active: last=%d, curr=%d\n", chart
->lastactive
, chart
->active
) );
1728 if(chart
->lastactive
!= chart
->active
)
1730 DB( g_print(" rollover redraw :: active=%d\n", chart
->active
) );
1731 //chart->drawmode = CHART_DRAW_OVERCHANGE;
1732 //gtk_widget_queue_draw_area(widget, chart->graph_x, chart->graph_y, chart->graph_width, chart->graph_height);
1734 gtk_widget_queue_draw( widget
);
1738 DB( g_print(" x=%d, y=%d, time=%d\n", x
, y
, event
->time
) );
1739 DB( g_print(" trigger tooltip query\n") );
1741 gtk_tooltip_trigger_tooltip_query(gtk_widget_get_display(chart
->drawarea
));
1747 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1748 /* public functions */
1749 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1751 void gtk_chart_queue_redraw(GtkChart
*chart
)
1753 chart_recompute(chart
);
1754 drawarea_full_redraw(chart
->drawarea
, chart
);
1755 gtk_widget_queue_draw( chart
->drawarea
);
1760 ** change the model and/or column
1762 void gtk_chart_set_datas(GtkChart
*chart
, GtkTreeModel
*model
, guint column
, gchar
*title
)
1764 g_return_if_fail (GTK_IS_CHART (chart
));
1766 if( GTK_IS_TREE_MODEL(model
) )
1768 chart_setup_with_model(chart
, model
, column
, column
);
1770 chart
->title
= g_strdup(title
);
1774 gtk_chart_queue_redraw(chart
);
1778 chart_clear(chart
, TRUE
);
1783 ** change the model and/or column
1785 void gtk_chart_set_dualdatas(GtkChart
*chart
, GtkTreeModel
*model
, guint column1
, guint column2
, gchar
*title
)
1787 g_return_if_fail (GTK_IS_CHART (chart
));
1789 if( GTK_IS_TREE_MODEL(model
) )
1791 chart_setup_with_model(chart
, model
, column1
, column2
);
1793 chart
->title
= g_strdup(title
);
1797 gtk_chart_queue_redraw(chart
);
1801 chart_clear(chart
, TRUE
);
1807 ** change the type dynamically
1809 void gtk_chart_set_type(GtkChart
* chart
, gint type
)
1811 g_return_if_fail (GTK_IS_CHART (chart
));
1812 //g_return_if_fail (type < CHART_TYPE_MAX);
1814 DB( g_print("\n[gtkchart] set type %d\n", type
) );
1817 chart
->dual
= FALSE
;
1819 gtk_chart_queue_redraw(chart
);
1822 /* = = = = = = = = = = parameters = = = = = = = = = = */
1824 void gtk_chart_set_color_scheme(GtkChart
* chart
, gint colorscheme
)
1831 case CHART_COLMAP_HOMEBANK
:
1832 chart
->colors
= homebank_colors
;
1833 chart
->nb_cols
= homebank_nbcolors
;
1835 case CHART_COLMAP_MSMONEY
:
1836 chart
->colors
= money_colors
;
1837 chart
->nb_cols
= money_nbcolors
;
1840 case CHART_COLMAP_SAP
:
1841 chart
->colors
= sap_colors
;
1842 chart
->nb_cols
= sap_nbcolors
;
1844 case CHART_COLMAP_QUICKEN
:
1845 chart
->colors
= quicken_colors
;
1846 chart
->nb_cols
= quicken_nbcolors
;
1849 case CHART_COLMAP_OFFICE2010
:
1850 chart
->colors
= office2010_colors
;
1851 chart
->nb_cols
= office2010_nbcolors
;
1853 case CHART_COLMAP_OFFICE2013
:
1854 chart
->colors
= office2013_colors
;
1855 chart
->nb_cols
= office2013_nbcolors
;
1857 case CHART_COLMAP_ANALYTICS
:
1858 chart
->colors
= analytics_colors
;
1859 chart
->nb_cols
= analytics_nbcolors
;
1867 ** set the minor parameters
1869 void gtk_chart_set_minor_prefs(GtkChart
* chart
, gdouble rate
, gchar
*symbol
)
1871 g_return_if_fail (GTK_IS_CHART (chart
));
1873 chart
->minor_rate
= rate
;
1874 chart
->minor_symbol
= symbol
;
1878 void gtk_chart_set_absolute(GtkChart
* chart
, gboolean abs
)
1880 g_return_if_fail (GTK_IS_CHART (chart
));
1886 void gtk_chart_set_currency(GtkChart * chart, guint32 kcur)
1888 g_return_if_fail (GTK_IS_CHART (chart));
1895 ** set the overdrawn minimum
1897 void gtk_chart_set_overdrawn(GtkChart
* chart
, gdouble minimum
)
1899 g_return_if_fail (GTK_IS_CHART (chart
));
1901 chart
->minimum
= minimum
;
1903 //if(chart->type == CHART_TYPE_LINE)
1904 // chart_recompute(chart);
1908 ** set the every_xval
1910 void gtk_chart_set_every_xval(GtkChart
* chart
, gint gap
)
1912 g_return_if_fail (GTK_IS_CHART (chart
));
1914 chart
->every_xval
= gap
;
1916 //if(chart->type != CHART_TYPE_PIE)
1917 // chart_recompute(chart);
1924 void gtk_chart_set_barw(GtkChart
* chart
, gdouble barw
)
1926 g_return_if_fail (GTK_IS_CHART (chart
));
1930 if(chart
->type
!= CHART_TYPE_PIE
)
1931 gtk_chart_queue_redraw(chart
);
1935 /* = = = = = = = = = = visibility = = = = = = = = = = */
1938 ** change the legend visibility
1940 void gtk_chart_show_legend(GtkChart
* chart
, gboolean visible
, gboolean showextracol
)
1942 GtkTreeViewColumn
*column
;
1944 g_return_if_fail (GTK_IS_CHART (chart
));
1947 gtk_widget_show(chart
->scrollwin
);
1949 gtk_widget_hide(chart
->scrollwin
);
1951 /* manage column visibility */
1952 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(chart
->treeview
), 1); //amount
1953 gtk_tree_view_column_set_visible (column
, showextracol
);
1955 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(chart
->treeview
), 2); //percent
1956 gtk_tree_view_column_set_visible (column
, showextracol
);
1961 ** change the x-value visibility
1963 void gtk_chart_show_xval(GtkChart
* chart
, gboolean visible
)
1965 g_return_if_fail (GTK_IS_CHART (chart
));
1967 chart
->show_xval
= visible
;
1969 //if(chart->type != CHART_TYPE_PIE)
1970 // chart_recompute(chart);
1974 ** chnage the overdrawn visibility
1976 void gtk_chart_show_overdrawn(GtkChart
* chart
, gboolean visible
)
1978 g_return_if_fail (GTK_IS_CHART (chart
));
1980 chart
->show_over
= visible
;
1982 //if(chart->type == CHART_TYPE_LINE)
1983 // chart_recompute(chart);
1988 ** change the minor visibility
1990 void gtk_chart_show_minor(GtkChart
* chart
, gboolean minor
)
1992 g_return_if_fail (GTK_IS_CHART (chart
));
1994 chart
->minor
= minor
;
1996 if(chart
->type
!= CHART_TYPE_PIE
)
1997 gtk_chart_queue_redraw(chart
);
1999 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(chart
->treeview
));
2005 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2010 //create_color_pixbuf (const char *color)
2011 create_color_pixbuf (GdkColor
*col
)
2014 //GdkColor col = color;
2021 if (!gdk_color_parse (color, &col))
2025 #define squaredim 12
2027 pixbuf
= gdk_pixbuf_new (GDK_COLORSPACE_RGB
,
2029 squaredim
, squaredim
); //width,height
2031 //rowstride = gdk_pixbuf_get_rowstride (pixbuf);
2032 p
= gdk_pixbuf_get_pixels (pixbuf
);
2034 num
= gdk_pixbuf_get_width (pixbuf
) *
2035 gdk_pixbuf_get_height (pixbuf
);
2037 for (x
= 0; x
< num
; x
++) {
2044 p[0] = col->red / 65535 * 255;
2045 p[1] = col->green / 65535 * 255;
2046 p[2] = col->blue / 65535 * 255;
2054 static void legend_list_cell_data_function(GtkTreeViewColumn
*col
,
2055 GtkCellRenderer
*renderer
,
2056 GtkTreeModel
*model
,
2063 gtk_tree_model_get(model
, iter
,
2064 LST_LEGEND_COLOR
, &pixbuf
,
2065 LST_LEGEND_TITLE
, &title
,
2068 switch(GPOINTER_TO_INT(user_data
))
2070 case LST_LEGEND_COLOR
:
2071 g_object_set(renderer
, "pixbuf", pixbuf
, NULL
);
2073 case LST_LEGEND_TITLE
:
2074 g_object_set(renderer
, "text", title
, NULL
);
2081 legend_list_float_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
2083 GtkChart
*chart
= user_data
;
2084 gchar buf
[G_ASCII_DTOSTR_BUF_SIZE
];
2087 gtk_tree_model_get(model
, iter
,
2088 LST_LEGEND_AMOUNT
, &amount
,
2091 //hb_strfmon(buf, G_ASCII_DTOSTR_BUF_SIZE-1, value, kcur);
2092 //todo: manage GLOBALS->minor eq
2093 mystrfmon(buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, amount
, chart
->minor
);
2095 g_object_set(renderer
,
2101 static void legend_list_rate_cell_data_function (GtkTreeViewColumn
*col
,
2102 GtkCellRenderer
*renderer
,
2103 GtkTreeModel
*model
,
2110 gtk_tree_model_get(model
, iter
,
2111 LST_LEGEND_RATE
, &rate
,
2114 g_snprintf(buf
, sizeof(buf
), "%.02f %%", rate
);
2115 g_object_set(renderer
, "text", buf
, NULL
);
2120 static GtkWidget
*legend_list_new(GtkChart
*chart
)
2122 GtkListStore
*store
;
2124 GtkCellRenderer
*renderer
;
2125 GtkTreeViewColumn
*column
;
2127 store
= gtk_list_store_new(NUM_LST_LEGEND
,
2136 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
2137 g_object_unref(store
);
2141 PangoFontDescription *font_desc;
2143 g_print("legend_list_new font\n");
2145 style = gtk_widget_get_style(GTK_WIDGET(view));
2146 font_desc = style->font_desc;
2148 g_print("family: %s\n", pango_font_description_get_family(font_desc) );
2149 g_print("size: %d (%d)\n", pango_font_description_get_size (font_desc), pango_font_description_get_size (font_desc )/PANGO_SCALE );
2153 // change the font size to a smaller one
2154 PangoFontDescription
*font
= pango_font_description_new();
2155 pango_font_description_set_size (font
, 8 * PANGO_SCALE
);
2156 gtk_widget_modify_font(GTK_WIDGET(view
), font
);
2157 pango_font_description_free( font
);
2160 column
= gtk_tree_view_column_new();
2161 renderer
= gtk_cell_renderer_pixbuf_new ();
2162 gtk_tree_view_column_pack_start(column
, renderer
, FALSE
);
2163 gtk_tree_view_column_set_cell_data_func(column
, renderer
, legend_list_cell_data_function
, GINT_TO_POINTER(LST_LEGEND_COLOR
), NULL
);
2165 renderer
= gtk_cell_renderer_text_new ();
2166 gtk_tree_view_column_pack_start(column
, renderer
, FALSE
);
2167 gtk_tree_view_column_set_cell_data_func(column
, renderer
, legend_list_cell_data_function
, GINT_TO_POINTER(LST_LEGEND_TITLE
), NULL
);
2168 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
2170 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
2173 column
= gtk_tree_view_column_new();
2174 //gtk_tree_view_column_set_title(column, name);
2176 renderer
= gtk_cell_renderer_text_new ();
2177 g_object_set(renderer
, "xalign", 1.0, NULL
);
2178 gtk_tree_view_column_pack_start(column
, renderer
, FALSE
);
2179 gtk_tree_view_column_set_cell_data_func(column
, renderer
, legend_list_float_cell_data_function
, chart
, NULL
);
2180 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
2181 //gtk_tree_view_column_set_resizable(column, TRUE);
2182 //gtk_tree_view_column_set_alignment (column, 0.5);
2183 //gtk_tree_view_column_set_spacing( column, 16 );
2185 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
2186 gtk_tree_view_column_set_visible (column
, FALSE
);
2189 column
= gtk_tree_view_column_new();
2190 //gtk_tree_view_column_set_title(column, "%");
2191 renderer
= gtk_cell_renderer_text_new ();
2192 g_object_set(renderer
, "xalign", 1.0, NULL
);
2193 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
2194 //gtk_tree_view_column_add_attribute(column, renderer, "text", id);
2195 gtk_tree_view_column_set_cell_data_func(column
, renderer
, legend_list_rate_cell_data_function
, GINT_TO_POINTER(3), NULL
);
2196 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
2197 //gtk_tree_view_column_set_alignment (column, 0.5);
2198 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
2199 gtk_tree_view_column_set_visible (column
, FALSE
);
2202 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view
)), GTK_SELECTION_NONE
);
2203 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(view
), FALSE
);
2204 //gtk_tree_view_set_reorderable (GTK_TREE_VIEW(view), TRUE);
2207 GValue value = { 0, };
2208 g_value_init (&value, G_TYPE_INT);
2209 g_value_set_int (&value, 20);
2210 g_object_set_property(view, "vertical-separator", &value);
2211 g_value_unset (&value);