1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "grid.h"
30
31 #include "../../ucx/cx/array_list.h"
32 #include "../common/context.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 UiGridLayout* ui_grid_layout_create(
const CxAllocator *a,
short columnspacing,
short rowspacing) {
38 UiGridLayout *grid = cxZalloc(a,
sizeof(UiGridLayout));
39 grid->widgets = cxArrayListCreate(a,
NULL,
sizeof(GridElm),
32);
40 grid->columnspacing = columnspacing;
41 grid->rowspacing = rowspacing;
42 return grid;
43 }
44
45 void ui_grid_add_widget(
46 UiGridLayout *grid,
47 short x,
48 short y,
49 W32Widget *widget,
50 GridLayoutInfo *layout)
51 {
52
53 GridElm elm;
54 elm.widget = widget;
55 elm.gridx = x;
56 elm.gridy = y;
57 elm.layout = *layout;
58 cxListAdd(grid->widgets, &elm);
59
60
61 if (x > grid->max_column) {
62 grid->max_column = x;
63 }
64 if (y > grid->max_row) {
65 grid->max_row = y;
66 }
67 }
68
69 void ui_grid_layout(UiGridLayout *grid,
int width,
int height) {
70 if (width ==
0 || height ==
0) {
71 return;
72 }
73
74 int ncols = grid->max_column
+1;
75 int nrows = grid->max_row
+1;
76
77 GridDef *cols = calloc(ncols,
sizeof(GridDef));
78 GridDef *rows = calloc(nrows,
sizeof(GridDef));
79
80 int colspacing = grid->columnspacing;
81 int rowspacing = grid->rowspacing;
82
83 int span_max =
1;
84 for(
int r=
0;r<
2;r++) {
85 CxIterator i = cxListIterator(grid->widgets);
86 cx_foreach(GridElm *, elm, i) {
87 int x = elm->gridx;
88 int y = elm->gridy;
89 GridDef *col = &cols[x];
90 GridDef *row = &rows[y];
91
92 W32Size size = w32_widget_get_preferred_size(elm->widget);
93 elm->layout.preferred_width = size.width;
94 elm->layout.preferred_height = size.height;
95
96 int elm_width = size.width + elm->layout.margin.left + elm->layout.margin.right;
97 if(elm_width > cols[elm->gridx].preferred_size && elm->layout.colspan <=
1 && span_max ==
1) {
98 cols[elm->gridx].preferred_size = elm_width;
99 }
100 int elm_height = size.height + elm->layout.margin.top + elm->layout.margin.bottom;
101 if(elm_height > rows[elm->gridy].preferred_size && elm->layout.rowspan <=
1 && span_max ==
1) {
102 rows[elm->gridy].preferred_size = elm_height;
103 }
104
105 if(elm->layout.rowspan > span_max || elm->layout.colspan > span_max) {
106 continue;
107 }
108
109 int end_col = x+elm->layout.colspan;
110 if(end_col > ncols) {
111 end_col = ncols;
112 }
113 int end_row = y+elm->layout.rowspan;
114 if(end_row > nrows) {
115 end_row = nrows;
116 }
117
118
119 if(elm->layout.colspan >
1) {
120 int span_width =
0;
121 GridDef *last_col = col;
122 for(
int c=x;c<end_col;c++) {
123 span_width += cols[c].size;
124 last_col = &cols[c];
125 }
126 if(span_width < elm->layout.preferred_width) {
127 last_col->size += elm->layout.preferred_width - span_width;
128 }
129 }
130
131
132 if(elm->layout.rowspan >
1) {
133 int span_height =
0;
134 GridDef *last_row = row;
135 for(
int c=x;c<end_row;c++) {
136 span_height += rows[c].size;
137 last_row = &rows[c];
138 }
139 if(span_height < elm->layout.preferred_height) {
140 last_row->size += elm->layout.preferred_height - span_height;
141 }
142 }
143
144 if(elm->layout.hexpand) {
145 if(elm->layout.colspan >
1) {
146
147
148 GridDef *last_col = col;
149 for(
int c=x;c<end_col;c++) {
150 last_col = &cols[c];
151 if(last_col->expand) {
152 break;
153 }
154 }
155 last_col->expand =
TRUE;
156 }
else {
157 col->expand =
TRUE;
158 }
159 }
160 if(elm->layout.vexpand) {
161 if(elm->layout.rowspan >
1) {
162
163 GridDef *last_row = row;
164 for(
int c=x;c<nrows;c++) {
165 last_row = &rows[c];
166 if(last_row->expand) {
167 break;
168 }
169 }
170 last_row->expand =
TRUE;
171 }
else {
172 row->expand =
TRUE;
173 }
174 }
175 }
176 span_max =
50000;
177 }
178
179 int col_ext =
0;
180 int row_ext =
0;
181
182 int preferred_width =
0;
183 int preferred_height =
0;
184 for(
int j=
0;j<ncols;j++) {
185 preferred_width += cols[j].preferred_size;
186 if(cols[j].expand) {
187 col_ext++;
188 }
189 }
190 for(
int j=
0;j<nrows;j++) {
191 preferred_height += rows[j].preferred_size;
192 if(rows[j].expand) {
193 row_ext++;
194 }
195 }
196 if(ncols >
0) {
197 preferred_width += (ncols
-1) * colspacing;
198 }
199 if(nrows >
0) {
200 preferred_height += (nrows
-1) * rowspacing;
201 }
202
203 grid->preferred_width = preferred_width;
204 grid->preferred_height = preferred_height;
205
206 int hremaining = width - preferred_width;
207 int vremaining = height - preferred_height;
208 int hext = col_ext >
0 ? hremaining/col_ext :
0;
209 int vext = row_ext >
0 ? vremaining/row_ext :
0;
210
211 for(
int j=
0;j<ncols;j++) {
212 GridDef *col = &cols[j];
213 if(col->expand) {
214 col->size = col->preferred_size + hext;
215 }
else {
216 col->size = col->preferred_size;
217 }
218 }
219 for(
int j=
0;j<nrows;j++) {
220 GridDef *row = &rows[j];
221 if(row->expand) {
222 row->size = row->preferred_size + vext;
223 }
else {
224 row->size = row->preferred_size;
225 }
226 }
227
228 int pos =
0;
229 for(
int j=
0;j<ncols;j++) {
230 cols[j].pos = pos;
231 pos += cols[j].size + colspacing;
232 }
233 pos =
0;
234 for(
int j=
0;j<nrows;j++) {
235 rows[j].pos = pos;
236 pos += rows[j].size + rowspacing;
237 }
238
239 CxIterator i = cxListIterator(grid->widgets);
240 cx_foreach(GridElm *, elm, i) {
241 GridDef *col = &cols[elm->gridx];
242 GridDef *row = &rows[elm->gridy];
243
244 int child_width =
0;
245 int child_height =
0;
246 int child_x =
0;
247 int child_y =
0;
248 if(elm->layout.hfill) {
249 if(elm->layout.colspan >
1) {
250 int cwidth =
0;
251 int end_col = elm->gridx + elm->layout.colspan;
252 if(end_col > ncols) {
253 end_col = ncols;
254 }
255 int real_span =
0;
256 for(
int c=elm->gridx;c<end_col;c++) {
257 cwidth += cols[c].size;
258 real_span++;
259 }
260 if(real_span >
0) {
261 cwidth += (real_span
-1) * colspacing;
262 }
263 child_width = cwidth;
264 }
else {
265 child_width = col->size;
266 }
267 child_width -= elm->layout.margin.left + elm->layout.margin.right;
268 }
else {
269 child_width = elm->layout.preferred_width;
270 }
271
272 if(elm->layout.vfill) {
273 if(elm->layout.rowspan >
1) {
274 int rheight =
0;
275 int end_row = elm->gridy + elm->layout.rowspan;
276 if(end_row > nrows) {
277 end_row = nrows;
278 }
279 int real_span =
0;
280 for(
int r=elm->gridy;r<end_row;r++) {
281 rheight += rows[r].size;
282 real_span++;
283 }
284 if(real_span >
0) {
285 rheight += (real_span
-1) * rowspacing;
286 }
287 child_height = rheight;
288 }
289 child_height = row->size - elm->layout.margin.top - elm->layout.margin.bottom;
290 }
else {
291 child_height = elm->layout.preferred_height;
292 }
293
294 child_x = col->pos + elm->layout.margin.left;
295 child_y = row->pos + elm->layout.margin.top;
296 SetWindowPos(elm->widget->hwnd,
NULL, child_x, child_y, child_width, child_height,
SWP_NOZORDER |
SWP_NOACTIVATE);
297 InvalidateRect(elm->widget->hwnd,
NULL,
TRUE);
298
299 if (elm->widget->layout) {
300 elm->widget->layout(elm->widget->layoutmanager, child_width, child_height);
301 }
302 }
303
304 free(cols);
305 free(rows);
306 }
307