Line data Source code
1 : /* File: gui_sketch_card_layouter.c; Copyright and License: see below */
2 :
3 : #include "gui_sketch_card_layouter.h"
4 : #include "sketch/gui_sketch_area.h"
5 : #include "u8/u8_trace.h"
6 : #include "u8/u8_log.h"
7 :
8 0 : void gui_sketch_card_layouter_init( gui_sketch_card_layouter_t *this_, shape_int_rectangle_t *bounds )
9 : {
10 0 : U8_TRACE_BEGIN();
11 0 : assert( NULL != bounds );
12 :
13 0 : (*this_).bounds = *bounds;
14 :
15 0 : U8_TRACE_END();
16 0 : }
17 :
18 0 : void gui_sketch_card_layouter_destroy( gui_sketch_card_layouter_t *this_ )
19 : {
20 0 : U8_TRACE_BEGIN();
21 :
22 0 : U8_TRACE_END();
23 0 : }
24 :
25 : static const uint_fast32_t RATIO_WIDTH = 36;
26 : static const uint_fast32_t RATIO_HEIGHT = 24;
27 : static const uint_fast32_t BORDER = 8;
28 :
29 0 : void gui_sketch_card_layouter_layout ( gui_sketch_card_layouter_t *this_,
30 : gui_tool_t selected_tool,
31 : gui_sketch_card_t io_cards[],
32 : uint32_t cards_num,
33 : const data_small_set_t *card_draw_list,
34 : cairo_t *cr )
35 : {
36 0 : U8_TRACE_BEGIN();
37 0 : assert( NULL != cr );
38 0 : assert( NULL != io_cards );
39 0 : assert( cards_num <= GUI_SKETCH_AREA_CONST_MAX_CARDS );
40 :
41 : /* fetch area bounds */
42 0 : const uint_fast32_t width = shape_int_rectangle_get_width( &((*this_).bounds) );
43 0 : const uint_fast32_t height = shape_int_rectangle_get_height( &((*this_).bounds) );
44 0 : const int_fast32_t left = shape_int_rectangle_get_left( &((*this_).bounds) );
45 0 : const int_fast32_t top = shape_int_rectangle_get_top( &((*this_).bounds) );
46 0 : U8_TRACE_INFO_INT_INT( "width, height", width, height );
47 :
48 : /* calculate card sizes */
49 : uint_fast32_t focus_card_height;
50 : uint_fast32_t focus_card_width;
51 : {
52 0 : const uint_fast32_t focus_card_w_space = (width * 7) / 10;
53 0 : const uint_fast32_t focus_card_h_space = (height * 4) / 10;
54 0 : if ( (focus_card_w_space * RATIO_HEIGHT) > (focus_card_h_space * RATIO_WIDTH) )
55 : {
56 0 : focus_card_height = focus_card_h_space;
57 0 : focus_card_width = (focus_card_height * RATIO_WIDTH) / RATIO_HEIGHT;
58 : }
59 : else
60 : {
61 0 : focus_card_width = focus_card_w_space;
62 0 : focus_card_height = (focus_card_width * RATIO_HEIGHT) / RATIO_WIDTH;
63 : }
64 : }
65 0 : const uint_fast32_t parent_card_height = (focus_card_height * 6) / 10;
66 0 : const uint_fast32_t parent_card_width = (focus_card_width * 6) / 10;
67 :
68 : /* layout cards */
69 0 : switch( selected_tool )
70 : {
71 0 : case GUI_TOOL_SEARCH:
72 : {
73 : shape_int_rectangle_t card_bounds;
74 :
75 : /* search results */
76 : {
77 0 : shape_int_rectangle_init( &card_bounds, left, top, width, height );
78 0 : gui_sketch_card_layouter_private_layout_to_grid( this_,
79 : &card_bounds,
80 : focus_card_height,
81 : io_cards,
82 : cards_num,
83 : cr
84 : );
85 :
86 : /* hide cards that are not on current visible page */
87 0 : for ( uint_fast32_t idx = 0; idx < cards_num; idx ++ )
88 : {
89 0 : gui_sketch_card_t* current_card = &(io_cards[idx]);
90 0 : const data_id_t diag_id = gui_sketch_card_get_diagram_id( current_card );
91 0 : const bool draw = data_small_set_contains( card_draw_list, diag_id );
92 0 : gui_sketch_card_set_visible( current_card, draw );
93 : }
94 : }
95 : }
96 0 : break;
97 :
98 0 : case GUI_TOOL_NAVIGATE:
99 : {
100 : shape_int_rectangle_t card_bounds;
101 :
102 : /* self */
103 0 : assert(cards_num > GUI_SKETCH_AREA_CONST_FOCUSED_CARD);
104 : {
105 0 : const int_fast32_t self_left = (left + width) - focus_card_width - BORDER;
106 0 : const int_fast32_t self_top = top + BORDER + (parent_card_height/2);
107 0 : shape_int_rectangle_init( &card_bounds, self_left, self_top, focus_card_width, focus_card_height );
108 0 : shape_int_rectangle_trace( &card_bounds );
109 0 : gui_sketch_card_set_bounds( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]), card_bounds );
110 0 : const bool valid_card = gui_sketch_card_is_valid( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]) );
111 0 : gui_sketch_card_do_layout( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]), cr );
112 0 : gui_sketch_card_set_visible( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]), valid_card );
113 : }
114 :
115 : /* parent */
116 0 : assert(cards_num > GUI_SKETCH_AREA_CONST_PARENT_CARD);
117 : {
118 0 : const int_fast32_t parent_left = left + BORDER;
119 0 : const int_fast32_t parent_top = top + BORDER;
120 0 : shape_int_rectangle_init( &card_bounds, parent_left, parent_top, parent_card_width, parent_card_height );
121 0 : shape_int_rectangle_trace( &card_bounds );
122 0 : gui_sketch_card_set_bounds( &(io_cards[GUI_SKETCH_AREA_CONST_PARENT_CARD]), card_bounds );
123 0 : const bool valid_parent = gui_sketch_card_is_valid( &(io_cards[GUI_SKETCH_AREA_CONST_PARENT_CARD]) );
124 0 : gui_sketch_card_do_layout( &(io_cards[GUI_SKETCH_AREA_CONST_PARENT_CARD]), cr );
125 0 : gui_sketch_card_set_visible( &(io_cards[GUI_SKETCH_AREA_CONST_PARENT_CARD]), valid_parent );
126 : }
127 :
128 : /* children */
129 0 : assert(cards_num >= GUI_SKETCH_AREA_CONST_FIRST_CHILD_CARD);
130 : {
131 0 : const int_fast32_t children_top = top + focus_card_height + (parent_card_height/2) + 2*BORDER;
132 0 : const uint_fast32_t children_height = (height > (children_top-top)) ? (height - (children_top-top)) : 0;
133 0 : shape_int_rectangle_init( &card_bounds, left, children_top, width, children_height );
134 0 : gui_sketch_card_layouter_private_layout_to_grid( this_,
135 : &card_bounds,
136 : parent_card_height,
137 : &(io_cards[GUI_SKETCH_AREA_CONST_FIRST_CHILD_CARD]),
138 0 : cards_num-GUI_SKETCH_AREA_CONST_FIRST_CHILD_CARD,
139 : cr
140 : );
141 : }
142 : }
143 0 : break;
144 :
145 0 : case GUI_TOOL_EDIT: /* or */
146 : case GUI_TOOL_CREATE:
147 : {
148 : shape_int_rectangle_t card_bounds;
149 :
150 0 : assert(cards_num == GUI_SKETCH_AREA_CONST_FOCUSED_CARD+1);
151 : {
152 0 : card_bounds = (*this_).bounds;
153 0 : shape_int_rectangle_shrink_by_border( &card_bounds, BORDER );
154 0 : shape_int_rectangle_shrink_to_ratio( &card_bounds, RATIO_WIDTH, RATIO_HEIGHT, SHAPE_H_ALIGN_CENTER, SHAPE_V_ALIGN_CENTER );
155 0 : shape_int_rectangle_trace( &card_bounds );
156 0 : gui_sketch_card_set_bounds( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]), card_bounds );
157 0 : const bool valid_card = gui_sketch_card_is_valid( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]) );
158 0 : gui_sketch_card_do_layout( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]), cr );
159 0 : gui_sketch_card_set_visible( &(io_cards[GUI_SKETCH_AREA_CONST_FOCUSED_CARD]), valid_card );
160 : }
161 : }
162 0 : break;
163 :
164 0 : default:
165 : {
166 0 : assert(false);
167 : }
168 : break;
169 : }
170 :
171 0 : U8_TRACE_END();
172 0 : }
173 :
174 0 : void gui_sketch_card_layouter_private_layout_to_grid ( gui_sketch_card_layouter_t *this_,
175 : shape_int_rectangle_t *bounds,
176 : uint_fast32_t max_card_height,
177 : gui_sketch_card_t io_cards[],
178 : uint_fast32_t cards_num,
179 : cairo_t *cr )
180 : {
181 0 : U8_TRACE_BEGIN();
182 0 : assert( NULL != cr );
183 0 : assert( NULL != bounds );
184 0 : assert( NULL != io_cards );
185 0 : assert( cards_num <= GUI_SKETCH_AREA_CONST_MAX_CARDS );
186 :
187 : /* fetch outer bounds */
188 0 : const uint_fast32_t width = shape_int_rectangle_get_width( bounds );
189 0 : const uint_fast32_t height = shape_int_rectangle_get_height( bounds );
190 0 : const int_fast32_t left = shape_int_rectangle_get_left( bounds );
191 0 : const int_fast32_t top = shape_int_rectangle_get_top( bounds );
192 :
193 : /* determine number of columns and rows for layout */
194 0 : uint_fast32_t cols = 0; /* initial value, overwritten if a card exists */
195 0 : uint_fast32_t rows = 0; /* initial value, overwritten if a card exists */
196 0 : uint_fast32_t card_width = 0; /* initial value, overwritten if a card exists */
197 0 : uint_fast32_t card_height = 0; /* initial value, overwritten if a card exists */
198 : {
199 0 : for ( uint_fast32_t probe_rows = 1; probe_rows <= cards_num; probe_rows ++ )
200 : {
201 0 : assert( probe_rows > 0 );
202 0 : uint_fast32_t probe_cols = (cards_num + probe_rows - 1) / probe_rows;
203 : shape_int_rectangle_t probe_bounds;
204 0 : shape_int_rectangle_init( &probe_bounds, 0, 0, ((width*2)/((probe_cols*2)+1)), height/probe_rows );
205 0 : shape_int_rectangle_shrink_by_border( &probe_bounds, BORDER );
206 0 : shape_int_rectangle_shrink_to_ratio( &probe_bounds, RATIO_WIDTH, RATIO_HEIGHT, SHAPE_H_ALIGN_LEFT, SHAPE_V_ALIGN_TOP );
207 0 : if ( card_height <= shape_int_rectangle_get_height( &probe_bounds ) )
208 : {
209 0 : cols = probe_cols;
210 0 : rows = probe_rows;
211 0 : card_width = shape_int_rectangle_get_width( &probe_bounds );
212 0 : card_height = shape_int_rectangle_get_height( &probe_bounds );
213 : }
214 : }
215 : }
216 :
217 : /* children shall not be bigger than the parent */
218 0 : if ( card_height > max_card_height )
219 : {
220 0 : assert( card_height > 0 );
221 0 : card_width = ( card_width * max_card_height ) / card_height;
222 0 : card_height = max_card_height;
223 : }
224 :
225 : /* layout cards to grid */
226 0 : for ( uint_fast32_t y = 0; y < rows; y ++ )
227 : {
228 0 : for ( uint_fast32_t x = 0; x < cols; x ++ )
229 : {
230 0 : uint_fast32_t card_idx = (y * cols) + x;
231 0 : if ( card_idx < cards_num )
232 : {
233 0 : assert( rows > 0 );
234 0 : const uint_fast32_t left_grid_gap = (cols==1) ? 0 : ((card_width*y)/(2*rows)); /* this gap is beautification only */
235 0 : const int_fast32_t rel_left = left_grid_gap + BORDER + (x * ( card_width + BORDER + BORDER ));
236 0 : const int_fast32_t rel_top = BORDER + (y * ( card_height + BORDER + BORDER ));
237 : shape_int_rectangle_t card_bounds;
238 0 : shape_int_rectangle_init( &card_bounds, left+rel_left, top+rel_top, card_width, card_height );
239 0 : shape_int_rectangle_trace( &card_bounds );
240 0 : gui_sketch_card_set_bounds( &(io_cards[card_idx]), card_bounds );
241 0 : const bool valid_card = gui_sketch_card_is_valid( &(io_cards[card_idx]) );
242 0 : gui_sketch_card_do_layout( &(io_cards[card_idx]), cr );
243 0 : gui_sketch_card_set_visible( &(io_cards[card_idx]), valid_card );
244 : }
245 : }
246 : }
247 :
248 0 : U8_TRACE_END();
249 0 : }
250 :
251 :
252 : /*
253 : Copyright 2019-2025 Andreas Warnke
254 :
255 : Licensed under the Apache License, Version 2.0 (the "License");
256 : you may not use this file except in compliance with the License.
257 : You may obtain a copy of the License at
258 :
259 : http://www.apache.org/licenses/LICENSE-2.0
260 :
261 : Unless required by applicable law or agreed to in writing, software
262 : distributed under the License is distributed on an "AS IS" BASIS,
263 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
264 : See the License for the specific language governing permissions and
265 : limitations under the License.
266 : */
267 :
|