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 "data_classifier.h"
6 : #include "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 : static const int DRAW_LABEL_PANGO_AUTO_DETECT_LENGTH = -1;
17 :
18 0 : void draw_feature_label_get_key_and_value_dimensions ( const draw_feature_label_t *this_,
19 : const data_feature_t *feature,
20 : const data_profile_part_t *profile,
21 : const geometry_dimensions_t *proposed_bounds,
22 : const pencil_size_t *pencil_size,
23 : PangoLayout *font_layout,
24 : geometry_dimensions_t *out_label_dim )
25 : {
26 0 : U8_TRACE_BEGIN();
27 0 : assert( NULL != feature );
28 0 : assert( NULL != profile );
29 0 : assert( NULL != proposed_bounds );
30 0 : assert( NULL != pencil_size );
31 0 : assert( NULL != font_layout );
32 0 : assert( NULL != out_label_dim );
33 :
34 0 : if ( data_feature_is_valid( feature ) )
35 : {
36 : /* calc stereotype image bounds */
37 0 : const char *const feature_stereotype = data_feature_get_value_const( feature );
38 : const bool has_stereotype_image
39 0 : = draw_stereotype_image_exists( &((*this_).image_renderer), feature_stereotype, profile );
40 0 : const geometry_dimensions_t icon_dim
41 : = has_stereotype_image
42 0 : ? draw_stereotype_image_get_dimensions( &((*this_).image_renderer), pencil_size )
43 0 : : (geometry_dimensions_t){ .width = 0.0, .height = 0.0 };
44 0 : const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
45 :
46 : /* draw text - except for lifelines */
47 0 : int proposed_pango_width = geometry_dimensions_get_width( proposed_bounds );
48 0 : int text_width = 0;
49 0 : int text_height = 0;
50 0 : if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type (feature) )
51 : {
52 : /* prepare text */
53 : char label_text[DATA_FEATURE_MAX_KEY_SIZE + DATA_FEATURE_MAX_VALUE_SIZE + 2 ];
54 0 : utf8stringbuf_t label_buf = UTF8STRINGBUF(label_text);
55 0 : utf8stringbuf_copy_str( label_buf, data_feature_get_key_const( feature ) );
56 0 : if ( data_feature_has_value( feature ) && ( ! has_stereotype_image ) )
57 : {
58 0 : utf8stringbuf_append_str( label_buf, ": " );
59 0 : utf8stringbuf_append_str( label_buf, data_feature_get_value_const( feature ) );
60 : }
61 :
62 : /* determine text width and height */
63 0 : pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) );
64 0 : pango_layout_set_text (font_layout, utf8stringbuf_get_string( label_buf ), DRAW_LABEL_PANGO_AUTO_DETECT_LENGTH );
65 0 : pango_layout_set_width(font_layout, proposed_pango_width * PANGO_SCALE );
66 0 : pango_layout_get_pixel_size (font_layout, &text_width, &text_height);
67 0 : text_height += PENCIL_SIZE_FONT_ALIGN_MARGIN; /* allow to align font with pixel border */
68 0 : text_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
69 : /* restore pango context */
70 0 : pango_layout_set_width(font_layout, DRAW_FEATURE_PANGO_UNLIMITED_WIDTH);
71 : }
72 :
73 0 : *out_label_dim = (geometry_dimensions_t) {
74 0 : .width = geometry_dimensions_get_width( &icon_dim ) + icon_gap + text_width,
75 0 : .height = u8_f64_max2( geometry_dimensions_get_height( &icon_dim ), text_height )
76 : };
77 : }
78 : else
79 : {
80 0 : U8_LOG_ERROR("invalid feature in draw_feature_label_get_key_and_value_dimensions()");
81 0 : *out_label_dim = (geometry_dimensions_t) { .width = 0.0, .height = 0.0 };
82 : }
83 0 : U8_TRACE_END();
84 0 : }
85 :
86 0 : void draw_feature_label_draw_key_and_value ( const draw_feature_label_t *this_,
87 : const data_feature_t *feature,
88 : const data_profile_part_t *profile,
89 : const GdkRGBA *color,
90 : const geometry_rectangle_t *label_box,
91 : const pencil_size_t *pencil_size,
92 : PangoLayout *font_layout,
93 : cairo_t *cr )
94 : {
95 0 : U8_TRACE_BEGIN();
96 0 : assert( NULL != feature );
97 0 : assert( NULL != profile );
98 0 : assert( NULL != color );
99 0 : assert( NULL != label_box );
100 0 : assert( NULL != pencil_size );
101 0 : assert( NULL != font_layout );
102 0 : assert( NULL != cr );
103 :
104 : /* calc bounds of stereotype icon */
105 0 : const char *const feature_stereotype = data_feature_get_value_const( feature );
106 : const bool has_stereotype_image
107 0 : = draw_stereotype_image_exists( &((*this_).image_renderer), feature_stereotype, profile );
108 0 : const geometry_rectangle_t stereotype_box
109 : = has_stereotype_image
110 0 : ? draw_stereotype_image_get_bounds( &((*this_).image_renderer),
111 : geometry_rectangle_get_left( label_box ),
112 : geometry_rectangle_get_top( label_box ),
113 : GEOMETRY_H_ALIGN_LEFT,
114 : GEOMETRY_V_ALIGN_TOP,
115 : pencil_size
116 : )
117 0 : : (geometry_rectangle_t){ .left = 0.0, .top = 0.0, .width = 0.0, .height = 0.0 };
118 0 : const double icon_gap = has_stereotype_image ? pencil_size_get_standard_object_border( pencil_size ) : 0.0;
119 :
120 : /* draw stereotype icon */
121 0 : if ( has_stereotype_image )
122 : {
123 : u8_error_info_t err_info;
124 : const u8_error_t stereotype_err
125 0 : = draw_stereotype_image_draw( &((*this_).image_renderer),
126 : feature_stereotype,
127 : profile,
128 : color,
129 : &err_info,
130 : &stereotype_box,
131 : cr
132 : );
133 0 : if ( u8_error_info_is_error( &err_info ) )
134 : {
135 0 : U8_LOG_WARNING_INT( "stereotype image: unxpected token in svg path in line",
136 : u8_error_info_get_line( &err_info )
137 : );
138 : }
139 0 : else if ( stereotype_err != U8_ERROR_NONE )
140 : {
141 0 : U8_LOG_WARNING_HEX( "error at drawing stereotype image", stereotype_err );
142 : }
143 : }
144 :
145 : /* define names for input data: */
146 0 : const double text_left
147 0 : = geometry_rectangle_get_left( label_box ) + geometry_rectangle_get_width( &stereotype_box ) + icon_gap;
148 0 : const double text_top = geometry_rectangle_get_top( label_box );
149 0 : const double text_width
150 0 : = geometry_rectangle_get_width( label_box ) - geometry_rectangle_get_width( &stereotype_box ) - icon_gap;
151 :
152 : /* draw text - except for lifelines */
153 0 : if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type (feature) )
154 : {
155 : /* prepare text */
156 : char label_text[DATA_FEATURE_MAX_KEY_SIZE + DATA_FEATURE_MAX_VALUE_SIZE + 2 ];
157 0 : utf8stringbuf_t label_buf = UTF8STRINGBUF(label_text);
158 0 : utf8stringbuf_copy_str( label_buf, data_feature_get_key_const( feature ) );
159 0 : if ( data_feature_has_value( feature ) && ( ! has_stereotype_image ) )
160 : {
161 0 : utf8stringbuf_append_str( label_buf, ": " );
162 0 : utf8stringbuf_append_str( label_buf, data_feature_get_value_const( feature ) );
163 : }
164 :
165 0 : const double f_size = pencil_size_get_standard_font_size( pencil_size );
166 0 : cairo_set_source_rgba( cr, color->red, color->green, color->blue, color->alpha );
167 0 : pango_layout_set_font_description (font_layout, pencil_size_get_standard_font_description(pencil_size) );
168 0 : pango_layout_set_text (font_layout, utf8stringbuf_get_string( label_buf ), DRAW_LABEL_PANGO_AUTO_DETECT_LENGTH);
169 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 */
170 :
171 : /* draw text */
172 0 : cairo_move_to ( cr, ceil( text_left ), ceil( text_top ) ); /* align font with pixel border */
173 0 : pango_cairo_show_layout (cr, font_layout);
174 :
175 : /* restore pango context */
176 0 : pango_layout_set_width(font_layout, DRAW_FEATURE_PANGO_UNLIMITED_WIDTH);
177 : }
178 :
179 0 : U8_TRACE_END();
180 0 : }
181 :
182 :
183 : /*
184 : Copyright 2017-2024 Andreas Warnke
185 : http://www.apache.org/licenses/LICENSE-2.0
186 :
187 : Licensed under the Apache License, Version 2.0 (the "License");
188 : you may not use this file except in compliance with the License.
189 : You may obtain a copy of the License at
190 :
191 :
192 : Unless required by applicable law or agreed to in writing, software
193 : distributed under the License is distributed on an "AS IS" BASIS,
194 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
195 : See the License for the specific language governing permissions and
196 : limitations under the License.
197 : */
|