fixed pango markup switch ... we still want the text to show even if no markup is...
[rrdtool.git] / src / rrd_gfx.c
1 /****************************************************************************
2  * RRDtool 1.3rc8  Copyright by Tobi Oetiker, 1997-2008
3  ****************************************************************************
4  * rrd_gfx.c  graphics wrapper for rrdtool
5   **************************************************************************/
6
7 /* #define DEBUG */
8
9 /* stupid MSVC doesnt support variadic macros = no debug for now! */
10 #ifdef _MSC_VER
11 # define RRDPRINTF()
12 #else
13 # ifdef DEBUG
14 #  define RRDPRINTF(...)  fprintf(stderr, __VA_ARGS__);
15 # else
16 #  define RRDPRINTF(...)
17 # endif                         /* DEBUG */
18 #endif                          /* _MSC_VER */
19
20 #include "rrd_tool.h"
21 #include "rrd_graph.h"
22
23
24 /* create a new line */
25 void gfx_line(
26     image_desc_t *im,
27     double X0,
28     double Y0,
29     double X1,
30     double Y1,
31     double width,
32     gfx_color_t color)
33 {
34     gfx_dashed_line(im, X0, Y0, X1, Y1, width, color, 0, 0);
35 }
36
37 void gfx_dashed_line(
38     image_desc_t *im,
39     double X0,
40     double Y0,
41     double X1,
42     double Y1,
43     double width,
44     gfx_color_t color,
45     double dash_on,
46     double dash_off)
47 {
48     cairo_t  *cr = im->cr;
49     double    dashes[] = { dash_on, dash_off };
50     double    x = 0;
51     double    y = 0;
52
53     cairo_save(cr);
54     cairo_new_path(cr);
55     cairo_set_line_width(cr, width);
56     gfx_line_fit(im, &x, &y);
57     gfx_line_fit(im, &X0, &Y0);
58     cairo_move_to(cr, X0, Y0);
59     gfx_line_fit(im, &X1, &Y1);
60     cairo_line_to(cr, X1, Y1);
61     if (dash_on > 0 || dash_off > 0)
62         cairo_set_dash(cr, dashes, 2, x);
63     cairo_set_source_rgba(cr, color.red, color.green, color.blue,
64                           color.alpha);
65     cairo_stroke(cr);
66     cairo_restore(cr);
67 }
68
69 /* create a new area */
70 void gfx_new_area(
71     image_desc_t *im,
72     double X0,
73     double Y0,
74     double X1,
75     double Y1,
76     double X2,
77     double Y2,
78     gfx_color_t color)
79 {
80     cairo_t  *cr = im->cr;
81
82     cairo_new_path(cr);
83     gfx_area_fit(im, &X0, &Y0);
84     cairo_move_to(cr, X0, Y0);
85     gfx_area_fit(im, &X1, &Y1);
86     cairo_line_to(cr, X1, Y1);
87     gfx_area_fit(im, &X2, &Y2);
88     cairo_line_to(cr, X2, Y2);
89     cairo_set_source_rgba(cr, color.red, color.green, color.blue,
90                           color.alpha);
91 }
92
93 /* add a point to a line or to an area */
94 void gfx_add_point(
95     image_desc_t *im,
96     double x,
97     double y)
98 {
99     cairo_t  *cr = im->cr;
100
101     gfx_area_fit(im, &x, &y);
102     cairo_line_to(cr, x, y);
103 }
104
105 void gfx_close_path(
106     image_desc_t *im)
107 {
108     cairo_t  *cr = im->cr;
109
110     cairo_close_path(cr);
111     cairo_fill(cr);
112 }
113
114 /* create a text node */
115 static PangoLayout *gfx_prep_text(
116     image_desc_t *im,
117     double x,
118     gfx_color_t color,
119     char *font,
120     double size,
121     double tabwidth,
122     const char *text)
123 {
124     PangoLayout *layout;
125     PangoFontDescription *font_desc;
126     cairo_t  *cr = im->cr;
127
128     /* for performance reasons we might
129        want todo that only once ... tabs will always
130        be the same */
131     long      i;
132     long      tab_count = strlen(text);
133     long      tab_shift = fmod(x, tabwidth);
134     int       border = im->text_prop[TEXT_PROP_LEGEND].size * 2.0;
135
136     PangoTabArray *tab_array;
137     PangoContext *pango_context;
138
139     tab_array = pango_tab_array_new(tab_count, (gboolean) (1));
140     for (i = 1; i <= tab_count; i++) {
141         pango_tab_array_set_tab(tab_array,
142                                 i, PANGO_TAB_LEFT,
143                                 tabwidth * i - tab_shift + border);
144     }
145     cairo_new_path(cr);
146     cairo_set_source_rgba(cr, color.red, color.green, color.blue,
147                           color.alpha);
148     layout = pango_cairo_create_layout(cr);
149     pango_context = pango_layout_get_context(layout);
150     pango_cairo_context_set_font_options(pango_context, im->font_options);
151     pango_cairo_context_set_resolution(pango_context, 100);
152
153 /*     pango_cairo_update_context(cr, pango_context); */
154
155     pango_layout_set_tabs(layout, tab_array);
156     font_desc = pango_font_description_from_string(font);
157     pango_font_description_set_size(font_desc, size * PANGO_SCALE);
158     pango_layout_set_font_description(layout, font_desc);
159     if (im->with_markup)
160         pango_layout_set_markup(layout, text, -1);
161     else
162         pango_layout_set_text(layout, text, -1);
163     return layout;
164 }
165
166 /* Size Text Node */
167 double gfx_get_text_width(
168     image_desc_t *im,
169     double start,
170     char *font,
171     double size,
172     double tabwidth,
173     char *text)
174 {
175     PangoLayout *layout;
176     PangoRectangle log_rect;
177     gfx_color_t color = { 0, 0, 0, 0 };
178     layout = gfx_prep_text(im, start, color, font, size, tabwidth, text);
179     pango_layout_get_pixel_extents(layout, NULL, &log_rect);
180     pango_tab_array_free(pango_layout_get_tabs(layout));
181     g_object_unref(layout);
182     return log_rect.width;
183 }
184
185 void gfx_text(
186     image_desc_t *im,
187     double x,
188     double y,
189     gfx_color_t color,
190     char *font,
191     double size,
192     double tabwidth,
193     double angle,
194     enum gfx_h_align_en h_align,
195     enum gfx_v_align_en v_align,
196     const char *text)
197 {
198     PangoLayout *layout;
199     PangoRectangle log_rect;
200     PangoRectangle ink_rect;
201     cairo_t  *cr = im->cr;
202     double    sx = 0;
203     double    sy = 0;
204
205     cairo_save(cr);
206     cairo_translate(cr, x, y);
207 /*    gfx_line(cr,-2,0,2,0,1,color);
208     gfx_line(cr,0,-2,0,2,1,color); */
209     layout = gfx_prep_text(im, x, color, font, size, tabwidth, text);
210     pango_layout_get_pixel_extents(layout, &ink_rect, &log_rect);
211     cairo_rotate(cr, -angle * G_PI / 180.0);
212     sx = log_rect.x;
213     switch (h_align) {
214     case GFX_H_RIGHT:
215         sx -= log_rect.width;
216         break;
217     case GFX_H_CENTER:
218         sx -= log_rect.width / 2;
219         break;
220     case GFX_H_LEFT:
221         break;
222     case GFX_H_NULL:
223         break;
224     }
225     sy = log_rect.y;
226     switch (v_align) {
227     case GFX_V_TOP:
228         break;
229     case GFX_V_CENTER:
230         sy -= log_rect.height / 2;
231         break;
232     case GFX_V_BOTTOM:
233         sy -= log_rect.height;
234         break;
235     case GFX_V_NULL:
236         break;
237     }
238     pango_cairo_update_layout(cr, layout);
239     cairo_move_to(cr, sx, sy);
240     pango_cairo_show_layout(cr, layout);
241     pango_tab_array_free(pango_layout_get_tabs(layout));
242     g_object_unref(layout);
243     cairo_restore(cr);
244
245 }
246
247 /* convert color */
248 struct gfx_color_t gfx_hex_to_col(
249     long unsigned int color)
250 {
251     struct gfx_color_t gfx_color;
252
253     gfx_color.red = 1.0 / 255.0 * ((color & 0xff000000) >> (3 * 8));
254     gfx_color.green = 1.0 / 255.0 * ((color & 0x00ff0000) >> (2 * 8));
255     gfx_color.blue = 1.0 / 255.0 * ((color & 0x0000ff00) >> (1 * 8));
256     gfx_color.alpha = 1.0 / 255.0 * (color & 0x000000ff);
257     return gfx_color;
258 }
259
260 /* gridfit_lines */
261
262 void gfx_line_fit(
263     image_desc_t *im,
264     double *x,
265     double *y)
266 {
267     cairo_t  *cr = im->cr;
268     double    line_width;
269     double    line_height;
270
271     if (!im->gridfit)
272         return;
273     cairo_user_to_device(cr, x, y);
274     line_width = cairo_get_line_width(cr);
275     line_height = line_width;
276     cairo_user_to_device_distance(cr, &line_width, &line_height);
277     line_width = line_width / 2.0 - (long) (line_width / 2.0);
278     line_height = line_height / 2.0 - (long) (line_height / 2.0);
279     *x = (double) ((long) (*x + 0.5)) - line_width;
280     *y = (double) ((long) (*y + 0.5)) + line_height;
281     cairo_device_to_user(cr, x, y);
282 }
283
284 /* gridfit_areas */
285
286 void gfx_area_fit(
287     image_desc_t *im,
288     double *x,
289     double *y)
290 {
291     cairo_t  *cr = im->cr;
292
293     if (!im->gridfit)
294         return;
295     cairo_user_to_device(cr, x, y);
296     *x = (double) ((long) (*x + 0.5));
297     *y = (double) ((long) (*y + 0.5));
298     cairo_device_to_user(cr, x, y);
299 }