ui/win32/grid.c

changeset 112
c3f2f16fa4b8
parent 108
77254bd6dccb
equal deleted inserted replaced
111:81c4f73236a4 112:c3f2f16fa4b8
29 #include "grid.h" 29 #include "grid.h"
30 30
31 #include "../../ucx/cx/array_list.h" 31 #include "../../ucx/cx/array_list.h"
32 #include "../common/context.h" 32 #include "../common/context.h"
33 33
34 UiGridLayout* ui_grid_container(UiObject *obj, HWND control, short padding, short columnspacing, short rowspacing) { 34 #include <stdio.h>
35 UiGridLayout *grid = cxZalloc(obj->ctx->allocator, sizeof(UiGridLayout)); 35 #include <stdlib.h>
36 grid->hwnd = control; 36
37 grid->widgets = cxArrayListCreate(obj->ctx->allocator, NULL, sizeof(GridElm), 32); 37 UiGridLayout* ui_grid_layout_create(const CxAllocator *a, short columnspacing, short rowspacing) {
38 grid->padding = padding; 38 UiGridLayout *grid = cxZalloc(a, sizeof(UiGridLayout));
39 grid->widgets = cxArrayListCreate(a, NULL, sizeof(GridElm), 32);
39 grid->columnspacing = columnspacing; 40 grid->columnspacing = columnspacing;
40 grid->rowspacing = rowspacing; 41 grid->rowspacing = rowspacing;
41 return grid; 42 return grid;
42 } 43 }
43 44
46 short x, 47 short x,
47 short y, 48 short y,
48 W32Widget *widget, 49 W32Widget *widget,
49 GridLayoutInfo *layout) 50 GridLayoutInfo *layout)
50 { 51 {
52 // add the widget
51 GridElm elm; 53 GridElm elm;
52 elm.widget = widget; 54 elm.widget = widget;
53 elm.x = x; 55 elm.gridx = x;
54 elm.y = y; 56 elm.gridy = y;
55 elm.layout = *layout; 57 elm.layout = *layout;
56 cxListAdd(grid->widgets, elm); 58 cxListAdd(grid->widgets, &elm);
59
60 // adjust max col/row count
61 if (x > grid->max_column) {
62 grid->max_column = x;
63 }
64 if (y > grid->max_row) {
65 grid->max_row = y;
66 }
57 } 67 }
58 68
59 void ui_grid_layout(UiGridLayout *grid) { 69 void ui_grid_layout(UiGridLayout *grid, int width, int height) {
60 // TODO 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 // are all columns in the span > preferred_width?
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 // are all rows in the span > preferred_height?
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 // check if any column in the span is expanding
147 // if not, make the last column expanding
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 // same as colspan
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; // not sure if this is unreasonable low or high
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);
297 if (elm->widget->layout) {
298 elm->widget->layout(elm->widget->layoutmanager, child_width, child_height);
299 }
300 }
301
302 free(cols);
303 free(rows);
61 } 304 }

mercurial