Line data Source code
1 : /* File: pencil_feat_label_layouter.c; Copyright and License: see below */
2 :
3 : #include "pencil_feat_label_layouter.h"
4 : #include "u8/u8_trace.h"
5 : #include "utf8stringbuf/utf8string.h"
6 :
7 0 : void pencil_feat_label_layouter_init( pencil_feat_label_layouter_t *this_,
8 : layout_visible_set_t *layout_data,
9 : const data_profile_part_t *profile,
10 : const pencil_size_t *pencil_size )
11 : {
12 0 : U8_TRACE_BEGIN();
13 0 : assert( NULL != layout_data );
14 0 : assert( NULL != profile );
15 0 : assert( NULL != pencil_size );
16 :
17 0 : (*this_).layout_data = layout_data;
18 0 : (*this_).profile = profile;
19 0 : (*this_).pencil_size = pencil_size;
20 0 : draw_feature_label_init( &((*this_).draw_feature_label) );
21 0 : pencil_label_layout_helper_init ( &((*this_).label_layout_helper) );
22 :
23 0 : U8_TRACE_END();
24 0 : }
25 :
26 0 : void pencil_feat_label_layouter_reinit( pencil_feat_label_layouter_t *this_,
27 : layout_visible_set_t *layout_data,
28 : const data_profile_part_t *profile,
29 : const pencil_size_t *pencil_size )
30 : {
31 0 : U8_TRACE_BEGIN();
32 0 : assert( NULL != layout_data );
33 0 : assert( NULL != profile );
34 0 : assert( NULL != pencil_size );
35 :
36 0 : (*this_).layout_data = layout_data;
37 0 : (*this_).profile = profile;
38 0 : (*this_).pencil_size = pencil_size;
39 :
40 0 : U8_TRACE_END();
41 0 : }
42 :
43 0 : void pencil_feat_label_layouter_destroy( pencil_feat_label_layouter_t *this_ )
44 : {
45 0 : U8_TRACE_BEGIN();
46 :
47 0 : pencil_label_layout_helper_destroy ( &((*this_).label_layout_helper) );
48 0 : draw_feature_label_destroy( &((*this_).draw_feature_label) );
49 :
50 0 : U8_TRACE_END();
51 0 : }
52 :
53 0 : void pencil_feat_label_layouter_do_layout ( pencil_feat_label_layouter_t *this_, PangoLayout *font_layout )
54 : {
55 0 : U8_TRACE_BEGIN();
56 : assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) LAYOUT_VISIBLE_SET_MAX_FEATURES );
57 0 : assert( NULL != font_layout );
58 :
59 : universal_array_index_sorter_t sorted;
60 0 : universal_array_index_sorter_init( &sorted );
61 :
62 : /* sort the features by their label-box layouting needs, drop invisible relations */
63 0 : pencil_feat_label_layouter_private_propose_processing_order ( this_, &sorted );
64 :
65 : /* layout the features label-boxes */
66 : const uint32_t count_sorted
67 0 : = universal_array_index_sorter_get_count( &sorted );
68 0 : for ( uint32_t sort_index = 0; sort_index < count_sorted; sort_index ++ )
69 : {
70 : /* determine pointer to feature */
71 : const uint32_t index
72 0 : = universal_array_index_sorter_get_array_index( &sorted, sort_index );
73 : layout_feature_t *current_feature;
74 0 : current_feature = layout_visible_set_get_feature_ptr( (*this_).layout_data, index );
75 0 : geometry_point_t feature_middle = layout_feature_get_symbol_middle ( current_feature );
76 :
77 : /* declaration of list of options */
78 0 : uint32_t solutions_count = 0;
79 : static const uint32_t SOLUTIONS_MAX = 8;
80 : geometry_rectangle_t solution[8];
81 :
82 : /* propose options */
83 0 : pencil_feat_label_layouter_private_propose_solutions ( this_,
84 : current_feature,
85 : font_layout,
86 : SOLUTIONS_MAX,
87 : solution,
88 : &solutions_count
89 : );
90 :
91 : /* select best option */
92 : uint32_t index_of_best;
93 0 : if ( 1 == solutions_count )
94 : {
95 0 : index_of_best = 0;
96 : }
97 : else
98 : {
99 0 : pencil_label_layout_helper_select_solution ( &((*this_).label_layout_helper),
100 : (*this_).layout_data,
101 : feature_middle,
102 : solutions_count,
103 : solution,
104 : &index_of_best
105 : );
106 : }
107 :
108 : /* store best option to (*this_).layout_data */
109 0 : layout_feature_set_label_box( current_feature, &(solution[index_of_best]) );
110 : }
111 :
112 0 : universal_array_index_sorter_destroy( &sorted );
113 :
114 0 : U8_TRACE_END();
115 0 : }
116 :
117 0 : void pencil_feat_label_layouter_private_propose_processing_order ( pencil_feat_label_layouter_t *this_, universal_array_index_sorter_t *out_sorted )
118 : {
119 0 : U8_TRACE_BEGIN();
120 0 : assert( NULL != out_sorted );
121 :
122 : /* sort the features by their label-box: the less simple, the earlier it shall be processed */
123 : const uint32_t count_features
124 0 : = layout_visible_set_get_feature_count ( (*this_).layout_data );
125 0 : for ( uint32_t index = 0; index < count_features; index ++ )
126 : {
127 : const layout_feature_t *const current_feature
128 0 : = layout_visible_set_get_feature_ptr ( (*this_).layout_data, index );
129 0 : const data_feature_t *const feature_data = layout_feature_get_data_const ( current_feature );
130 0 : assert( NULL != feature_data );
131 0 : const data_feature_type_t current_type = data_feature_get_main_type( feature_data );
132 :
133 0 : int64_t simpleness = 0;
134 :
135 : /* determine simpleness by length of label */
136 0 : simpleness -= utf8string_get_length( data_feature_get_key_const( feature_data ) );
137 0 : simpleness -= utf8string_get_length( data_feature_get_value_const( feature_data ) );
138 :
139 : /* do the properties and operations first, they have a fixed positiion given by the classifier */
140 0 : if ( ! data_feature_type_outside_compartment( current_type ) )
141 : {
142 0 : simpleness = -100000;
143 : }
144 :
145 : /* insert relation to sorted array - except for lifelines which have no label */
146 0 : if ( DATA_FEATURE_TYPE_LIFELINE != current_type )
147 : {
148 : const int insert_error
149 0 : = universal_array_index_sorter_insert( out_sorted, index, simpleness );
150 0 : if ( 0 != insert_error )
151 : {
152 0 : U8_LOG_WARNING( "not all relationship label-boxes are layouted" );
153 : }
154 : }
155 : }
156 :
157 0 : U8_TRACE_END();
158 0 : }
159 :
160 0 : void pencil_feat_label_layouter_private_propose_solutions ( pencil_feat_label_layouter_t *this_,
161 : layout_feature_t *current_feature,
162 : PangoLayout *font_layout,
163 : uint32_t solutions_max,
164 : geometry_rectangle_t out_solutions[],
165 : uint32_t *out_solutions_count )
166 : {
167 0 : U8_TRACE_BEGIN();
168 0 : assert( NULL != current_feature );
169 0 : assert( NULL != font_layout );
170 0 : assert( NULL != out_solutions );
171 0 : assert( NULL != out_solutions_count );
172 :
173 0 : const data_feature_t *feature_data = layout_feature_get_data_const ( current_feature );
174 0 : assert( NULL != feature_data );
175 0 : const data_feature_type_t current_type = data_feature_get_main_type( feature_data );
176 :
177 0 : if ( data_feature_type_inside_compartment( current_type ) )
178 : {
179 : /* the label-box is already calculated by pencil_feature_layouter_do_layout() */
180 : /* which is called before pencil_feat_label_layouter_do_layout() */
181 0 : assert( solutions_max >= 1 );
182 0 : geometry_rectangle_copy( &(out_solutions[0]), layout_feature_get_label_box_const ( current_feature ) );
183 0 : *out_solutions_count = 1;
184 : }
185 : else
186 : {
187 : /* key and value dimensions */
188 0 : const geometry_dimensions_t label_dim_proposal = {
189 0 : .width = 25.0 * pencil_size_get_standard_font_size( (*this_).pencil_size ),
190 0 : .height = pencil_size_get_standard_font_size( (*this_).pencil_size )
191 : };
192 : geometry_dimensions_t label_dim;
193 0 : draw_feature_label_get_key_and_value_dimensions( &((*this_).draw_feature_label),
194 : feature_data,
195 : (*this_).profile,
196 : &label_dim_proposal,
197 : (*this_).pencil_size,
198 : font_layout,
199 : &label_dim
200 : );
201 0 : const double text_width = geometry_dimensions_get_width( &label_dim );
202 0 : const double text_height = geometry_dimensions_get_height( &label_dim );
203 0 : const double half_width = text_width/2.0;
204 0 : const double half_height = text_height/2.0;
205 :
206 0 : const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
207 0 : const geometry_rectangle_t *const bounds = layout_feature_get_symbol_box_const ( current_feature );
208 0 : const double left = geometry_rectangle_get_left( bounds );
209 0 : const double top = geometry_rectangle_get_top( bounds );
210 0 : const double center_x = geometry_rectangle_get_center_x( bounds );
211 0 : const double center_y = geometry_rectangle_get_center_y( bounds );
212 0 : const double bottom = geometry_rectangle_get_bottom( bounds );
213 0 : const double right = geometry_rectangle_get_right( bounds );
214 :
215 0 : assert( solutions_max >= 8 );
216 : /* top */
217 0 : geometry_rectangle_init( &(out_solutions[0]),
218 : center_x - half_width,
219 0 : top - text_height - gap,
220 : text_width,
221 : text_height
222 : );
223 : /* bottom */
224 0 : geometry_rectangle_init( &(out_solutions[1]),
225 : center_x - half_width,
226 : bottom + gap,
227 : text_width,
228 : text_height
229 : );
230 : /* left */
231 0 : geometry_rectangle_init( &(out_solutions[2]),
232 0 : left - text_width - gap,
233 : center_y - half_height,
234 : text_width,
235 : text_height
236 : );
237 : /* right */
238 0 : geometry_rectangle_init( &(out_solutions[3]),
239 : right + gap,
240 : center_y - half_height,
241 : text_width,
242 : text_height
243 : );
244 : /* top-left */
245 0 : geometry_rectangle_init( &(out_solutions[4]),
246 : left - text_width,
247 : top - text_height,
248 : text_width,
249 : text_height
250 : );
251 : /* top-right */
252 0 : geometry_rectangle_init( &(out_solutions[5]),
253 : right,
254 : top - text_height,
255 : text_width,
256 : text_height
257 : );
258 : /* bottom-left */
259 0 : geometry_rectangle_init( &(out_solutions[6]),
260 : left - text_width,
261 : bottom,
262 : text_width,
263 : text_height
264 : );
265 : /* bottom-right */
266 0 : geometry_rectangle_init( &(out_solutions[7]),
267 : right,
268 : bottom,
269 : text_width,
270 : text_height
271 : );
272 0 : *out_solutions_count = 8;
273 : }
274 :
275 0 : U8_TRACE_END();
276 0 : }
277 :
278 :
279 : /*
280 : * Copyright 2019-2024 Andreas Warnke
281 : *
282 : * Licensed under the Apache License, Version 2.0 (the "License");
283 : * you may not use this file except in compliance with the License.
284 : * You may obtain a copy of the License at
285 : *
286 : * http://www.apache.org/licenses/LICENSE-2.0
287 : *
288 : * Unless required by applicable law or agreed to in writing, software
289 : * distributed under the License is distributed on an "AS IS" BASIS,
290 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
291 : * See the License for the specific language governing permissions and
292 : * limitations under the License.
293 : */
|