UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2025 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "container.h" 30 #include "grid.h" 31 32 #include "../common/context.h" 33 #include "../common/container.h" 34 #include "../motif/container.h" 35 36 37 static W32WidgetClass grid_layout_widget_class = { 38 .eventproc = ui_grid_widget_event, 39 .enable = NULL, 40 .show = w32_widget_default_show, 41 .get_preferred_size = ui_grid_layout_get_preferred_size, 42 .destroy = w32_widget_default_destroy 43 }; 44 45 UiContainerPrivate* ui_obj_container(UiObject *obj) { 46 return (UiContainerPrivate*)obj->container_end; 47 } 48 49 HWND ui_container_get_parent(UiContainerPrivate *ctn) { 50 return ctn->parent ? ctn->parent(ctn) : ctn->hwnd; 51 } 52 53 void ui_container_add(UiContainerPrivate *ctn, W32Widget *widget, UiLayout *layout) { 54 UiLayout layout2 = *layout; 55 if (layout2.margin > 0) { 56 layout2.margin_left = layout2.margin; 57 layout2.margin_right = layout2.margin; 58 layout2.margin_top = layout2.margin; 59 layout2.margin_bottom = layout2.margin; 60 } 61 ctn->add(ctn, widget, &layout2); 62 ctn->container.newline = FALSE; 63 } 64 65 int ui_grid_widget_event(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 66 if (uMsg == WM_ERASEBKGND) { 67 HDC hdc = (HDC)wParam; 68 UiGridWidget *grid = (UiGridWidget*)widget; 69 RECT rc; 70 GetClientRect(hwnd, &rc); 71 FillRect(hdc, &rc, grid->brush); 72 return 1; 73 } 74 return 0; 75 } 76 77 W32Size ui_grid_layout_get_preferred_size(W32Widget *widget) { 78 UiGridLayout *grid = widget->layoutmanager; 79 W32Size size; 80 size.width = grid->preferred_width; 81 size.height = grid->preferred_height; 82 return size; 83 } 84 85 86 /* ---------------------------- Box Container ---------------------------- */ 87 88 static UIWIDGET box_create(UiObject *obj, UiContainerArgs *args, UiBoxOrientation orientation) { 89 return NULL; 90 } 91 92 // public 93 UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) { 94 return box_create(obj, args, UI_BOX_VERTICAL); 95 } 96 97 // public 98 UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs *args) { 99 return box_create(obj, args, UI_BOX_HORIZONTAL); 100 } 101 102 UiContainerX* ui_box_container_create(UiObject *obj, HWND hwnd, UiBoxOrientation orientation, short spacing, GridEdgeInsets padding) { 103 UiBoxContainer *container = cxZalloc(obj->ctx->allocator, sizeof(UiBoxContainer)); 104 container->container.hwnd = hwnd; 105 container->container.add = ui_box_container_add; 106 container->layout = ui_grid_layout_create(obj->ctx->allocator, spacing, spacing); 107 container->layout->padding = padding; 108 container->orientation = orientation; 109 return (UiContainerX*)container; 110 } 111 112 void ui_box_container_add(UiContainerPrivate *ctn, W32Widget *widget, UiLayout *layout) { 113 UiBoxContainer *box = (UiBoxContainer*)ctn; 114 GridLayoutInfo gridLayout = (GridLayoutInfo) { 115 .margin = (GridEdgeInsets) { layout->margin_top, layout->margin_bottom, layout->margin_left, layout->margin_right }, 116 }; 117 if (box->orientation == UI_BOX_HORIZONTAL) { 118 gridLayout.vexpand = TRUE; 119 gridLayout.vfill = TRUE; 120 gridLayout.hexpand = layout->fill; 121 gridLayout.hfill = layout->fill; 122 } else { 123 gridLayout.hexpand = TRUE; 124 gridLayout.hfill = TRUE; 125 gridLayout.vexpand = layout->fill; 126 gridLayout.vfill = layout->fill; 127 } 128 ui_grid_add_widget(box->layout, box->x, box->y, widget, &gridLayout); 129 if (box->orientation == UI_BOX_HORIZONTAL) { 130 box->x++; 131 } else { 132 box->y++; 133 } 134 } 135 136 /* ---------------------------- Grid Container ---------------------------- */ 137 138 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { 139 HINSTANCE hInstance = GetModuleHandle(NULL); 140 UiContainerPrivate *container = ui_obj_container(obj); 141 HWND parent = ui_container_get_parent(container); 142 UiLayout layout = UI_ARGS2LAYOUT(args); 143 144 HWND hwnd = CreateWindowEx( 145 0, 146 TEXT("STATIC"), 147 NULL, 148 WS_CHILD | WS_VISIBLE, 149 0, 0, 300, 300, 150 parent, 151 NULL, 152 hInstance, 153 NULL); 154 SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ui_default_eventproc); 155 156 UiGridWidget *widget = w32_widget_create(&grid_layout_widget_class, hwnd, sizeof(UiGridWidget)); 157 ui_container_add(container, (W32Widget*)widget, &layout); 158 159 UiContainerX *gridContainer = ui_grid_container_create(obj, hwnd, args->columnspacing, args->rowspacing, INSETS_ZERO); 160 uic_object_push_container(obj, gridContainer); 161 162 UiGridLayoutContainer *grid = (UiGridLayoutContainer*)gridContainer; 163 widget->widget.layout = (W32LayoutFunc)ui_grid_layout; 164 widget->widget.layoutmanager = grid->layout; 165 widget->brush = GetSysColorBrush(COLOR_BTNFACE); 166 grid->layout->preferred_width = 200; 167 grid->layout->preferred_height = 200; 168 169 return (W32Widget*)widget; 170 } 171 172 UiContainerX* ui_grid_container_create(UiObject *obj, HWND hwnd, short columnspacing, short rowspacing, GridEdgeInsets padding) { 173 UiGridLayoutContainer *container = cxZalloc(obj->ctx->allocator, sizeof(UiGridLayoutContainer)); 174 container->container.hwnd = hwnd; 175 container->container.add = ui_grid_container_add; 176 container->layout = ui_grid_layout_create(obj->ctx->allocator, columnspacing, rowspacing); 177 container->layout->padding = padding; 178 return (UiContainerX*)container; 179 } 180 181 void ui_grid_container_add(UiContainerPrivate *ctn, W32Widget *widget, UiLayout *layout) { 182 UiGridLayoutContainer *grid = (UiGridLayoutContainer*)ctn; 183 if (ctn->container.newline) { 184 grid->y++; 185 grid->x = 0; 186 } 187 188 uic_layout_setup_expand_fill(layout, grid->def_hexpand, grid->def_vexpand, grid->def_hfill, grid->def_vfill); 189 GridLayoutInfo gridLayout = (GridLayoutInfo) { 190 .margin = (GridEdgeInsets) { layout->margin_top, layout->margin_bottom, layout->margin_left, layout->margin_right }, 191 .colspan = layout->colspan, 192 .rowspan = layout->rowspan, 193 .hexpand = layout->hexpand, 194 .vexpand = layout->vexpand, 195 .hfill = layout->hfill, 196 .vfill = layout->vfill, 197 }; 198 ui_grid_add_widget(grid->layout, grid->x, grid->y, widget, &gridLayout); 199 200 grid->x++; 201 } 202 203 204 /* ---------------------------- Container Helper ---------------------------- */ 205 206 void ui_container_begin_close(UiObject *obj) { 207 UiContainerX *ct = obj->container_end; 208 ct->close = 1; 209 } 210 211 int ui_container_finish(UiObject *obj) { 212 UiContainerX *ct = obj->container_end; 213 if(ct->close) { 214 ui_end_new(obj); 215 return 0; 216 } 217 return 1; 218 }