LCOV - code coverage report
Current view: top level - pencil/source/draw - draw_feature_label.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 0 108 0.0 %
Date: 2024-10-26 21:44:38 Functions: 0 4 0.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_image_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_image_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_image_exists( &((*this_).image_renderer), feature_stereotype, profile );
      57           0 :         const geometry_dimensions_t icon_dim
      58             :             = has_stereotype_image
      59           0 :             ? draw_stereotype_image_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_image_exists( &((*this_).image_renderer), feature_stereotype, profile );
     140           0 :     const geometry_rectangle_t stereotype_box
     141             :         = has_stereotype_image
     142           0 :         ? draw_stereotype_image_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_image_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-2024 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 1.16