fix indents
[rrdtool.git] / src / rrd_gfx.c
1 /****************************************************************************
2  * RRDtool 1.2.99907080300  Copyright by Tobi Oetiker, 1997-2007
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
135     PangoTabArray *tab_array;
136     PangoContext *pango_context;
137
138     tab_array = pango_tab_array_new(tab_count, (gboolean) (1));
139     for (i = 1; i <= tab_count; i++) {
140         pango_tab_array_set_tab(tab_array,
141                                 i, PANGO_TAB_LEFT, tabwidth * i - tab_shift);
142     }
143     cairo_new_path(cr);
144     cairo_set_source_rgba(cr, color.red, color.green, color.blue,
145                           color.alpha);
146     layout = pango_cairo_create_layout(cr);
147     pango_context = pango_layout_get_context(layout);
148     pango_cairo_context_set_font_options(pango_context, im->font_options);
149     pango_cairo_context_set_resolution(pango_context, 100);
150
151 /*     pango_cairo_update_context(cr, pango_context); */
152
153     pango_layout_set_tabs(layout, tab_array);
154     font_desc = pango_font_description_from_string(font);
155     pango_font_description_set_size(font_desc, size * PANGO_SCALE);
156     pango_layout_set_font_description(layout, font_desc);
157     pango_layout_set_markup(layout, text, -1);
158     return layout;
159 }
160
161 /* Size Text Node */
162 double gfx_get_text_width(
163     image_desc_t *im,
164     double start,
165     char *font,
166     double size,
167     double tabwidth,
168     char *text)
169 {
170     PangoLayout *layout;
171     PangoRectangle log_rect;
172     gfx_color_t color = { 0, 0, 0, 0 };
173     char     *tab;
174
175     /* turn \\t into tab */
176     while ((tab = strstr(text, "\\t"))) {
177         memmove(tab + 1, tab + 2, strlen(tab + 2));
178         tab[0] = (char) 9;
179     }
180     layout = gfx_prep_text(im, start, color, font, size, tabwidth, text);
181     pango_layout_get_pixel_extents(layout, NULL, &log_rect);
182     pango_tab_array_free(pango_layout_get_tabs(layout));
183     g_object_unref(layout);
184     return log_rect.width;
185 }
186
187 void gfx_text(
188     image_desc_t *im,
189     double x,
190     double y,
191     gfx_color_t color,
192     char *font,
193     double size,
194     double tabwidth,
195     double angle,
196     enum gfx_h_align_en h_align,
197     enum gfx_v_align_en v_align,
198     const char *text)
199 {
200     PangoLayout *layout;
201     PangoRectangle log_rect;
202     PangoRectangle ink_rect;
203     cairo_t  *cr = im->cr;
204     double    sx = 0;
205     double    sy = 0;
206
207     cairo_save(cr);
208     cairo_translate(cr, x, y);
209 /*    gfx_line(cr,-2,0,2,0,1,color);
210     gfx_line(cr,0,-2,0,2,1,color); */
211     layout = gfx_prep_text(im, x, color, font, size, tabwidth, text);
212     pango_layout_get_pixel_extents(layout, &ink_rect, &log_rect);
213     cairo_rotate(cr, -angle * G_PI / 180.0);
214     sx = log_rect.x;
215     switch (h_align) {
216     case GFX_H_RIGHT:
217         sx -= log_rect.width;
218         break;
219     case GFX_H_CENTER:
220         sx -= log_rect.width / 2;
221         break;
222     case GFX_H_LEFT:
223         break;
224     case GFX_H_NULL:
225         break;
226     }
227     sy = log_rect.y;
228     switch (v_align) {
229     case GFX_V_TOP:
230         break;
231     case GFX_V_CENTER:
232         sy -= log_rect.height / 2;
233         break;
234     case GFX_V_BOTTOM:
235         sy -= log_rect.height;
236         break;
237     case GFX_V_NULL:
238         break;
239     }
240     pango_cairo_update_layout(cr, layout);
241     cairo_move_to(cr, sx, sy);
242     pango_cairo_show_layout(cr, layout);
243     pango_tab_array_free(pango_layout_get_tabs(layout));
244     g_object_unref(layout);
245     cairo_restore(cr);
246
247 }
248
249 /* convert color */
250 struct gfx_color_t gfx_hex_to_col(
251     long unsigned int color)
252 {
253     struct gfx_color_t gfx_color;
254
255     gfx_color.red = 1.0 / 255.0 * ((color & 0xff000000) >> (3 * 8));
256     gfx_color.green = 1.0 / 255.0 * ((color & 0x00ff0000) >> (2 * 8));
257     gfx_color.blue = 1.0 / 255.0 * ((color & 0x0000ff00) >> (1 * 8));
258     gfx_color.alpha = 1.0 / 255.0 * (color & 0x000000ff);
259     return gfx_color;
260 }
261
262 /* gridfit_lines */
263
264 void gfx_line_fit(
265     image_desc_t *im,
266     double *x,
267     double *y)
268 {
269     cairo_t  *cr = im->cr;
270     double    line_width;
271     double    line_height;
272
273     if (!im->gridfit)
274         return;
275     cairo_user_to_device(cr, x, y);
276     line_width = cairo_get_line_width(cr);
277     line_height = line_width;
278     cairo_user_to_device_distance(cr, &line_width, &line_height);
279     line_width = line_width / 2.0 - (long) (line_width / 2.0);
280     line_height = line_height / 2.0 - (long) (line_height / 2.0);
281     *x = (double) ((long) (*x + 0.5)) - line_width;
282     *y = (double) ((long) (*y + 0.5)) + line_height;
283     cairo_device_to_user(cr, x, y);
284 }
285
286 /* gridfit_areas */
287
288 void gfx_area_fit(
289     image_desc_t *im,
290     double *x,
291     double *y)
292 {
293     cairo_t  *cr = im->cr;
294
295     if (!im->gridfit)
296         return;
297     cairo_user_to_device(cr, x, y);
298     *x = (double) ((long) (*x + 0.5));
299     *y = (double) ((long) (*y + 0.5));
300     cairo_device_to_user(cr, x, y);
301 }