Line data Source code
1 : /* File: draw_diagram_label.c; Copyright and License: see below */
2 :
3 : #include "draw/draw_diagram_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_DIAGRAM_PANGO_AUTO_DETECT_LENGTH = -1;
16 : #define DRAW_DIAGRAM_LEFT_GUILLEMETS "\xc2\xab"
17 : #define DRAW_DIAGRAM_RIGHT_GUILLEMETS "\xc2\xbb"
18 :
19 0 : void draw_diagram_label_init( draw_diagram_label_t *this_ )
20 : {
21 0 : utf8stream_writemem_init( &((*this_).text_builder), &((*this_).text_buffer), sizeof( (*this_).text_buffer) );
22 0 : draw_stereotype_icon_init( &((*this_).image_renderer) );
23 0 : }
24 :
25 0 : void draw_diagram_label_destroy( draw_diagram_label_t *this_ )
26 : {
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_diagram_label: buffer too small", text_err );
31 : }
32 0 : draw_stereotype_icon_destroy( &((*this_).image_renderer) );
33 0 : }
34 :
35 0 : void draw_diagram_label_get_type_and_name_dimensions ( draw_diagram_label_t *this_,
36 : const data_diagram_t *diagram,
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 != diagram );
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_diagram_is_valid( diagram ) )
52 : {
53 : /* calc stereotype image bounds */
54 0 : const char *const diagram_stereotype = data_diagram_get_stereotype_const( diagram );
55 : const bool has_stereotype_image
56 0 : = draw_stereotype_icon_exists( &((*this_).image_renderer), diagram_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 bool has_stereotype_text
62 0 : = ( ! has_stereotype_image ) && data_diagram_has_stereotype( diagram );
63 0 : const double f_tab_size = pencil_size_get_font_tab_size( pencil_size );
64 :
65 : /* calc stereotype/type text dimensions (unless has_stereotype_image) */
66 0 : int text1_width = 0;
67 0 : int text1_height = 0;
68 0 : if ( ! has_stereotype_image )
69 : {
70 : /* prepare text */
71 0 : u8_error_t stereotype_err = U8_ERROR_NONE;
72 0 : utf8stream_writer_t *to_type = utf8stream_writemem_get_writer( &((*this_).text_builder) );
73 :
74 : /* build text */
75 0 : if ( has_stereotype_text )
76 : {
77 0 : stereotype_err |= utf8stream_writer_write_str( to_type, DRAW_DIAGRAM_LEFT_GUILLEMETS );
78 0 : stereotype_err |= utf8stream_writer_write_str( to_type, diagram_stereotype );
79 0 : stereotype_err |= utf8stream_writer_write_str( to_type, DRAW_DIAGRAM_RIGHT_GUILLEMETS );
80 0 : stereotype_err |= utf8stream_writer_flush( to_type );
81 : }
82 : else
83 : {
84 0 : const char *element_kind = data_diagram_type_get_element_kind( data_diagram_get_diagram_type( diagram ) );
85 0 : stereotype_err |= utf8stream_writer_write_str( to_type, element_kind );
86 0 : stereotype_err |= utf8stream_writer_flush( to_type );
87 : }
88 0 : const utf8stringview_t stereotype_text = utf8stream_writemem_get_view( &((*this_).text_builder) );
89 :
90 : /* determine text width and height */
91 0 : pango_layout_set_font_description( font_layout, pencil_size_get_standard_font_description( pencil_size ) );
92 0 : pango_layout_set_text( font_layout,
93 : utf8stringview_get_start( &stereotype_text ),
94 0 : utf8stringview_get_length( &stereotype_text )
95 : );
96 0 : pango_layout_get_pixel_size( font_layout, &text1_width, &text1_height );
97 0 : text1_height += PENCIL_SIZE_FONT_ALIGN_MARGIN; /* allow to align font with pixel border */
98 0 : text1_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
99 :
100 : /* cleanup the text_builder */
101 0 : stereotype_err |= utf8stream_writemem_reset( &((*this_).text_builder) );
102 0 : if ( stereotype_err != U8_ERROR_NONE )
103 : {
104 0 : U8_LOG_WARNING_HEX( "error at get_dim/draw_line_breaker_append", stereotype_err );
105 : }
106 : }
107 :
108 : /* calc name text dimensions */
109 : /* int proposed_pango_width = geometry_dimensions_get_width( proposed_bounds ); */
110 0 : int text2_height = 0;
111 0 : int text2_width = 0;
112 0 : if ( 0 != utf8string_get_length( data_diagram_get_name_const( diagram ) ))
113 : {
114 0 : pango_layout_set_font_description( font_layout, pencil_size_get_standard_font_description( pencil_size ) );
115 0 : pango_layout_set_text( font_layout,
116 : data_diagram_get_name_const( diagram ),
117 : DRAW_DIAGRAM_PANGO_AUTO_DETECT_LENGTH
118 : );
119 0 : pango_layout_get_pixel_size (font_layout, &text2_width, &text2_height);
120 0 : text2_height += PENCIL_SIZE_FONT_ALIGN_MARGIN; /* allow to align font with pixel border */
121 0 : text2_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
122 : }
123 :
124 0 : *out_label_dim = (geometry_dimensions_t) {
125 0 : .width = geometry_dimensions_get_width( &icon_dim ) + text1_width + f_tab_size + text2_width + f_tab_size,
126 0 : .height = u8_f64_max3( geometry_dimensions_get_height( &icon_dim ), text1_height, text2_height )
127 : };
128 : }
129 : else
130 : {
131 0 : U8_LOG_ERROR("invalid diagram in draw_diagram_label_get_type_and_name_dimensions()");
132 0 : *out_label_dim = (geometry_dimensions_t) { .width = 0.0, .height = 0.0 };
133 : }
134 0 : U8_TRACE_END();
135 0 : }
136 :
137 0 : void draw_diagram_label_draw_type_and_name ( draw_diagram_label_t *this_,
138 : const data_diagram_t *diagram,
139 : const data_profile_part_t *profile,
140 : const GdkRGBA *color,
141 : const geometry_rectangle_t *label_box,
142 : const pencil_size_t *pencil_size,
143 : PangoLayout *font_layout,
144 : cairo_t *cr )
145 : {
146 0 : U8_TRACE_BEGIN();
147 0 : assert( NULL != diagram );
148 0 : assert( NULL != profile );
149 0 : assert( NULL != color );
150 0 : assert( NULL != label_box );
151 0 : assert( NULL != pencil_size );
152 0 : assert( NULL != font_layout );
153 0 : assert( NULL != cr );
154 :
155 : /* calc bounds of stereotype icon */
156 0 : const char *const diagram_stereotype = data_diagram_get_stereotype_const( diagram );
157 : const bool has_stereotype_image
158 0 : = draw_stereotype_icon_exists( &((*this_).image_renderer), diagram_stereotype, profile );
159 0 : const geometry_rectangle_t stereotype_box
160 : = has_stereotype_image
161 0 : ? draw_stereotype_icon_get_bounds( &((*this_).image_renderer),
162 : geometry_rectangle_get_left( label_box ),
163 : geometry_rectangle_get_top( label_box ),
164 : GEOMETRY_H_ALIGN_LEFT,
165 : GEOMETRY_V_ALIGN_TOP,
166 : pencil_size
167 : )
168 0 : : (geometry_rectangle_t){ .left = 0.0, .top = 0.0, .width = 0.0, .height = 0.0 };
169 0 : const bool has_stereotype_text
170 0 : = ( ! has_stereotype_image ) && data_diagram_has_stereotype( diagram );
171 0 : const double f_tab_size = pencil_size_get_font_tab_size( pencil_size );
172 :
173 : /* draw stereotype icon */
174 0 : if ( has_stereotype_image )
175 : {
176 : u8_error_info_t err_info;
177 : const u8_error_t stereotype_err
178 0 : = draw_stereotype_icon_draw( &((*this_).image_renderer),
179 : diagram_stereotype,
180 : profile,
181 : color,
182 : &err_info,
183 : &stereotype_box,
184 : cr
185 : );
186 0 : if ( u8_error_info_is_error( &err_info ) )
187 : {
188 0 : U8_LOG_WARNING_INT( "stereotype image: unxpected token in svg path in line",
189 : u8_error_info_get_line( &err_info )
190 : );
191 : }
192 0 : else if ( stereotype_err != U8_ERROR_NONE )
193 : {
194 0 : U8_LOG_WARNING_HEX( "error at drawing stereotype image", stereotype_err );
195 : }
196 : }
197 :
198 : /* calc stereotype/type text dimensions (unless has_stereotype_image) */
199 0 : int text1_width = 0;
200 0 : int text1_height = 0;
201 0 : if ( ! has_stereotype_image )
202 : {
203 : /* prepare text */
204 0 : u8_error_t stereotype_err = U8_ERROR_NONE;
205 0 : utf8stream_writer_t *to_type = utf8stream_writemem_get_writer( &((*this_).text_builder) );
206 :
207 : /* build text */
208 0 : if ( has_stereotype_text )
209 : {
210 0 : stereotype_err |= utf8stream_writer_write_str( to_type, DRAW_DIAGRAM_LEFT_GUILLEMETS );
211 0 : stereotype_err |= utf8stream_writer_write_str( to_type, diagram_stereotype );
212 0 : stereotype_err |= utf8stream_writer_write_str( to_type, DRAW_DIAGRAM_RIGHT_GUILLEMETS );
213 0 : stereotype_err |= utf8stream_writer_flush( to_type );
214 : }
215 : else
216 : {
217 0 : const char *element_kind = data_diagram_type_get_element_kind( data_diagram_get_diagram_type( diagram ) );
218 0 : stereotype_err |= utf8stream_writer_write_str( to_type, element_kind );
219 0 : stereotype_err |= utf8stream_writer_flush( to_type );
220 : }
221 0 : const utf8stringview_t stereotype_text = utf8stream_writemem_get_view( &((*this_).text_builder) );
222 :
223 : /* determine text width and height */
224 0 : pango_layout_set_font_description( font_layout, pencil_size_get_standard_font_description( pencil_size ) );
225 0 : pango_layout_set_text( font_layout,
226 : utf8stringview_get_start( &stereotype_text ),
227 0 : utf8stringview_get_length( &stereotype_text )
228 : );
229 0 : pango_layout_get_pixel_size( font_layout, &text1_width, &text1_height );
230 0 : text1_height += PENCIL_SIZE_FONT_ALIGN_MARGIN; /* allow to align font with pixel border */
231 0 : text1_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
232 :
233 : /* draw */
234 0 : const GdkRGBA grey_color = pencil_size_get_gray_out_color( pencil_size );
235 0 : cairo_set_source_rgba( cr, grey_color.red, grey_color.green, grey_color.blue, grey_color.alpha );
236 0 : cairo_move_to( cr,
237 : ceil( geometry_rectangle_get_left( label_box ) ),
238 : ceil( geometry_rectangle_get_top( label_box ) )
239 : ); /* align font with pixel border */
240 0 : pango_cairo_show_layout( cr, font_layout );
241 0 : const GdkRGBA black_color = pencil_size_get_standard_color( pencil_size );
242 0 : cairo_set_source_rgba( cr, black_color.red, black_color.green, black_color.blue, black_color.alpha );
243 :
244 : /* cleanup the text_builder */
245 0 : stereotype_err |= utf8stream_writemem_reset( &((*this_).text_builder) );
246 0 : if ( stereotype_err != U8_ERROR_NONE )
247 : {
248 0 : U8_LOG_WARNING_HEX( "error at get_dim/draw_line_breaker_append", stereotype_err );
249 : }
250 : }
251 :
252 : /* define names for input data */
253 0 : const double text_left
254 0 : = geometry_rectangle_get_left( label_box ) + geometry_rectangle_get_width( &stereotype_box ) + text1_width + f_tab_size;
255 0 : const double text_top = geometry_rectangle_get_top( label_box );
256 :
257 : /* draw name text */
258 0 : if ( 0 != utf8string_get_length( data_diagram_get_name_const( diagram ) ))
259 : {
260 0 : cairo_set_source_rgba( cr, color->red, color->green, color->blue, color->alpha );
261 0 : pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) );
262 0 : pango_layout_set_text( font_layout,
263 : data_diagram_get_name_const( diagram ),
264 : DRAW_DIAGRAM_PANGO_AUTO_DETECT_LENGTH
265 : );
266 :
267 : /* draw text */
268 0 : cairo_move_to ( cr, ceil( text_left ), ceil( text_top ) ); /* align font with pixel border */
269 0 : pango_cairo_show_layout (cr, font_layout);
270 : }
271 :
272 0 : U8_TRACE_END();
273 0 : }
274 :
275 :
276 : /*
277 : Copyright 2017-2026 Andreas Warnke
278 : http://www.apache.org/licenses/LICENSE-2.0
279 :
280 : Licensed under the Apache License, Version 2.0 (the "License");
281 : you may not use this file except in compliance with the License.
282 : You may obtain a copy of the License at
283 :
284 :
285 : Unless required by applicable law or agreed to in writing, software
286 : distributed under the License is distributed on an "AS IS" BASIS,
287 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
288 : See the License for the specific language governing permissions and
289 : limitations under the License.
290 : */
|