LCOV - code coverage report
Current view: top level - pencil/source/draw - draw_feature_label.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 0.0 % 108 0
Test Date: 2025-05-01 10:10:14 Functions: 0.0 % 4 0

            Line data    Source code
       1              : /* File: draw_feature_label.c; Copyright and License: see below */
       2              : 
       3              : #include "draw/draw_feature_label.h"
       4              : #include "u8/u8_trace.h"
       5              : #include "entity/data_classifier.h"
       6              : #include "entity/data_diagramelement.h"
       7              : #include "u8/u8_f64.h"
       8              : #include "utf8stringbuf/utf8stringbuf.h"
       9              : #include "utf8stringbuf/utf8string.h"
      10              : #include <pango/pangocairo.h>
      11              : #include <stdio.h>
      12              : #include <stdlib.h>
      13              : #include <assert.h>
      14              : 
      15              : static const int DRAW_FEATURE_PANGO_UNLIMITED_WIDTH = -1;
      16              : 
      17            0 : void draw_feature_label_init( draw_feature_label_t *this_ )
      18              : {
      19            0 :     utf8stream_writemem_init( &((*this_).text_builder), &((*this_).text_buffer), sizeof( (*this_).text_buffer) );
      20            0 :     draw_line_breaker_init( &((*this_).linebr) );
      21            0 :     draw_stereotype_icon_init( &((*this_).image_renderer) );
      22            0 : }
      23              : 
      24            0 : void draw_feature_label_destroy( draw_feature_label_t *this_ )
      25              : {
      26            0 :     draw_line_breaker_destroy( &((*this_).linebr) );
      27            0 :     const u8_error_t text_err = utf8stream_writemem_destroy( &((*this_).text_builder) );
      28            0 :     if ( text_err != U8_ERROR_NONE )
      29              :     {
      30            0 :         U8_LOG_WARNING_HEX( "error at draw/draw_classifier_label: buffer too small", text_err );
      31              :     }
      32            0 :     draw_stereotype_icon_destroy( &((*this_).image_renderer) );
      33            0 : }
      34              : 
      35            0 : void draw_feature_label_get_key_and_value_dimensions ( draw_feature_label_t *this_,
      36              :                                                        const data_feature_t *feature,
      37              :                                                        const data_profile_part_t *profile,
      38              :                                                        const geometry_dimensions_t *proposed_bounds,
      39              :                                                        const pencil_size_t *pencil_size,
      40              :                                                        PangoLayout *font_layout,
      41              :                                                        geometry_dimensions_t *out_label_dim )
      42              : {
      43            0 :     U8_TRACE_BEGIN();
      44            0 :     assert( NULL != feature );
      45            0 :     assert( NULL != profile );
      46            0 :     assert( NULL != proposed_bounds );
      47            0 :     assert( NULL != pencil_size );
      48            0 :     assert( NULL != font_layout );
      49            0 :     assert( NULL != out_label_dim );
      50              : 
      51            0 :     if ( data_feature_is_valid( feature ) )
      52              :     {
      53              :         /* calc stereotype image bounds */
      54            0 :         const char *const feature_stereotype = data_feature_get_value_const( feature );
      55              :         const bool has_stereotype_image
      56            0 :             = draw_stereotype_icon_exists( &((*this_).image_renderer), feature_stereotype, profile );
      57            0 :         const geometry_dimensions_t icon_dim
      58              :             = has_stereotype_image
      59            0 :             ? draw_stereotype_icon_get_dimensions( &((*this_).image_renderer), pencil_size )
      60            0 :             : (geometry_dimensions_t){ .width = 0.0, .height = 0.0 };
      61            0 :         const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
      62              : 
      63              :         /* draw text - except for lifelines */
      64            0 :         int proposed_pango_width = geometry_dimensions_get_width( proposed_bounds );
      65            0 :         int text_width = 0;
      66            0 :         int text_height = 0;
      67            0 :         if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type (feature) )
      68              :         {
      69              :             /* prepare text */
      70            0 :             u8_error_t name_err = U8_ERROR_NONE;
      71            0 :             utf8stream_writer_t *to_name = utf8stream_writemem_get_writer( &((*this_).text_builder) );
      72              : 
      73              :             /* append parts to name and insert linebreaks */
      74            0 :             utf8stringview_t feat_key = UTF8STRINGVIEW_STR( data_feature_get_key_const( feature ) );
      75            0 :             name_err |= draw_line_breaker_append( &((*this_).linebr), &feat_key, to_name );
      76            0 :             if ( data_feature_has_value( feature ) && ( ! has_stereotype_image ) )
      77              :             {
      78            0 :                 name_err |= utf8stream_writer_write_str( to_name, ": " );
      79            0 :                 utf8stringview_t feat_value = UTF8STRINGVIEW_STR( data_feature_get_value_const( feature ) );
      80            0 :                 name_err |= draw_line_breaker_append( &((*this_).linebr), &feat_value, to_name );
      81              :             }
      82            0 :             const utf8stringview_t name = utf8stream_writemem_get_view( &((*this_).text_builder) );
      83              : 
      84              :             /* determine text width and height */
      85            0 :             pango_layout_set_font_description( font_layout, pencil_size_get_standard_font_description( pencil_size ) );
      86            0 :             pango_layout_set_text( font_layout,
      87              :                                    utf8stringview_get_start( &name ),
      88            0 :                                    utf8stringview_get_length( &name )
      89              :                                  );
      90            0 :             pango_layout_set_width( font_layout, proposed_pango_width * PANGO_SCALE );
      91            0 :             pango_layout_get_pixel_size( font_layout, &text_width, &text_height );
      92            0 :             text_height += PENCIL_SIZE_FONT_ALIGN_MARGIN;  /* allow to align font with pixel border */
      93            0 :             text_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
      94              :             /* restore pango context */
      95            0 :             pango_layout_set_width( font_layout, DRAW_FEATURE_PANGO_UNLIMITED_WIDTH );
      96              : 
      97              :             /* cleanup the text_builder */
      98            0 :             name_err |= utf8stream_writemem_reset( &((*this_).text_builder) );
      99            0 :             if ( name_err != U8_ERROR_NONE )
     100              :             {
     101            0 :                 U8_LOG_WARNING_HEX( "error at get_dim/draw_line_breaker_append", name_err );
     102              :             }
     103              :         }
     104              : 
     105            0 :         *out_label_dim = (geometry_dimensions_t) {
     106            0 :             .width = geometry_dimensions_get_width( &icon_dim ) + icon_gap + text_width,
     107            0 :             .height = u8_f64_max2( geometry_dimensions_get_height( &icon_dim ), text_height )
     108              :         };
     109              :     }
     110              :     else
     111              :     {
     112            0 :         U8_LOG_ERROR("invalid feature in draw_feature_label_get_key_and_value_dimensions()");
     113            0 :         *out_label_dim = (geometry_dimensions_t) { .width = 0.0, .height = 0.0 };
     114              :     }
     115            0 :     U8_TRACE_END();
     116            0 : }
     117              : 
     118            0 : void draw_feature_label_draw_key_and_value ( draw_feature_label_t *this_,
     119              :                                              const data_feature_t *feature,
     120              :                                              const data_profile_part_t *profile,
     121              :                                              const GdkRGBA *color,
     122              :                                              const geometry_rectangle_t *label_box,
     123              :                                              const pencil_size_t *pencil_size,
     124              :                                              PangoLayout *font_layout,
     125              :                                              cairo_t *cr )
     126              : {
     127            0 :     U8_TRACE_BEGIN();
     128            0 :     assert( NULL != feature );
     129            0 :     assert( NULL != profile );
     130            0 :     assert( NULL != color );
     131            0 :     assert( NULL != label_box );
     132            0 :     assert( NULL != pencil_size );
     133            0 :     assert( NULL != font_layout );
     134            0 :     assert( NULL != cr );
     135              : 
     136              :     /* calc bounds of stereotype icon */
     137            0 :     const char *const feature_stereotype = data_feature_get_value_const( feature );
     138              :     const bool has_stereotype_image
     139            0 :         = draw_stereotype_icon_exists( &((*this_).image_renderer), feature_stereotype, profile );
     140            0 :     const geometry_rectangle_t stereotype_box
     141              :         = has_stereotype_image
     142            0 :         ? draw_stereotype_icon_get_bounds( &((*this_).image_renderer),
     143              :                                             geometry_rectangle_get_left( label_box ),
     144              :                                             geometry_rectangle_get_top( label_box ),
     145              :                                             GEOMETRY_H_ALIGN_LEFT,
     146              :                                             GEOMETRY_V_ALIGN_TOP,
     147              :                                             pencil_size
     148              :                                           )
     149            0 :         : (geometry_rectangle_t){ .left = 0.0, .top = 0.0, .width = 0.0, .height = 0.0 };
     150            0 :     const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
     151              : 
     152              :     /* draw stereotype icon */
     153            0 :     if ( has_stereotype_image )
     154              :     {
     155              :         u8_error_info_t err_info;
     156              :         const u8_error_t stereotype_err
     157            0 :             = draw_stereotype_icon_draw( &((*this_).image_renderer),
     158              :                                           feature_stereotype,
     159              :                                           profile,
     160              :                                           color,
     161              :                                           &err_info,
     162              :                                           &stereotype_box,
     163              :                                           cr
     164              :                                         );
     165            0 :         if ( u8_error_info_is_error( &err_info ) )
     166              :         {
     167            0 :             U8_LOG_WARNING_INT( "stereotype image: unxpected token in svg path in line",
     168              :                                 u8_error_info_get_line( &err_info )
     169              :                               );
     170              :         }
     171            0 :         else if ( stereotype_err != U8_ERROR_NONE )
     172              :         {
     173            0 :             U8_LOG_WARNING_HEX( "error at drawing stereotype image", stereotype_err );
     174              :         }
     175              :     }
     176              : 
     177              :     /* define names for input data: */
     178            0 :     const double text_left
     179            0 :         = geometry_rectangle_get_left( label_box ) + geometry_rectangle_get_width( &stereotype_box ) + icon_gap;
     180            0 :     const double text_top = geometry_rectangle_get_top( label_box );
     181            0 :     const double text_width
     182            0 :         = geometry_rectangle_get_width( label_box ) - geometry_rectangle_get_width( &stereotype_box ) - icon_gap;
     183              : 
     184              :     /* draw text - except for lifelines */
     185            0 :     if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type (feature) )
     186              :     {
     187              :         /* prepare text */
     188            0 :         u8_error_t name_err = U8_ERROR_NONE;
     189            0 :         utf8stream_writer_t *to_name = utf8stream_writemem_get_writer( &((*this_).text_builder) );
     190              : 
     191              :         /* append parts to name and insert linebreaks */
     192            0 :         utf8stringview_t feat_key = UTF8STRINGVIEW_STR( data_feature_get_key_const( feature ) );
     193            0 :         name_err |= draw_line_breaker_append( &((*this_).linebr), &feat_key, to_name );
     194            0 :         if ( data_feature_has_value( feature ) && ( ! has_stereotype_image ) )
     195              :         {
     196            0 :             name_err |= utf8stream_writer_write_str( to_name, ": " );
     197            0 :             utf8stringview_t feat_value = UTF8STRINGVIEW_STR( data_feature_get_value_const( feature ) );
     198            0 :             name_err |= draw_line_breaker_append( &((*this_).linebr), &feat_value, to_name );
     199              :         }
     200            0 :         const utf8stringview_t name = utf8stream_writemem_get_view( &((*this_).text_builder) );
     201              : 
     202            0 :         const double f_size = pencil_size_get_standard_font_size( pencil_size );
     203            0 :         cairo_set_source_rgba( cr, color->red, color->green, color->blue, color->alpha );
     204            0 :         pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) );
     205            0 :         pango_layout_set_text (font_layout,
     206              :                                utf8stringview_get_start( &name ),
     207            0 :                                utf8stringview_get_length( &name )
     208              :                              );
     209            0 :         pango_layout_set_width(font_layout, (text_width+f_size) * PANGO_SCALE );  /* add gap to avoid line breaks by rounding errors and whitespace character widths */
     210              : 
     211              :         /* draw text */
     212            0 :         cairo_move_to ( cr, ceil( text_left ), ceil( text_top ) );  /* align font with pixel border */
     213            0 :         pango_cairo_show_layout (cr, font_layout);
     214              : 
     215              :         /* restore pango context */
     216            0 :         pango_layout_set_width(font_layout, DRAW_FEATURE_PANGO_UNLIMITED_WIDTH);
     217              : 
     218              :         /* cleanup the text_builder */
     219            0 :         name_err |= utf8stream_writemem_reset( &((*this_).text_builder) );
     220            0 :         if ( name_err != U8_ERROR_NONE )
     221              :         {
     222            0 :             U8_LOG_WARNING_HEX( "error at get_dim/draw_line_breaker_append", name_err );
     223              :         }
     224              :     }
     225              : 
     226            0 :     U8_TRACE_END();
     227            0 : }
     228              : 
     229              : 
     230              : /*
     231              : Copyright 2017-2025 Andreas Warnke
     232              :     http://www.apache.org/licenses/LICENSE-2.0
     233              : 
     234              : Licensed under the Apache License, Version 2.0 (the "License");
     235              : you may not use this file except in compliance with the License.
     236              : You may obtain a copy of the License at
     237              : 
     238              : 
     239              : Unless required by applicable law or agreed to in writing, software
     240              : distributed under the License is distributed on an "AS IS" BASIS,
     241              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     242              : See the License for the specific language governing permissions and
     243              : limitations under the License.
     244              : */
        

Generated by: LCOV version 2.0-1