Line data Source code
1 : /* File: pencil_feature_painter.c; Copyright and License: see below */
2 :
3 : #include "pencil_feature_painter.h"
4 : #include "layout/layout_visible_set.h"
5 : #include "u8/u8_trace.h"
6 : #include <pango/pangocairo.h>
7 : #include <stdio.h>
8 : #include <stdlib.h>
9 : #include <assert.h>
10 :
11 : /*! where to place the control points of a bezier curve to get a good approximation for a 90 degree curve */
12 : const static double BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE = 0.552284749831;
13 : const static double SINE_OF_45_DEGREE = 0.707106781187;
14 :
15 0 : void pencil_feature_painter_init( pencil_feature_painter_t *this_ )
16 : {
17 0 : U8_TRACE_BEGIN();
18 :
19 0 : pencil_marker_init( &((*this_).marker) );
20 0 : draw_feature_label_init( &((*this_).draw_feature_label) );
21 0 : draw_feature_symbol_init( &((*this_).draw_feature_symbol) );
22 :
23 0 : U8_TRACE_END();
24 0 : }
25 :
26 0 : void pencil_feature_painter_destroy( pencil_feature_painter_t *this_ )
27 : {
28 0 : U8_TRACE_BEGIN();
29 :
30 0 : draw_feature_symbol_destroy( &((*this_).draw_feature_symbol) );
31 0 : draw_feature_label_destroy( &((*this_).draw_feature_label) );
32 0 : pencil_marker_destroy( &((*this_).marker) );
33 :
34 0 : U8_TRACE_END();
35 0 : }
36 :
37 0 : void pencil_feature_painter_draw( pencil_feature_painter_t *this_,
38 : const layout_feature_t *layouted_feature,
39 : bool mark_focused,
40 : bool mark_highlighted,
41 : bool mark_selected,
42 : bool gray_out,
43 : layout_relationship_iter_t *relationships,
44 : const data_profile_part_t *profile,
45 : const pencil_size_t *pencil_size,
46 : PangoLayout *layout,
47 : cairo_t *cr )
48 : {
49 0 : U8_TRACE_BEGIN();
50 0 : assert( NULL != profile );
51 0 : assert( NULL != pencil_size );
52 0 : assert( NULL != layouted_feature );
53 0 : assert( NULL != layout );
54 0 : assert( NULL != cr );
55 :
56 0 : const data_feature_t *the_feature = layout_feature_get_data_const( layouted_feature );
57 0 : const geometry_rectangle_t *const feature_symbol_box = layout_feature_get_symbol_box_const( layouted_feature );
58 :
59 0 : if ( data_feature_is_valid( the_feature ) )
60 : {
61 0 : U8_TRACE_INFO_INT("drawing feature id", data_feature_get_row_id( the_feature ) );
62 :
63 : /* select color */
64 : GdkRGBA foreground_color;
65 : {
66 0 : if ( mark_highlighted )
67 : {
68 0 : foreground_color = pencil_size_get_highlight_color( pencil_size );
69 : }
70 0 : else if ( gray_out )
71 : {
72 0 : foreground_color = pencil_size_get_gray_out_color( pencil_size );
73 : }
74 : else
75 : {
76 0 : foreground_color = pencil_size_get_standard_color( pencil_size );
77 : }
78 0 : cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha );
79 : }
80 :
81 0 : switch ( data_feature_get_main_type (the_feature) )
82 : {
83 0 : case DATA_FEATURE_TYPE_PORT: /* or */
84 : case DATA_FEATURE_TYPE_IN_PORT_PIN: /* or */
85 : case DATA_FEATURE_TYPE_OUT_PORT_PIN:
86 : {
87 0 : pencil_feature_painter_private_draw_port_pin_icon( this_, layouted_feature, pencil_size, foreground_color, cr );
88 : }
89 0 : break;
90 :
91 0 : case DATA_FEATURE_TYPE_ENTRY: /* or */
92 : case DATA_FEATURE_TYPE_EXIT:
93 : {
94 0 : pencil_feature_painter_private_draw_entry_exit_icon( this_, layouted_feature, pencil_size, foreground_color, cr );
95 : }
96 0 : break;
97 :
98 0 : case DATA_FEATURE_TYPE_PROVIDED_INTERFACE: /* or */
99 : case DATA_FEATURE_TYPE_REQUIRED_INTERFACE:
100 : {
101 0 : pencil_feature_painter_private_draw_interface_icon( this_, layouted_feature, pencil_size, cr );
102 : }
103 0 : break;
104 :
105 0 : case DATA_FEATURE_TYPE_LIFELINE:
106 : {
107 0 : pencil_feature_painter_private_draw_lifeline_icon( this_,
108 : layouted_feature,
109 : mark_highlighted,
110 : relationships,
111 : pencil_size,
112 : cr
113 : );
114 : }
115 0 : break;
116 :
117 0 : case DATA_FEATURE_TYPE_PROPERTY: /* or */
118 : case DATA_FEATURE_TYPE_OPERATION: /* or */
119 : case DATA_FEATURE_TYPE_TAGGED_VALUE:
120 : {
121 : /* no icon */
122 : }
123 0 : break;
124 :
125 0 : default:
126 : {
127 0 : U8_LOG_ANOMALY("unknown feature type in pencil_feature_painter_draw");
128 : /* this may happen if a new database file has been read by an old program version */
129 : /* no icon */
130 : }
131 0 : break;
132 : }
133 :
134 : /* draw the label */
135 0 : draw_feature_label_draw_key_and_value( &((*this_).draw_feature_label),
136 : layout_feature_get_data_const( layouted_feature ),
137 : profile,
138 : &foreground_color,
139 : layout_feature_get_label_box_const( layouted_feature ),
140 : pencil_size,
141 : layout,
142 : cr
143 : );
144 :
145 0 : if ( mark_selected )
146 : {
147 0 : pencil_marker_mark_selected_rectangle( &((*this_).marker), *feature_symbol_box, cr );
148 : }
149 :
150 0 : if ( mark_focused )
151 : {
152 0 : pencil_marker_mark_focused_rectangle( &((*this_).marker), *feature_symbol_box, cr );
153 : }
154 : }
155 : else
156 : {
157 0 : U8_LOG_ERROR("invalid visible feature in array!");
158 : }
159 :
160 0 : U8_TRACE_END();
161 0 : }
162 :
163 0 : void pencil_feature_painter_private_draw_lifeline_icon ( pencil_feature_painter_t *this_,
164 : const layout_feature_t *layouted_feature,
165 : bool marked,
166 : layout_relationship_iter_t *relationships,
167 : const pencil_size_t *pencil_size,
168 : cairo_t *cr )
169 : {
170 0 : U8_TRACE_BEGIN();
171 0 : assert( NULL != pencil_size );
172 0 : assert( NULL != layouted_feature );
173 0 : assert( NULL != cr );
174 :
175 : /* reset the draw_feature_symbol helper class */
176 0 : draw_feature_symbol_reinit( &((*this_).draw_feature_symbol) );
177 :
178 0 : const geometry_rectangle_t *const feature_symbol_box = layout_feature_get_symbol_box_const( layouted_feature );
179 0 : const data_feature_t *const feature_data = layout_feature_get_data_const( layouted_feature );
180 0 : const data_id_t feature_id = data_feature_get_data_id( feature_data );
181 :
182 0 : if ( GEOMETRY_DIRECTION_RIGHT == layout_feature_get_icon_direction( layouted_feature ) )
183 : {
184 : /* lifeline in timing diagrams */
185 0 : bool past_active = false; /* flag that tells if the line left of the current drawing position is active (bold) or inactive (dashed) */
186 0 : while ( layout_relationship_iter_has_next( relationships ) )
187 : {
188 0 : const layout_relationship_t *const message_layout = layout_relationship_iter_next( relationships );
189 0 : const data_relationship_t *const message_data = layout_relationship_get_data_const( message_layout );
190 0 : const data_relationship_type_t message_type = data_relationship_get_main_type( message_data );
191 0 : const data_id_t from_feat = data_relationship_get_from_feature_data_id( message_data );
192 0 : const data_id_t to_feat = data_relationship_get_to_feature_data_id( message_data );
193 0 : const bool depart_from_here = data_id_equals( &feature_id, &from_feat );
194 0 : const bool arrive_here = data_id_equals( &feature_id, &to_feat );
195 :
196 0 : if ((( message_type == DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL )
197 0 : || ( message_type == DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL ))
198 0 : && ( depart_from_here || arrive_here ))
199 : {
200 : /* determine x location */
201 0 : const geometry_connector_t *const conn = layout_relationship_get_shape_const( message_layout );
202 0 : if ( arrive_here )
203 : {
204 0 : const double x1 = geometry_connector_get_destination_end_x( conn );
205 0 : draw_feature_symbol_draw_timeline( &((*this_).draw_feature_symbol),
206 : feature_symbol_box,
207 : x1, /* to_x */
208 : true, /* active */
209 : pencil_size,
210 : cr
211 : );
212 0 : past_active = false; /* note that we are traversing backwards in time */
213 : }
214 0 : if ( depart_from_here )
215 : {
216 0 : const double x2 = geometry_connector_get_source_end_x( conn );
217 0 : draw_feature_symbol_draw_timeline( &((*this_).draw_feature_symbol),
218 : feature_symbol_box,
219 : x2, /* to_x */
220 : false, /* active */
221 : pencil_size,
222 : cr
223 : );
224 0 : past_active = true; /* note that we are traversing backwards in time */
225 : }
226 :
227 :
228 : }
229 : }
230 0 : draw_feature_symbol_draw_timeline( &((*this_).draw_feature_symbol),
231 : feature_symbol_box,
232 : -INFINITY, /* to_x */
233 : past_active, /* active */
234 : pencil_size,
235 : cr
236 : );
237 : }
238 0 : else if ( GEOMETRY_DIRECTION_DOWN == layout_feature_get_icon_direction( layouted_feature ) )
239 : {
240 : /* lifeline in sequence diagrams */
241 0 : uint32_t past_depth = 0; /* estimated depth of activity bars above the current drawing position */
242 0 : while ( layout_relationship_iter_has_next( relationships ) )
243 : {
244 0 : const layout_relationship_t *const message_layout = layout_relationship_iter_next( relationships );
245 0 : const data_relationship_t *const message_data = layout_relationship_get_data_const( message_layout );
246 0 : const data_relationship_type_t message_type = data_relationship_get_main_type( message_data );
247 0 : const data_id_t from_feat = data_relationship_get_from_feature_data_id( message_data );
248 0 : const data_id_t to_feat = data_relationship_get_to_feature_data_id( message_data );
249 0 : const bool depart_from_here = data_id_equals( &feature_id, &from_feat );
250 0 : const bool arrive_here = data_id_equals( &feature_id, &to_feat );
251 :
252 0 : if ((( message_type == DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL )
253 0 : || ( message_type == DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL ))
254 0 : && ( depart_from_here || arrive_here ))
255 : {
256 : /* determine y location */
257 0 : const geometry_connector_t *const conn = layout_relationship_get_shape_const( message_layout );
258 0 : if ( arrive_here && ( message_type == DATA_RELATIONSHIP_TYPE_UML_SYNC_CALL ))
259 : {
260 : /* past_depth = ( past_depth == 0 ) ? 1 : past_depth; */ /* adjust the estimation when there is an arriving edge */
261 0 : const double y1 = geometry_connector_get_destination_end_y( conn );
262 0 : draw_feature_symbol_draw_execution_spec( &((*this_).draw_feature_symbol),
263 : feature_symbol_box,
264 : y1, /* to_y */
265 : past_depth, /* depth */
266 : pencil_size,
267 : cr
268 : );
269 0 : past_depth = ( past_depth > 0 ) ? ( past_depth - 1 ) : 0; /* decrease the depth of activity bars */
270 : }
271 0 : if ( depart_from_here && ( message_type == DATA_RELATIONSHIP_TYPE_UML_RETURN_CALL ) )
272 : {
273 0 : const double y2 = geometry_connector_get_source_end_y( conn );
274 0 : draw_feature_symbol_draw_execution_spec( &((*this_).draw_feature_symbol),
275 : feature_symbol_box,
276 : y2, /* to_y */
277 : past_depth, /* depth */
278 : pencil_size,
279 : cr
280 : );
281 0 : past_depth = past_depth + 1; /* increase the depth of activity bars */
282 : }
283 : }
284 : }
285 0 : draw_feature_symbol_draw_execution_spec( &((*this_).draw_feature_symbol),
286 : feature_symbol_box,
287 : -INFINITY, /* to_y */
288 : past_depth, /* depth */
289 : pencil_size,
290 : cr
291 : );
292 : }
293 : else
294 : {
295 : /* lifeline in communication and interaction overview diagrams, */
296 : /* or comments in other interaction diagrams */
297 : /* are only drawn if highlighted (marked): */
298 0 : draw_feature_symbol_draw_life_rectangle( &((*this_).draw_feature_symbol),
299 : feature_symbol_box,
300 : marked,
301 : pencil_size,
302 : cr
303 : );
304 : }
305 :
306 0 : U8_TRACE_END();
307 0 : }
308 :
309 0 : void pencil_feature_painter_private_draw_port_pin_icon ( pencil_feature_painter_t *this_,
310 : const layout_feature_t *layouted_feature,
311 : const pencil_size_t *pencil_size,
312 : GdkRGBA foreground_color,
313 : cairo_t *cr )
314 : {
315 0 : U8_TRACE_BEGIN();
316 0 : assert( NULL != pencil_size );
317 0 : assert( NULL != layouted_feature );
318 0 : assert( NULL != cr );
319 :
320 0 : const geometry_rectangle_t *const symbol_box_bounds = layout_feature_get_symbol_box_const( layouted_feature );
321 :
322 0 : const double left = geometry_rectangle_get_left ( symbol_box_bounds );
323 0 : const double top = geometry_rectangle_get_top ( symbol_box_bounds );
324 0 : const double width = geometry_rectangle_get_width ( symbol_box_bounds );
325 0 : const double height = geometry_rectangle_get_height ( symbol_box_bounds );
326 :
327 0 : cairo_rectangle ( cr, left, top, width, height );
328 :
329 : /* Note: It is possible to read out the current color and set it again */
330 : /* but the interface for that looks like this might result in 1 additional memory allocation */
331 : /* which shall be avoided */
332 : /* cairo_pattern_t *const defined_color = cairo_get_source( cr ); */
333 : /* cairo_pattern_reference( defined_color ); */
334 : /* ... */
335 : /* cairo_set_source( cr, defined_color ); */
336 : /* cairo_pattern_destroy( defined_color ); */
337 :
338 0 : cairo_set_source_rgba( cr, 1.0, 1.0, 1.0, 1.0 ); /* white background */
339 0 : cairo_fill_preserve (cr);
340 0 : cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha );
341 0 : cairo_stroke (cr);
342 :
343 : /* draw the arrow */
344 0 : const double center_x = geometry_rectangle_get_center_x ( symbol_box_bounds );
345 0 : const double center_y = geometry_rectangle_get_center_y ( symbol_box_bounds );
346 0 : const double h_arrow_left = left + 0.25*width;
347 0 : const double h_arrow_right = left + 0.75*width;
348 0 : const double h_arrow_top = top + 0.25*height;
349 0 : const double h_arrow_bottom = top + 0.75*height;
350 0 : const double v_arrow_left = left + 0.25*width;
351 0 : const double v_arrow_right = left + 0.75*width;
352 0 : const double v_arrow_top = top + 0.25*height;
353 0 : const double v_arrow_bottom = top + 0.75*height;
354 0 : switch ( layout_feature_get_icon_direction( layouted_feature ) )
355 : {
356 0 : case GEOMETRY_DIRECTION_LEFT:
357 : {
358 0 : cairo_move_to ( cr, h_arrow_left, center_y );
359 0 : cairo_line_to ( cr, h_arrow_right, center_y );
360 0 : cairo_move_to ( cr, h_arrow_right, h_arrow_top );
361 0 : cairo_line_to ( cr, h_arrow_left, center_y );
362 0 : cairo_line_to ( cr, h_arrow_right, h_arrow_bottom );
363 :
364 0 : cairo_stroke (cr);
365 : }
366 0 : break;
367 :
368 0 : case GEOMETRY_DIRECTION_UP:
369 : {
370 0 : cairo_move_to ( cr, center_x, v_arrow_top );
371 0 : cairo_line_to ( cr, center_x, v_arrow_bottom );
372 0 : cairo_move_to ( cr, v_arrow_left, v_arrow_bottom );
373 0 : cairo_line_to ( cr, center_x, v_arrow_top );
374 0 : cairo_line_to ( cr, v_arrow_right, v_arrow_bottom );
375 :
376 0 : cairo_stroke (cr);
377 : }
378 0 : break;
379 :
380 0 : case GEOMETRY_DIRECTION_RIGHT:
381 : {
382 0 : cairo_move_to ( cr, h_arrow_right, center_y );
383 0 : cairo_line_to ( cr, h_arrow_left, center_y );
384 0 : cairo_move_to ( cr, h_arrow_left, h_arrow_top );
385 0 : cairo_line_to ( cr, h_arrow_right, center_y );
386 0 : cairo_line_to ( cr, h_arrow_left, h_arrow_bottom );
387 :
388 0 : cairo_stroke (cr);
389 : }
390 0 : break;
391 :
392 0 : case GEOMETRY_DIRECTION_DOWN:
393 : {
394 0 : cairo_move_to ( cr, center_x, v_arrow_bottom );
395 0 : cairo_line_to ( cr, center_x, v_arrow_top );
396 0 : cairo_move_to ( cr, v_arrow_left, v_arrow_top );
397 0 : cairo_line_to ( cr, center_x, v_arrow_bottom );
398 0 : cairo_line_to ( cr, v_arrow_right, v_arrow_top );
399 :
400 0 : cairo_stroke (cr);
401 : }
402 0 : break;
403 :
404 0 : case GEOMETRY_DIRECTION_CENTER:
405 : {
406 : /* no arrow */
407 : }
408 0 : break;
409 :
410 0 : default:
411 : {
412 0 : U8_LOG_ERROR( "unexpected value in geometry_direction_t." );
413 : }
414 0 : break;
415 : }
416 :
417 0 : U8_TRACE_END();
418 0 : }
419 :
420 0 : void pencil_feature_painter_private_draw_entry_exit_icon ( pencil_feature_painter_t *this_,
421 : const layout_feature_t *layouted_feature,
422 : const pencil_size_t *pencil_size,
423 : GdkRGBA foreground_color,
424 : cairo_t *cr )
425 : {
426 0 : U8_TRACE_BEGIN();
427 0 : assert( NULL != pencil_size );
428 0 : assert( NULL != layouted_feature );
429 0 : assert( NULL != cr );
430 :
431 0 : const data_feature_t *the_feature = layout_feature_get_data_const( layouted_feature );
432 0 : const geometry_rectangle_t *const symbol_box_bounds = layout_feature_get_symbol_box_const( layouted_feature );
433 :
434 0 : const double left = geometry_rectangle_get_left ( symbol_box_bounds );
435 0 : const double top = geometry_rectangle_get_top ( symbol_box_bounds );
436 0 : const double center_x = geometry_rectangle_get_center_x( symbol_box_bounds );
437 0 : const double center_y = geometry_rectangle_get_center_y( symbol_box_bounds );
438 0 : const double circle_x_radius = center_x - left;
439 0 : const double circle_y_radius = center_y - top;
440 0 : const double bottom = geometry_rectangle_get_bottom( symbol_box_bounds );
441 0 : const double right = geometry_rectangle_get_right( symbol_box_bounds );
442 0 : const double ctrl_x_offset = circle_x_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE);
443 0 : const double ctrl_y_offset = circle_y_radius * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE);
444 :
445 0 : cairo_move_to ( cr, center_x, bottom );
446 0 : cairo_curve_to ( cr, left + ctrl_x_offset, bottom, left, bottom - ctrl_y_offset, left /* end point x */, center_y /* end point y */ );
447 0 : cairo_curve_to ( cr, left, top + ctrl_y_offset, left + ctrl_x_offset, top, center_x /* end point x */, top /* end point y */ );
448 0 : cairo_curve_to ( cr, right - ctrl_x_offset, top, right, top + ctrl_y_offset, right /* end point x */, center_y /* end point y */ );
449 0 : cairo_curve_to ( cr, right, bottom - ctrl_y_offset, right - ctrl_x_offset, bottom, center_x /* end point x */, bottom /* end point y */ );
450 :
451 0 : cairo_set_source_rgba( cr, 1.0, 1.0, 1.0, 1.0 ); /* white background */
452 0 : cairo_fill_preserve (cr);
453 0 : cairo_set_source_rgba( cr, foreground_color.red, foreground_color.green, foreground_color.blue, foreground_color.alpha );
454 0 : cairo_stroke (cr);
455 :
456 : /* draw X of exit icon */
457 0 : if ( data_feature_get_main_type( the_feature ) == DATA_FEATURE_TYPE_EXIT )
458 : {
459 0 : const double half_width = geometry_rectangle_get_width ( symbol_box_bounds )/2.0;
460 0 : const double half_height = geometry_rectangle_get_height ( symbol_box_bounds )/2.0;
461 0 : const double cross_end_dx = half_width * SINE_OF_45_DEGREE;
462 0 : const double cross_end_dy = half_height * SINE_OF_45_DEGREE;
463 :
464 0 : cairo_move_to ( cr, center_x + cross_end_dx, center_y - cross_end_dy );
465 0 : cairo_line_to ( cr, center_x - cross_end_dx, center_y + cross_end_dy );
466 0 : cairo_move_to ( cr, center_x - cross_end_dx, center_y - cross_end_dy );
467 0 : cairo_line_to ( cr, center_x + cross_end_dx, center_y + cross_end_dy );
468 :
469 0 : cairo_stroke (cr);
470 : }
471 :
472 0 : U8_TRACE_END();
473 0 : }
474 :
475 0 : void pencil_feature_painter_private_draw_interface_icon ( pencil_feature_painter_t *this_,
476 : const layout_feature_t *layouted_feature,
477 : const pencil_size_t *pencil_size,
478 : cairo_t *cr )
479 : {
480 0 : U8_TRACE_BEGIN();
481 0 : assert( NULL != pencil_size );
482 0 : assert( NULL != layouted_feature );
483 0 : assert( NULL != cr );
484 :
485 0 : const geometry_rectangle_t *const symbol_box_bounds = layout_feature_get_symbol_box_const( layouted_feature );
486 :
487 0 : const double left = geometry_rectangle_get_left ( symbol_box_bounds );
488 0 : const double top = geometry_rectangle_get_top ( symbol_box_bounds );
489 0 : const double width = geometry_rectangle_get_width ( symbol_box_bounds );
490 0 : const double height = geometry_rectangle_get_height ( symbol_box_bounds );
491 :
492 0 : double bottom = top + height;
493 0 : double right = left + width;
494 0 : double half_width = 0.5 * width;
495 0 : double half_height = 0.5 * height;
496 0 : double center_x = left + half_width;
497 0 : double center_y = top + half_height;
498 0 : double ctrl_xoffset = half_width * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE);
499 0 : double ctrl_yoffset = half_height * (1.0-BEZIER_CTRL_POINT_FOR_90_DEGREE_CIRCLE);
500 :
501 0 : switch ( layout_feature_get_icon_direction( layouted_feature ) )
502 : {
503 0 : case GEOMETRY_DIRECTION_LEFT:
504 : {
505 0 : cairo_move_to ( cr, center_x, top );
506 0 : cairo_curve_to ( cr, right - ctrl_xoffset, top, right, top + ctrl_yoffset, right /* end point x */, center_y /* end point y */ );
507 0 : cairo_curve_to ( cr, right, bottom - ctrl_yoffset, right - ctrl_xoffset, bottom, center_x /* end point x */, bottom /* end point y */ );
508 0 : cairo_stroke (cr);
509 : }
510 0 : break;
511 :
512 0 : case GEOMETRY_DIRECTION_UP:
513 : {
514 0 : cairo_move_to ( cr, right, center_y );
515 0 : cairo_curve_to ( cr, right, bottom - ctrl_yoffset, right - ctrl_xoffset, bottom, center_x /* end point x */, bottom /* end point y */ );
516 0 : cairo_curve_to ( cr, left + ctrl_xoffset, bottom, left, bottom - ctrl_yoffset, left /* end point x */, center_y /* end point y */ );
517 0 : cairo_stroke (cr);
518 : }
519 0 : break;
520 :
521 0 : case GEOMETRY_DIRECTION_RIGHT:
522 : {
523 0 : cairo_move_to ( cr, center_x, bottom );
524 0 : cairo_curve_to ( cr, left + ctrl_xoffset, bottom, left, bottom - ctrl_yoffset, left /* end point x */, center_y /* end point y */ );
525 0 : cairo_curve_to ( cr, left, top + ctrl_yoffset, left + ctrl_xoffset, top, center_x /* end point x */, top /* end point y */ );
526 0 : cairo_stroke (cr);
527 : }
528 0 : break;
529 :
530 0 : case GEOMETRY_DIRECTION_DOWN:
531 : {
532 0 : cairo_move_to ( cr, left, center_y );
533 0 : cairo_curve_to ( cr, left, top + ctrl_yoffset, left + ctrl_xoffset, top, center_x /* end point x */, top /* end point y */ );
534 0 : cairo_curve_to ( cr, right - ctrl_xoffset, top, right, top + ctrl_yoffset, right /* end point x */, center_y /* end point y */ );
535 0 : cairo_stroke (cr);
536 : }
537 0 : break;
538 :
539 0 : case GEOMETRY_DIRECTION_CENTER:
540 : {
541 0 : cairo_move_to ( cr, center_x, bottom );
542 0 : cairo_curve_to ( cr, left + ctrl_xoffset, bottom, left, bottom - ctrl_yoffset, left /* end point x */, center_y /* end point y */ );
543 0 : cairo_curve_to ( cr, left, top + ctrl_yoffset, left + ctrl_xoffset, top, center_x /* end point x */, top /* end point y */ );
544 0 : cairo_curve_to ( cr, right - ctrl_xoffset, top, right, top + ctrl_yoffset, right /* end point x */, center_y /* end point y */ );
545 0 : cairo_curve_to ( cr, right, bottom - ctrl_yoffset, right - ctrl_xoffset, bottom, center_x /* end point x */, bottom /* end point y */ );
546 0 : cairo_stroke (cr);
547 : }
548 0 : break;
549 :
550 0 : default:
551 : {
552 0 : U8_LOG_ERROR( "unexpected value in geometry_direction_t." );
553 : }
554 0 : break;
555 : }
556 :
557 0 : U8_TRACE_END();
558 0 : }
559 :
560 0 : void pencil_feature_painter_get_minimum_bounds ( pencil_feature_painter_t *this_,
561 : const data_feature_t *the_feature,
562 : const data_profile_part_t *profile,
563 : const pencil_size_t *pencil_size,
564 : PangoLayout *font_layout,
565 : geometry_dimensions_t *out_feature_bounds )
566 : {
567 0 : U8_TRACE_BEGIN();
568 0 : assert( NULL != the_feature );
569 0 : assert( NULL != profile );
570 0 : assert( NULL != pencil_size );
571 0 : assert( NULL != font_layout );
572 0 : assert( NULL != out_feature_bounds );
573 :
574 0 : const geometry_dimensions_t label_dim_proposal = {
575 0 : .width = 25.0 * pencil_size_get_standard_font_size( pencil_size ),
576 0 : .height = pencil_size_get_standard_font_size( pencil_size )
577 : };
578 0 : draw_feature_label_get_key_and_value_dimensions( &((*this_).draw_feature_label),
579 : the_feature,
580 : profile,
581 : &label_dim_proposal,
582 : pencil_size,
583 : font_layout,
584 : out_feature_bounds
585 : );
586 :
587 0 : U8_TRACE_END();
588 0 : }
589 :
590 :
591 : /*
592 : Copyright 2017-2026 Andreas Warnke
593 :
594 : Licensed under the Apache License, Version 2.0 (the "License");
595 : you may not use this file except in compliance with the License.
596 : You may obtain a copy of the License at
597 :
598 : http://www.apache.org/licenses/LICENSE-2.0
599 :
600 : Unless required by applicable law or agreed to in writing, software
601 : distributed under the License is distributed on an "AS IS" BASIS,
602 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
603 : See the License for the specific language governing permissions and
604 : limitations under the License.
605 : */
|