LCOV - code coverage report
Current view: top level - pencil/source/draw - draw_relationship_label.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 0 143 0.0 %
Date: 2024-10-26 21:44:38 Functions: 0 4 0.0 %

          Line data    Source code
       1             :   /* File: draw_relationship_label.c; Copyright and License: see below */
       2             : 
       3             : #include "draw/draw_relationship_label.h"
       4             : #include "u8/u8_trace.h"
       5             : #include "entity/data_classifier.h"
       6             : #include "entity/data_diagramelement.h"
       7             : #include "u8/u8_i32.h"
       8             : #include "u8/u8_f64.h"
       9             : #include "utf8stringbuf/utf8stringbuf.h"
      10             : #include "utf8stringbuf/utf8string.h"
      11             : #include <pango/pangocairo.h>
      12             : #include <stdio.h>
      13             : #include <stdlib.h>
      14             : #include <assert.h>
      15             : 
      16             : static const int DRAW_RELATIONSHIP_PANGO_UNLIMITED_WIDTH = -1;
      17             : static const int DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH = -1;
      18             : #define DRAW_RELATIONSHIP_LEFT_GUILLEMENTS "\xc2\xab"
      19             : #define DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS "\xc2\xbb"
      20             : 
      21           0 : void draw_relationship_label_init( draw_relationship_label_t *this_ )
      22             : {
      23           0 :     utf8stream_writemem_init( &((*this_).text_builder), &((*this_).text_buffer), sizeof( (*this_).text_buffer) );
      24           0 :     draw_line_breaker_init( &((*this_).linebr) );
      25           0 :     draw_stereotype_image_init( &((*this_).image_renderer) );
      26           0 : }
      27             : 
      28           0 : void draw_relationship_label_destroy( draw_relationship_label_t *this_ )
      29             : {
      30           0 :     draw_line_breaker_destroy( &((*this_).linebr) );
      31           0 :     const u8_error_t text_err = utf8stream_writemem_destroy( &((*this_).text_builder) );
      32           0 :     if ( text_err != U8_ERROR_NONE )
      33             :     {
      34           0 :         U8_LOG_WARNING_HEX( "error at draw/draw_classifier_label: buffer too small", text_err );
      35             :     }
      36           0 :     draw_stereotype_image_destroy( &((*this_).image_renderer) );
      37           0 : }
      38             : 
      39           0 : void draw_relationship_label_get_type_and_name_dimensions ( draw_relationship_label_t *this_,
      40             :                                                             const data_relationship_t *relationship,
      41             :                                                             const data_profile_part_t *profile,
      42             :                                                             const geometry_dimensions_t *proposed_bounds,
      43             :                                                             const pencil_size_t *pencil_size,
      44             :                                                             PangoLayout *font_layout,
      45             :                                                             geometry_dimensions_t *out_label_dim )
      46             : {
      47           0 :     U8_TRACE_BEGIN();
      48           0 :     assert( NULL != relationship );
      49           0 :     assert( NULL != profile );
      50           0 :     assert( NULL != proposed_bounds );
      51           0 :     assert( NULL != pencil_size );
      52           0 :     assert( NULL != font_layout );
      53           0 :     assert( NULL != out_label_dim );
      54             : 
      55           0 :     if ( data_relationship_is_valid( relationship ) )
      56             :     {
      57             :         /* calc stereotype image bounds */
      58           0 :         const char *const relationship_stereotype = data_relationship_get_stereotype_const( relationship );
      59             :         const bool has_stereotype_image
      60           0 :             = draw_stereotype_image_exists( &((*this_).image_renderer), relationship_stereotype, profile );
      61           0 :         const geometry_dimensions_t icon_dim
      62             :             = has_stereotype_image
      63           0 :             ? draw_stereotype_image_get_dimensions( &((*this_).image_renderer), pencil_size )
      64           0 :             : (geometry_dimensions_t){ .width = 0.0, .height = 0.0 };
      65           0 :         const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
      66             : 
      67             :         /* define names for input data */
      68           0 :         int proposed_pango_width = geometry_dimensions_get_width( proposed_bounds );
      69           0 :         const double f_line_gap = pencil_size_get_font_line_gap( pencil_size );
      70             : 
      71             :         /* calc dimensions of stereotype as text */
      72           0 :         int text1_height = 0;
      73           0 :         int text1_width = 0;
      74             :         {
      75           0 :             const data_relationship_type_t rel_type = data_relationship_get_main_type( relationship );
      76             :             const char *const pseudo_stereotype
      77           0 :                 = draw_relationship_label_private_stereotype_from_type( this_, rel_type );
      78           0 :             const bool has_pseudo_stereotype = ( ! utf8string_equals_str( pseudo_stereotype, "" ) );
      79           0 :             const bool has_stereotype = ( ! utf8string_equals_str( relationship_stereotype, "" ) );
      80             : 
      81           0 :             if ( ( ! has_stereotype_image ) && ( has_pseudo_stereotype || has_stereotype ) )
      82             :             {
      83             :                 /* prepare text */
      84             :                 char stereotype_text[DATA_CLASSIFIER_MAX_STEREOTYPE_SIZE+4];
      85           0 :                 utf8stringbuf_t stereotype_buf = UTF8STRINGBUF(stereotype_text);
      86           0 :                 utf8stringbuf_copy_str( stereotype_buf, DRAW_RELATIONSHIP_LEFT_GUILLEMENTS );
      87           0 :                 if ( has_stereotype )
      88             :                 {
      89           0 :                     utf8stringbuf_append_str( stereotype_buf, relationship_stereotype );
      90             :                 }
      91             :                 else
      92             :                 {
      93           0 :                     utf8stringbuf_append_str( stereotype_buf, pseudo_stereotype );
      94             :                 }
      95           0 :                 utf8stringbuf_append_str( stereotype_buf, DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS );
      96             : 
      97             :                 /* determine text width and height */
      98           0 :                 pango_layout_set_font_description( font_layout, pencil_size_get_footnote_font_description( pencil_size ) );
      99           0 :                 pango_layout_set_text( font_layout, utf8stringbuf_get_string( stereotype_buf ), DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH );
     100           0 :                 pango_layout_get_pixel_size( font_layout, &text1_width, &text1_height );
     101           0 :                 text1_height += PENCIL_SIZE_FONT_ALIGN_MARGIN;  /* allow to align font with pixel border */
     102           0 :                 text1_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
     103             :             }
     104             :         }
     105             : 
     106             :         /* calc name text dimensions */
     107           0 :         int text2_height = 0;
     108           0 :         int text2_width = 0;
     109           0 :         if ( 0 != utf8string_get_length( data_relationship_get_name_const( relationship ) ))
     110             :         {
     111           0 :             u8_error_t name_err = U8_ERROR_NONE;
     112           0 :             utf8stream_writer_t *to_name = utf8stream_writemem_get_writer( &((*this_).text_builder) );
     113             : 
     114             :             /* append parts to name and insert linebreaks */
     115           0 :             utf8stringview_t rel_name = UTF8STRINGVIEW_STR( data_relationship_get_name_const( relationship ) );
     116           0 :             name_err |= draw_line_breaker_append( &((*this_).linebr), &rel_name, to_name );
     117           0 :             const utf8stringview_t name = utf8stream_writemem_get_view( &((*this_).text_builder) );
     118             : 
     119           0 :             pango_layout_set_font_description( font_layout, pencil_size_get_standard_font_description(pencil_size) );
     120           0 :             pango_layout_set_text( font_layout,
     121             :                                    utf8stringview_get_start( &name ),
     122           0 :                                    utf8stringview_get_length( &name )
     123             :                                  );
     124           0 :             pango_layout_set_width( font_layout, proposed_pango_width * PANGO_SCALE );
     125           0 :             pango_layout_get_pixel_size( font_layout, &text2_width, &text2_height );
     126           0 :             text2_height += PENCIL_SIZE_FONT_ALIGN_MARGIN;  /* allow to align font with pixel border */
     127           0 :             text2_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
     128             : 
     129             :             /* restore pango context */
     130           0 :             pango_layout_set_width(font_layout, DRAW_RELATIONSHIP_PANGO_UNLIMITED_WIDTH);
     131             : 
     132             :             /* cleanup the text_builder */
     133           0 :             name_err |= utf8stream_writemem_reset( &((*this_).text_builder) );
     134           0 :             if ( name_err != U8_ERROR_NONE )
     135             :             {
     136           0 :                 U8_LOG_WARNING_HEX( "error at get_dim/draw_line_breaker_append", name_err );
     137             :             }
     138             :         }
     139             : 
     140           0 :         *out_label_dim = (geometry_dimensions_t){
     141           0 :             .width = geometry_dimensions_get_width( &icon_dim ) + icon_gap + u8_i32_max2( text2_width, text1_width ),
     142           0 :             .height = u8_f64_max2( geometry_dimensions_get_height( &icon_dim ), text1_height + f_line_gap + text2_height )
     143             :         };
     144             :     }
     145             :     else
     146             :     {
     147           0 :         U8_LOG_ERROR("invalid relationship in draw_relationship_label_get_type_and_name_dimensions()");
     148           0 :         *out_label_dim = (geometry_dimensions_t) { .width = 0.0, .height = 0.0 };
     149             :     }
     150           0 :     U8_TRACE_END();
     151           0 : }
     152             : 
     153           0 : void draw_relationship_label_draw_type_and_name ( draw_relationship_label_t *this_,
     154             :                                                   const data_relationship_t *relationship,
     155             :                                                   const data_profile_part_t *profile,
     156             :                                                   const GdkRGBA *color,
     157             :                                                   const geometry_rectangle_t *label_box,
     158             :                                                   const pencil_size_t *pencil_size,
     159             :                                                   PangoLayout *font_layout,
     160             :                                                   cairo_t *cr )
     161             : {
     162           0 :     U8_TRACE_BEGIN();
     163           0 :     assert( NULL != relationship );
     164           0 :     assert( NULL != profile );
     165           0 :     assert( NULL != color );
     166           0 :     assert( NULL != label_box );
     167           0 :     assert( NULL != pencil_size );
     168           0 :     assert( NULL != font_layout );
     169           0 :     assert( NULL != cr );
     170             : 
     171             :     /* calc bounds of stereotype icon */
     172           0 :     const char *const relationship_stereotype = data_relationship_get_stereotype_const( relationship );
     173             :     const bool has_stereotype_image
     174           0 :         = draw_stereotype_image_exists( &((*this_).image_renderer), relationship_stereotype, profile );
     175           0 :     const geometry_rectangle_t stereotype_box
     176             :         = has_stereotype_image
     177           0 :         ? draw_stereotype_image_get_bounds( &((*this_).image_renderer),
     178             :                                             geometry_rectangle_get_left( label_box ),
     179             :                                             geometry_rectangle_get_top( label_box ),
     180             :                                             GEOMETRY_H_ALIGN_LEFT,
     181             :                                             GEOMETRY_V_ALIGN_TOP,
     182             :                                             pencil_size
     183             :                                           )
     184           0 :         : (geometry_rectangle_t){ .left = 0.0, .top = 0.0, .width = 0.0, .height = 0.0 };
     185           0 :     const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
     186             : 
     187             :     /* draw stereotype icon */
     188           0 :     if ( has_stereotype_image )
     189             :     {
     190             :         u8_error_info_t err_info;
     191             :         const u8_error_t stereotype_err
     192           0 :             = draw_stereotype_image_draw( &((*this_).image_renderer),
     193             :                                           relationship_stereotype,
     194             :                                           profile,
     195             :                                           color,
     196             :                                           &err_info,
     197             :                                           &stereotype_box,
     198             :                                           cr
     199             :                                         );
     200           0 :         if ( u8_error_info_is_error( &err_info ) )
     201             :         {
     202           0 :             U8_LOG_WARNING_INT( "stereotype image: unxpected token in svg path in line",
     203             :                                 u8_error_info_get_line( &err_info )
     204             :                               );
     205             :         }
     206           0 :         else if ( stereotype_err != U8_ERROR_NONE )
     207             :         {
     208           0 :             U8_LOG_WARNING_HEX( "error at drawing stereotype image", stereotype_err );
     209             :         }
     210             :     }
     211             : 
     212             :     /* define names for input data */
     213           0 :     const double text_width
     214           0 :         = geometry_rectangle_get_width( label_box ) - geometry_rectangle_get_width( &stereotype_box ) - icon_gap;
     215           0 :     const double center_x
     216           0 :         = geometry_rectangle_get_left( label_box ) + geometry_rectangle_get_width( &stereotype_box ) + icon_gap
     217           0 :         + 0.5 * text_width;
     218           0 :     const double top = geometry_rectangle_get_top( label_box );
     219           0 :     const double f_line_gap = pencil_size_get_font_line_gap( pencil_size );
     220             : 
     221             :     /* draw stereotype as text */
     222           0 :     int text1_height = 0;
     223             :     {
     224           0 :         const data_relationship_type_t rel_type = data_relationship_get_main_type( relationship );
     225             :         const char *const pseudo_stereotype
     226           0 :             = draw_relationship_label_private_stereotype_from_type( this_, rel_type );
     227           0 :         const bool has_pseudo_stereotype = ( ! utf8string_equals_str( pseudo_stereotype, "" ) );
     228           0 :         const bool has_stereotype = ( ! utf8string_equals_str( relationship_stereotype, "" ) );
     229             : 
     230           0 :         if ( ( ! has_stereotype_image ) && ( has_pseudo_stereotype || has_stereotype ) )
     231             :         {
     232             :             /* prepare text */
     233             :             char stereotype_text[DATA_CLASSIFIER_MAX_STEREOTYPE_SIZE+4];
     234           0 :             utf8stringbuf_t stereotype_buf = UTF8STRINGBUF(stereotype_text);
     235           0 :             utf8stringbuf_copy_str( stereotype_buf, DRAW_RELATIONSHIP_LEFT_GUILLEMENTS );
     236           0 :             if ( has_stereotype )
     237             :             {
     238           0 :                 utf8stringbuf_append_str( stereotype_buf, relationship_stereotype );
     239             :             }
     240             :             else
     241             :             {
     242           0 :                 utf8stringbuf_append_str( stereotype_buf, pseudo_stereotype );
     243             :             }
     244           0 :             utf8stringbuf_append_str( stereotype_buf, DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS );
     245             : 
     246             :             int text1_width;
     247           0 :             cairo_set_source_rgba( cr, color->red, color->green, color->blue, color->alpha );
     248           0 :             pango_layout_set_font_description( font_layout, pencil_size_get_footnote_font_description( pencil_size ) );
     249           0 :             pango_layout_set_text( font_layout,
     250           0 :                                    utf8stringbuf_get_string( stereotype_buf ),
     251             :                                    DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH
     252             :                                  );
     253           0 :             pango_layout_get_pixel_size( font_layout, &text1_width, &text1_height );
     254             : 
     255             :             /* draw text */
     256           0 :             cairo_move_to( cr, ceil( center_x - 0.5*text1_width ), ceil( top ) );  /* align font with pixel border */
     257           0 :             pango_cairo_show_layout( cr, font_layout );
     258             :         }
     259             :     }
     260             : 
     261             :     /* draw name text */
     262           0 :     if ( 0 != utf8string_get_length( data_relationship_get_name_const( relationship ) ))
     263             :     {
     264           0 :         u8_error_t name_err = U8_ERROR_NONE;
     265           0 :         utf8stream_writer_t *to_name = utf8stream_writemem_get_writer( &((*this_).text_builder) );
     266             : 
     267             :         /* append parts to name and insert linebreaks */
     268           0 :         utf8stringview_t rel_name = UTF8STRINGVIEW_STR( data_relationship_get_name_const( relationship ) );
     269           0 :         name_err |= draw_line_breaker_append( &((*this_).linebr), &rel_name, to_name );
     270           0 :         const utf8stringview_t name = utf8stream_writemem_get_view( &((*this_).text_builder) );
     271             : 
     272             :         int text2_height;
     273             :         int text2_width;
     274           0 :         const double f_size = pencil_size_get_standard_font_size( pencil_size );
     275           0 :         cairo_set_source_rgba( cr, color->red, color->green, color->blue, color->alpha );
     276           0 :         pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) );
     277           0 :         pango_layout_set_text( font_layout,
     278             :                                utf8stringview_get_start( &name ),
     279           0 :                                utf8stringview_get_length( &name )
     280             :                              );
     281           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 */
     282           0 :         pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height);
     283             : 
     284             :         /* draw text */
     285           0 :         cairo_move_to( cr,
     286           0 :                        ceil( center_x - 0.5*text2_width ),
     287           0 :                        ceil( top + text1_height + f_line_gap )
     288             :                      );  /* align font with pixel border */
     289           0 :         pango_cairo_show_layout( cr, font_layout );
     290             : 
     291             :         /* restore pango context */
     292           0 :         pango_layout_set_width(font_layout, DRAW_RELATIONSHIP_PANGO_UNLIMITED_WIDTH);
     293             : 
     294             :         /* cleanup the text_builder */
     295           0 :         name_err |= utf8stream_writemem_reset( &((*this_).text_builder) );
     296           0 :         if ( name_err != U8_ERROR_NONE )
     297             :         {
     298           0 :             U8_LOG_WARNING_HEX( "error at get_dim/draw_line_breaker_append", name_err );
     299             :         }
     300             :     }
     301             : 
     302           0 :     U8_TRACE_END();
     303           0 : }
     304             : 
     305             : 
     306             : /*
     307             : Copyright 2017-2024 Andreas Warnke
     308             :     http://www.apache.org/licenses/LICENSE-2.0
     309             : 
     310             : Licensed under the Apache License, Version 2.0 (the "License");
     311             : you may not use this file except in compliance with the License.
     312             : You may obtain a copy of the License at
     313             : 
     314             : 
     315             : Unless required by applicable law or agreed to in writing, software
     316             : distributed under the License is distributed on an "AS IS" BASIS,
     317             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     318             : See the License for the specific language governing permissions and
     319             : limitations under the License.
     320             : */

Generated by: LCOV version 1.16