1 /*  HomeBank -- Free, easy, personal accounting for everyone.
2  *  Copyright (C) 1995-2021 Maxime DOYEN
3  *
4  *  This file is part of HomeBank.
5  *
6  *  HomeBank is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  HomeBank is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 #include <math.h>
22 #include <string.h>
23 
24 #include <gtk/gtk.h>
25 
26 #include "homebank.h"
27 #include "gtk-chart-colors.h"
28 #include "gtk-chart-progress.h"
29 
30 
31 /****************************************************************************/
32 /* Debug macros                                                             */
33 /****************************************************************************/
34 
35 
36 #define DB(x);
37 //#define DB(x) (x);
38 
39 //calculation
40 #define DBC(x);
41 //#define DBC(x) (x);
42 
43 //DB dynamics
44 #define DBD(x);
45 //#define DBD(x) (x);
46 
47 
48 #define DYNAMICS 1
49 
50 #define DBGDRAW_RECT 0
51 #define DBGDRAW_TEXT 0
52 #define DBGDRAW_ITEM 0
53 
54 
55 
56 /* --- prototypes --- */
57 static void ui_chart_progress_class_init      (ChartProgressClass *klass);
58 static void ui_chart_progress_init            (ChartProgress      *chart);
59 static void ui_chart_progress_destroy         (GtkWidget     *chart);
60 /*static void	ui_chart_progress_set_property		 (GObject           *object,
61 						  guint              prop_id,
62 						  const GValue      *value,
63 						  GParamSpec        *pspec);*/
64 
65 static gboolean drawarea_configure_event_callback (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data);
66 static gboolean drawarea_draw_callback(GtkWidget *widget, cairo_t *cr, gpointer user_data);
67 static void drawarea_style_changed_callback(GtkWidget *widget, gpointer   user_data);
68 static gboolean drawarea_scroll_event_callback( GtkWidget *widget, GdkEventScroll *event, gpointer user_data);
69 static gboolean drawarea_motionnotifyevent_callback(GtkWidget *widget, GdkEventMotion *event, gpointer user_data);
70 static void ui_chart_progress_first_changed( GtkAdjustment *adj, gpointer user_data);
71 
72 static void ui_chart_progress_clear(ChartProgress *chart, gboolean store);
73 
74 static gboolean drawarea_full_redraw(GtkWidget *widget, gpointer user_data);
75 static void ui_chart_progress_queue_redraw(ChartProgress *chart);
76 
77 /* --- variables --- */
78 static GtkBoxClass *parent_class = NULL;
79 
80 
81 /* --- functions --- */
82 
83 
84 
ui_chart_progress_set_font_size(ChartProgress * chart,PangoLayout * layout,gint font_size)85 static void ui_chart_progress_set_font_size(ChartProgress *chart, PangoLayout *layout, gint font_size)
86 {
87 PangoAttrList *attrs;
88 PangoAttribute *attr;
89 double scale = PANGO_SCALE_MEDIUM;
90 
91 	//PANGO_SCALE_MEDIUM = normal size
92 
93 	//DB( g_print("\n[chartprogress] set font size\n") );
94 
95 	switch(font_size)
96 	{
97 		case CHART_FONT_SIZE_TITLE:
98 			//size = chart->pfd_size + 3;
99 			scale = PANGO_SCALE_X_LARGE;
100 			break;
101 		case CHART_FONT_SIZE_SUBTITLE:
102 			//size = chart->pfd_size + 1;
103 			scale = PANGO_SCALE_LARGE;
104 			break;
105 		//case CHART_FONT_SIZE_NORMAL:
106 			//size = chart->pfd_size - 1;
107 		//	break;
108 		case CHART_FONT_SIZE_SMALL:
109 			//size = chart->pfd_size - 2;
110 			scale = PANGO_SCALE_SMALL;
111 			break;
112 	}
113 
114 	//DB( g_print(" size=%d\n", size) );
115 
116 	attrs = pango_attr_list_new ();
117 	attr  = pango_attr_scale_new(scale);
118 	pango_attr_list_insert (attrs, attr);
119 
120 	pango_layout_set_attributes (layout, attrs);
121 	pango_layout_set_font_description (layout, chart->pfd);
122 
123 	//pango_attribute_destroy(attr);
124 	pango_attr_list_unref (attrs);
125 
126 }
127 
128 
129 /*
130 ** print a integer number
131 */
ui_chart_progress_print_int(ChartProgress * chart,gdouble value)132 static gchar *ui_chart_progress_print_int(ChartProgress *chart, gdouble value)
133 {
134 
135 	hb_strfmon(chart->buffer, CHART_BUFFER_LENGTH-1, value, chart->kcur, chart->minor);
136 	return chart->buffer;
137 }
138 
139 
140 /*
141 ** get the bar under the mouse pointer
142 */
ui_chart_progress_get_hover(GtkWidget * widget,gint x,gint y,gpointer user_data)143 static gint ui_chart_progress_get_hover(GtkWidget *widget, gint x, gint y, gpointer user_data)
144 {
145 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
146 HbtkDrawProgContext *context = &chart->context;
147 gint retval, first, index, py;
148 gint blkw = context->blkw;
149 double oy;
150 
151 	DB( g_print("\n[chartprogress] get hover\n") );
152 
153 	retval = -1;
154 
155 	oy = context->t + context->title_zh + context->header_zh + context->subtitle_zh;
156 
157 	//DB( g_print(" y=%d, oy=%f, cb=%f\n", y, oy, chart->b) );
158 
159 	if( (y <= context->b && y >= oy) && (x >= context->l && x <= context->r) )
160 	{
161 		first = gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
162 		py = (y - oy);
163 		index = first + (py / blkw);
164 
165 
166 		if(index < chart->nb_items)
167 			retval = index;
168 
169 		DB( g_print(" hover=%d\n", retval) );
170 	}
171 
172 	return(retval);
173 }
174 
175 
ui_chart_progress_first_changed(GtkAdjustment * adj,gpointer user_data)176 static void ui_chart_progress_first_changed( GtkAdjustment *adj, gpointer user_data)
177 {
178 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
179 //gint first;
180 
181 	DB( g_print("\n[chartprogress] bar first changed\n") );
182 
183 	//first = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj));
184 
185 	//DB( g_print(" first=%d\n", first) );
186 
187 /*
188 	DB( g_print("scrollbar\n adj=%8x, low=%.2f upp=%.2f val=%.2f step=%.2f page=%.2f size=%.2f\n", adj,
189 		adj->lower, adj->upper, adj->value, adj->step_increment, adj->page_increment, adj->page_size) );
190  */
191     /* Set the number of decimal places to which adj->value is rounded */
192     //gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
193     //gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
194     drawarea_full_redraw (chart->drawarea, chart);
195 	gtk_widget_queue_draw(chart->drawarea);
196 
197 }
198 
199 /*
200 ** scrollbar set values for upper, page size, and also show/hide
201 */
ui_chart_progress_scrollbar_setvalues(ChartProgress * chart)202 static void ui_chart_progress_scrollbar_setvalues(ChartProgress *chart)
203 {
204 GtkAdjustment *adj = chart->adjustment;
205 HbtkDrawProgContext *context = &chart->context;
206 gint first;
207 
208 	g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
209 
210 	DB( g_print("\n[chartprogress] sb_set_values\n") );
211 
212 	//if(visible < entries)
213 	//{
214 		first = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj));
215 
216 		DB( g_print(" entries=%d, visible=%d\n", chart->nb_items, context->visible) );
217 		DB( g_print(" first=%d, upper=%d, pagesize=%d\n", first, chart->nb_items, context->visible) );
218 
219 		gtk_adjustment_set_upper(adj, (gdouble)chart->nb_items);
220 		gtk_adjustment_set_page_size(adj, (gdouble)context->visible);
221 		gtk_adjustment_set_page_increment(adj, (gdouble)context->visible);
222 
223 		if(first+context->visible > chart->nb_items)
224 		{
225 			gtk_adjustment_set_value(adj, (gdouble)chart->nb_items - context->visible);
226 		}
227 
228 		#if( (GTK_MAJOR_VERSION == 3) && (GTK_MINOR_VERSION < 18) )
229 			gtk_adjustment_changed (adj);
230 		#endif
231 
232 		//gtk_widget_show(GTK_WIDGET(scrollbar));
233 	//}
234 	//else
235 		//gtk_widget_hide(GTK_WIDGET(scrollbar));
236 
237 
238 }
239 
240 
ui_chart_progress_clear(ChartProgress * chart,gboolean store)241 static void ui_chart_progress_clear(ChartProgress *chart, gboolean store)
242 {
243 gint i;
244 
245 	DB( g_print("\n[chartprogress] clear\n") );
246 
247 	//free & clear any previous allocated datas
248 	if(chart->title != NULL)
249 	{
250 		g_free(chart->title);
251 		chart->title = NULL;
252 	}
253 
254 	if(chart->subtitle != NULL)
255 	{
256 		g_free(chart->subtitle);
257 		chart->subtitle = NULL;
258 	}
259 
260 	if(chart->items != NULL)
261 	{
262 		for(i=0;i<chart->nb_items;i++)
263 		{
264 		StackItem *item = &g_array_index(chart->items, StackItem, i);
265 
266 			g_free(item->label);	//we free label as it comes from a model_get into setup_with_model
267 			g_free(item->status);	//we free status as it comes from a model_get into setup_with_model
268 		}
269 		g_array_free(chart->items, TRUE);
270 		chart->items =  NULL;
271 	}
272 
273 	chart->nb_items = 0;
274 
275 }
276 
277 
ui_chart_progress_setup_with_model(ChartProgress * chart,GtkTreeModel * list_store,gchar * coltitle1,gchar * coltitle2)278 static void ui_chart_progress_setup_with_model(ChartProgress *chart, GtkTreeModel *list_store, gchar *coltitle1, gchar *coltitle2)
279 {
280 guint i;
281 gboolean valid;
282 GtkTreeIter iter;
283 
284 	DB( g_print("\n[chartprogress] setup with model\n") );
285 
286 	ui_chart_progress_clear(chart, TRUE);
287 
288 	chart->nb_items = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store), NULL);
289 
290 	chart->items = g_array_sized_new(FALSE, FALSE, sizeof(StackItem), chart->nb_items);
291 
292 	DB( g_print(" nb=%d\n", chart->nb_items) );
293 
294 	if(coltitle1)
295 		chart->budget_title = coltitle1;
296 	if(coltitle2)
297 		chart->result_title = coltitle2;
298 
299 	/* Get the first iter in the list */
300 	valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL(list_store), &iter);
301 	i = 0;
302 	while (valid)
303     {
304 	gint id;
305 	gchar *label, *status;
306 	gdouble	value1, value2;
307 	StackItem item;
308 
309 		gtk_tree_model_get (GTK_TREE_MODEL(list_store), &iter,
310 			0, &id,
311 			//1, &pos,
312 			2, &label,
313 			3, &value1,   //spent
314 			4, &value2,   //budget
315 			//5, &result,
316 			6, &status,
317 			-1);
318 
319 		item.label = label;
320 		item.spent = value1;
321 		item.budget = value2;
322 		item.status = status;
323 
324 		/* additional pre-compute */
325 		item.result = item.spent - item.budget;
326 		item.rawrate = 0;
327 		if(ABS(item.budget) > 0)
328 		{
329 			item.rawrate = item.spent / item.budget;
330 		}
331 
332 		item.warn = item.result < 0.0 ? TRUE : FALSE;
333 
334 		item.rate = CLAMP(item.rawrate, 0, 1.0);
335 
336 		g_array_append_vals(chart->items, &item, 1);
337 
338 		//don't g_free(label); here done into chart_clear
339 		//don't g_free(status); here done into chart_clear
340 
341 		i++;
342 		valid = gtk_tree_model_iter_next (list_store, &iter);
343 	}
344 
345 }
346 
347 
chart_progress_layout_area(cairo_t * cr,ChartProgress * chart,HbtkDrawProgContext * context)348 static void chart_progress_layout_area(cairo_t *cr, ChartProgress *chart, HbtkDrawProgContext *context)
349 {
350 PangoLayout *layout;
351 gchar *valstr;
352 int tw, th;
353 gint blkw;
354 gint i;
355 
356 	DB( g_print("\n[chartprogress] layout area\n") );
357 
358 	DB( g_print(" print %d ctx:%p\n", context->isprint, context) );
359 
360 
361 	/* Create a PangoLayout, set the font and text */
362 	layout = pango_cairo_create_layout (cr);
363 
364 
365 	// compute title
366 	context->title_zh = 0;
367 	if(chart->title)
368 	{
369 		//pango_font_description_set_size(chart->pfd, CHART_FONT_SIZE_TITLE * PANGO_SCALE);
370 		ui_chart_progress_set_font_size(chart, layout, CHART_FONT_SIZE_TITLE);
371 		pango_layout_set_font_description (layout, chart->pfd);
372 
373 		pango_layout_set_text (layout, chart->title, -1);
374 		pango_layout_get_size (layout, &tw, &th);
375 		context->title_zh = (th / PANGO_SCALE) + CHART_SPACING;
376 		DBC( g_print(" - title: %s w=%d h=%d\n", chart->title, tw, th) );
377 	}
378 
379 	// compute period
380 	context->subtitle_zh = 0;
381 	if(chart->subtitle)
382 	{
383 		//pango_font_description_set_size(chart->pfd, CHART_FONT_SIZE_PERIOD * PANGO_SCALE);
384 		ui_chart_progress_set_font_size(chart, layout, CHART_FONT_SIZE_SUBTITLE);
385 		pango_layout_set_font_description (layout, chart->pfd);
386 
387 		pango_layout_set_text (layout, chart->subtitle, -1);
388 		pango_layout_get_size (layout, &tw, &th);
389 		context->subtitle_zh = (th / PANGO_SCALE) + CHART_SPACING;
390 		DBC( g_print(" - period: %s w=%d h=%d\n", chart->subtitle, tw, th) );
391 	}
392 
393 	// compute other text
394 	//pango_font_description_set_size(chart->pfd, CHART_FONT_SIZE_NORMAL * PANGO_SCALE);
395 	ui_chart_progress_set_font_size(chart, layout, CHART_FONT_SIZE_NORMAL);
396 	pango_layout_set_font_description (layout, chart->pfd);
397 
398 	double title_w = 0;
399 	context->bud_col_w = 0;
400 	context->rel_col_w = 0;
401 
402 	gdouble maxbudget = 0;
403 	gdouble maxresult = 0;
404 	gdouble result;
405 	for(i=0;i<chart->nb_items;i++)
406 	{
407 	StackItem *item = &g_array_index(chart->items, StackItem, i);
408 
409 		// category width
410 		if( item->label != NULL )
411 		{
412 			pango_layout_set_text (layout, item->label, -1);
413 			pango_layout_get_size (layout, &tw, &th);
414 			title_w = MAX(title_w, (tw / PANGO_SCALE));
415 		}
416 
417 		DBC( g_print(" - calc '%s' title_w=%f (w=%d)\n", item->label, title_w, tw) );
418 
419 		//result = ABS(chart->spent[i]) - ABS(chart->budget[i]);
420 		result = ABS(item->spent - item->budget);
421 
422 		maxbudget = MAX(maxbudget, ABS(item->budget) );
423 		maxresult = MAX(maxresult, result);
424 
425 		DBC( g_print(" - maxbudget maxbudget=%f (w=%d)\n", maxbudget, tw) );
426 
427 		if( item->status != NULL )
428 		{
429 			pango_layout_set_text (layout, item->status, -1);
430 			pango_layout_get_size (layout, &tw, &th);
431 			context->rel_col_w = MAX(context->rel_col_w, (tw / PANGO_SCALE));
432 		}
433 	}
434 
435 	context->rel_col_w += CHART_SPACING;
436 
437 	// compute budget/result width
438 	valstr = ui_chart_progress_print_int(chart, -maxbudget);
439 	pango_layout_set_text (layout, valstr, -1);
440 	pango_layout_get_size (layout, &tw, &th);
441 	context->bud_col_w = (tw / PANGO_SCALE);
442 	pango_layout_set_text (layout, chart->budget_title, -1);
443 	pango_layout_get_size (layout, &tw, &th);
444 	context->bud_col_w = MAX(context->bud_col_w, (tw / PANGO_SCALE));
445 	DB( g_print(" budget-col: w=%f, %.2f, '%s'\n", context->bud_col_w, maxbudget, valstr) );
446 
447 
448 	valstr = ui_chart_progress_print_int(chart, -maxresult);
449 	pango_layout_set_text (layout, valstr, -1);
450 	pango_layout_get_size (layout, &tw, &th);
451 	context->res_col_w = (tw / PANGO_SCALE);
452 	pango_layout_set_text (layout, chart->result_title, -1);
453 	pango_layout_get_size (layout, &tw, &th);
454 	context->res_col_w = MAX(context->res_col_w, (tw / PANGO_SCALE));
455 	DB( g_print(" result-col: w=%f, %.2f, '%s'\n", context->res_col_w, maxresult, valstr) );
456 
457 
458 	// collect other width, add margins
459 	context->header_zh = (th / PANGO_SCALE) + CHART_SPACING;
460 	context->cat_col_w = title_w + CHART_SPACING;
461 
462 	//chart->title_y = chart->t;
463 	context->subtitle_y = context->t + context->title_zh;
464 	context->header_y = context->subtitle_y + context->subtitle_zh;
465 
466 
467 	context->graph_width  = context->w - context->cat_col_w - context->bud_col_w - context->res_col_w - context->rel_col_w - (double)(CHART_SPACING*4);
468 	context->graph_height = context->h - context->title_zh - context->subtitle_zh - context->header_zh;
469 
470 
471 	DB( g_print(" gfx_w = %.2f - %.2f - %.2f  - %.2f - %.2f \n",
472 		            context->w , context->cat_col_w , context->bud_col_w , context->res_col_w , (double)(CHART_SPACING*4)) );
473 
474 	DB( g_print(" gfx_w = %.2f\n", context->graph_width) );
475 
476 	//if expand : we compute available space
477 	//chart->barw = MAX(32, (chart->graph_width)/chart->nb_items);
478 	//chart->barw = 32; // usr setted or defaut to BARW
479 
480 	blkw = context->barw + floor(context->barw * 0.2);
481 	context->blkw = blkw;
482 
483 	context->visible = (context->graph_height - context->t) / blkw;
484 	context->visible = MIN(context->visible, chart->nb_items);
485 
486 	g_object_unref (layout);
487 
488 }
489 
490 
ui_chart_progress_recompute(ChartProgress * chart)491 static void ui_chart_progress_recompute(ChartProgress *chart)
492 {
493 GtkWidget *drawarea = chart->drawarea;
494 HbtkDrawProgContext *context = &chart->context;
495 GtkAllocation allocation;
496 cairo_surface_t *surf;
497 cairo_t *cr;
498 
499 	DB( g_print("\n[chartprogress] recompute \n") );
500 
501 	if( !gtk_widget_get_realized(chart->drawarea) || chart->surface == NULL )
502 		return;
503 
504 	gtk_widget_get_allocation(drawarea, &allocation);
505 
506 	context->l = CHART_MARGIN;
507 	context->t = CHART_MARGIN;
508 	context->r = allocation.width  - CHART_MARGIN;
509 	context->b = allocation.height - CHART_MARGIN;
510 	context->w = allocation.width  - (CHART_MARGIN*2);
511 	context->h = allocation.height - (CHART_MARGIN*2);
512 
513 	//todo: seems not working well...
514 	surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
515 	cr = cairo_create (surf);
516 
517 	chart_progress_layout_area(cr, chart, context);
518 
519 	cairo_destroy(cr);
520 	cairo_surface_destroy(surf);
521 
522 	gtk_adjustment_set_value(chart->adjustment, 0);
523 	ui_chart_progress_scrollbar_setvalues(chart);
524 	gtk_widget_show(chart->scrollbar);
525 
526 	//gtk_widget_queue_draw( chart->drawarea );
527 }
528 
529 
530 #if (DBGDRAW_RECT + DBGDRAW_TEXT + DBGDRAW_ITEM) > 0
ui_chart_progress_draw_help(cairo_t * cr,ChartProgress * chart,HbtkDrawProgContext * context)531 static void ui_chart_progress_draw_help(cairo_t *cr, ChartProgress *chart, HbtkDrawProgContext *context)
532 {
533 double x, y, y2;
534 gint first = 0;
535 gint i;
536 
537 	DB( g_print("\n[chartprogress] draw help\n") );
538 
539 	DB( g_print(" rect is: %f %f %f %f, barw=%f, ctx=%p\n", context->l, context->t, context->w, context->h, context->barw, context) );
540 
541 
542 	cairo_set_line_width (cr, 1);
543 
544 	#if DBGDRAW_RECT == 1
545 	//clip area
546 	cairo_set_line_width(cr, 1.0);
547 	cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); //green
548 	cairo_rectangle(cr, context->l+0.5, context->t+0.5, context->w, context->h);
549 	cairo_stroke(cr);
550 
551 	//graph area
552 	y = context->header_y + context->header_zh;
553 	cairo_set_source_rgb(cr, 1.0, 0.5, 0.0); //orange
554 	cairo_rectangle(cr, context->l+context->cat_col_w+0.5, y+0.5, context->graph_width+0.5, context->graph_height+0.5);
555 	cairo_stroke(cr);
556 	#endif
557 
558 	#if DBGDRAW_TEXT == 1
559 	//title rect
560 	cairo_set_source_rgb(cr, .0, .0, 1.0);
561 	cairo_rectangle(cr, context->l+0.5, context->t+0.5, context->w, context->title_zh);
562 	cairo_stroke(cr);
563 
564 	//period rect
565 	cairo_set_source_rgb(cr, .0, 0, 1.0);
566 	cairo_rectangle(cr, context->l+0.5, context->subtitle_y+0.5, context->w, context->subtitle_zh);
567 	cairo_stroke(cr);
568 
569 	//header rect
570 	cairo_set_source_rgb(cr, .0, 1.0, 1.0);
571 	cairo_rectangle(cr, context->l+0.5, context->header_y+0.5, context->w, context->header_zh);
572 	cairo_stroke(cr);
573 
574 	//category column
575 	y = context->t + context->title_zh + context->header_zh + context->subtitle_zh;
576 	cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); //blue
577 	cairo_rectangle(cr, context->l+0.5, y+0.5, context->cat_col_w, context->h - y);
578 	cairo_stroke(cr);
579 
580 	//budget column
581 	x = context->l + context->cat_col_w + context->graph_width + CHART_SPACING ;
582 	cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); //blue
583 	cairo_rectangle(cr, x+0.5, y+0.5, context->bud_col_w, context->h - y);
584 	cairo_stroke(cr);
585 
586 	//result column
587 	x = context->l + context->cat_col_w + context->graph_width + context->bud_col_w + (CHART_SPACING*3);
588 	cairo_set_source_rgb(cr, 0.0, 0.0, 1.0); //blue
589 	cairo_rectangle(cr, x+0.5, y+0.5, context->res_col_w, context->h - y);
590 	cairo_stroke(cr);
591 	#endif
592 
593 
594 	// draw item lines
595 	#if DBGDRAW_ITEM == 1
596 	y2 = y+0.5;
597 	cairo_set_line_width(cr, 1.0);
598 	double dashlength;
599 	dashlength = 4;
600 	cairo_set_dash (cr, &dashlength, 1, 0);
601 	cairo_set_source_rgb(cr, 1.0, 0.0, 1.0); // violet
602 	for(i=first; i<=(first+context->visible) ;i++)
603 	{
604 		cairo_move_to(cr, context->l, y2);
605 		cairo_line_to(cr, context->r, y2);
606 
607 		y2 += context->blkw;
608 	}
609 	cairo_stroke(cr);
610 	#endif
611 
612 }
613 #endif
614 
615 
616 /*
617 ** draw all visible bars
618 */
ui_chart_progress_draw_bars(cairo_t * cr,ChartProgress * chart,HbtkDrawProgContext * context)619 static void ui_chart_progress_draw_bars(cairo_t *cr, ChartProgress *chart, HbtkDrawProgContext *context)
620 {
621 double x, y, x2, y2, h;
622 gint first;
623 gint i, idx;
624 gchar *valstr;
625 PangoLayout *layout;
626 int tw, th;
627 
628 	DB( g_print("\n[chartprogress] draw bars\n") );
629 
630 	DB( g_print(" print %d ctx:%p\n", context->isprint, context) );
631 	DB( g_print(" rect is: %f %f %f %f, barw=%f, ctx=%p\n", context->l, context->t, context->w, context->h, context->barw, context) );
632 
633 
634 	layout = pango_cairo_create_layout (cr);
635 
636 	x = context->l + context->cat_col_w;
637 	y = context->t + context->title_zh + context->header_zh + context->subtitle_zh;
638 	first = context->first;
639 
640 		if(!context->isprint)
641 			cairo_user_set_rgbcol(cr, &global_colors[THTEXT]);
642 		else
643 			cairo_user_set_rgbcol(cr, &global_colors[BLACK]);
644 
645 	// draw title
646 	if(chart->title)
647 	{
648 		//pango_font_description_set_size(chart->pfd, CHART_FONT_SIZE_TITLE * PANGO_SCALE);
649 		ui_chart_progress_set_font_size(chart, layout, CHART_FONT_SIZE_TITLE);
650 		pango_layout_set_font_description (layout, chart->pfd);
651 		pango_layout_set_text (layout, chart->title, -1);
652 		pango_layout_get_size (layout, &tw, &th);
653 
654 		cairo_move_to(cr, context->l, context->t);
655 		pango_cairo_show_layout (cr, layout);
656 	}
657 
658 	// draw period
659 	if(chart->subtitle)
660 	{
661 		//pango_font_description_set_size(chart->pfd, CHART_FONT_SIZE_PERIOD * PANGO_SCALE);
662 		ui_chart_progress_set_font_size(chart, layout, CHART_FONT_SIZE_SUBTITLE);
663 		pango_layout_set_font_description (layout, chart->pfd);
664 		pango_layout_set_text (layout, chart->subtitle, -1);
665 		pango_layout_get_size (layout, &tw, &th);
666 
667 		cairo_move_to(cr, context->l, context->subtitle_y);
668 		pango_cairo_show_layout (cr, layout);
669 	}
670 
671 	// draw column title
672 	if(!context->isprint)
673 		cairo_user_set_rgbacol (cr, &global_colors[THTEXT], 0.78);
674 	else
675 		cairo_user_set_rgbacol (cr, &global_colors[BLACK], 0.78);
676 
677 	//pango_font_description_set_size(chart->pfd, CHART_FONT_SIZE_NORMAL * PANGO_SCALE);
678 	ui_chart_progress_set_font_size(chart, layout, CHART_FONT_SIZE_NORMAL);
679 	pango_layout_set_font_description (layout, chart->pfd);
680 
681 	pango_layout_set_text (layout, chart->budget_title, -1);
682 	pango_layout_get_size (layout, &tw, &th);
683 	cairo_move_to(cr, context->l + context->cat_col_w + context->graph_width + context->bud_col_w + CHART_SPACING - (tw /PANGO_SCALE), context->header_y);
684 	pango_cairo_show_layout (cr, layout);
685 
686 	pango_layout_set_text (layout, chart->result_title, -1);
687 	pango_layout_get_size (layout, &tw, &th);
688 	cairo_move_to(cr, context->l + context->cat_col_w + context->graph_width + context->bud_col_w + context->res_col_w - (tw /PANGO_SCALE) + (CHART_SPACING*3), context->header_y);
689 	pango_cairo_show_layout (cr, layout);
690 
691 
692 	// draw items
693 	//pango_font_description_set_size(chart->pfd, CHART_FONT_SIZE_NORMAL * PANGO_SCALE);
694 	ui_chart_progress_set_font_size(chart, layout, CHART_FONT_SIZE_NORMAL);
695 	pango_layout_set_font_description (layout, chart->pfd);
696 
697 	for(i=0; i<context->visible ;i++)
698 	{
699 	StackItem *item;
700 	gint barw = context->barw;
701 	gint blkw = context->blkw;
702 
703 		idx = i + first;
704 
705 		if( (guint)idx > (chart->items->len - 1) )
706 			break;
707 
708 		DB( g_print(" draw i:%d idx=%d", i, idx) );
709 
710 		item = &g_array_index(chart->items, StackItem, idx);
711 
712 		x2 = x;
713 		y2 = y + (CHART_SPACING/2) + (blkw * i);
714 
715 		DB( g_print(" '%-32s' wrn=%d %.2f%% (%.2f%%) :: r=% 4.2f s=% 4.2f b=% 4.2f\n",
716 			item->label, item->warn, item->rawrate, item->rate, item->result, item->spent, item->budget) );
717 
718 		valstr = item->label;
719 		pango_layout_set_text (layout, valstr, -1);
720 		pango_layout_get_size (layout, &tw, &th);
721 
722 		double ytext = y2 + ((barw - (th / PANGO_SCALE))/2);
723 
724 		if(!context->isprint)
725 			cairo_user_set_rgbacol (cr, &global_colors[THTEXT], 0.78);
726 		else
727 			cairo_user_set_rgbacol (cr, &global_colors[BLACK], 0.78);
728 		cairo_move_to(cr, context->l + context->cat_col_w - (tw / PANGO_SCALE) - CHART_SPACING, ytext);
729 		pango_cairo_show_layout (cr, layout);
730 
731 		// bar background
732 		if(!context->isprint)
733 			cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 0.15);
734 		else
735 			cairo_user_set_rgbacol(cr, &global_colors[BLACK], 0.15);
736 		cairo_rectangle(cr, x2, y2, context->graph_width, barw);
737 		cairo_fill(cr);
738 
739 		//bar with color :: todo migrate this
740 		h = floor(item->rate * context->graph_width);
741 		if(item->warn)
742 		{
743 			cairo_user_set_rgbcol_over(cr, &chart->color_scheme.colors[chart->color_scheme.cs_red], idx == chart->hover);
744 		}
745 		else
746 		{
747 			if(item->rate > 0.8 && item->rate < 1.0)
748 				cairo_user_set_rgbcol_over(cr, &chart->color_scheme.colors[chart->color_scheme.cs_orange], idx == chart->hover);
749 			else
750 				cairo_user_set_rgbcol_over(cr, &chart->color_scheme.colors[chart->color_scheme.cs_green], idx == chart->hover);
751 		}
752 
753 		cairo_rectangle(cr, x2, y2, h, barw);
754 		cairo_fill(cr);
755 
756 		// spent value
757 		if( item->result != 0)
758 		{
759 			valstr = ui_chart_progress_print_int(chart, item->spent);
760 			pango_layout_set_text (layout, valstr, -1);
761 			pango_layout_get_size (layout, &tw, &th);
762 
763 			if( h  >= ( (tw / PANGO_SCALE) + (CHART_SPACING*2)) )
764 			{
765 				// draw inside
766 				cairo_user_set_rgbcol(cr, &global_colors[WHITE]);
767 				cairo_move_to(cr, x2 + h - (tw / PANGO_SCALE) - CHART_SPACING, ytext);
768 			}
769 			else
770 			{
771 				// draw outside
772 				//cairo_user_set_rgbacol(cr, &global_colors[THTEXT], 0.78);
773 				//#1897696 draw out of budget text in red
774 				if( item->warn )
775 					cairo_user_set_rgbcol (cr, &chart->color_scheme.colors[chart->color_scheme.cs_red]);
776 				else
777 				{
778 					if(!context->isprint)
779 						cairo_user_set_rgbacol (cr, &global_colors[THTEXT], 0.78);
780 					else
781 						cairo_user_set_rgbacol (cr, &global_colors[BLACK], 0.78);
782 				}
783 				cairo_move_to(cr, x2 + h + CHART_SPACING, ytext);
784 			}
785 
786 			pango_cairo_show_layout (cr, layout);
787 		}
788 
789 		// budget value
790 		valstr = ui_chart_progress_print_int(chart, item->budget);
791 		pango_layout_set_text (layout, valstr, -1);
792 		pango_layout_get_size (layout, &tw, &th);
793 
794 		if(!context->isprint)
795 			cairo_user_set_rgbacol (cr, &global_colors[THTEXT], 0.78);
796 		else
797 			cairo_user_set_rgbacol (cr, &global_colors[BLACK], 0.78);
798 		cairo_move_to(cr, context->l + context->cat_col_w + context->graph_width + context->bud_col_w + CHART_SPACING - (tw / PANGO_SCALE), ytext);
799 		pango_cairo_show_layout (cr, layout);
800 
801 		// result value
802 
803 		if( item->result != 0)
804 		{
805 			valstr = ui_chart_progress_print_int(chart, item->result);
806 
807 			if(item->warn)
808 				//cairo_set_source_rgb(cr, COLTOCAIRO(164), COLTOCAIRO(0), COLTOCAIRO(0));
809 				cairo_user_set_rgbcol(cr, &chart->color_scheme.colors[chart->color_scheme.cs_red]);
810 			else
811 			{
812 				if(!context->isprint)
813 					cairo_user_set_rgbacol (cr, &global_colors[THTEXT], 0.78);
814 				else
815 					cairo_user_set_rgbacol (cr, &global_colors[BLACK], 0.78);
816 			}
817 
818 			pango_layout_set_text (layout, valstr, -1);
819 			pango_layout_get_size (layout, &tw, &th);
820 			cairo_move_to(cr, context->l + context->cat_col_w + context->graph_width + context->bud_col_w + context->res_col_w - (tw / PANGO_SCALE) + (CHART_SPACING*3), ytext);
821 			pango_cairo_show_layout (cr, layout);
822 
823 			// status
824 			if( item->status )
825 			{
826 				pango_layout_set_text (layout, item->status, -1);
827 				pango_layout_get_size (layout, &tw, &th);
828 				cairo_move_to(cr, context->l + context->cat_col_w + context->graph_width + context->bud_col_w + context->res_col_w  + (CHART_SPACING*4), ytext);
829 				pango_cairo_show_layout (cr, layout);
830 			}
831 		}
832 
833 		//y += blkw;
834 
835 	}
836 
837 	g_object_unref (layout);
838 
839 }
840 
841 
842 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
843 
844 
drawarea_full_redraw(GtkWidget * widget,gpointer user_data)845 static gboolean drawarea_full_redraw(GtkWidget *widget, gpointer user_data)
846 {
847 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
848 HbtkDrawProgContext *context = &chart->context;
849 cairo_t *cr;
850 
851 	DB( g_print("\n[chartprogress] drawarea full redraw\n") );
852 
853 	cr = cairo_create (chart->surface);
854 
855 	/* fillin the back in white */
856 	if(!context->isprint)
857 		cairo_user_set_rgbcol(cr, &global_colors[THBASE]);
858 	else
859 		cairo_user_set_rgbcol(cr, &global_colors[WHITE]);
860 
861 	cairo_paint(cr);
862 
863 	if(chart->nb_items == 0)
864 	{
865 		cairo_destroy(cr);
866 		return FALSE;
867 	}
868 
869 	cairo_rectangle(cr, context->l, context->t, context->w, context->h);
870 	cairo_clip(cr);
871 
872 
873 #if (DBGDRAW_RECT + DBGDRAW_TEXT + DBGDRAW_ITEM) > 0
874 	ui_chart_progress_draw_help(cr, chart, context);
875 #endif
876 
877 	context->first = (gint)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
878 
879 	ui_chart_progress_draw_bars(cr, chart, context);
880 
881 	cairo_destroy(cr);
882 
883 	return TRUE;
884 }
885 
886 
887 //static void drawarea_get_style(GtkWidget *widget, gpointer user_data)
888 
889 
890 static gboolean
drawarea_configure_event_callback(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)891 drawarea_configure_event_callback (GtkWidget         *widget,
892                           GdkEventConfigure *event,
893                           gpointer           user_data)
894 {
895 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
896 HbtkDrawProgContext *context = &chart->context;
897 GtkAllocation allocation;
898 GtkStyleContext *stylctx;
899 PangoFontDescription *desc;
900 gboolean colfound;
901 GdkRGBA color;
902 
903 	DB( g_print("\n[chartprogress] drawarea configure \n") );
904 
905 	DB( g_print("w=%d h=%d\n", allocation.width, allocation.height) );
906 
907 	gtk_widget_get_allocation (widget, &allocation);
908 
909 	if (chart->surface)
910 		cairo_surface_destroy (chart->surface);
911 
912 	chart->surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
913                                                CAIRO_CONTENT_COLOR,
914                                                allocation.width,
915                                                allocation.height);
916 
917 	stylctx = gtk_widget_get_style_context (widget);
918 
919 	chart_color_global_default();
920 
921 	// get base color
922 	colfound = gtk_style_context_lookup_color(stylctx, "theme_base_color", &color);
923 	if(!colfound)
924 		colfound = gtk_style_context_lookup_color(stylctx, "base_color", &color);
925 
926 	if( colfound )
927 	{
928 		struct rgbcol *tcol = &global_colors[THBASE];
929 		tcol->r = color.red * 255;
930 		tcol->g = color.green * 255;
931 		tcol->b = color.blue * 255;
932 		DB( g_print(" - theme base col: %x %x %x\n", tcol->r, tcol->g, tcol->b) );
933 	}
934 
935 	//get text color
936 	colfound = gtk_style_context_lookup_color(stylctx, "theme_text_color", &color);
937 	if(!colfound)
938 		//#1916932 colfound was not assigned
939 		colfound = gtk_style_context_lookup_color(stylctx, "text_color", &color);
940 
941 	if( colfound )
942 	{
943 		struct rgbcol *tcol = &global_colors[THTEXT];
944 		tcol->r = color.red * 255;
945 		tcol->g = color.green * 255;
946 		tcol->b = color.blue * 255;
947 		DB( g_print(" - theme text (bg) col: %x %x %x\n", tcol->r, tcol->g, tcol->b) );
948 	}
949 
950 	/* get and copy the font */
951 	gtk_style_context_get(stylctx, GTK_STATE_FLAG_NORMAL, "font", &desc, NULL);
952 	if(chart->pfd)
953 	{
954 		pango_font_description_free (chart->pfd);
955 		chart->pfd = NULL;
956 	}
957 	chart->pfd = pango_font_description_copy(desc);
958 	chart->pfd_size = pango_font_description_get_size (desc) / PANGO_SCALE;
959 	context->barw = (6 + chart->pfd_size) * PHI;
960 
961 	//leak: we should free desc here ?
962 	//or no need to copy above ?
963 	//pango_font_description_free(desc);
964 
965 	DB( g_print("family: %s\n", pango_font_description_get_family(chart->pfd) ) );
966 	DB( g_print("size  : %d (%d)\n", chart->pfd_size, chart->pfd_size/PANGO_SCALE ) );
967 	DB( g_print("isabs : %d\n", pango_font_description_get_size_is_absolute (chart->pfd) ) );
968 
969 	if( gtk_widget_get_realized(widget) )
970 	{
971 		ui_chart_progress_recompute(chart);
972 		drawarea_full_redraw(widget, user_data);
973 	}
974 
975 	/* We've handled the configure event, no need for further processing. */
976 	return TRUE;
977 }
978 
979 
980 //state
981 
982 
drawarea_style_changed_callback(GtkWidget * widget,gpointer user_data)983 static void drawarea_style_changed_callback(GtkWidget *widget, gpointer   user_data)
984 {
985 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
986 
987 	DB( g_print("\n[chartprogress] drawarea style changed\n") );
988 
989 	if( gtk_widget_get_realized(widget))
990 	{
991 		drawarea_full_redraw(widget, chart);
992 	}
993 }
994 
995 
drawarea_draw_callback(GtkWidget * widget,cairo_t * cr,gpointer user_data)996 static gboolean drawarea_draw_callback(GtkWidget *widget, cairo_t *cr, gpointer user_data)
997 {
998 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
999 HbtkDrawProgContext *context = &chart->context;
1000 
1001 	if( !gtk_widget_get_realized(widget) || chart->surface == NULL )
1002 		return FALSE;
1003 
1004 	DB( g_print("\n[chartprogress] drawarea draw cb\n") );
1005 
1006 	cairo_set_source_surface (cr, chart->surface, 0, 0);
1007 	cairo_paint (cr);
1008 
1009 	/* always redraw directly the hover block */
1010 	gint first;
1011 	double ox, oy;
1012 
1013 	first = (gint)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
1014 	ox = context->l + context->cat_col_w;
1015 	oy = context->t + context->title_zh + context->header_zh + context->subtitle_zh;
1016 
1017 
1018 	if(chart->hover != -1)
1019 	{
1020 		DB( g_print(" draw hover\n") );
1021 
1022 		cairo_rectangle(cr, context->l, context->t, context->w, context->h);
1023 		cairo_clip(cr);
1024 
1025 		oy += CHART_SPACING/2 + (chart->hover - first) * context->blkw;
1026 		cairo_user_set_rgbacol(cr, &global_colors[WHITE], OVER_ALPHA);
1027 
1028 		cairo_rectangle(cr, ox, oy, context->graph_width, context->barw);
1029 		cairo_fill(cr);
1030 	}
1031 
1032 	return FALSE;
1033 }
1034 
1035 
drawarea_motionnotifyevent_callback(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)1036 static gboolean drawarea_motionnotifyevent_callback(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
1037 {
1038 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
1039 HbtkDrawProgContext *context = &chart->context;
1040 gint x, y;
1041 
1042 	if(chart->surface == NULL || chart->nb_items == 0)
1043 		return FALSE;
1044 
1045 	DBD( g_print("\n[chartprogress] drawarea motion cb\n") );
1046 	x = event->x;
1047 	y = event->y;
1048 
1049 	//todo see this
1050 	if(event->is_hint)
1051 	{
1052 		//DB( g_print(" is hint\n") );
1053 
1054 		gdk_window_get_device_position(event->window, event->device, &x, &y, NULL);
1055 		//gdk_window_get_pointer(event->window, &x, &y, NULL);
1056 		//return FALSE;
1057 	}
1058 
1059 	chart->hover = ui_chart_progress_get_hover(widget, x, y, chart);
1060 
1061 
1062 	// rollover redraw ?
1063 	DBD( g_print(" %d, %d :: hover: last=%d, curr=%d\n", x, y, chart->lasthover, chart->hover) );
1064 
1065 	if(chart->lasthover != chart->hover)
1066 	{
1067 	GdkRectangle update_rect;
1068 	gint first;
1069 	double oy;
1070 
1071 		DBD( g_print(" motion rollover redraw :: hover=%d\n", chart->hover) );
1072 
1073 		first = (gint)gtk_adjustment_get_value(GTK_ADJUSTMENT(chart->adjustment));
1074 		oy = context->t + context->title_zh + context->header_zh + context->subtitle_zh;
1075 
1076 		if(chart->lasthover != -1)
1077 		{
1078 			update_rect.x = context->l;
1079 			update_rect.y = oy + (chart->lasthover - first) * context->blkw;
1080 			update_rect.width = context->r;
1081 			update_rect.height = context->blkw;
1082 
1083 			/* Now invalidate the affected region of the drawing area. */
1084 			gdk_window_invalidate_rect (gtk_widget_get_window (widget),
1085 		                          &update_rect,
1086 		                          FALSE);
1087 		}
1088 
1089 		update_rect.x = context->l;
1090 		update_rect.y = oy + (chart->hover - first) * context->blkw;
1091 		update_rect.width = context->r;
1092 		update_rect.height = context->blkw;
1093 
1094 		/* Now invalidate the affected region of the drawing area. */
1095 		gdk_window_invalidate_rect (gtk_widget_get_window (widget),
1096 	                          &update_rect,
1097 	                          FALSE);
1098 
1099 		//gtk_widget_queue_draw( widget );
1100 		//retval = FALSE;
1101 	}
1102 
1103 	chart->lasthover = chart->hover;
1104 
1105 	return TRUE;
1106 }
1107 
1108 
drawarea_scroll_event_callback(GtkWidget * widget,GdkEventScroll * event,gpointer user_data)1109 static gboolean drawarea_scroll_event_callback( GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
1110 {
1111 ChartProgress *chart = GTK_CHARTPROGRESS(user_data);
1112 GtkAdjustment *adj = chart->adjustment;
1113 gdouble first, upper, pagesize;
1114 
1115 	DB( g_print("\n[chartprogress] scroll\n") );
1116 
1117 	first = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj));
1118 	//lower = gtk_adjustment_get_lower(GTK_ADJUSTMENT(adj));
1119 	upper = gtk_adjustment_get_upper(GTK_ADJUSTMENT(adj));
1120 	pagesize = gtk_adjustment_get_page_size(GTK_ADJUSTMENT(adj));
1121 
1122 	DB( g_print("- pos is %.2f, [%.2f - %.2f]\n", first, 0.0, upper) );
1123 
1124 	switch(event->direction)
1125 	{
1126 		case GDK_SCROLL_UP:
1127 			gtk_adjustment_set_value(adj, first - 1);
1128 			break;
1129 		case GDK_SCROLL_DOWN:
1130 			gtk_adjustment_set_value(adj, CLAMP(first + 1, 0, upper - pagesize) );
1131 			break;
1132 		default:
1133 			break;
1134 	}
1135 
1136 	drawarea_full_redraw(widget, user_data);
1137 
1138 	return TRUE;
1139 }
1140 
1141 
1142 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1143 /* public functions */
1144 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1145 static void
gtk_chart_progress_begin_print(GtkPrintOperation * operation,GtkPrintContext * context,gpointer user_data)1146 gtk_chart_progress_begin_print (GtkPrintOperation *operation,
1147              GtkPrintContext   *context,
1148              gpointer           user_data)
1149 {
1150 GtkChartProgPrintData *data = user_data;
1151 HbtkDrawProgContext *drawctx;
1152 gdouble t, l, w, h;
1153 cairo_t *cr;
1154 
1155 	DB( g_print("\n[chartprogress] begin print\n") );
1156 
1157 
1158 	//gtk_print_context_get_hard_margins(context, &t, &b, &l, &r);
1159 	t = 0;
1160 	l = 0;
1161 	w = gtk_print_context_get_width(context);
1162 	h = gtk_print_context_get_height(context);
1163 
1164 
1165 	//TODO: test keeping a ratio and handle orientation myself
1166 	/*
1167 	settings = gtk_print_operation_get_print_settings(operation);
1168 	ratio = (height < width) ? width/height : height/width;
1169 
1170 	DB( g_print(" orientation: %d\n", gtk_print_settings_get_orientation(settings)) );
1171 	DB( g_print(" w=%g h=%g // ratio %g\n", width, height, ratio) );
1172 
1173 	if( height < width )
1174 		height = width * ratio;
1175 	*/
1176 
1177 	//setup our context
1178 	drawctx = &data->drawctx;
1179 	drawctx->isprint = TRUE;
1180 	drawctx->l = l;
1181 	drawctx->t = t;
1182 	drawctx->w = w;
1183 	drawctx->h = h;
1184 
1185 
1186 
1187 	//hack
1188 	PangoContext *pctx = gtk_print_context_create_pango_context(context);
1189 	PangoFontDescription *pfd = pango_context_get_font_description(pctx);
1190 	drawctx->barw = (6 + (pango_font_description_get_size(pfd) / PANGO_SCALE )) * PHI;
1191 	g_object_unref(pctx);
1192 
1193 
1194 	cr = gtk_print_context_get_cairo_context (context);
1195 
1196 	DB( g_print(" rect is: %f %f %f %f, barw=%f, ctx=%p\n", l, t, w, h, drawctx->barw, drawctx) );
1197 
1198 
1199 	chart_progress_layout_area(cr, data->chart, drawctx);
1200 
1201 
1202 	data->num_pages = ceil((gdouble)data->chart->nb_items / (gdouble)drawctx->visible);
1203 
1204 	g_print(" nb pages: %d, nbitems %d / visi %d = %.2f\n", data->num_pages, data->chart->nb_items, drawctx->visible, (gdouble)data->chart->nb_items / (gdouble)drawctx->visible);
1205 
1206 	gtk_print_operation_set_n_pages (operation, data->num_pages);
1207 
1208 
1209 }
1210 
1211 
gtk_chart_progress_draw_page(GtkPrintOperation * operation,GtkPrintContext * context,gint page_nr,gpointer user_data)1212 static void gtk_chart_progress_draw_page (GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data)
1213 {
1214 GtkChartProgPrintData *data = user_data;
1215 HbtkDrawProgContext *drawctx;
1216 cairo_t *cr;
1217 
1218 	DB( g_print("\n[chartprogress] draw page\n") );
1219 
1220 
1221 	cr = gtk_print_context_get_cairo_context (context);
1222 
1223 	drawctx = &data->drawctx;
1224 
1225 	//cairo_rectangle (cr, drawctx->l, drawctx->t, drawctx->w - drawctx->r, drawctx->h - drawctx->b);
1226 	//cairo_clip(cr);
1227 
1228 	cairo_set_line_width (cr, 1);
1229 
1230 	//draw debug rectangle
1231 	/*
1232 	cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); //red
1233 	cairo_rectangle(cr, 0, 0, drawctx->w-drawctx->r, drawctx->h-drawctx->b);
1234 	cairo_stroke(cr);
1235 	*/
1236 
1237 	drawctx->first = page_nr * drawctx->visible;
1238 
1239 	g_print(" draw page %d, with first=%d\n", page_nr, drawctx->first);
1240 
1241 
1242 #if (DBGDRAW_RECT + DBGDRAW_TEXT + DBGDRAW_ITEM) > 0
1243 	ui_chart_progress_draw_help(cr, data->chart, drawctx);
1244 #endif
1245 
1246 	ui_chart_progress_draw_bars(cr, data->chart, drawctx);
1247 
1248 }
1249 
1250 
gtk_chart_progress_print(ChartProgress * chart,GtkWindow * parent,gchar * dirname,gchar * filename)1251 void gtk_chart_progress_print(ChartProgress *chart, GtkWindow *parent, gchar *dirname, gchar *filename)
1252 {
1253 GtkChartProgPrintData *data;
1254 GtkPrintOperation *operation;
1255 GtkPrintSettings *settings;
1256 gchar *ext, *uri = NULL;
1257 GError *error = NULL;
1258 
1259 	g_return_if_fail (GTK_IS_CHARTPROGRESS (chart));
1260 
1261 
1262 	g_print("\n[chartprogress] print\n");
1263 
1264 	data = g_new0 (GtkChartProgPrintData, 1);
1265 
1266 	data->chart = chart;
1267 
1268 	settings = gtk_print_settings_new ();
1269 	//TODO: this doesn't work for unknown reason...
1270 	gtk_print_settings_set_orientation(settings, GTK_PAGE_ORIENTATION_PORTRAIT);
1271 
1272 	if( dirname !=  NULL && filename != NULL )
1273 	{
1274 		if (g_strcmp0 (gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT), "ps") == 0)
1275 		ext = ".ps";
1276 		else if (g_strcmp0 (gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT), "svg") == 0)
1277 		ext = ".svg";
1278 		else
1279 		ext = ".pdf";
1280 		uri = g_strconcat ("file://", dirname, "/", filename, ext, NULL);
1281 		gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
1282 	}
1283 
1284 
1285 	operation = gtk_print_operation_new ();
1286 
1287 	g_signal_connect (G_OBJECT (operation), "begin-print", G_CALLBACK (gtk_chart_progress_begin_print), data);
1288 	g_signal_connect (G_OBJECT (operation), "draw-page", G_CALLBACK (gtk_chart_progress_draw_page), data);
1289 	//g_signal_connect (G_OBJECT (operation), "end-print", G_CALLBACK (end_print), data);
1290 
1291 
1292 	gtk_print_operation_set_use_full_page (operation, FALSE);
1293 	gtk_print_operation_set_unit (operation, GTK_UNIT_POINTS);
1294 	gtk_print_operation_set_embed_page_setup (operation, TRUE);
1295 
1296 	gtk_print_operation_set_print_settings (operation, settings);
1297 
1298 	//test forec pagfe
1299 	//GtkPageSetup *ps = gtk_print_operation_get_default_page_setup(operation);
1300 
1301 	GtkPageSetup *ps = gtk_page_setup_new();
1302 
1303 
1304 	if( ps )
1305 		gtk_page_setup_set_orientation(ps, GTK_PAGE_ORIENTATION_LANDSCAPE);
1306 	else
1307 		g_print("pagesetup fail\n");
1308 
1309 	gtk_print_operation_set_default_page_setup(operation, ps);
1310 
1311 
1312 	gtk_print_operation_run (operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW (parent), &error);
1313 
1314 	//to use with GTK_PRINT_OPERATION_ACTION_EXPORT
1315 	//gtk_print_operation_set_export_filename(operation, "/home/max/Desktop/testpdffile.pdf");
1316 	//gtk_print_operation_run (operation, GTK_PRINT_OPERATION_ACTION_EXPORT, GTK_WINDOW (window), &error);
1317 
1318 
1319 	g_object_unref (operation);
1320 	g_object_unref (settings);
1321 	g_free (uri);
1322 
1323 	if (error)
1324 	{
1325 	GtkWidget *dialog;
1326 
1327 		dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
1328 			GTK_DIALOG_DESTROY_WITH_PARENT,
1329 			GTK_MESSAGE_ERROR,
1330 			GTK_BUTTONS_CLOSE,
1331 			"%s", error->message);
1332 
1333 		g_error_free (error);
1334 
1335 		g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
1336 
1337 		gtk_widget_show (dialog);
1338 	}
1339 
1340 	g_free(data);
1341 }
1342 
1343 
1344 
1345 
1346 
ui_chart_progress_queue_redraw(ChartProgress * chart)1347 static void ui_chart_progress_queue_redraw(ChartProgress *chart)
1348 {
1349 
1350 	DB( g_print("\n[chartprogress] queue redraw\n") );
1351 
1352 
1353 	if( gtk_widget_get_realized(GTK_WIDGET(chart)) )
1354 	{
1355 		ui_chart_progress_recompute(chart);
1356 		drawarea_full_redraw(chart->drawarea, chart);
1357 		gtk_widget_queue_draw( chart->drawarea );
1358 	}
1359 }
1360 
1361 /*
1362 ** change the model and/or column
1363 */
ui_chart_progress_set_dualdatas(ChartProgress * chart,GtkTreeModel * model,gchar * coltitle1,gchar * coltitle2,gchar * title,gchar * subtitle)1364 void ui_chart_progress_set_dualdatas(ChartProgress *chart, GtkTreeModel *model, gchar *coltitle1, gchar *coltitle2, gchar *title, gchar *subtitle)
1365 {
1366 	g_return_if_fail (GTK_IS_CHARTPROGRESS (chart));
1367 
1368 	DB( g_print("\n[chartprogress] set dual datas\n") );
1369 
1370 
1371 	if( GTK_IS_TREE_MODEL(model) )
1372 	{
1373 		ui_chart_progress_setup_with_model(chart, model, coltitle1, coltitle2 );
1374 		if(title != NULL)
1375 			chart->title = g_strdup(title);
1376 		if(subtitle != NULL)
1377 			chart->subtitle = g_strdup(subtitle);
1378 
1379 		ui_chart_progress_queue_redraw(chart);
1380 	}
1381 	else
1382 	{
1383 		ui_chart_progress_clear(chart, TRUE);
1384 	}
1385 }
1386 
1387 /*
1388 ** change the tooltip title
1389 */
ui_chart_progress_set_title(ChartProgress * chart,gchar * title)1390 void ui_chart_progress_set_title(ChartProgress * chart, gchar *title)
1391 {
1392 	g_return_if_fail (GTK_IS_CHARTPROGRESS (chart));
1393 
1394 	chart->title = g_strdup(title);
1395 
1396 	DB( g_print("\n[chartprogress] set title = %s\n", chart->title) );
1397 
1398 	ui_chart_progress_recompute(chart);
1399 
1400 }
1401 
ui_chart_progress_set_subtitle(ChartProgress * chart,gchar * subtitle)1402 void ui_chart_progress_set_subtitle(ChartProgress * chart, gchar *subtitle)
1403 {
1404 	g_return_if_fail (GTK_IS_CHARTPROGRESS (chart));
1405 
1406 	chart->subtitle = g_strdup(subtitle);
1407 
1408 	DB( g_print("\n[chartprogress] set period = %s\n", chart->subtitle) );
1409 
1410 	ui_chart_progress_recompute(chart);
1411 
1412 }
1413 
1414 
1415 /*
1416 ** change the minor visibility
1417 */
ui_chart_progress_show_minor(ChartProgress * chart,gboolean minor)1418 void ui_chart_progress_show_minor(ChartProgress * chart, gboolean minor)
1419 {
1420 	g_return_if_fail (GTK_IS_CHARTPROGRESS (chart));
1421 
1422 	chart->minor = minor;
1423 
1424 	ui_chart_progress_queue_redraw(chart);
1425 
1426 }
1427 
ui_chart_progress_set_color_scheme(ChartProgress * chart,gint index)1428 void ui_chart_progress_set_color_scheme(ChartProgress * chart, gint index)
1429 {
1430 	colorscheme_init(&chart->color_scheme, index);
1431 }
1432 
1433 
1434 /*
1435 ** set the minor parameters
1436 */
1437 /*void ui_chart_progress_set_minor_prefs(ChartProgress * chart, gdouble rate, gchar *symbol)
1438 {
1439 	g_return_if_fail (GTK_IS_CHARTPROGRESS (chart));
1440 
1441 	chart->minor_rate   = rate;
1442 	chart->minor_symbol = symbol;
1443 }*/
1444 
ui_chart_progress_set_currency(ChartProgress * chart,guint32 kcur)1445 void ui_chart_progress_set_currency(ChartProgress * chart, guint32 kcur)
1446 {
1447 	g_return_if_fail (GTK_IS_CHARTPROGRESS (chart));
1448 
1449 	chart->kcur = kcur;
1450 }
1451 
1452 
1453 /* = = = = = = = = = = = = = = = = */
1454 
1455 
1456 static void
ui_chart_progress_init(ChartProgress * chart)1457 ui_chart_progress_init (ChartProgress * chart)
1458 {
1459 GtkWidget *widget, *hbox, *frame;
1460 HbtkDrawProgContext *context = &chart->context;
1461 
1462 
1463 	DB( g_print("\n[chartprogress] init\n") );
1464 
1465 	chart->surface = NULL;
1466  	chart->nb_items = 0;
1467 	chart->hover = -1;
1468  	chart->title = NULL;
1469 	chart->subtitle = NULL;
1470  	chart->pfd = NULL;
1471 
1472  	chart->budget_title = "Budget";
1473  	chart->result_title = "Result";
1474 
1475 	context->barw = GTK_CHARTPROGRESS_BARW;
1476 	ui_chart_progress_set_color_scheme(chart, CHART_COLMAP_HOMEBANK);
1477 
1478 	widget=GTK_WIDGET(chart);
1479 
1480 	gtk_box_set_homogeneous(GTK_BOX(widget), FALSE);
1481 
1482 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1483     gtk_box_pack_start (GTK_BOX (widget), hbox, TRUE, TRUE, 0);
1484 
1485 	/* frame & drawing area */
1486 	frame = gtk_frame_new(NULL);
1487     gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
1488     gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1489 
1490 	chart->drawarea = gtk_drawing_area_new();
1491 	//gtk_widget_set_double_buffered (GTK_WIDGET(widget), FALSE);
1492 
1493 	gtk_container_add( GTK_CONTAINER(frame), chart->drawarea );
1494 	gtk_widget_set_size_request(chart->drawarea, 150, 150 );
1495 	#if DYNAMICS == 1
1496 	gtk_widget_set_has_tooltip(chart->drawarea, TRUE);
1497 	#endif
1498 	gtk_widget_show(chart->drawarea);
1499 
1500 	/* scrollbar */
1501     chart->adjustment = GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 1.0, 1.0, 1.0, 1.0));
1502     chart->scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL,GTK_ADJUSTMENT (chart->adjustment));
1503     gtk_box_pack_start (GTK_BOX (hbox), chart->scrollbar, FALSE, TRUE, 0);
1504 
1505 
1506 	g_signal_connect( G_OBJECT(chart->drawarea), "configure-event", G_CALLBACK (drawarea_configure_event_callback), chart);
1507 	//g_signal_connect( G_OBJECT(chart->drawarea), "realize", G_CALLBACK(drawarea_realize_callback), chart ) ;
1508 	g_signal_connect( G_OBJECT(chart->drawarea), "draw", G_CALLBACK(drawarea_draw_callback), chart );
1509 	//TODO check this to redraw when gtk theme chnage
1510 	g_signal_connect( G_OBJECT(chart->drawarea), "style-updated", G_CALLBACK(drawarea_style_changed_callback), chart ) ;
1511 
1512 #if DYNAMICS == 1
1513 	gtk_widget_add_events(GTK_WIDGET(chart->drawarea),
1514 		GDK_EXPOSURE_MASK |
1515 		//GDK_POINTER_MOTION_MASK |
1516 		//GDK_POINTER_MOTION_HINT_MASK |
1517 		GDK_SCROLL_MASK
1518 		);
1519 
1520 	//g_signal_connect( G_OBJECT(chart->drawarea), "query-tooltip", G_CALLBACK(drawarea_querytooltip_callback), chart );
1521 	g_signal_connect( G_OBJECT(chart->drawarea), "scroll-event", G_CALLBACK(drawarea_scroll_event_callback), chart ) ;
1522 	g_signal_connect( G_OBJECT(chart->drawarea), "motion-notify-event", G_CALLBACK(drawarea_motionnotifyevent_callback), chart );
1523 #endif
1524 
1525 	g_signal_connect (G_OBJECT(chart->adjustment), "value-changed", G_CALLBACK (ui_chart_progress_first_changed), chart);
1526 
1527 	/*
1528 	g_signal_connect( G_OBJECT(chart->drawarea), "leave-notify-event", G_CALLBACK(ui_chart_progress_leave), chart );
1529 	g_signal_connect( G_OBJECT(chart->drawarea), "enter-notify-event", G_CALLBACK(ui_chart_progress_enter), chart );
1530 	g_signal_connect( G_OBJECT(chart->drawarea), "button-press-event", G_CALLBACK(ui_chart_progress_button_press), chart );
1531 	g_signal_connect( G_OBJECT(chart->drawarea), "button-release-event", G_CALLBACK(ui_chart_progress_button_release), chart );
1532 	*/
1533 
1534 
1535 }
1536 
1537 
1538 void
ui_chart_progress_destroy(GtkWidget * object)1539 ui_chart_progress_destroy (GtkWidget * object)
1540 {
1541 ChartProgress *chart = GTK_CHARTPROGRESS(object);
1542 
1543 	g_return_if_fail (GTK_IS_CHARTPROGRESS (object));
1544 
1545 	DB( g_print("\n[chartprogress] destroy\n") );
1546 
1547 
1548 	ui_chart_progress_clear(GTK_CHARTPROGRESS (object), FALSE);
1549 
1550 	if(chart->pfd)
1551 	{
1552 		pango_font_description_free (chart->pfd);
1553 		chart->pfd = NULL;
1554 	}
1555 
1556 	if (chart->surface)
1557 	{
1558 		cairo_surface_destroy (chart->surface);
1559 		chart->surface = NULL;
1560 	}
1561 
1562 	GTK_WIDGET_CLASS (parent_class)->destroy (object);
1563 }
1564 
1565 
ui_chart_progress_class_init(ChartProgressClass * class)1566 static void ui_chart_progress_class_init (ChartProgressClass * class)
1567 {
1568 //GObjectClass *gobject_class;
1569 GtkWidgetClass *widget_class;
1570 
1571 	DB( g_print("\n[chartprogress] class_init\n") );
1572 
1573 	//gobject_class = (GObjectClass*) class;
1574 	widget_class = (GtkWidgetClass*) class;
1575 
1576 	parent_class = g_type_class_peek_parent (class);
1577 
1578 	//gobject_class->dispose = ui_chart_progress_dispose;
1579 	//gobject_class->finalize = ui_chart_progress_finalize;
1580 	//gobject_class->set_property = ui_chart_progress_set_property;
1581 	//gobject_class->get_property = ui_chart_progress_get_property;
1582 
1583 	widget_class->destroy = ui_chart_progress_destroy;
1584 
1585 
1586 }
1587 
1588 //gtk_chart_class_intern_init
1589 
1590 
ui_chart_progress_get_type()1591 GType ui_chart_progress_get_type ()
1592 {
1593 static GType ui_chart_progress_type = 0;
1594 
1595 	if (G_UNLIKELY(ui_chart_progress_type == 0))
1596     {
1597 		const GTypeInfo ui_chart_progress_info =
1598 		{
1599 		sizeof (ChartProgressClass),
1600 		NULL,	/* base_init */
1601 		NULL,	/* base_finalize */
1602 		(GClassInitFunc) ui_chart_progress_class_init,
1603 		NULL,	/* class_finalize */
1604 		NULL,	/* class_init */
1605 		sizeof (ChartProgress),
1606 		0,		/* n_preallocs */
1607 		(GInstanceInitFunc) ui_chart_progress_init,
1608 		NULL	/* value_table */
1609 		};
1610 
1611 		ui_chart_progress_type = g_type_register_static (GTK_TYPE_BOX, "ChartProgress",
1612 							 &ui_chart_progress_info, 0);
1613 
1614 	}
1615 	return ui_chart_progress_type;
1616 }
1617 
1618 
1619 GtkWidget *
ui_chart_progress_new(void)1620 ui_chart_progress_new (void)
1621 {
1622 GtkWidget *chart;
1623 
1624 	DB( g_print("\n======================================================\n") );
1625 	DB( g_print("\n[chartprogress] new\n") );
1626 
1627 	chart = (GtkWidget *)g_object_new (GTK_TYPE_CHARTPROGRESS, NULL);
1628 
1629 	return chart;
1630 }
1631 
1632 
1633 
1634