LCOV - code coverage report
Current view: top level - pencil/source - pencil_classifier_composer.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.71.2_covts Lines: 97.5 % 277 270
Test Date: 2026-08-22 19:47:36 Functions: 100.0 % 5 5

            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( &current_envelope );
     232           64 :         const double shift_to_bottom = geometry_rectangle_get_center_y( envelope ) - geometry_rectangle_get_center_y( &current_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              : */
        

Generated by: LCOV version 2.0-1