Line data Source code
1 : /* File: pencil_diagram_painter.c; Copyright and License: see below */
2 :
3 : #include "pencil_diagram_painter.h"
4 : #include "u8/u8_trace.h"
5 : #include <pango/pangocairo.h>
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <assert.h>
9 :
10 0 : void pencil_diagram_painter_init( pencil_diagram_painter_t *this_ )
11 : {
12 0 : U8_TRACE_BEGIN();
13 :
14 0 : pencil_marker_init( &((*this_).marker) );
15 0 : draw_diagram_label_init( &((*this_).draw_diagram_label) );
16 0 : draw_diagram_ornaments_init( &((*this_).draw_diagram_ornaments) );
17 :
18 0 : U8_TRACE_END();
19 0 : }
20 :
21 0 : void pencil_diagram_painter_destroy( pencil_diagram_painter_t *this_ )
22 : {
23 0 : U8_TRACE_BEGIN();
24 :
25 0 : draw_diagram_ornaments_destroy( &((*this_).draw_diagram_ornaments) );
26 0 : draw_diagram_label_init( &((*this_).draw_diagram_label) );
27 0 : pencil_marker_destroy( &((*this_).marker) );
28 :
29 0 : U8_TRACE_END();
30 0 : }
31 :
32 0 : void pencil_diagram_painter_draw ( pencil_diagram_painter_t *this_,
33 : const layout_diagram_t *layouted_diagram,
34 : bool mark_focused,
35 : bool mark_highlighted,
36 : bool mark_selected,
37 : const data_profile_part_t *profile,
38 : const pencil_size_t *pencil_size,
39 : PangoLayout *font_layout,
40 : cairo_t *cr )
41 : {
42 0 : U8_TRACE_BEGIN();
43 0 : assert( NULL != layouted_diagram );
44 0 : assert( NULL != profile );
45 0 : assert( NULL != pencil_size );
46 0 : assert( NULL != font_layout );
47 0 : assert( NULL != cr );
48 :
49 0 : const data_diagram_t *const the_diagram = layout_diagram_get_data_const( layouted_diagram );
50 0 : const geometry_rectangle_t *const diagram_bounds = layout_diagram_get_bounds_const( layouted_diagram );
51 0 : const geometry_rectangle_t *const label_box = layout_diagram_get_label_box_const( layouted_diagram );
52 :
53 0 : const double left = geometry_rectangle_get_left ( diagram_bounds );
54 0 : const double top = geometry_rectangle_get_top ( diagram_bounds );
55 0 : const double right = geometry_rectangle_get_right ( diagram_bounds );
56 0 : const double bottom = geometry_rectangle_get_bottom ( diagram_bounds );
57 0 : const double width = geometry_rectangle_get_width ( diagram_bounds );
58 0 : const double height = geometry_rectangle_get_height ( diagram_bounds );
59 :
60 0 : U8_TRACE_INFO_INT( "w", (int)(width) );
61 0 : U8_TRACE_INFO_INT( "h", (int)(height) );
62 :
63 0 : const double gap = pencil_size_get_standard_object_border( pencil_size );
64 :
65 : /* draw diagram border and name */
66 : {
67 0 : U8_TRACE_INFO_INT("drawing diagram id",data_diagram_get_row_id(the_diagram));
68 :
69 0 : const double std_line_width = pencil_size_get_standard_line_width( pencil_size );
70 0 : cairo_set_line_width( cr, std_line_width );
71 0 : if ( data_diagram_is_valid(the_diagram) )
72 : {
73 : /* draw border line */
74 : const GdkRGBA fg_color
75 : = mark_highlighted
76 0 : ? pencil_size_get_highlight_color( pencil_size )
77 0 : : pencil_size_get_standard_color( pencil_size );
78 0 : cairo_set_source_rgba( cr, fg_color.red, fg_color.green, fg_color.blue, fg_color.alpha );
79 0 : cairo_rectangle ( cr, left+gap, top+gap, width-2.0*gap, height-2.0*gap );
80 0 : cairo_stroke (cr);
81 :
82 : /* draw title corner */
83 0 : draw_diagram_label_draw_type_and_name( &((*this_).draw_diagram_label),
84 : the_diagram,
85 : profile,
86 : &fg_color,
87 : label_box,
88 : pencil_size,
89 : font_layout,
90 : cr
91 : );
92 :
93 0 : const double title_corner_height = geometry_rectangle_get_height( label_box ) + 2.0 * gap;
94 0 : const double title_corner_edge45 = 0.4 * title_corner_height;
95 0 : double title_corner_width
96 0 : = geometry_rectangle_get_width( label_box ) + 3.0 * gap + title_corner_edge45;
97 0 : if ( title_corner_width > width*0.9 )
98 : {
99 0 : title_corner_width = width*0.9;
100 : }
101 0 : cairo_move_to ( cr, left+gap, top+gap+title_corner_height );
102 0 : cairo_line_to ( cr, left+gap+title_corner_width - title_corner_edge45, top+gap+title_corner_height );
103 0 : cairo_line_to ( cr, left+gap+title_corner_width, top+gap+title_corner_height-title_corner_edge45 );
104 0 : cairo_line_to ( cr, left+gap+title_corner_width, top+gap );
105 0 : cairo_stroke (cr);
106 : }
107 : else
108 : {
109 : /* draw cross line */
110 0 : const GdkRGBA standard_color = pencil_size_get_standard_color( pencil_size );
111 0 : cairo_set_source_rgba( cr, standard_color.red, standard_color.green, standard_color.blue, standard_color.alpha );
112 0 : cairo_move_to ( cr, left, top );
113 0 : cairo_line_to ( cr, right, bottom );
114 0 : cairo_move_to ( cr, left, bottom );
115 0 : cairo_line_to ( cr, right, top );
116 0 : cairo_stroke (cr);
117 : }
118 : }
119 :
120 : /* draw id */
121 : {
122 : /* prepare text */
123 0 : const data_id_t the_id = data_diagram_get_data_id(the_diagram);
124 :
125 : char id_buf[DATA_ID_MAX_UTF8STRING_SIZE+5];
126 0 : utf8stringbuf_t id_str = UTF8STRINGBUF( id_buf );
127 0 : utf8stringbuf_copy_str( &id_str, "{id=" );
128 0 : data_id_to_utf8stringbuf( &the_id, id_str );
129 0 : utf8stringbuf_append_str( &id_str, "}" );
130 :
131 : int text4_width;
132 : int text4_height;
133 0 : pango_layout_set_font_description (font_layout, pencil_size_get_footnote_font_description(pencil_size) );
134 0 : pango_layout_set_text (font_layout, utf8stringbuf_get_string( &id_str ), -1);
135 0 : pango_layout_get_pixel_size (font_layout, &text4_width, &text4_height);
136 0 : text4_height += PENCIL_SIZE_FONT_ALIGN_MARGIN; /* allow to align font with pixel border */
137 0 : text4_width += PENCIL_SIZE_FONT_ALIGN_MARGIN;
138 :
139 : /* draw text */
140 0 : const GdkRGBA grey_color = pencil_size_get_gray_out_color( pencil_size );
141 0 : cairo_set_source_rgba( cr, grey_color.red, grey_color.green, grey_color.blue, grey_color.alpha );
142 0 : cairo_move_to( cr,
143 0 : ceil( left + width - text4_width - gap - gap ),
144 : ceil( top + gap )
145 : ); /* align font with pixel border */
146 0 : pango_cairo_show_layout( cr, font_layout );
147 : }
148 :
149 : /* draw ornaments */
150 0 : if ( data_diagram_is_valid( the_diagram ) )
151 : {
152 : /* draw color */
153 : const GdkRGBA fg_color
154 : = mark_highlighted
155 0 : ? pencil_size_get_highlight_color( pencil_size )
156 0 : : pencil_size_get_standard_color( pencil_size );
157 0 : cairo_set_source_rgba( cr, fg_color.red, fg_color.green, fg_color.blue, fg_color.alpha );
158 :
159 : /* get locations */
160 0 : const geometry_rectangle_t *const diagram_draw_area = layout_diagram_get_draw_area_const( layouted_diagram );
161 0 : const double draw_left = geometry_rectangle_get_left ( diagram_draw_area );
162 0 : const double draw_bottom = geometry_rectangle_get_bottom ( diagram_draw_area );
163 0 : const double draw_width = geometry_rectangle_get_width ( diagram_draw_area );
164 :
165 0 : if ( data_diagram_get_diagram_type( the_diagram ) == DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM )
166 : {
167 0 : const double obj_dist = pencil_size_get_preferred_object_distance( pencil_size );
168 0 : const double used_draw_width = draw_width - 2.0 * obj_dist;
169 : /* const double phi = 1.6180339; */
170 0 : const double minor_ratio = (1.0 - 0.6180339);
171 0 : const double classifier_width = used_draw_width * minor_ratio / 2.0;
172 0 : const geometry_rectangle_t scale_bounds
173 0 : = { .left = draw_left + obj_dist + classifier_width + obj_dist,
174 0 : .top = draw_bottom - obj_dist,
175 0 : .width = used_draw_width - classifier_width - obj_dist,
176 : .height = obj_dist
177 : };
178 0 : draw_diagram_ornaments_draw_scale( &((*this_).draw_diagram_ornaments),
179 : &scale_bounds,
180 : pencil_size,
181 : cr
182 : );
183 : }
184 : }
185 :
186 : /* mark focused and highlighted */
187 : {
188 0 : if ( mark_focused )
189 : {
190 0 : pencil_marker_mark_focused_rectangle( &((*this_).marker), *diagram_bounds, cr );
191 : }
192 :
193 0 : if ( mark_selected )
194 : {
195 : geometry_rectangle_t selected_rect;
196 0 : geometry_rectangle_init( &selected_rect, left+gap, top+gap, width-2.0*gap, height-2.0*gap );
197 0 : pencil_marker_mark_selected_rectangle( &((*this_).marker), selected_rect, cr );
198 0 : geometry_rectangle_destroy( &selected_rect );
199 : }
200 : }
201 :
202 0 : U8_TRACE_END();
203 0 : }
204 :
205 0 : void pencil_diagram_painter_do_layout ( pencil_diagram_painter_t *this_,
206 : const data_diagram_t *the_diagram,
207 : const geometry_rectangle_t *diagram_bounds,
208 : const data_profile_part_t *profile,
209 : const pencil_size_t *pencil_size,
210 : PangoLayout *font_layout,
211 : layout_diagram_t *io_layout_diagram )
212 : {
213 0 : U8_TRACE_BEGIN();
214 0 : assert( NULL != the_diagram );
215 0 : assert( NULL != diagram_bounds );
216 0 : assert( NULL != profile );
217 0 : assert( NULL != pencil_size );
218 0 : assert( NULL != font_layout );
219 0 : assert( NULL != io_layout_diagram );
220 :
221 : /* determine diagram bounds */
222 0 : const double left = geometry_rectangle_get_left ( diagram_bounds );
223 0 : const double top = geometry_rectangle_get_top ( diagram_bounds );
224 0 : const double width = geometry_rectangle_get_width ( diagram_bounds );
225 0 : const double height = geometry_rectangle_get_height ( diagram_bounds );
226 0 : const double gap = pencil_size_get_standard_object_border( pencil_size );
227 :
228 : /* calculate label_box */
229 0 : const double text_left = left + 3.0 * gap;
230 0 : const double text_top = top + 2.0 * gap;
231 0 : const geometry_dimensions_t label_dim_proposal
232 0 : = { .width = width, .height = pencil_size_get_standard_font_size( pencil_size ) };
233 : geometry_dimensions_t label_dim;
234 0 : draw_diagram_label_get_type_and_name_dimensions( &((*this_).draw_diagram_label),
235 : the_diagram,
236 : profile,
237 : &label_dim_proposal,
238 : pencil_size,
239 : font_layout,
240 : &label_dim
241 : );
242 0 : const double text_width = geometry_dimensions_get_width( &label_dim );
243 0 : const double text_height = geometry_dimensions_get_height( &label_dim );
244 : geometry_rectangle_t label_box;
245 0 : geometry_rectangle_init( &label_box, text_left, text_top, text_width, text_height );
246 :
247 : /* calculate space */
248 0 : const double space_left = left + 2.0 * gap;
249 0 : const double space_top = top + 4.0 * gap + text_height;
250 0 : const double space_width = width - 4.0 * gap;
251 0 : const double space_height = height - 6.0 * gap - text_height;
252 : geometry_rectangle_t space;
253 0 : if ( ( space_width <= 0.0 ) || ( space_height <= 0.0 ) )
254 : {
255 0 : geometry_rectangle_init_empty( &space );
256 : }
257 : else
258 : {
259 0 : geometry_rectangle_init( &space, space_left, space_top, space_width, space_height );
260 : }
261 :
262 : /* set new metrics */
263 0 : layout_diagram_set_bounds( io_layout_diagram, diagram_bounds );
264 0 : layout_diagram_set_draw_area( io_layout_diagram, &space );
265 0 : layout_diagram_set_label_box( io_layout_diagram, &label_box );
266 :
267 0 : geometry_rectangle_destroy( &space );
268 0 : geometry_rectangle_destroy( &label_box );
269 0 : U8_TRACE_END();
270 0 : }
271 :
272 :
273 : /*
274 : Copyright 2017-2026 Andreas Warnke
275 :
276 : Licensed under the Apache License, Version 2.0 (the "License");
277 : you may not use this file except in compliance with the License.
278 : You may obtain a copy of the License at
279 :
280 : http://www.apache.org/licenses/LICENSE-2.0
281 :
282 : Unless required by applicable law or agreed to in writing, software
283 : distributed under the License is distributed on an "AS IS" BASIS,
284 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
285 : See the License for the specific language governing permissions and
286 : limitations under the License.
287 : */
|