diff -r 81c4f73236a4 -r c3f2f16fa4b8 ui/win32/grid.c --- a/ui/win32/grid.c Sat Oct 04 14:54:25 2025 +0200 +++ b/ui/win32/grid.c Sun Oct 19 21:20:08 2025 +0200 @@ -31,11 +31,12 @@ #include "../../ucx/cx/array_list.h" #include "../common/context.h" -UiGridLayout* ui_grid_container(UiObject *obj, HWND control, short padding, short columnspacing, short rowspacing) { - UiGridLayout *grid = cxZalloc(obj->ctx->allocator, sizeof(UiGridLayout)); - grid->hwnd = control; - grid->widgets = cxArrayListCreate(obj->ctx->allocator, NULL, sizeof(GridElm), 32); - grid->padding = padding; +#include +#include + +UiGridLayout* ui_grid_layout_create(const CxAllocator *a, short columnspacing, short rowspacing) { + UiGridLayout *grid = cxZalloc(a, sizeof(UiGridLayout)); + grid->widgets = cxArrayListCreate(a, NULL, sizeof(GridElm), 32); grid->columnspacing = columnspacing; grid->rowspacing = rowspacing; return grid; @@ -48,14 +49,256 @@ W32Widget *widget, GridLayoutInfo *layout) { + // add the widget GridElm elm; elm.widget = widget; - elm.x = x; - elm.y = y; + elm.gridx = x; + elm.gridy = y; elm.layout = *layout; - cxListAdd(grid->widgets, elm); + cxListAdd(grid->widgets, &elm); + + // adjust max col/row count + if (x > grid->max_column) { + grid->max_column = x; + } + if (y > grid->max_row) { + grid->max_row = y; + } } -void ui_grid_layout(UiGridLayout *grid) { - // TODO +void ui_grid_layout(UiGridLayout *grid, int width, int height) { + if (width == 0 || height == 0) { + return; + } + + int ncols = grid->max_column+1; + int nrows = grid->max_row+1; + + GridDef *cols = calloc(ncols, sizeof(GridDef)); + GridDef *rows = calloc(nrows, sizeof(GridDef)); + + int colspacing = grid->columnspacing; + int rowspacing = grid->rowspacing; + + int span_max = 1; + for(int r=0;r<2;r++) { + CxIterator i = cxListIterator(grid->widgets); + cx_foreach(GridElm *, elm, i) { + int x = elm->gridx; + int y = elm->gridy; + GridDef *col = &cols[x]; + GridDef *row = &rows[y]; + + W32Size size = w32_widget_get_preferred_size(elm->widget); + elm->layout.preferred_width = size.width; + elm->layout.preferred_height = size.height; + + int elm_width = size.width + elm->layout.margin.left + elm->layout.margin.right; + if(elm_width > cols[elm->gridx].preferred_size && elm->layout.colspan <= 1 && span_max == 1) { + cols[elm->gridx].preferred_size = elm_width; + } + int elm_height = size.height + elm->layout.margin.top + elm->layout.margin.bottom; + if(elm_height > rows[elm->gridy].preferred_size && elm->layout.rowspan <= 1 && span_max == 1) { + rows[elm->gridy].preferred_size = elm_height; + } + + if(elm->layout.rowspan > span_max || elm->layout.colspan > span_max) { + continue; + } + + int end_col = x+elm->layout.colspan; + if(end_col > ncols) { + end_col = ncols; + } + int end_row = y+elm->layout.rowspan; + if(end_row > nrows) { + end_row = nrows; + } + + // are all columns in the span > preferred_width? + if(elm->layout.colspan > 1) { + int span_width = 0; + GridDef *last_col = col; + for(int c=x;clayout.preferred_width) { + last_col->size += elm->layout.preferred_width - span_width; + } + } + + // are all rows in the span > preferred_height? + if(elm->layout.rowspan > 1) { + int span_height = 0; + GridDef *last_row = row; + for(int c=x;clayout.preferred_height) { + last_row->size += elm->layout.preferred_height - span_height; + } + } + + if(elm->layout.hexpand) { + if(elm->layout.colspan > 1) { + // check if any column in the span is expanding + // if not, make the last column expanding + GridDef *last_col = col; + for(int c=x;cexpand) { + break; + } + } + last_col->expand = TRUE; + } else { + col->expand = TRUE; + } + } + if(elm->layout.vexpand) { + if(elm->layout.rowspan > 1) { + // same as colspan + GridDef *last_row = row; + for(int c=x;cexpand) { + break; + } + } + last_row->expand = TRUE; + } else { + row->expand = TRUE; + } + } + } + span_max = 50000; // not sure if this is unreasonable low or high + } + + int col_ext = 0; + int row_ext = 0; + + int preferred_width = 0; + int preferred_height = 0; + for(int j=0;j 0) { + preferred_width += (ncols-1) * colspacing; + } + if(nrows > 0) { + preferred_height += (nrows-1) * rowspacing; + } + + grid->preferred_width = preferred_width; + grid->preferred_height = preferred_height; + + int hremaining = width - preferred_width; + int vremaining = height - preferred_height; + int hext = col_ext > 0 ? hremaining/col_ext : 0; + int vext = row_ext > 0 ? vremaining/row_ext : 0; + + for(int j=0;jexpand) { + col->size = col->preferred_size + hext; + } else { + col->size = col->preferred_size; + } + } + for(int j=0;jexpand) { + row->size = row->preferred_size + vext; + } else { + row->size = row->preferred_size; + } + } + + int pos = 0; + for(int j=0;jwidgets); + cx_foreach(GridElm *, elm, i) { + GridDef *col = &cols[elm->gridx]; + GridDef *row = &rows[elm->gridy]; + + int child_width = 0; + int child_height = 0; + int child_x = 0; + int child_y = 0; + if(elm->layout.hfill) { + if(elm->layout.colspan > 1) { + int cwidth = 0; + int end_col = elm->gridx + elm->layout.colspan; + if(end_col > ncols) { + end_col = ncols; + } + int real_span = 0; + for(int c=elm->gridx;c 0) { + cwidth += (real_span-1) * colspacing; + } + child_width = cwidth; + } else { + child_width = col->size; + } + child_width -= elm->layout.margin.left + elm->layout.margin.right; + } else { + child_width = elm->layout.preferred_width; + } + + if(elm->layout.vfill) { + if(elm->layout.rowspan > 1) { + int rheight = 0; + int end_row = elm->gridy + elm->layout.rowspan; + if(end_row > nrows) { + end_row = nrows; + } + int real_span = 0; + for(int r=elm->gridy;r 0) { + rheight += (real_span-1) * rowspacing; + } + child_height = rheight; + } + child_height = row->size - elm->layout.margin.top - elm->layout.margin.bottom; + } else { + child_height = elm->layout.preferred_height; + } + + child_x = col->pos + elm->layout.margin.left; + child_y = row->pos + elm->layout.margin.top; + SetWindowPos(elm->widget->hwnd, NULL, child_x, child_y, child_width, child_height, SWP_NOZORDER); + if (elm->widget->layout) { + elm->widget->layout(elm->widget->layoutmanager, child_width, child_height); + } + } + + free(cols); + free(rows); }