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