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.57.0_covts Lines: 0 113 0.0 %
Date: 2024-04-07 11:14:42 Functions: 0 2 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 "data_classifier.h"
       6             : #include "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_get_type_and_name_dimensions ( const draw_relationship_label_t *this_,
      22             :                                                             const data_relationship_t *relationship,
      23             :                                                             const data_profile_part_t *profile,
      24             :                                                             const geometry_dimensions_t *proposed_bounds,
      25             :                                                             const pencil_size_t *pencil_size,
      26             :                                                             PangoLayout *font_layout,
      27             :                                                             geometry_dimensions_t *out_label_dim )
      28             : {
      29           0 :     U8_TRACE_BEGIN();
      30           0 :     assert( NULL != relationship );
      31           0 :     assert( NULL != profile );
      32           0 :     assert( NULL != proposed_bounds );
      33           0 :     assert( NULL != pencil_size );
      34           0 :     assert( NULL != font_layout );
      35           0 :     assert( NULL != out_label_dim );
      36             : 
      37           0 :     if ( data_relationship_is_valid( relationship ) )
      38             :     {
      39             :         /* calc stereotype image bounds */
      40           0 :         const char *const relationship_stereotype = data_relationship_get_stereotype_const( relationship );
      41             :         const bool has_stereotype_image
      42           0 :             = draw_stereotype_image_exists( &((*this_).image_renderer), relationship_stereotype, profile );
      43           0 :         const geometry_dimensions_t icon_dim
      44             :             = has_stereotype_image
      45           0 :             ? draw_stereotype_image_get_dimensions( &((*this_).image_renderer), pencil_size )
      46           0 :             : (geometry_dimensions_t){ .width = 0.0, .height = 0.0 };
      47           0 :         const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
      48             : 
      49             :         /* define names for input data */
      50           0 :         int proposed_pango_width = geometry_dimensions_get_width( proposed_bounds );
      51           0 :         const double f_line_gap = pencil_size_get_font_line_gap( pencil_size );
      52             : 
      53             :         /* calc dimensions of stereotype as text */
      54           0 :         int text1_height = 0;
      55           0 :         int text1_width = 0;
      56             :         {
      57           0 :             const data_relationship_type_t rel_type = data_relationship_get_main_type( relationship );
      58             :             const char *const pseudo_stereotype
      59           0 :                 = draw_relationship_label_private_stereotype_from_type( this_, rel_type );
      60           0 :             const bool has_pseudo_stereotype = ( ! utf8string_equals_str( pseudo_stereotype, "" ) );
      61           0 :             const bool has_stereotype = ( ! utf8string_equals_str( relationship_stereotype, "" ) );
      62             : 
      63           0 :             if ( ( ! has_stereotype_image ) && ( has_pseudo_stereotype || has_stereotype ) )
      64             :             {
      65             :                 /* prepare text */
      66             :                 char stereotype_text[DATA_CLASSIFIER_MAX_STEREOTYPE_SIZE+4];
      67           0 :                 utf8stringbuf_t stereotype_buf = UTF8STRINGBUF(stereotype_text);
      68           0 :                 utf8stringbuf_copy_str( stereotype_buf, DRAW_RELATIONSHIP_LEFT_GUILLEMENTS );
      69           0 :                 if ( has_stereotype )
      70             :                 {
      71           0 :                     utf8stringbuf_append_str( stereotype_buf, relationship_stereotype );
      72             :                 }
      73             :                 else
      74             :                 {
      75           0 :                     utf8stringbuf_append_str( stereotype_buf, pseudo_stereotype );
      76             :                 }
      77           0 :                 utf8stringbuf_append_str( stereotype_buf, DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS );
      78             : 
      79             :                 /* determine text width and height */
      80           0 :                 pango_layout_set_font_description( font_layout, pencil_size_get_footnote_font_description( pencil_size ) );
      81           0 :                 pango_layout_set_text( font_layout, utf8stringbuf_get_string( stereotype_buf ), DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH );
      82           0 :                 pango_layout_get_pixel_size( font_layout, &text1_width, &text1_height );
      83           0 :                 text1_height += PENCIL_SIZE_FONT_ALIGN_MARGIN;  /* allow to align font with pixel border */
      84           0 :                 text1_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
      85             :             }
      86             :         }
      87             : 
      88             :         /* calc name text dimensions */
      89           0 :         int text2_height = 0;
      90           0 :         int text2_width = 0;
      91           0 :         if ( 0 != utf8string_get_length( data_relationship_get_name_const( relationship ) ))
      92             :         {
      93           0 :             pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) );
      94           0 :             pango_layout_set_text( font_layout,
      95             :                                    data_relationship_get_name_const( relationship ),
      96             :                                    DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH
      97             :                                  );
      98           0 :             pango_layout_set_width(font_layout, proposed_pango_width * PANGO_SCALE );
      99           0 :             pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height);
     100           0 :             text2_height += PENCIL_SIZE_FONT_ALIGN_MARGIN;  /* allow to align font with pixel border */
     101           0 :             text2_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
     102             :             /* restore pango context */
     103           0 :             pango_layout_set_width(font_layout, DRAW_RELATIONSHIP_PANGO_UNLIMITED_WIDTH);
     104             :         }
     105             : 
     106           0 :         *out_label_dim = (geometry_dimensions_t){
     107           0 :             .width = geometry_dimensions_get_width( &icon_dim ) + icon_gap + u8_i32_max2( text2_width, text1_width ),
     108           0 :             .height = u8_f64_max2( geometry_dimensions_get_height( &icon_dim ), text1_height + f_line_gap + text2_height )
     109             :         };
     110             :     }
     111             :     else
     112             :     {
     113           0 :         U8_LOG_ERROR("invalid relationship in draw_relationship_label_get_type_and_name_dimensions()");
     114           0 :         *out_label_dim = (geometry_dimensions_t) { .width = 0.0, .height = 0.0 };
     115             :     }
     116           0 :     U8_TRACE_END();
     117           0 : }
     118             : 
     119           0 : void draw_relationship_label_draw_type_and_name ( const draw_relationship_label_t *this_,
     120             :                                                   const data_relationship_t *relationship,
     121             :                                                   const data_profile_part_t *profile,
     122             :                                                   const GdkRGBA *color,
     123             :                                                   const geometry_rectangle_t *label_box,
     124             :                                                   const pencil_size_t *pencil_size,
     125             :                                                   PangoLayout *font_layout,
     126             :                                                   cairo_t *cr )
     127             : {
     128           0 :     U8_TRACE_BEGIN();
     129           0 :     assert( NULL != relationship );
     130           0 :     assert( NULL != profile );
     131           0 :     assert( NULL != color );
     132           0 :     assert( NULL != label_box );
     133           0 :     assert( NULL != pencil_size );
     134           0 :     assert( NULL != font_layout );
     135           0 :     assert( NULL != cr );
     136             : 
     137             :     /* calc bounds of stereotype icon */
     138           0 :     const char *const relationship_stereotype = data_relationship_get_stereotype_const( relationship );
     139             :     const bool has_stereotype_image
     140           0 :         = draw_stereotype_image_exists( &((*this_).image_renderer), relationship_stereotype, profile );
     141           0 :     const geometry_rectangle_t stereotype_box
     142             :         = has_stereotype_image
     143           0 :         ? draw_stereotype_image_get_bounds( &((*this_).image_renderer),
     144             :                                             geometry_rectangle_get_left( label_box ),
     145             :                                             geometry_rectangle_get_top( label_box ),
     146             :                                             GEOMETRY_H_ALIGN_LEFT,
     147             :                                             GEOMETRY_V_ALIGN_TOP,
     148             :                                             pencil_size
     149             :                                           )
     150           0 :         : (geometry_rectangle_t){ .left = 0.0, .top = 0.0, .width = 0.0, .height = 0.0 };
     151           0 :     const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
     152             : 
     153             :     /* draw stereotype icon */
     154           0 :     if ( has_stereotype_image )
     155             :     {
     156             :         u8_error_info_t err_info;
     157             :         const u8_error_t stereotype_err
     158           0 :             = draw_stereotype_image_draw( &((*this_).image_renderer),
     159             :                                           relationship_stereotype,
     160             :                                           profile,
     161             :                                           color,
     162             :                                           &err_info,
     163             :                                           &stereotype_box,
     164             :                                           cr
     165             :                                         );
     166           0 :         if ( u8_error_info_is_error( &err_info ) )
     167             :         {
     168           0 :             U8_LOG_WARNING_INT( "stereotype image: unxpected token in svg path in line",
     169             :                                 u8_error_info_get_line( &err_info )
     170             :                               );
     171             :         }
     172           0 :         else if ( stereotype_err != U8_ERROR_NONE )
     173             :         {
     174           0 :             U8_LOG_WARNING_HEX( "error at drawing stereotype image", stereotype_err );
     175             :         }
     176             :     }
     177             : 
     178             :     /* define names for input data */
     179           0 :     const double text_width
     180           0 :         = geometry_rectangle_get_width( label_box ) - geometry_rectangle_get_width( &stereotype_box ) - icon_gap;
     181           0 :     const double center_x
     182           0 :         = geometry_rectangle_get_left( label_box ) + geometry_rectangle_get_width( &stereotype_box ) + icon_gap
     183           0 :         + 0.5 * text_width;
     184           0 :     const double top = geometry_rectangle_get_top( label_box );
     185           0 :     const double f_line_gap = pencil_size_get_font_line_gap( pencil_size );
     186             : 
     187             :     /* draw stereotype as text */
     188           0 :     int text1_height = 0;
     189             :     {
     190           0 :         const data_relationship_type_t rel_type = data_relationship_get_main_type( relationship );
     191             :         const char *const pseudo_stereotype
     192           0 :             = draw_relationship_label_private_stereotype_from_type( this_, rel_type );
     193           0 :         const bool has_pseudo_stereotype = ( ! utf8string_equals_str( pseudo_stereotype, "" ) );
     194           0 :         const bool has_stereotype = ( ! utf8string_equals_str( relationship_stereotype, "" ) );
     195             : 
     196           0 :         if ( ( ! has_stereotype_image ) && ( has_pseudo_stereotype || has_stereotype ) )
     197             :         {
     198             :             /* prepare text */
     199             :             char stereotype_text[DATA_CLASSIFIER_MAX_STEREOTYPE_SIZE+4];
     200           0 :             utf8stringbuf_t stereotype_buf = UTF8STRINGBUF(stereotype_text);
     201           0 :             utf8stringbuf_copy_str( stereotype_buf, DRAW_RELATIONSHIP_LEFT_GUILLEMENTS );
     202           0 :             if ( has_stereotype )
     203             :             {
     204           0 :                 utf8stringbuf_append_str( stereotype_buf, relationship_stereotype );
     205             :             }
     206             :             else
     207             :             {
     208           0 :                 utf8stringbuf_append_str( stereotype_buf, pseudo_stereotype );
     209             :             }
     210           0 :             utf8stringbuf_append_str( stereotype_buf, DRAW_RELATIONSHIP_RIGHT_GUILLEMENTS );
     211             : 
     212             :             int text1_width;
     213           0 :             cairo_set_source_rgba( cr, color->red, color->green, color->blue, color->alpha );
     214           0 :             pango_layout_set_font_description( font_layout, pencil_size_get_footnote_font_description( pencil_size ) );
     215           0 :             pango_layout_set_text( font_layout,
     216           0 :                                    utf8stringbuf_get_string( stereotype_buf ),
     217             :                                    DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH
     218             :                                  );
     219           0 :             pango_layout_get_pixel_size( font_layout, &text1_width, &text1_height );
     220             : 
     221             :             /* draw text */
     222           0 :             cairo_move_to( cr, ceil( center_x - 0.5*text1_width ), ceil( top ) );  /* align font with pixel border */
     223           0 :             pango_cairo_show_layout( cr, font_layout );
     224             :         }
     225             :     }
     226             : 
     227             :     /* draw name text */
     228           0 :     if ( 0 != utf8string_get_length( data_relationship_get_name_const( relationship ) ))
     229             :     {
     230             :         int text2_height;
     231             :         int text2_width;
     232           0 :         const double f_size = pencil_size_get_standard_font_size( pencil_size );
     233           0 :         cairo_set_source_rgba( cr, color->red, color->green, color->blue, color->alpha );
     234           0 :         pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) );
     235           0 :         pango_layout_set_text( font_layout,
     236             :                                data_relationship_get_name_const( relationship ),
     237             :                                DRAW_RELATIONSHIP_PANGO_AUTO_DETECT_LENGTH
     238             :                              );
     239           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 */
     240           0 :         pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height);
     241             : 
     242             :         /* draw text */
     243           0 :         cairo_move_to( cr,
     244           0 :                        ceil( center_x - 0.5*text2_width ),
     245           0 :                        ceil( top + text1_height + f_line_gap )
     246             :                      );  /* align font with pixel border */
     247           0 :         pango_cairo_show_layout( cr, font_layout );
     248             : 
     249             :         /* restore pango context */
     250           0 :         pango_layout_set_width(font_layout, DRAW_RELATIONSHIP_PANGO_UNLIMITED_WIDTH);
     251             :     }
     252             : 
     253           0 :     U8_TRACE_END();
     254           0 : }
     255             : 
     256             : 
     257             : /*
     258             : Copyright 2017-2024 Andreas Warnke
     259             :     http://www.apache.org/licenses/LICENSE-2.0
     260             : 
     261             : Licensed under the Apache License, Version 2.0 (the "License");
     262             : you may not use this file except in compliance with the License.
     263             : You may obtain a copy of the License at
     264             : 
     265             : 
     266             : Unless required by applicable law or agreed to in writing, software
     267             : distributed under the License is distributed on an "AS IS" BASIS,
     268             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     269             : See the License for the specific language governing permissions and
     270             : limitations under the License.
     271             : */

Generated by: LCOV version 1.16