Line data Source code
1 : /* File: pencil_classifier_composer.c; Copyright and License: see below */
2 :
3 : #include "pencil_classifier_composer.h"
4 : #include "u8/u8_trace.h"
5 : #include "u8/u8_f64.h"
6 : #include "utf8stringbuf/utf8stringbuf.h"
7 : #include "utf8stringbuf/utf8string.h"
8 : #include <pango/pangocairo.h>
9 : #include <stdio.h>
10 : #include <stdlib.h>
11 : #include <assert.h>
12 :
13 3 : void pencil_classifier_composer_init( pencil_classifier_composer_t *this_ )
14 : {
15 3 : U8_TRACE_BEGIN();
16 :
17 3 : draw_classifier_icon_init( &((*this_).draw_classifier_icon) );
18 3 : draw_classifier_label_init( &((*this_).draw_classifier_label) );
19 3 : draw_classifier_contour_init( &((*this_).draw_classifier_contour) );
20 3 : draw_stereotype_icon_init( &((*this_).draw_stereotype_icon) );
21 :
22 3 : U8_TRACE_END();
23 3 : }
24 :
25 3 : void pencil_classifier_composer_destroy( pencil_classifier_composer_t *this_ )
26 : {
27 3 : U8_TRACE_BEGIN();
28 :
29 3 : draw_classifier_icon_destroy( &((*this_).draw_classifier_icon) );
30 3 : draw_classifier_label_destroy( &((*this_).draw_classifier_label) );
31 3 : draw_classifier_contour_destroy( &((*this_).draw_classifier_contour) );
32 3 : draw_stereotype_icon_destroy( &((*this_).draw_stereotype_icon) );
33 :
34 3 : U8_TRACE_END();
35 3 : }
36 :
37 128 : pencil_error_t pencil_classifier_composer_set_envelope_box( pencil_classifier_composer_t *this_,
38 : const geometry_rectangle_t *envelope,
39 : bool shows_contained_children,
40 : const geometry_compartments_t *features_dimensions,
41 : const data_profile_part_t *profile,
42 : const pencil_size_t *pencil_size,
43 : PangoLayout *font_layout,
44 : layout_visible_classifier_t *io_classifier_layout )
45 : {
46 128 : U8_TRACE_BEGIN();
47 128 : assert( NULL != envelope );
48 128 : assert( NULL != pencil_size );
49 128 : assert( NULL != font_layout );
50 128 : assert( NULL != io_classifier_layout );
51 :
52 128 : pencil_error_t result_err = PENCIL_ERROR_NONE;
53 :
54 : /* get data that shall be layouted/composed */
55 : const data_visible_classifier_t *const visible_classifier
56 128 : = layout_visible_classifier_get_data_const( io_classifier_layout );
57 : const data_classifier_t *const classifier
58 128 : = data_visible_classifier_get_classifier_const( visible_classifier );
59 : const data_classifier_type_t classifier_type
60 128 : = data_classifier_get_main_type( classifier );
61 128 : const char *const classifier_stereotype = data_classifier_get_stereotype_const( classifier );
62 : const bool has_stereotype_icon
63 128 : = draw_stereotype_icon_exists( &((*this_).draw_stereotype_icon), classifier_stereotype, profile );
64 128 : const double half_gap = 0.5 * pencil_size_get_preferred_object_distance( pencil_size );
65 :
66 128 : U8_TRACE_INFO_INT("calculating bounds of classifier id, type:", data_classifier_get_row( classifier ) );
67 128 : U8_TRACE_INFO_INT_INT("calculating bounds of classifier type, children:", classifier_type, shows_contained_children?1:0 );
68 :
69 : /* determine inner_area of the classifier-shape */
70 : const geometry_dimensions_t *const compartment_dim
71 128 : = geometry_compartments_get_feature_compartments( features_dimensions );
72 : const geometry_rectangle_t inner_area
73 128 : = draw_classifier_contour_calc_inner_area( &((*this_).draw_classifier_contour),
74 : classifier_type,
75 : envelope,
76 : pencil_size
77 : );
78 : /* take number of ports into account: geometry_compartments_get_outer_width */
79 128 : const double inner_to_outer_width_delta
80 128 : = geometry_rectangle_get_width( envelope ) - geometry_rectangle_get_width( &inner_area ) ;
81 128 : const double inner_to_outer_height_delta
82 128 : = geometry_rectangle_get_height( envelope ) - geometry_rectangle_get_height( &inner_area ) ;
83 128 : const double needed_outer_width = geometry_compartments_get_outer_width( features_dimensions );
84 128 : const double needed_inner_width = needed_outer_width - inner_to_outer_width_delta;
85 128 : U8_TRACE_INFO_INT_INT("needed_outer/inner_width :", (int) needed_outer_width, (int) needed_inner_width );
86 128 : const double needed_outer_height = geometry_compartments_get_outer_height( features_dimensions );
87 128 : const double needed_inner_height = needed_outer_height - inner_to_outer_height_delta;
88 128 : U8_TRACE_INFO_INT_INT("needed_outer/inner_height :", (int) needed_outer_height, (int) needed_inner_height );
89 256 : const double preferred_inner_width = u8_f64_max3( geometry_rectangle_get_width( &inner_area ),
90 128 : geometry_dimensions_get_width( compartment_dim ),
91 : needed_inner_width
92 : );
93 : const geometry_rectangle_t preferred_inner_area
94 128 : = geometry_rectangle_new( geometry_rectangle_get_left( &inner_area ),
95 : geometry_rectangle_get_top( &inner_area ),
96 : preferred_inner_width,
97 : geometry_rectangle_get_height( &inner_area )
98 : );
99 128 : U8_TRACE_INFO("==== preferred_inner_area ====" );
100 128 : geometry_rectangle_trace( &preferred_inner_area );
101 :
102 : /* determine border sizes of the label (and optionally the right-aligned icon) */
103 : geometry_rectangle_t label_rect;
104 128 : geometry_rectangle_init_empty( &label_rect );
105 : geometry_rectangle_t icon_rect;
106 128 : geometry_rectangle_init_empty( &icon_rect );
107 : geometry_rectangle_t label_compartment;
108 128 : geometry_rectangle_init_empty( &label_compartment );
109 : const pencil_error_t area_too_small
110 128 : = pencil_classifier_composer_private_get_label_box( this_,
111 : visible_classifier,
112 : shows_contained_children,
113 : has_stereotype_icon,
114 : &preferred_inner_area,
115 : pencil_size,
116 : font_layout,
117 : &label_rect,
118 : &icon_rect,
119 : &label_compartment
120 : );
121 128 : result_err |= area_too_small;
122 :
123 : /* set label_box */
124 128 : layout_visible_classifier_set_label_box( io_classifier_layout, &label_rect );
125 128 : layout_visible_classifier_set_label_anchor( io_classifier_layout,
126 : GEOMETRY_H_ALIGN_CENTER,
127 : GEOMETRY_V_ALIGN_TOP
128 : );
129 :
130 : /* set icon_box */
131 128 : layout_visible_classifier_set_icon_box( io_classifier_layout, &icon_rect );
132 :
133 : /* position feature compartments box below label box */
134 256 : const double new_inner_left = u8_f64_min2( geometry_rectangle_get_left( &inner_area ),
135 128 : geometry_rectangle_get_left( &label_compartment )
136 : );
137 256 : const double new_inner_width = u8_f64_max3( geometry_rectangle_get_width( &label_compartment ),
138 128 : geometry_dimensions_get_width( compartment_dim ),
139 128 : geometry_rectangle_get_width( &inner_area )
140 : );
141 : const geometry_rectangle_t compartments_rect
142 128 : = geometry_rectangle_new( new_inner_left,
143 : geometry_rectangle_get_bottom( &label_compartment ),
144 : geometry_dimensions_get_width( compartment_dim ),
145 : geometry_dimensions_get_height( compartment_dim )
146 : );
147 128 : layout_visible_classifier_set_compartments( io_classifier_layout, &compartments_rect );
148 :
149 : /* calculate space */
150 128 : const double label_and_features_height
151 128 : = geometry_rectangle_get_height( &label_compartment )
152 128 : + geometry_dimensions_get_height( compartment_dim );
153 : const double classifier_space_height
154 128 : = u8_f64_max3( geometry_rectangle_get_height( &preferred_inner_area ) - label_and_features_height,
155 : half_gap,
156 128 : needed_inner_height - label_and_features_height
157 : );
158 : const geometry_rectangle_t classifier_space
159 128 : = geometry_rectangle_new( new_inner_left,
160 128 : geometry_rectangle_get_top( &preferred_inner_area ) + label_and_features_height,
161 : new_inner_width,
162 : classifier_space_height
163 : );
164 128 : if ( classifier_space_height
165 128 : > geometry_rectangle_get_height( &preferred_inner_area ) - label_and_features_height + 0.000000001 )
166 : {
167 64 : result_err |= PENCIL_ERROR_OUT_OF_BOUNDS;
168 : }
169 128 : layout_visible_classifier_set_space( io_classifier_layout, &classifier_space );
170 :
171 : /* set symbol */
172 : const bool has_contour
173 128 : = draw_classifier_contour_has_contour( &((*this_).draw_classifier_contour), classifier_type );
174 128 : if ( has_contour )
175 : {
176 92 : U8_TRACE_INFO("calculating symbol box as envelope around label and space..." );
177 : /* calculate symbol bounds */
178 92 : const double new_inner_height = geometry_rectangle_get_height( &label_compartment )
179 92 : + geometry_rectangle_get_height( &compartments_rect )
180 92 : + geometry_rectangle_get_height( &classifier_space );
181 : const geometry_rectangle_t new_inner_area
182 92 : = geometry_rectangle_new( new_inner_left,
183 : geometry_rectangle_get_top( &label_compartment ),
184 : new_inner_width,
185 : new_inner_height
186 : );
187 : const geometry_rectangle_t new_envelope
188 92 : = draw_classifier_contour_calc_outer_bounds( &((*this_).draw_classifier_contour),
189 : classifier_type,
190 : &new_inner_area,
191 : pencil_size
192 : );
193 92 : layout_visible_classifier_set_symbol_box( io_classifier_layout, &new_envelope );
194 : }
195 : else
196 : {
197 36 : U8_TRACE_INFO("calculating symbol box for fixed-sized icon..." );
198 36 : const double symbol_height = pencil_size_get_classifier_symbol_height( pencil_size );
199 36 : const double symbol_width = symbol_height;
200 :
201 : /* calculate symbol bounds */
202 36 : const geometry_h_align_t H_CENTER = GEOMETRY_H_ALIGN_CENTER;
203 : const double symbol_left
204 36 : = geometry_h_align_get_left( &H_CENTER,
205 : symbol_width,
206 : geometry_rectangle_get_left( &preferred_inner_area ),
207 : geometry_rectangle_get_width( &preferred_inner_area )
208 : );
209 36 : const double symbol_top = geometry_rectangle_get_top( &label_compartment ) - symbol_height;
210 : const geometry_rectangle_t classifier_symbol_box
211 36 : = geometry_rectangle_new( symbol_left, symbol_top, symbol_width, symbol_height );
212 36 : layout_visible_classifier_set_symbol_box( io_classifier_layout, &classifier_symbol_box );
213 : }
214 :
215 128 : U8_TRACE_INFO("==== symbol_box ====" );
216 128 : geometry_rectangle_trace( layout_visible_classifier_get_symbol_box_const( io_classifier_layout ) );
217 128 : U8_TRACE_INFO("==== label_box ====" );
218 128 : geometry_rectangle_trace( &label_rect );
219 128 : U8_TRACE_INFO("==== icon_box ====" );
220 128 : geometry_rectangle_trace( &icon_rect );
221 128 : U8_TRACE_INFO("==== compartments =====" );
222 128 : geometry_rectangle_trace( layout_visible_classifier_get_compartments_const( io_classifier_layout ) );
223 128 : U8_TRACE_INFO("==== space =====" );
224 128 : geometry_rectangle_trace( &classifier_space );
225 :
226 128 : if ( result_err != PENCIL_ERROR_NONE )
227 : {
228 : /* shift: center to requested position after resizing beyond requested size */
229 : const geometry_rectangle_t current_envelope
230 64 : = layout_visible_classifier_get_envelope_box( io_classifier_layout );
231 64 : const double shift_to_right = geometry_rectangle_get_center_x( envelope ) - geometry_rectangle_get_center_x( ¤t_envelope );
232 64 : const double shift_to_bottom = geometry_rectangle_get_center_y( envelope ) - geometry_rectangle_get_center_y( ¤t_envelope );
233 64 : const geometry_offset_t offset = geometry_offset_new( shift_to_right, shift_to_bottom );
234 64 : layout_visible_classifier_shift( io_classifier_layout, &offset );
235 : }
236 :
237 128 : geometry_rectangle_destroy( &label_rect );
238 128 : geometry_rectangle_destroy( &icon_rect );
239 128 : geometry_rectangle_destroy( &label_compartment );
240 :
241 128 : U8_TRACE_END_ERR( result_err );
242 128 : return result_err;
243 : }
244 :
245 64 : pencil_error_t pencil_classifier_composer_expand_space( pencil_classifier_composer_t *this_,
246 : const geometry_rectangle_t *space,
247 : bool shows_contained_children,
248 : const geometry_compartments_t *features_dimensions,
249 : const data_profile_part_t *profile,
250 : const pencil_size_t *pencil_size,
251 : PangoLayout *font_layout,
252 : layout_visible_classifier_t *io_classifier_layout )
253 : {
254 64 : U8_TRACE_BEGIN();
255 64 : assert( NULL != space );
256 64 : assert( NULL != pencil_size );
257 64 : assert( NULL != font_layout );
258 64 : assert( NULL != io_classifier_layout );
259 :
260 64 : pencil_error_t result_err = PENCIL_ERROR_NONE;
261 :
262 : /* get data that shall be layouted/composed */
263 : const data_visible_classifier_t *const visible_classifier
264 64 : = layout_visible_classifier_get_data_const( io_classifier_layout );
265 : const data_classifier_t *const classifier
266 64 : = data_visible_classifier_get_classifier_const( visible_classifier );
267 : const data_classifier_type_t classifier_type
268 64 : = data_classifier_get_main_type( classifier );
269 64 : const char *const classifier_stereotype = data_classifier_get_stereotype_const( classifier );
270 : const bool has_stereotype_icon
271 64 : = draw_stereotype_icon_exists( &((*this_).draw_stereotype_icon), classifier_stereotype, profile );
272 :
273 64 : U8_TRACE_INFO_INT("expanding bounds of classifier id:", data_classifier_get_row( classifier ) );
274 64 : U8_TRACE_INFO_INT_INT("expanding bounds of classifier type, children:", classifier_type, shows_contained_children?1:0 );
275 :
276 : /* determine inner_area of the classifier-shape */
277 : const geometry_dimensions_t *const compartment_dim
278 64 : = geometry_compartments_get_feature_compartments( features_dimensions );
279 : const geometry_rectangle_t preliminry_envelope
280 64 : = draw_classifier_contour_calc_outer_bounds( &((*this_).draw_classifier_contour),
281 : classifier_type,
282 : space,
283 : pencil_size
284 : );
285 : /* take number of ports into account: geometry_compartments_get_outer_width */
286 64 : const double inner_to_outer_width_delta
287 64 : = geometry_rectangle_get_width( &preliminry_envelope ) - geometry_rectangle_get_width( space ) ;
288 64 : const double inner_to_outer_height_delta
289 64 : = geometry_rectangle_get_height( &preliminry_envelope ) - geometry_rectangle_get_height( space ) ;
290 64 : const double needed_outer_width = geometry_compartments_get_outer_width( features_dimensions );
291 64 : const double needed_inner_width = needed_outer_width - inner_to_outer_width_delta;
292 64 : U8_TRACE_INFO_INT_INT("needed_outer/inner_width :", (int) needed_outer_width, (int) needed_inner_width );
293 64 : const double needed_outer_height = geometry_compartments_get_outer_height( features_dimensions );
294 64 : const double needed_inner_height = needed_outer_height - inner_to_outer_height_delta;
295 64 : U8_TRACE_INFO_INT_INT("needed_outer/inner_height :", (int) needed_outer_height, (int) needed_inner_height );
296 128 : const double preferred_inner_width = u8_f64_max3( geometry_rectangle_get_width( space ),
297 64 : geometry_dimensions_get_width( compartment_dim ),
298 : needed_inner_width
299 : );
300 : const geometry_rectangle_t preferred_inner_area
301 128 : = geometry_rectangle_new( geometry_rectangle_get_left( space ),
302 : geometry_rectangle_get_top( space ),
303 : preferred_inner_width,
304 64 : geometry_dimensions_get_height( compartment_dim ) + geometry_rectangle_get_height( space )
305 : );
306 64 : U8_TRACE_INFO("==== preferred_inner_area ====" );
307 64 : geometry_rectangle_trace( &preferred_inner_area );
308 :
309 : /* determine border sizes of the label (and optionally the right-aligned icon) */
310 : geometry_rectangle_t label_rect;
311 64 : geometry_rectangle_init_empty( &label_rect );
312 : geometry_rectangle_t icon_rect;
313 64 : geometry_rectangle_init_empty( &icon_rect );
314 : geometry_rectangle_t label_compartment;
315 64 : geometry_rectangle_init_empty( &label_compartment );
316 : const pencil_error_t area_too_small
317 64 : = pencil_classifier_composer_private_get_label_box( this_,
318 : visible_classifier,
319 : shows_contained_children,
320 : has_stereotype_icon,
321 : &preferred_inner_area,
322 : pencil_size,
323 : font_layout,
324 : &label_rect,
325 : &icon_rect,
326 : &label_compartment
327 : );
328 64 : result_err |= area_too_small;
329 64 : if ( area_too_small != PENCIL_ERROR_NONE )
330 : {
331 0 : U8_TRACE_INFO("new width is defined by label-and-icon, not by requested inner space" );
332 : }
333 :
334 : /* shift the label and icon because preferred_inner_area was a fake; */
335 : /* the top side is at space top instead of label top */
336 64 : const double delta_top
337 64 : = geometry_rectangle_get_bottom( &label_compartment )
338 64 : + geometry_dimensions_get_height( compartment_dim )
339 64 : - geometry_rectangle_get_top( space );
340 64 : geometry_rectangle_set_top( &label_rect, geometry_rectangle_get_top( &label_rect ) - delta_top );
341 64 : geometry_rectangle_set_top( &icon_rect, geometry_rectangle_get_top( &icon_rect ) - delta_top );
342 64 : geometry_rectangle_set_top( &label_compartment, geometry_rectangle_get_top( &label_compartment ) - delta_top );
343 :
344 : /* determine inner area */
345 128 : const double inner_left = u8_f64_min2( geometry_rectangle_get_left( space ),
346 64 : geometry_rectangle_get_left( &label_compartment )
347 : );
348 : const double inner_height
349 64 : = u8_f64_max2( geometry_rectangle_get_height( &label_compartment ) + geometry_dimensions_get_height( compartment_dim )
350 64 : + geometry_rectangle_get_height( space ),
351 : needed_inner_height
352 : );
353 64 : const double inner_width = u8_f64_max2( preferred_inner_width, geometry_rectangle_get_width( &label_compartment ) );
354 : const geometry_rectangle_t inner_area
355 64 : = geometry_rectangle_new( inner_left,
356 : geometry_rectangle_get_top( &label_compartment ),
357 : inner_width,
358 : inner_height
359 : );
360 64 : if (( inner_width > geometry_rectangle_get_width( space ) + 0.000000001 )
361 64 : ||( inner_height > geometry_rectangle_get_height( &label_compartment )
362 64 : + geometry_dimensions_get_height( compartment_dim ) + geometry_rectangle_get_height( space ) + 0.000000001 ))
363 : {
364 : /* features or label have expanded the space */
365 0 : result_err |= PENCIL_ERROR_OUT_OF_BOUNDS;
366 : }
367 :
368 : /* set label_box */
369 64 : layout_visible_classifier_set_label_box( io_classifier_layout, &label_rect );
370 64 : layout_visible_classifier_set_label_anchor( io_classifier_layout,
371 : GEOMETRY_H_ALIGN_CENTER,
372 : GEOMETRY_V_ALIGN_TOP
373 : );
374 : /* set icon_box */
375 64 : layout_visible_classifier_set_icon_box( io_classifier_layout, &icon_rect );
376 :
377 : /* position feature compartments box below label box */
378 : const geometry_rectangle_t compartments_rect
379 64 : = geometry_rectangle_new( geometry_rectangle_get_left( &inner_area ),
380 : geometry_rectangle_get_bottom( &label_compartment ),
381 : geometry_dimensions_get_width( compartment_dim ),
382 : geometry_dimensions_get_height( compartment_dim )
383 : );
384 64 : layout_visible_classifier_set_compartments( io_classifier_layout, &compartments_rect );
385 :
386 : /* calculate space */
387 : /* get the symbol and label boxes and inner space rectangles to modify */
388 64 : const double adjusted_space_height
389 64 : = inner_height - geometry_rectangle_get_height( &label_compartment )
390 64 : - geometry_dimensions_get_height( compartment_dim );
391 : const geometry_rectangle_t classifier_space
392 64 : = geometry_rectangle_new( geometry_rectangle_get_left( &inner_area ),
393 : geometry_rectangle_get_top( space ),
394 : geometry_rectangle_get_width( &inner_area ),
395 : adjusted_space_height
396 : );
397 64 : layout_visible_classifier_set_space( io_classifier_layout, &classifier_space );
398 :
399 : /* sizes of geometric objects are determined, */
400 : /* now position the geometric objects */
401 : const bool has_contour
402 64 : = draw_classifier_contour_has_contour( &((*this_).draw_classifier_contour), classifier_type );
403 :
404 64 : if ( has_contour )
405 : {
406 46 : U8_TRACE_INFO("calculating symbol box as envelope around label and space..." );
407 :
408 : /* calculate symbol bounds */
409 : const geometry_rectangle_t envelope
410 46 : = draw_classifier_contour_calc_outer_bounds( &((*this_).draw_classifier_contour),
411 : classifier_type,
412 : &inner_area,
413 : pencil_size
414 : );
415 46 : layout_visible_classifier_set_symbol_box( io_classifier_layout, &envelope );
416 : }
417 : else
418 : {
419 18 : U8_TRACE_INFO("calculating symbol box for fixed-sized icon..." );
420 :
421 18 : const double symbol_height = pencil_size_get_classifier_symbol_height( pencil_size );
422 18 : const double symbol_width = symbol_height;
423 :
424 : /* calculate symbol bounds */
425 18 : const geometry_h_align_t H_CENTER = GEOMETRY_H_ALIGN_CENTER;
426 : const double symbol_left
427 18 : = geometry_h_align_get_left( &H_CENTER,
428 : symbol_width,
429 : geometry_rectangle_get_left( &inner_area ),
430 : geometry_rectangle_get_width( &inner_area )
431 : );
432 18 : const double symbol_top = geometry_rectangle_get_top( &inner_area ) - symbol_height;
433 : const geometry_rectangle_t classifier_symbol_box
434 18 : = geometry_rectangle_new( symbol_left, symbol_top, symbol_width, symbol_height );
435 18 : layout_visible_classifier_set_symbol_box( io_classifier_layout, &classifier_symbol_box );
436 : }
437 :
438 64 : U8_TRACE_INFO("==== symbol_box ====" );
439 64 : geometry_rectangle_trace( layout_visible_classifier_get_symbol_box_const( io_classifier_layout ) );
440 64 : U8_TRACE_INFO("==== label_box ====" );
441 64 : geometry_rectangle_trace( &label_rect );
442 64 : U8_TRACE_INFO("==== icon_box ====" );
443 64 : geometry_rectangle_trace( &icon_rect );
444 64 : U8_TRACE_INFO("==== compartments =====" );
445 64 : geometry_rectangle_trace( layout_visible_classifier_get_compartments_const( io_classifier_layout ) );
446 64 : U8_TRACE_INFO("==== space =====" );
447 64 : geometry_rectangle_trace( layout_visible_classifier_get_space_const( io_classifier_layout ) );
448 :
449 64 : if ( result_err != PENCIL_ERROR_NONE )
450 : {
451 : /* shift: center to requested position after resizing beyond requested size */
452 0 : const double shift_to_right = geometry_rectangle_get_center_x( space ) - geometry_rectangle_get_center_x( &classifier_space );
453 0 : const double shift_to_bottom = geometry_rectangle_get_center_y( space ) - geometry_rectangle_get_center_y( &classifier_space );
454 0 : const geometry_offset_t offset = geometry_offset_new( shift_to_right, shift_to_bottom );
455 0 : layout_visible_classifier_shift( io_classifier_layout, &offset );
456 : }
457 :
458 64 : geometry_rectangle_destroy( &label_rect );
459 64 : geometry_rectangle_destroy( &icon_rect );
460 64 : geometry_rectangle_destroy( &label_compartment );
461 :
462 64 : U8_TRACE_END_ERR(result_err);
463 64 : return result_err;
464 : }
465 :
466 192 : pencil_error_t pencil_classifier_composer_private_get_label_box( pencil_classifier_composer_t *this_,
467 : const data_visible_classifier_t *visible_classifier,
468 : bool shows_contained_children,
469 : bool has_stereotype_icon,
470 : const geometry_rectangle_t *inner_area,
471 : const pencil_size_t *pencil_size,
472 : PangoLayout *font_layout,
473 : geometry_rectangle_t *out_label_box,
474 : geometry_rectangle_t *out_icon_box,
475 : geometry_rectangle_t *out_label_compartment )
476 : {
477 192 : U8_TRACE_BEGIN();
478 192 : assert( NULL != visible_classifier );
479 192 : assert( NULL != inner_area );
480 192 : assert( NULL != pencil_size );
481 192 : assert( NULL != font_layout );
482 192 : assert( NULL != out_label_box );
483 192 : assert( NULL != out_icon_box );
484 192 : assert( NULL != out_label_compartment );
485 :
486 192 : pencil_error_t result_err = PENCIL_ERROR_NONE;
487 :
488 : /* get classifier type */
489 : const data_classifier_t *const classifier
490 192 : = data_visible_classifier_get_classifier_const( visible_classifier );
491 : const data_classifier_type_t classifier_type
492 192 : = data_classifier_get_main_type( classifier );
493 :
494 : /* get standard gap size */
495 192 : const double gap = pencil_size_get_standard_object_border( pencil_size );
496 :
497 : /* determine icon space */
498 : const geometry_dimensions_t icon_dim
499 : = has_stereotype_icon
500 0 : ? draw_stereotype_icon_get_dimensions( &((*this_).draw_stereotype_icon),
501 : pencil_size
502 : )
503 192 : : draw_classifier_icon_get_icon_dimensions( &((*this_).draw_classifier_icon),
504 : classifier_type,
505 : pencil_size
506 : );
507 :
508 : /* determine stereotype and name dimensions */
509 : geometry_dimensions_t label_dim;
510 : const bool has_contour
511 192 : = draw_classifier_contour_has_contour( &((*this_).draw_classifier_contour), classifier_type );
512 192 : const double icon_gap
513 192 : = ( ! has_contour ) ? 0.0 : ( geometry_dimensions_get_width( &icon_dim ) < 0.000001 ) ? 0.0 : gap;
514 138 : const double proposed_label_width
515 : = has_contour
516 138 : ? geometry_rectangle_get_width( inner_area ) - geometry_dimensions_get_width( &icon_dim ) - icon_gap
517 192 : : geometry_rectangle_get_width( inner_area );
518 192 : const double proposed_label_height = geometry_rectangle_get_height( inner_area );
519 192 : const geometry_dimensions_t proposed_label_dim = { .width = proposed_label_width, .height = proposed_label_height };
520 192 : draw_classifier_label_get_stereotype_and_name_dimensions( &((*this_).draw_classifier_label),
521 : visible_classifier,
522 : ( ! has_stereotype_icon ),
523 : &proposed_label_dim,
524 : 1, /* max_recursions */
525 : pencil_size,
526 : font_layout,
527 : &label_dim
528 192 : );
529 192 : const double text_width = geometry_dimensions_get_width( &label_dim );
530 192 : const double text_height = geometry_dimensions_get_height( &label_dim );
531 192 : if ( text_width > (proposed_label_width + 0.0001) )
532 : {
533 64 : U8_TRACE_INFO_INT_INT( "label does not fit to provided width",
534 : (int) text_width,
535 : (int) proposed_label_width
536 : );
537 64 : result_err = PENCIL_ERROR_OUT_OF_BOUNDS;
538 : }
539 192 : if ( text_height > (proposed_label_height + 0.0001) )
540 : {
541 64 : U8_TRACE_INFO_INT_INT( "label does not fit to provided height",
542 : (int) text_height,
543 : (int) proposed_label_height
544 : );
545 64 : result_err = PENCIL_ERROR_OUT_OF_BOUNDS;
546 : }
547 :
548 192 : if ( has_contour )
549 : {
550 138 : double top_border = geometry_rectangle_get_top( inner_area );
551 :
552 : /* calculate label_compartment */
553 138 : const double min_required_width = text_width + icon_gap + geometry_dimensions_get_width( &icon_dim );
554 138 : const double comp_width = u8_f64_max2( min_required_width, geometry_rectangle_get_width( inner_area ) );
555 138 : const geometry_h_align_t compartment_h_align = GEOMETRY_H_ALIGN_CENTER;
556 138 : const double comp_left = geometry_h_align_get_left( &compartment_h_align,
557 : comp_width,
558 : geometry_rectangle_get_left( inner_area ),
559 : geometry_rectangle_get_width( inner_area )
560 : );
561 138 : geometry_rectangle_reinit( out_label_compartment, comp_left, top_border, comp_width, text_height );
562 :
563 : /* calculate label_box and icon_box */
564 138 : const bool is_package_with_contents = (classifier_type == DATA_CLASSIFIER_TYPE_PACKAGE) && shows_contained_children;
565 138 : if ( is_package_with_contents )
566 : {
567 : /* re-calculate the outer bounds (envelope) to see the diff to top of packages, ignore inner_area */
568 : const geometry_rectangle_t envelope
569 3 : = draw_classifier_contour_calc_outer_bounds( &((*this_).draw_classifier_contour),
570 : classifier_type,
571 : out_label_compartment,
572 : pencil_size
573 : );
574 3 : double comp_top = geometry_rectangle_get_top( &envelope ) + 2.0 * gap;
575 :
576 : /* calculate label_box */
577 3 : geometry_rectangle_reinit( out_label_box,
578 : comp_left,
579 : comp_top,
580 : text_width,
581 : text_height
582 : );
583 : /* calculate icon_box */
584 3 : geometry_rectangle_reinit( out_icon_box,
585 3 : comp_left + text_width + icon_gap,
586 : comp_top,
587 : geometry_dimensions_get_width( &icon_dim ),
588 : geometry_dimensions_get_height( &icon_dim )
589 : );
590 : }
591 : else
592 : {
593 135 : const geometry_h_align_t text_h_align = GEOMETRY_H_ALIGN_CENTER;
594 270 : const double text_left = geometry_h_align_get_left( &text_h_align,
595 : text_width,
596 : geometry_rectangle_get_left( inner_area ),
597 135 : geometry_rectangle_get_width( inner_area ) - icon_gap - geometry_dimensions_get_width( &icon_dim )
598 : );
599 : /* calculate label_box */
600 135 : geometry_rectangle_reinit( out_label_box,
601 : text_left,
602 : top_border,
603 : text_width,
604 : text_height
605 : );
606 : /* calculate icon_box */
607 135 : geometry_rectangle_reinit( out_icon_box,
608 135 : comp_left + comp_width - geometry_dimensions_get_width( &icon_dim ),
609 : top_border,
610 : geometry_dimensions_get_width( &icon_dim ),
611 : geometry_dimensions_get_height( &icon_dim )
612 : );
613 : }
614 : }
615 : else
616 : {
617 : /* calculate text position */
618 54 : const geometry_h_align_t h_align_center = GEOMETRY_H_ALIGN_CENTER;
619 54 : const double text_left = geometry_h_align_get_left( &h_align_center,
620 : text_width,
621 : geometry_rectangle_get_left( inner_area ),
622 : geometry_rectangle_get_width( inner_area )
623 : );
624 54 : const double text_top = geometry_rectangle_get_top( inner_area );
625 :
626 : /* calculate label_compartment */
627 54 : const double comp_width = u8_f64_max2( text_width, geometry_rectangle_get_width( inner_area ) );
628 54 : const geometry_h_align_t compartment_h_align = GEOMETRY_H_ALIGN_CENTER;
629 54 : const double comp_left = geometry_h_align_get_left( &compartment_h_align,
630 : comp_width,
631 : geometry_rectangle_get_left( inner_area ),
632 : geometry_rectangle_get_width( inner_area )
633 : );
634 54 : geometry_rectangle_reinit( out_label_compartment, comp_left, text_top, comp_width, text_height );
635 :
636 : /* calculate label_box */
637 54 : geometry_rectangle_reinit( out_label_box, text_left, text_top, text_width, text_height );
638 : /* calculate icon_box */
639 54 : const double icon_left = geometry_h_align_get_left( &h_align_center,
640 : geometry_dimensions_get_width( &icon_dim ),
641 : geometry_rectangle_get_left( inner_area ),
642 : geometry_rectangle_get_width( inner_area )
643 : );
644 54 : geometry_rectangle_reinit( out_icon_box,
645 : icon_left,
646 54 : text_top - gap - geometry_dimensions_get_height( &icon_dim ),
647 : geometry_dimensions_get_width( &icon_dim ),
648 : geometry_dimensions_get_height( &icon_dim )
649 : );
650 : }
651 :
652 192 : U8_TRACE_END_ERR( result_err );
653 192 : return result_err;
654 : }
655 :
656 :
657 : /*
658 : Copyright 2016-2026 Andreas Warnke
659 : http://www.apache.org/licenses/LICENSE-2.0
660 :
661 : Licensed under the Apache License, Version 2.0 (the "License");
662 : you may not use this file except in compliance with the License.
663 : You may obtain a copy of the License at
664 :
665 :
666 : Unless required by applicable law or agreed to in writing, software
667 : distributed under the License is distributed on an "AS IS" BASIS,
668 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
669 : See the License for the specific language governing permissions and
670 : limitations under the License.
671 : */
|