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 : */
|