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_rules_init( &((*this_).rules) );
25 0 : (*this_).label_dimensions_initialized = false;
26 0 : pencil_feature_painter_init( &((*this_).feature_painter) );
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 : data_rules_destroy( &((*this_).rules) );
45 0 : (*this_).label_dimensions_initialized = false;
46 0 : pencil_feature_painter_destroy( &((*this_).feature_painter) );
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 space area, also the tagged values */
142 0 : const geometry_rectangle_t *const c_space = layout_visible_classifier_get_space_const ( layout_classifier );
143 0 : pencil_feature_layouter_private_layout_compartment ( this_,
144 : c_space,
145 : font_layout,
146 : feature_layout
147 : );
148 : }
149 0 : break;
150 :
151 0 : default:
152 : {
153 0 : U8_LOG_ANOMALY("unknown feature type in pencil_feature_layouter_do_layout");
154 : /* this may happen if a new database file has been read by an old program version */
155 : /* layout like property or operation or tagged values */
156 0 : const geometry_rectangle_t *const c_space = layout_visible_classifier_get_space_const ( layout_classifier );
157 0 : pencil_feature_layouter_private_layout_compartment ( this_,
158 : c_space,
159 : font_layout,
160 : feature_layout
161 : );
162 : }
163 0 : break;
164 : }
165 : }
166 :
167 0 : U8_TRACE_END();
168 0 : }
169 :
170 0 : void pencil_feature_layouter_calculate_features_bounds( pencil_feature_layouter_t *this_,
171 : data_row_id_t diagramelement_id,
172 : PangoLayout *font_layout,
173 : geometry_dimensions_t *out_features_bounds )
174 : {
175 0 : U8_TRACE_BEGIN();
176 0 : assert( NULL != font_layout );
177 0 : assert( NULL != out_features_bounds );
178 :
179 : /* establish precondition: precalculate the dimensions of labels */
180 0 : if ( ! (*this_).label_dimensions_initialized )
181 : {
182 0 : pencil_feature_layouter_private_init_label_dimensions( this_, font_layout );
183 : }
184 :
185 0 : double width = 0.0;
186 0 : double height = 0.0;
187 :
188 : /* search all contained features */
189 : const uint32_t count_features
190 0 : = layout_visible_set_get_feature_count( (*this_).layout_data );
191 0 : for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
192 : {
193 : const layout_feature_t *const feature_layout
194 0 : = layout_visible_set_get_feature_ptr( (*this_).layout_data, f_idx );
195 : const data_feature_t *const the_feature
196 0 : = layout_feature_get_data_const( feature_layout );
197 : const layout_visible_classifier_t *const layout_classifier
198 0 : = layout_feature_get_classifier_const( feature_layout );
199 0 : const data_feature_type_t the_feature_type = data_feature_get_main_type( the_feature );
200 :
201 0 : if (( diagramelement_id == layout_visible_classifier_get_diagramelement_id( layout_classifier ) )
202 0 : && data_feature_type_inside_compartment( the_feature_type ) )
203 : {
204 : /* feature label sizes are already precalculated */
205 0 : assert( (*this_).label_dimensions_initialized );
206 0 : const geometry_rectangle_t *const label_box = layout_feature_get_label_box_const( feature_layout );
207 :
208 : /* update width and height */
209 0 : width = u8_f64_max2( width, geometry_rectangle_get_width( label_box ) );
210 0 : height += geometry_rectangle_get_height( label_box );
211 : }
212 : }
213 :
214 0 : const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
215 0 : const double sum_of_gaps = 6.0 * gap; /* gaps above and below each of the 3 compartment lines */
216 :
217 0 : geometry_dimensions_reinit( out_features_bounds, width + 2.0 * gap, height + sum_of_gaps );
218 0 : U8_TRACE_END();
219 0 : }
220 :
221 0 : void pencil_feature_layouter_private_init_label_dimensions( pencil_feature_layouter_t *this_,
222 : PangoLayout *font_layout
223 : )
224 : {
225 0 : U8_TRACE_BEGIN();
226 0 : assert ( NULL != font_layout );
227 :
228 : const uint32_t count_features
229 0 : = layout_visible_set_get_feature_count( (*this_).layout_data );
230 0 : for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
231 : {
232 : layout_feature_t *const feature_layout
233 0 : = layout_visible_set_get_feature_ptr( (*this_).layout_data, f_idx );
234 : const data_feature_t *const the_feature
235 0 : = layout_feature_get_data_const( feature_layout );
236 0 : const data_feature_type_t the_feature_type = data_feature_get_main_type( the_feature );
237 :
238 0 : if ( data_feature_type_inside_compartment( the_feature_type ) )
239 : {
240 : geometry_dimensions_t min_feature_bounds;
241 0 : geometry_dimensions_init_empty( &min_feature_bounds );
242 0 : pencil_feature_painter_get_minimum_bounds( &((*this_).feature_painter),
243 : the_feature,
244 : (*this_).profile,
245 : (*this_).pencil_size,
246 : font_layout,
247 : &min_feature_bounds
248 : );
249 :
250 0 : const geometry_rectangle_t label_box = {
251 : .left = 0.0,
252 : .top = 0.0,
253 0 : .width = geometry_dimensions_get_width( &min_feature_bounds ),
254 0 : .height = geometry_dimensions_get_height( &min_feature_bounds ),
255 : };
256 0 : layout_feature_set_label_box( feature_layout, &label_box );
257 0 : geometry_dimensions_destroy( &min_feature_bounds );
258 : }
259 : }
260 :
261 0 : (*this_).label_dimensions_initialized = true;
262 0 : U8_TRACE_END();
263 0 : }
264 :
265 0 : void pencil_feature_layouter_private_layout_lifeline ( pencil_feature_layouter_t *this_,
266 : const geometry_rectangle_t *diagram_space,
267 : data_diagram_type_t diagram_type,
268 : data_classifier_type_t classifier_type,
269 : const geometry_rectangle_t *classifier_symbol_box,
270 : const geometry_rectangle_t *classifier_envelope_box,
271 : layout_feature_t *out_feature_layout )
272 : {
273 0 : U8_TRACE_BEGIN();
274 0 : assert ( NULL != diagram_space );
275 0 : assert ( NULL != classifier_symbol_box );
276 0 : assert ( NULL != classifier_envelope_box );
277 0 : assert ( NULL != out_feature_layout );
278 :
279 : /* get preferred object distance */
280 : const double obj_dist
281 0 : = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
282 0 : const double feature_width = obj_dist;
283 :
284 : const bool lifeline_has_semantics
285 0 : = data_rules_classifier_has_scenario_semantics( &((*this_).rules),
286 : diagram_type,
287 : classifier_type
288 : );
289 :
290 0 : if (( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diagram_type ) && lifeline_has_semantics )
291 0 : {
292 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_RIGHT );
293 0 : const double c_right = geometry_rectangle_get_right( classifier_envelope_box );
294 0 : const double c_top = geometry_rectangle_get_top( classifier_envelope_box );
295 0 : const double c_height = geometry_rectangle_get_height( classifier_envelope_box );
296 0 : const double dda_right = geometry_rectangle_get_right ( diagram_space );
297 : geometry_rectangle_t lifeline_bounds;
298 0 : geometry_rectangle_init ( &lifeline_bounds,
299 : c_right,
300 0 : c_top + ( 0.5 * ( c_height - feature_width ) ),
301 0 : dda_right - c_right - obj_dist,
302 : feature_width
303 : );
304 0 : layout_feature_set_symbol_box ( out_feature_layout, &lifeline_bounds );
305 0 : layout_feature_set_label_box ( out_feature_layout, &lifeline_bounds );
306 : }
307 0 : else if (( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diagram_type ) && lifeline_has_semantics )
308 0 : {
309 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_DOWN );
310 0 : const double c_bottom = geometry_rectangle_get_bottom( classifier_envelope_box );
311 0 : const double c_left = geometry_rectangle_get_left( classifier_envelope_box );
312 0 : const double c_width = geometry_rectangle_get_width( classifier_envelope_box );
313 0 : const double dda_bottom = geometry_rectangle_get_bottom ( diagram_space );
314 : geometry_rectangle_t lifeline_bounds;
315 0 : geometry_rectangle_init ( &lifeline_bounds,
316 0 : c_left + ( 0.5 * ( c_width - feature_width ) ),
317 : c_bottom,
318 : feature_width,
319 0 : dda_bottom - c_bottom - obj_dist
320 : );
321 0 : layout_feature_set_symbol_box ( out_feature_layout, &lifeline_bounds );
322 0 : layout_feature_set_label_box ( out_feature_layout, &lifeline_bounds );
323 : }
324 : else /*if (( DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM == diagram_type )||( DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM == diagram_type ))*/
325 : {
326 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_CENTER );
327 0 : layout_feature_set_symbol_box ( out_feature_layout, classifier_symbol_box );
328 0 : layout_feature_set_label_box ( out_feature_layout, classifier_symbol_box );
329 : }
330 :
331 0 : U8_TRACE_END();
332 0 : }
333 :
334 0 : void pencil_feature_layouter_private_layout_port_pin ( pencil_feature_layouter_t *this_,
335 : data_classifier_type_t classifier_type,
336 : const geometry_rectangle_t *classifier_symbol_box,
337 : const data_feature_t *the_feature,
338 : PangoLayout *font_layout,
339 : layout_feature_t *out_feature_layout )
340 : {
341 0 : U8_TRACE_BEGIN();
342 0 : assert ( NULL != classifier_symbol_box );
343 0 : assert ( NULL != the_feature );
344 0 : assert ( NULL != font_layout );
345 0 : assert ( NULL != out_feature_layout );
346 :
347 : /* get preferred object distance */
348 : const double gap
349 0 : = pencil_size_get_standard_object_border( (*this_).pencil_size );
350 :
351 : const double port_icon_size
352 0 : = pencil_size_get_standard_font_size( (*this_).pencil_size );
353 :
354 : /* determine the coordinates of the box-line */
355 : geometry_rectangle_t classifier_box;
356 0 : geometry_rectangle_copy( &classifier_box, classifier_symbol_box );
357 0 : geometry_rectangle_shift( &classifier_box, gap, gap );
358 0 : geometry_rectangle_enlarge( &classifier_box, -2.0*gap, -2.0*gap );
359 :
360 : const int32_t list_order
361 0 : = data_feature_get_list_order( the_feature );
362 :
363 : /* position the port icon */
364 0 : const bool is_sysml_constraint_block = (classifier_type == DATA_CLASSIFIER_TYPE_CONSTRAINT_BLOCK);
365 0 : const bool is_behavioral = data_classifier_type_is_behavioral( classifier_type );
366 0 : const data_feature_type_t feat_type = data_feature_get_main_type( the_feature );
367 0 : const bool is_state_entry_exit
368 0 : = (( feat_type == DATA_FEATURE_TYPE_ENTRY )||( feat_type == DATA_FEATURE_TYPE_EXIT ));
369 0 : const double outwards_distance
370 0 : = is_sysml_constraint_block ? 0.0 : (is_behavioral&&(!is_state_entry_exit)) ? port_icon_size : (0.5*port_icon_size);
371 : double port_icon_left;
372 : double port_icon_top;
373 0 : const double show_arrow_in = ( feat_type == DATA_FEATURE_TYPE_IN_PORT_PIN );
374 0 : const double show_arrow_out = ( feat_type == DATA_FEATURE_TYPE_OUT_PORT_PIN );
375 0 : geometry_direction_t arrow_dir = GEOMETRY_DIRECTION_CENTER;
376 0 : if ( list_order < 0 )
377 : {
378 : static const int32_t INT32_MIN_HALF = INT32_MIN/2;
379 0 : if ( list_order < INT32_MIN_HALF ) /* SHOW ON RIGHT BORDER */
380 : {
381 0 : const double y_pos_rel
382 0 : = (list_order - INT32_MIN_HALF) / ((double)(INT32_MIN_HALF));
383 0 : port_icon_left = geometry_rectangle_get_right( &classifier_box ) - port_icon_size + outwards_distance;
384 0 : port_icon_top = geometry_rectangle_get_top( &classifier_box ) + y_pos_rel * ( geometry_rectangle_get_height( &classifier_box ) - port_icon_size );
385 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_LEFT : show_arrow_out ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_CENTER;
386 : }
387 : else /* SHOW ON TOP BORDER */
388 : {
389 0 : const double x_pos_rel
390 0 : = (list_order) / ((double)(INT32_MIN_HALF));
391 0 : port_icon_left = geometry_rectangle_get_left( &classifier_box ) + x_pos_rel * ( geometry_rectangle_get_width( &classifier_box ) - port_icon_size );
392 0 : port_icon_top = geometry_rectangle_get_top( &classifier_box ) - outwards_distance;
393 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_DOWN : show_arrow_out ? GEOMETRY_DIRECTION_UP : GEOMETRY_DIRECTION_CENTER;
394 : }
395 : }
396 : else
397 : {
398 : static const int32_t INT32_MAX_HALF = (INT32_MAX/2)+1; /* round to ceiling */
399 0 : if ( list_order < INT32_MAX_HALF ) /* SHOW ON LEFT BORDER */
400 : {
401 0 : const double y_pos_rel
402 0 : = (list_order) / ((double)(INT32_MAX_HALF));
403 0 : port_icon_left = geometry_rectangle_get_left( &classifier_box ) - outwards_distance;
404 0 : port_icon_top = geometry_rectangle_get_top( &classifier_box ) + y_pos_rel * ( geometry_rectangle_get_height( &classifier_box ) - port_icon_size );
405 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_RIGHT : show_arrow_out ? GEOMETRY_DIRECTION_LEFT : GEOMETRY_DIRECTION_CENTER;
406 : }
407 : else /* SHOW ON BOTTOM BORDER */
408 : {
409 0 : const double x_pos_rel
410 0 : = (list_order - INT32_MAX_HALF) / ((double)(INT32_MAX_HALF));
411 0 : port_icon_left = geometry_rectangle_get_left( &classifier_box ) + x_pos_rel * ( geometry_rectangle_get_width( &classifier_box ) - port_icon_size );
412 0 : port_icon_top = geometry_rectangle_get_bottom( &classifier_box ) - port_icon_size + outwards_distance;
413 0 : arrow_dir = show_arrow_in ? GEOMETRY_DIRECTION_UP : show_arrow_out ? GEOMETRY_DIRECTION_DOWN : GEOMETRY_DIRECTION_CENTER;
414 : }
415 : }
416 :
417 : /* set feature bounding box */
418 : geometry_rectangle_t f_bounds;
419 0 : geometry_rectangle_init ( &f_bounds,
420 : port_icon_left,
421 : port_icon_top,
422 : port_icon_size,
423 : port_icon_size
424 : );
425 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
426 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
427 0 : layout_feature_set_icon_direction ( out_feature_layout, arrow_dir );
428 :
429 0 : U8_TRACE_END();
430 0 : }
431 :
432 0 : void pencil_feature_layouter_private_layout_interface ( pencil_feature_layouter_t *this_,
433 : const geometry_rectangle_t *classifier_symbol_box,
434 : const data_feature_t *the_feature,
435 : PangoLayout *font_layout,
436 : layout_feature_t *out_feature_layout )
437 : {
438 0 : U8_TRACE_BEGIN();
439 0 : assert ( NULL != classifier_symbol_box );
440 0 : assert ( NULL != the_feature );
441 0 : assert ( NULL != font_layout );
442 0 : assert ( NULL != out_feature_layout );
443 :
444 : /* get preferred object size + distance */
445 0 : const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
446 0 : const double interface_icon_size = pencil_size_get_standard_font_size( (*this_).pencil_size );
447 0 : const double interface_distance
448 0 : = 2.001 * pencil_size_get_preferred_object_distance( (*this_).pencil_size ) + gap; /* min dist formula as in relationship layouter */
449 :
450 0 : const int32_t list_order = data_feature_get_list_order( the_feature );
451 :
452 : /* position the interface icon */
453 0 : if ( list_order < 0 )
454 : {
455 : static const int32_t INT32_MIN_HALF = INT32_MIN/2;
456 0 : if ( list_order < INT32_MIN_HALF ) /* SHOW ON RIGHT BORDER */
457 : {
458 0 : const double y_pos_rel
459 0 : = (list_order - INT32_MIN_HALF) / ((double)(INT32_MIN_HALF));
460 : geometry_rectangle_t f_bounds;
461 0 : geometry_rectangle_init ( &f_bounds,
462 0 : geometry_rectangle_get_right( classifier_symbol_box ) + interface_distance,
463 0 : geometry_rectangle_get_top( classifier_symbol_box ) + y_pos_rel * ( geometry_rectangle_get_height( classifier_symbol_box ) - interface_icon_size ),
464 : interface_icon_size,
465 : interface_icon_size
466 : );
467 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
468 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
469 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_RIGHT );
470 : }
471 : else /* SHOW ON TOP BORDER */
472 : {
473 0 : const double x_pos_rel
474 0 : = (list_order) / ((double)(INT32_MIN_HALF));
475 : geometry_rectangle_t f_bounds;
476 0 : geometry_rectangle_init ( &f_bounds,
477 0 : geometry_rectangle_get_left( classifier_symbol_box ) + x_pos_rel * ( geometry_rectangle_get_width( classifier_symbol_box ) - interface_icon_size ),
478 0 : geometry_rectangle_get_top( classifier_symbol_box ) - interface_distance - interface_icon_size,
479 : interface_icon_size,
480 : interface_icon_size
481 : );
482 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
483 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
484 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_UP );
485 : }
486 : }
487 : else
488 : {
489 : static const int32_t INT32_MAX_HALF = (INT32_MAX/2)+1; /* round to ceiling */
490 0 : if ( list_order < INT32_MAX_HALF ) /* SHOW ON LEFT BORDER */
491 : {
492 0 : const double y_pos_rel
493 0 : = (list_order) / ((double)(INT32_MAX_HALF));
494 : geometry_rectangle_t f_bounds;
495 0 : geometry_rectangle_init ( &f_bounds,
496 0 : geometry_rectangle_get_left( classifier_symbol_box ) - interface_distance - interface_icon_size,
497 0 : geometry_rectangle_get_top( classifier_symbol_box ) + y_pos_rel * ( geometry_rectangle_get_height( classifier_symbol_box ) - interface_icon_size ),
498 : interface_icon_size,
499 : interface_icon_size
500 : );
501 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
502 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
503 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_LEFT );
504 : }
505 : else /* SHOW ON BOTTOM BORDER */
506 : {
507 0 : const double x_pos_rel
508 0 : = (list_order - INT32_MAX_HALF) / ((double)(INT32_MAX_HALF));
509 : geometry_rectangle_t f_bounds;
510 0 : geometry_rectangle_init ( &f_bounds,
511 0 : geometry_rectangle_get_left( classifier_symbol_box ) + x_pos_rel * ( geometry_rectangle_get_width( classifier_symbol_box ) - interface_icon_size ),
512 0 : geometry_rectangle_get_bottom( classifier_symbol_box ) + interface_distance,
513 : interface_icon_size,
514 : interface_icon_size
515 : );
516 0 : layout_feature_set_symbol_box ( out_feature_layout, &f_bounds );
517 0 : layout_feature_set_label_box ( out_feature_layout, &f_bounds );
518 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_DOWN );
519 : }
520 : }
521 :
522 0 : if ( DATA_FEATURE_TYPE_PROVIDED_INTERFACE == data_feature_get_main_type (the_feature) )
523 : {
524 : /* a provided interface has no direction, it is a circle */
525 0 : layout_feature_set_icon_direction ( out_feature_layout, GEOMETRY_DIRECTION_CENTER );
526 : }
527 :
528 0 : U8_TRACE_END();
529 0 : }
530 :
531 0 : void pencil_feature_layouter_private_layout_compartment ( pencil_feature_layouter_t *this_,
532 : const geometry_rectangle_t *classifier_space,
533 : PangoLayout *font_layout,
534 : layout_feature_t *io_feature_layout )
535 : {
536 0 : U8_TRACE_BEGIN();
537 0 : assert( NULL != classifier_space );
538 0 : assert( NULL != font_layout );
539 0 : assert( NULL != io_feature_layout );
540 :
541 : /* feature label sizes are already precalculated */
542 0 : assert( (*this_).label_dimensions_initialized );
543 :
544 : /* define names for input data */
545 : const layout_visible_classifier_t * const vis_classfy
546 0 : = layout_feature_get_classifier_const( io_feature_layout );
547 0 : assert( NULL != vis_classfy );
548 0 : const data_row_id_t diagele_id = layout_visible_classifier_get_diagramelement_id( vis_classfy );
549 0 : const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
550 0 : const data_feature_t *const the_feature = layout_feature_get_data_const( io_feature_layout );
551 :
552 : /* calculate the feat_top by summing up the heights of the features above */
553 0 : double feat_top = geometry_rectangle_get_top( classifier_space );
554 0 : const uint32_t num_features = layout_visible_set_get_feature_count( (*this_).layout_data );
555 0 : for ( uint32_t f_probe_idx = 0; f_probe_idx < num_features; f_probe_idx ++ )
556 : {
557 : const layout_feature_t *const f_probe_layout
558 0 : = layout_visible_set_get_feature_ptr( (*this_).layout_data, f_probe_idx );
559 0 : assert( NULL != f_probe_layout );
560 : const layout_visible_classifier_t *const probe_vis_classfy
561 0 : = layout_feature_get_classifier_const( f_probe_layout );
562 0 : assert( NULL != probe_vis_classfy );
563 :
564 : /* check if this f_probe_layout has the same diagram element id as the_feature */
565 0 : if ( diagele_id == layout_visible_classifier_get_diagramelement_id( probe_vis_classfy ) )
566 : {
567 : /* this is a feature of the same visible_classifier_t */
568 : /* define names for input data */
569 : const data_feature_t *f_probe_data;
570 0 : f_probe_data = layout_feature_get_data_const( f_probe_layout );
571 0 : assert( NULL != f_probe_data );
572 0 : const data_feature_type_t f_probe_type = data_feature_get_main_type ( f_probe_data );
573 0 : if ( data_feature_type_inside_compartment( f_probe_type ) )
574 : {
575 0 : const bool is_above
576 0 : = (( data_feature_get_list_order( f_probe_data ) < data_feature_get_list_order( the_feature ))
577 0 : || (( data_feature_get_list_order( f_probe_data ) == data_feature_get_list_order( the_feature ) )
578 0 : && ( data_feature_get_row_id( f_probe_data ) < data_feature_get_row_id( the_feature ) )));
579 0 : if ( is_above )
580 : {
581 : const geometry_rectangle_t *const probe_label_box
582 0 : = layout_feature_get_label_box_const( f_probe_layout );
583 0 : feat_top += geometry_rectangle_get_height( probe_label_box );
584 : }
585 : }
586 : }
587 : }
588 :
589 : /* determine compartments above the current */
590 0 : const data_feature_type_t f_type = data_feature_get_main_type (the_feature);
591 0 : const uint32_t count_compartments_above
592 : = ( DATA_FEATURE_TYPE_PROPERTY == f_type )
593 : ? 0
594 0 : : ( DATA_FEATURE_TYPE_OPERATION == f_type )
595 : ? 1
596 : : ( DATA_FEATURE_TYPE_TAGGED_VALUE == f_type )
597 : ? 2 /* first compartment for properties, second for operations, third for tagged values */
598 : : 2; /* the last compartment is for all unknown feature types. */
599 : /* this may happen if a new database file has been read by an old program version */
600 : /* note that today, there is no separator line yet - so the number is the same */
601 0 : feat_top += ( count_compartments_above * 2 * gap ) + 2.0 * gap;
602 :
603 : /* determine the bounds of the feature */
604 : const geometry_rectangle_t *const feat_label_box
605 0 : = layout_feature_get_label_box_const( io_feature_layout );
606 :
607 : /* layout feature into parent classifier */
608 0 : const geometry_rectangle_t label_box = {
609 0 : .left = geometry_rectangle_get_left( classifier_space ) + gap,
610 : .top = feat_top,
611 0 : .width = geometry_rectangle_get_width( feat_label_box ),
612 0 : .height = geometry_rectangle_get_height( feat_label_box )
613 : };
614 0 : const geometry_rectangle_t feat_bounds = {
615 0 : .left = geometry_rectangle_get_left( classifier_space ),
616 : .top = feat_top,
617 0 : .width = geometry_rectangle_get_width( feat_label_box ) + 2.0 * gap,
618 0 : .height = geometry_rectangle_get_height( feat_label_box )
619 : };
620 :
621 0 : layout_feature_set_label_box( io_feature_layout, &label_box );
622 0 : layout_feature_set_symbol_box( io_feature_layout, &feat_bounds );
623 0 : layout_feature_set_icon_direction( io_feature_layout, GEOMETRY_DIRECTION_CENTER ); /* dummy direction */
624 :
625 0 : U8_TRACE_END();
626 0 : }
627 :
628 :
629 : /*
630 : Copyright 2017-2024 Andreas Warnke
631 :
632 : Licensed under the Apache License, Version 2.0 (the "License");
633 : you may not use this file except in compliance with the License.
634 : You may obtain a copy of the License at
635 :
636 : http://www.apache.org/licenses/LICENSE-2.0
637 :
638 : Unless required by applicable law or agreed to in writing, software
639 : distributed under the License is distributed on an "AS IS" BASIS,
640 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
641 : See the License for the specific language governing permissions and
642 : limitations under the License.
643 : */
|