Line data Source code
1 : /* File: pencil_feature_layouter.c; Copyright and License: see below */
2 :
3 : #include "pencil_feature_layouter.h"
4 : #include "u8/u8_f64.h"
5 : #include "u8/u8_trace.h"
6 : #include <pango/pangocairo.h>
7 : #include <stdio.h>
8 : #include <stdlib.h>
9 : #include <math.h>
10 :
11 0 : void pencil_feature_layouter_init( pencil_feature_layouter_t *this_,
12 : layout_visible_set_t *layout_data,
13 : const data_profile_part_t *profile,
14 : const pencil_size_t *pencil_size )
15 : {
16 0 : U8_TRACE_BEGIN();
17 0 : assert( NULL != layout_data );
18 0 : assert( NULL != profile );
19 0 : assert( NULL != pencil_size );
20 :
21 0 : (*this_).layout_data = layout_data;
22 0 : (*this_).profile = profile;
23 0 : (*this_).pencil_size = pencil_size;
24 0 : data_guidelines_init( &((*this_).guidelines) );
25 0 : (*this_).label_dimensions_initialized = false;
26 0 : draw_feature_label_init( &((*this_).draw_feature_label) );
27 :
28 0 : U8_TRACE_END();
29 0 : }
30 :
31 0 : void pencil_feature_layouter_reset( pencil_feature_layouter_t *this_ )
32 : {
33 0 : U8_TRACE_BEGIN();
34 :
35 0 : (*this_).label_dimensions_initialized = false;
36 :
37 0 : U8_TRACE_END();
38 0 : }
39 :
40 0 : void pencil_feature_layouter_destroy( pencil_feature_layouter_t *this_ )
41 : {
42 0 : U8_TRACE_BEGIN();
43 :
44 0 : draw_feature_label_destroy( &((*this_).draw_feature_label) );
45 0 : data_guidelines_destroy( &((*this_).guidelines) );
46 0 : (*this_).label_dimensions_initialized = false;
47 :
48 0 : U8_TRACE_END();
49 0 : }
50 :
51 0 : void pencil_feature_layouter_do_layout ( pencil_feature_layouter_t *this_, PangoLayout *font_layout )
52 : {
53 0 : U8_TRACE_BEGIN();
54 : assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) LAYOUT_VISIBLE_SET_MAX_FEATURES );
55 :
56 : /* establish precondition: precalculate the dimensions of labels */
57 0 : if ( ! (*this_).label_dimensions_initialized )
58 : {
59 0 : pencil_feature_layouter_private_init_label_dimensions( this_, font_layout );
60 : }
61 : /* get diagram draw area */
62 : const layout_diagram_t *const diagram_layout
63 0 : = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
64 : const geometry_rectangle_t *const diagram_draw_area
65 0 : = layout_diagram_get_draw_area_const( diagram_layout );
66 : const data_diagram_t *const diagram_data
67 0 : = layout_diagram_get_data_const ( diagram_layout );
68 : const data_diagram_type_t diag_type
69 0 : = data_diagram_get_diagram_type ( diagram_data );
70 :
71 : /* layout the unsorted features */
72 : const uint32_t count_features
73 0 : = layout_visible_set_get_feature_count ( (*this_).layout_data );
74 0 : for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
75 : {
76 : layout_feature_t *const feature_layout
77 0 : = layout_visible_set_get_feature_ptr ( (*this_).layout_data, f_idx );
78 : const data_feature_t *const the_feature
79 0 : = layout_feature_get_data_const ( feature_layout );
80 : const layout_visible_classifier_t *const layout_classifier
81 0 : = layout_feature_get_classifier_const ( feature_layout );
82 : const data_classifier_t *const classifier
83 0 : = layout_visible_classifier_get_classifier_const( layout_classifier );
84 : const data_classifier_type_t classifier_type
85 0 : = data_classifier_get_main_type( classifier );
86 :
87 : const geometry_rectangle_t *const c_symbol_box
88 0 : = layout_visible_classifier_get_symbol_box_const ( layout_classifier );
89 : const geometry_rectangle_t *const c_envelope_box
90 0 : = layout_visible_classifier_get_envelope_box_const ( layout_classifier );
91 0 : switch ( data_feature_get_main_type (the_feature) )
92 : {
93 0 : case DATA_FEATURE_TYPE_LIFELINE:
94 : {
95 : /* layout lifeline feature next to parent classifier */
96 0 : pencil_feature_layouter_private_layout_lifeline ( this_,
97 : diagram_draw_area,
98 : diag_type,
99 : classifier_type,
100 : c_symbol_box,
101 : c_envelope_box,
102 : feature_layout
103 : );
104 : }
105 0 : break;
106 :
107 0 : case DATA_FEATURE_TYPE_PORT: /* or */
108 : case DATA_FEATURE_TYPE_IN_PORT_PIN: /* or */
109 : case DATA_FEATURE_TYPE_OUT_PORT_PIN: /* or */
110 : case DATA_FEATURE_TYPE_ENTRY: /* or */
111 : case DATA_FEATURE_TYPE_EXIT:
112 : {
113 : /* layout port feature onto parent classifier box */
114 0 : pencil_feature_layouter_private_layout_port_pin ( this_,
115 : classifier_type,
116 : c_symbol_box,
117 : the_feature,
118 : font_layout,
119 : feature_layout
120 : );
121 : }
122 0 : break;
123 :
124 0 : case DATA_FEATURE_TYPE_PROVIDED_INTERFACE: /* or */
125 : case DATA_FEATURE_TYPE_REQUIRED_INTERFACE:
126 : {
127 : /* layout interface feature close to parent classifier */
128 0 : pencil_feature_layouter_private_layout_interface ( this_,
129 : c_symbol_box,
130 : the_feature,
131 : font_layout,
132 : feature_layout
133 : );
134 : }
135 0 : break;
136 :
137 0 : case DATA_FEATURE_TYPE_PROPERTY: /* or */
138 : case DATA_FEATURE_TYPE_OPERATION: /* or */
139 : case DATA_FEATURE_TYPE_TAGGED_VALUE:
140 : {
141 : /* layout property or operation feature within the feature compartments, also the tagged values */
142 : const geometry_rectangle_t *const c_compartments
143 0 : = layout_visible_classifier_get_compartments_const ( layout_classifier );
144 0 : pencil_feature_layouter_private_layout_compartment ( this_,
145 : c_compartments,
146 : font_layout,
147 : feature_layout
148 : );
149 : }
150 0 : break;
151 :
152 0 : default:
153 : {
154 0 : U8_LOG_ANOMALY("unknown feature type in pencil_feature_layouter_do_layout");
155 : /* this may happen if a new database file has been read by an old program version */
156 : /* layout like property or operation or tagged values */
157 : const geometry_rectangle_t *const c_compartments
158 0 : = layout_visible_classifier_get_compartments_const ( layout_classifier );
159 0 : pencil_feature_layouter_private_layout_compartment ( this_,
160 : c_compartments,
161 : font_layout,
162 : feature_layout
163 : );
164 : }
165 0 : break;
166 : }
167 : }
168 :
169 0 : U8_TRACE_END();
170 0 : }
171 :
172 0 : void pencil_feature_layouter_calculate_features_dimensions( pencil_feature_layouter_t *this_,
173 : data_row_t diagramelement_id,
174 : PangoLayout *font_layout,
175 : geometry_compartments_t *out_features_dim )
176 : {
177 0 : U8_TRACE_BEGIN();
178 0 : assert( NULL != font_layout );
179 0 : assert( NULL != out_features_dim );
180 :
181 : /* establish precondition: precalculate the dimensions of labels */
182 0 : if ( ! (*this_).label_dimensions_initialized )
183 : {
184 0 : pencil_feature_layouter_private_init_label_dimensions( this_, font_layout );
185 : }
186 :
187 : /* init result */
188 0 : const double obj_border = pencil_size_get_standard_object_border( (*this_).pencil_size );
189 0 : const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
190 0 : geometry_compartments_reinit( out_features_dim, obj_border, gap );
191 :
192 : /* search all contained features */
193 : const uint32_t count_features
194 0 : = layout_visible_set_get_feature_count( (*this_).layout_data );
195 0 : for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
196 : {
197 : const layout_feature_t *const feature_layout
198 0 : = layout_visible_set_get_feature_ptr( (*this_).layout_data, f_idx );
199 : const data_feature_t *const the_feature
200 0 : = layout_feature_get_data_const( feature_layout );
201 : const layout_visible_classifier_t *const layout_classifier
202 0 : = layout_feature_get_classifier_const( feature_layout );
203 0 : const data_feature_type_t the_feature_type = data_feature_get_main_type( the_feature );
204 0 : const uint32_t list_order = data_feature_get_list_order( the_feature );
205 :
206 0 : if ( diagramelement_id == layout_visible_classifier_get_diagramelement_id( layout_classifier ) )
207 : {
208 : const geometry_compartment_type_t compartment
209 0 : = geometry_compartment_type_new( the_feature_type, list_order );
210 :
211 0 : if ( data_feature_type_inside_compartment( the_feature_type ) )
212 : {
213 : /* feature label sizes are already precalculated */
214 0 : assert( (*this_).label_dimensions_initialized );
215 0 : const geometry_rectangle_t *const label_box = layout_feature_get_label_box_const( feature_layout );
216 0 : const geometry_dimensions_t label_dim = geometry_rectangle_get_dimensions( label_box );
217 :
218 : /* update compartment dimensions */
219 0 : geometry_compartments_add_feature( out_features_dim,
220 : compartment,
221 : &label_dim
222 : );
223 : }
224 : else
225 : {
226 : /* interface and port icon sizes are based on the standard_font_size: */
227 0 : const double symbol_size = pencil_size_get_standard_font_size( (*this_).pencil_size );
228 0 : const geometry_dimensions_t symbol_dim = geometry_dimensions_new( symbol_size, symbol_size );
229 :
230 : /* update compartment dimensions */
231 0 : geometry_compartments_add_feature( out_features_dim,
232 : compartment,
233 : &symbol_dim
234 : );
235 : }
236 : }
237 : }
238 :
239 0 : U8_TRACE_END();
240 0 : }
241 :
242 0 : void pencil_feature_layouter_private_init_label_dimensions( pencil_feature_layouter_t *this_,
243 : PangoLayout *font_layout
244 : )
245 : {
246 0 : U8_TRACE_BEGIN();
247 0 : assert ( NULL != font_layout );
248 :
249 : const uint32_t count_features
250 0 : = layout_visible_set_get_feature_count( (*this_).layout_data );
251 0 : for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
252 : {
253 : layout_feature_t *const feature_layout
254 0 : = layout_visible_set_get_feature_ptr( (*this_).layout_data, f_idx );
255 : const data_feature_t *const the_feature
256 0 : = layout_feature_get_data_const( feature_layout );
257 0 : const data_feature_type_t the_feature_type = data_feature_get_main_type( the_feature );
258 :
259 0 : if ( data_feature_type_inside_compartment( the_feature_type ) )
260 : {
261 : geometry_dimensions_t min_feature_bounds;
262 0 : geometry_dimensions_init_empty( &min_feature_bounds );
263 0 : pencil_feature_layouter_private_get_minimum_bounds( this_,
264 : the_feature,
265 : (*this_).profile,
266 : (*this_).pencil_size,
267 : font_layout,
268 : &min_feature_bounds
269 : );
270 :
271 0 : const geometry_rectangle_t label_box = {
272 : .left = 0.0,
273 : .top = 0.0,
274 0 : .width = geometry_dimensions_get_width( &min_feature_bounds ),
275 0 : .height = geometry_dimensions_get_height( &min_feature_bounds ),
276 : };
277 0 : layout_feature_set_label_box( feature_layout, &label_box );
278 0 : geometry_dimensions_destroy( &min_feature_bounds );
279 : }
280 : }
281 :
282 0 : (*this_).label_dimensions_initialized = true;
283 0 : U8_TRACE_END();
284 0 : }
285 :
286 0 : void pencil_feature_layouter_private_layout_lifeline ( pencil_feature_layouter_t *this_,
287 : const geometry_rectangle_t *diagram_space,
288 : data_diagram_type_t diagram_type,
289 : data_classifier_type_t classifier_type,
290 : const geometry_rectangle_t *classifier_symbol_box,
291 : const geometry_rectangle_t *classifier_envelope_box,
292 : layout_feature_t *out_feature_layout )
293 : {
294 0 : U8_TRACE_BEGIN();
295 0 : assert ( NULL != diagram_space );
296 0 : assert ( NULL != classifier_symbol_box );
297 0 : assert ( NULL != classifier_envelope_box );
298 0 : assert ( NULL != out_feature_layout );
299 :
300 : /* get preferred object distance */
301 : const double obj_dist
302 0 : = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
303 0 : const double feature_width = obj_dist;
304 :
305 : const bool lifeline_has_semantics
306 0 : = data_guidelines_classifier_has_scenario_semantics( &((*this_).guidelines),
307 : diagram_type,
308 : classifier_type
309 : );
310 :
311 0 : if (( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diagram_type ) && lifeline_has_semantics )
312 0 : {
313 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_RIGHT );
314 0 : const double c_right = geometry_rectangle_get_right( classifier_envelope_box );
315 0 : const double c_top = geometry_rectangle_get_top( classifier_envelope_box );
316 0 : const double c_height = geometry_rectangle_get_height( classifier_envelope_box );
317 0 : const double dda_right = geometry_rectangle_get_right ( diagram_space );
318 : geometry_rectangle_t lifeline_bounds;
319 0 : geometry_rectangle_init ( &lifeline_bounds,
320 : c_right,
321 0 : c_top + ( 0.5 * ( c_height - feature_width ) ),
322 0 : dda_right - c_right - obj_dist,
323 : feature_width
324 : );
325 0 : layout_feature_set_symbol_box ( out_feature_layout, &lifeline_bounds );
326 0 : layout_feature_set_label_box ( out_feature_layout, &lifeline_bounds );
327 : }
328 0 : else if (( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diagram_type ) && lifeline_has_semantics )
329 0 : {
330 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_DOWN );
331 0 : const double c_bottom = geometry_rectangle_get_bottom( classifier_envelope_box );
332 0 : const double c_left = geometry_rectangle_get_left( classifier_envelope_box );
333 0 : const double c_width = geometry_rectangle_get_width( classifier_envelope_box );
334 0 : const double dda_bottom = geometry_rectangle_get_bottom ( diagram_space );
335 : geometry_rectangle_t lifeline_bounds;
336 0 : geometry_rectangle_init ( &lifeline_bounds,
337 0 : c_left + ( 0.5 * ( c_width - feature_width ) ),
338 : c_bottom,
339 : feature_width,
340 0 : dda_bottom - c_bottom - obj_dist
341 : );
342 0 : layout_feature_set_symbol_box ( out_feature_layout, &lifeline_bounds );
343 0 : layout_feature_set_label_box ( out_feature_layout, &lifeline_bounds );
344 : }
345 : else /*if (( DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM == diagram_type )||( DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM == diagram_type ))*/
346 : {
347 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_CENTER );
348 0 : layout_feature_set_symbol_box ( out_feature_layout, classifier_symbol_box );
349 0 : layout_feature_set_label_box ( out_feature_layout, classifier_symbol_box );
350 : }
351 :
352 0 : U8_TRACE_END();
353 0 : }
354 :
355 0 : void pencil_feature_layouter_private_layout_port_pin ( pencil_feature_layouter_t *this_,
356 : data_classifier_type_t classifier_type,
357 : const geometry_rectangle_t *classifier_symbol_box,
358 : const data_feature_t *the_feature,
359 : PangoLayout *font_layout,
360 : layout_feature_t *out_feature_layout )
361 : {
362 0 : U8_TRACE_BEGIN();
363 0 : assert ( NULL != classifier_symbol_box );
364 0 : assert ( NULL != the_feature );
365 0 : assert ( NULL != font_layout );
366 0 : assert ( NULL != out_feature_layout );
367 :
368 : /* get preferred object distance */
369 : const double gap
370 0 : = pencil_size_get_standard_object_border( (*this_).pencil_size );
371 :
372 : const double port_icon_size
373 0 : = pencil_size_get_standard_font_size( (*this_).pencil_size );
374 :
375 : /* determine the coordinates of the box-line */
376 : geometry_rectangle_t classifier_box;
377 0 : geometry_rectangle_copy( &classifier_box, classifier_symbol_box );
378 0 : geometry_rectangle_shift( &classifier_box, gap, gap );
379 0 : geometry_rectangle_enlarge( &classifier_box, -2.0*gap, -2.0*gap );
380 :
381 : const int32_t list_order
382 0 : = data_feature_get_list_order( the_feature );
383 :
384 : /* position the port icon */
385 0 : const bool is_sysml_constraint_block = (classifier_type == DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK);
386 0 : const bool is_behavioral = data_classifier_type_is_behavioral( classifier_type );
387 0 : const data_feature_type_t feat_type = data_feature_get_main_type( the_feature );
388 0 : const bool is_state_entry_exit
389 0 : = (( feat_type == DATA_FEATURE_TYPE_ENTRY )||( feat_type == DATA_FEATURE_TYPE_EXIT ));
390 0 : const double outwards_distance
391 0 : = is_sysml_constraint_block ? 0.0 : (is_behavioral&&(!is_state_entry_exit)) ? port_icon_size : (0.5*port_icon_size);
392 : double port_icon_left;
393 : double port_icon_top;
394 0 : const double show_arrow_in = ( feat_type == DATA_FEATURE_TYPE_IN_PORT_PIN );
395 0 : const double show_arrow_out = ( feat_type == DATA_FEATURE_TYPE_OUT_PORT_PIN );
396 0 : geometry_direction_t arrow_dir = GEOMETRY_DIRECTION_CENTER;
397 0 : if ( list_order < 0 )
398 : {
399 : static const int32_t INT32_MIN_HALF = INT32_MIN/2;
400 0 : if ( list_order < INT32_MIN_HALF ) /* SHOW ON RIGHT BORDER */
401 : {
402 0 : const double y_pos_rel
403 0 : = (list_order - INT32_MIN_HALF) / ((double)(INT32_MIN_HALF));
404 0 : port_icon_left = geometry_rectangle_get_right( &classifier_box ) - port_icon_size + outwards_distance;
405 0 : port_icon_top = geometry_rectangle_get_top( &classifier_box ) + y_pos_rel * ( geometry_rectangle_get_height( &classifier_box ) - port_icon_size );
406 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_LEFT : show_arrow_out ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_CENTER;
407 : }
408 : else /* SHOW ON TOP BORDER */
409 : {
410 0 : const double x_pos_rel
411 0 : = (list_order) / ((double)(INT32_MIN_HALF));
412 0 : port_icon_left = geometry_rectangle_get_left( &classifier_box ) + x_pos_rel * ( geometry_rectangle_get_width( &classifier_box ) - port_icon_size );
413 0 : port_icon_top = geometry_rectangle_get_top( &classifier_box ) - outwards_distance;
414 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_DOWN : show_arrow_out ? GEOMETRY_DIRECTION_UP : GEOMETRY_DIRECTION_CENTER;
415 : }
416 : }
417 : else
418 : {
419 : static const int32_t INT32_MAX_HALF = (INT32_MAX/2)+1; /* round to ceiling */
420 0 : if ( list_order < INT32_MAX_HALF ) /* SHOW ON LEFT BORDER */
421 : {
422 0 : const double y_pos_rel
423 0 : = (list_order) / ((double)(INT32_MAX_HALF));
424 0 : port_icon_left = geometry_rectangle_get_left( &classifier_box ) - outwards_distance;
425 0 : port_icon_top = geometry_rectangle_get_top( &classifier_box ) + y_pos_rel * ( geometry_rectangle_get_height( &classifier_box ) - port_icon_size );
426 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_RIGHT : show_arrow_out ? GEOMETRY_DIRECTION_LEFT : GEOMETRY_DIRECTION_CENTER;
427 : }
428 : else /* SHOW ON BOTTOM BORDER */
429 : {
430 0 : const double x_pos_rel
431 0 : = (list_order - INT32_MAX_HALF) / ((double)(INT32_MAX_HALF));
432 0 : port_icon_left = geometry_rectangle_get_left( &classifier_box ) + x_pos_rel * ( geometry_rectangle_get_width( &classifier_box ) - port_icon_size );
433 0 : port_icon_top = geometry_rectangle_get_bottom( &classifier_box ) - port_icon_size + outwards_distance;
434 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_UP : show_arrow_out ? GEOMETRY_DIRECTION_DOWN : GEOMETRY_DIRECTION_CENTER;
435 : }
436 : }
437 :
438 : /* set feature bounding box */
439 : geometry_rectangle_t f_bounds;
440 0 : geometry_rectangle_init ( &f_bounds,
441 : port_icon_left,
442 : port_icon_top,
443 : port_icon_size,
444 : port_icon_size
445 : );
446 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
447 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
448 0 : layout_feature_set_icon_direction ( out_feature_layout, arrow_dir );
449 :
450 0 : U8_TRACE_END();
451 0 : }
452 :
453 0 : void pencil_feature_layouter_private_layout_interface ( pencil_feature_layouter_t *this_,
454 : const geometry_rectangle_t *classifier_symbol_box,
455 : const data_feature_t *the_feature,
456 : PangoLayout *font_layout,
457 : layout_feature_t *out_feature_layout )
458 : {
459 0 : U8_TRACE_BEGIN();
460 0 : assert ( NULL != classifier_symbol_box );
461 0 : assert ( NULL != the_feature );
462 0 : assert ( NULL != font_layout );
463 0 : assert ( NULL != out_feature_layout );
464 :
465 : /* get preferred object size + distance */
466 0 : const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
467 0 : const double interface_icon_size = pencil_size_get_standard_font_size( (*this_).pencil_size );
468 0 : const double interface_distance
469 0 : = 2.001 * pencil_size_get_preferred_object_distance( (*this_).pencil_size ) + gap; /* min dist formula as in relationship layouter */
470 :
471 0 : const int32_t list_order = data_feature_get_list_order( the_feature );
472 :
473 : /* position the interface icon */
474 0 : if ( list_order < 0 )
475 : {
476 : static const int32_t INT32_MIN_HALF = INT32_MIN/2;
477 0 : if ( list_order < INT32_MIN_HALF ) /* SHOW ON RIGHT BORDER */
478 : {
479 0 : const double y_pos_rel
480 0 : = (list_order - INT32_MIN_HALF) / ((double)(INT32_MIN_HALF));
481 : geometry_rectangle_t f_bounds;
482 0 : geometry_rectangle_init ( &f_bounds,
483 0 : geometry_rectangle_get_right( classifier_symbol_box ) + interface_distance,
484 0 : geometry_rectangle_get_top( classifier_symbol_box ) + y_pos_rel * ( geometry_rectangle_get_height( classifier_symbol_box ) - interface_icon_size ),
485 : interface_icon_size,
486 : interface_icon_size
487 : );
488 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
489 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
490 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_RIGHT );
491 : }
492 : else /* SHOW ON TOP BORDER */
493 : {
494 0 : const double x_pos_rel
495 0 : = (list_order) / ((double)(INT32_MIN_HALF));
496 : geometry_rectangle_t f_bounds;
497 0 : geometry_rectangle_init ( &f_bounds,
498 0 : geometry_rectangle_get_left( classifier_symbol_box ) + x_pos_rel * ( geometry_rectangle_get_width( classifier_symbol_box ) - interface_icon_size ),
499 0 : geometry_rectangle_get_top( classifier_symbol_box ) - interface_distance - interface_icon_size,
500 : interface_icon_size,
501 : interface_icon_size
502 : );
503 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
504 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
505 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_UP );
506 : }
507 : }
508 : else
509 : {
510 : static const int32_t INT32_MAX_HALF = (INT32_MAX/2)+1; /* round to ceiling */
511 0 : if ( list_order < INT32_MAX_HALF ) /* SHOW ON LEFT BORDER */
512 : {
513 0 : const double y_pos_rel
514 0 : = (list_order) / ((double)(INT32_MAX_HALF));
515 : geometry_rectangle_t f_bounds;
516 0 : geometry_rectangle_init ( &f_bounds,
517 0 : geometry_rectangle_get_left( classifier_symbol_box ) - interface_distance - interface_icon_size,
518 0 : geometry_rectangle_get_top( classifier_symbol_box ) + y_pos_rel * ( geometry_rectangle_get_height( classifier_symbol_box ) - interface_icon_size ),
519 : interface_icon_size,
520 : interface_icon_size
521 : );
522 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
523 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
524 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_LEFT );
525 : }
526 : else /* SHOW ON BOTTOM BORDER */
527 : {
528 0 : const double x_pos_rel
529 0 : = (list_order - INT32_MAX_HALF) / ((double)(INT32_MAX_HALF));
530 : geometry_rectangle_t f_bounds;
531 0 : geometry_rectangle_init ( &f_bounds,
532 0 : geometry_rectangle_get_left( classifier_symbol_box ) + x_pos_rel * ( geometry_rectangle_get_width( classifier_symbol_box ) - interface_icon_size ),
533 0 : geometry_rectangle_get_bottom( classifier_symbol_box ) + interface_distance,
534 : interface_icon_size,
535 : interface_icon_size
536 : );
537 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
538 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
539 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_DOWN );
540 : }
541 : }
542 :
543 0 : if ( DATA_FEATURE_TYPE_PROVIDED_INTERFACE == data_feature_get_main_type (the_feature) )
544 : {
545 : /* a provided interface has no direction, it is a circle */
546 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_CENTER );
547 : }
548 :
549 0 : U8_TRACE_END();
550 0 : }
551 :
552 0 : void pencil_feature_layouter_private_layout_compartment ( pencil_feature_layouter_t *this_,
553 : const geometry_rectangle_t *compartments_space,
554 : PangoLayout *font_layout,
555 : layout_feature_t *io_feature_layout )
556 : {
557 0 : U8_TRACE_BEGIN();
558 0 : assert( NULL != compartments_space );
559 0 : assert( NULL != font_layout );
560 0 : assert( NULL != io_feature_layout );
561 :
562 : /* feature label sizes are already precalculated */
563 0 : assert( (*this_).label_dimensions_initialized );
564 :
565 : /* define names for input data */
566 : const layout_visible_classifier_t * const vis_classfy
567 0 : = layout_feature_get_classifier_const( io_feature_layout );
568 0 : assert( NULL != vis_classfy );
569 0 : const data_row_t diagele_id = layout_visible_classifier_get_diagramelement_id( vis_classfy );
570 0 : const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
571 0 : const data_feature_t *const the_feature = layout_feature_get_data_const( io_feature_layout );
572 0 : const data_feature_type_t f_type = data_feature_get_main_type (the_feature);
573 :
574 : /* calculate the feat_top by summing up the heights of the UNORDERED features above */
575 0 : double feat_top = geometry_rectangle_get_top( compartments_space );
576 0 : bool feat_is_first_in_compartment = true;
577 0 : bool compartment_property_above = false; /* true if a feature of type DATA_FEATURE_TYPE_PROPERTY is above */
578 0 : bool compartment_operation_above = false; /* true if a feature of type DATA_FEATURE_TYPE_OPERATION is above */
579 0 : bool compartment_tagged_value_above = false; /* true if a feature of type DATA_FEATURE_TYPE_TAGGED_VALUE is above */
580 0 : const uint32_t num_features = layout_visible_set_get_feature_count( (*this_).layout_data );
581 0 : for ( uint32_t f_probe_idx = 0; f_probe_idx < num_features; f_probe_idx ++ )
582 : {
583 : const layout_feature_t *const f_probe_layout
584 0 : = layout_visible_set_get_feature_ptr( (*this_).layout_data, f_probe_idx );
585 0 : assert( NULL != f_probe_layout );
586 : const layout_visible_classifier_t *const probe_vis_classfy
587 0 : = layout_feature_get_classifier_const( f_probe_layout );
588 0 : assert( NULL != probe_vis_classfy );
589 :
590 : /* check if this f_probe_layout has the same diagram element id as the_feature */
591 0 : if ( diagele_id == layout_visible_classifier_get_diagramelement_id( probe_vis_classfy ) )
592 : {
593 : /* this is a feature of the same visible_classifier_t */
594 : /* define names for input data */
595 : const data_feature_t *f_probe_data;
596 0 : f_probe_data = layout_feature_get_data_const( f_probe_layout );
597 0 : assert( NULL != f_probe_data );
598 0 : const data_feature_type_t f_probe_type = data_feature_get_main_type ( f_probe_data );
599 0 : if ( data_feature_type_inside_compartment( f_probe_type ) )
600 : {
601 0 : const bool is_above
602 0 : = (( data_feature_get_list_order( f_probe_data ) < data_feature_get_list_order( the_feature ))
603 0 : || (( data_feature_get_list_order( f_probe_data ) == data_feature_get_list_order( the_feature ) )
604 0 : && ( data_feature_get_row( f_probe_data ) < data_feature_get_row( the_feature ) )));
605 0 : if ( is_above )
606 : {
607 : const geometry_rectangle_t *const probe_label_box
608 0 : = layout_feature_get_label_box_const( f_probe_layout );
609 0 : feat_top += geometry_rectangle_get_height( probe_label_box );
610 0 : if ( f_type == f_probe_type )
611 : {
612 0 : feat_is_first_in_compartment = false;
613 : }
614 : compartment_property_above
615 0 : = compartment_property_above || ( f_probe_type == DATA_FEATURE_TYPE_PROPERTY );
616 : compartment_operation_above
617 0 : = compartment_operation_above || ( f_probe_type == DATA_FEATURE_TYPE_OPERATION );
618 : compartment_tagged_value_above
619 0 : = compartment_tagged_value_above || ( f_probe_type == DATA_FEATURE_TYPE_TAGGED_VALUE );
620 : }
621 : }
622 : }
623 : }
624 :
625 : /* determine compartments above the current */
626 0 : feat_top += feat_is_first_in_compartment ? ( 4.0 * gap ) : 0.0; /* a line for own compartment needed */
627 0 : feat_top += compartment_property_above ? ( 4.0 * gap ) : 0.0; /* 2.0 * gap is reserved for compartment label */
628 0 : feat_top += compartment_operation_above ? ( 4.0 * gap ) : 0.0;
629 0 : feat_top += compartment_tagged_value_above ? ( 4.0 * gap ) : 0.0;
630 :
631 : /* determine the bounds of the feature */
632 : const geometry_rectangle_t *const feat_label_box
633 0 : = layout_feature_get_label_box_const( io_feature_layout );
634 :
635 : /* layout feature into parent classifier */
636 0 : const geometry_rectangle_t label_box = {
637 0 : .left = geometry_rectangle_get_left( compartments_space ) + gap,
638 : .top = feat_top,
639 0 : .width = geometry_rectangle_get_width( feat_label_box ),
640 0 : .height = geometry_rectangle_get_height( feat_label_box )
641 : };
642 0 : const geometry_rectangle_t feat_bounds = {
643 0 : .left = geometry_rectangle_get_left( compartments_space ),
644 : .top = feat_top,
645 0 : .width = geometry_rectangle_get_width( feat_label_box ) + 2.0 * gap,
646 0 : .height = geometry_rectangle_get_height( feat_label_box )
647 : };
648 :
649 0 : layout_feature_set_label_box( io_feature_layout, &label_box );
650 0 : layout_feature_set_symbol_box( io_feature_layout, &feat_bounds );
651 0 : layout_feature_set_icon_direction( io_feature_layout, GEOMETRY_DIRECTION_CENTER ); /* dummy direction */
652 0 : layout_feature_set_first_in_compartment( io_feature_layout, feat_is_first_in_compartment );
653 :
654 0 : U8_TRACE_END();
655 0 : }
656 :
657 0 : void pencil_feature_layouter_private_get_minimum_bounds( pencil_feature_layouter_t *this_,
658 : const data_feature_t *the_feature,
659 : const data_profile_part_t *profile,
660 : const pencil_size_t *pencil_size,
661 : PangoLayout *font_layout,
662 : geometry_dimensions_t *out_feature_bounds )
663 : {
664 0 : U8_TRACE_BEGIN();
665 0 : assert( NULL != the_feature );
666 0 : assert( NULL != profile );
667 0 : assert( NULL != pencil_size );
668 0 : assert( NULL != font_layout );
669 0 : assert( NULL != out_feature_bounds );
670 :
671 0 : const geometry_dimensions_t label_dim_proposal = {
672 0 : .width = 25.0 * pencil_size_get_standard_font_size( pencil_size ),
673 0 : .height = pencil_size_get_standard_font_size( pencil_size )
674 : };
675 0 : draw_feature_label_get_key_and_value_dimensions( &((*this_).draw_feature_label),
676 : the_feature,
677 : profile,
678 : &label_dim_proposal,
679 : pencil_size,
680 : font_layout,
681 : out_feature_bounds
682 : );
683 :
684 0 : U8_TRACE_END();
685 0 : }
686 :
687 :
688 : /*
689 : Copyright 2017-2026 Andreas Warnke
690 :
691 : Licensed under the Apache License, Version 2.0 (the "License");
692 : you may not use this file except in compliance with the License.
693 : You may obtain a copy of the License at
694 :
695 : http://www.apache.org/licenses/LICENSE-2.0
696 :
697 : Unless required by applicable law or agreed to in writing, software
698 : distributed under the License is distributed on an "AS IS" BASIS,
699 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
700 : See the License for the specific language governing permissions and
701 : limitations under the License.
702 : */
|