Mon, 02 Oct 2023 19:56:18 +0200
add combobox (WinUI3)
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2023 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "container.h" #include "../common/context.h" #include "../common/object.h" #include "util.h" #include <winrt/Windows.UI.Xaml.Media.h> #include <winrt/Microsoft.UI.Xaml.Media.h> void ui_container_begin_close(UiObject* obj) { UiContainer* ct = uic_get_current_container(obj); ct->close = 1; } int ui_container_finish(UiObject* obj) { UiContainer* ct = uic_get_current_container(obj); if (ct->close) { ui_end(obj); return 0; } return 1; } // --------------------- UiBoxContainer --------------------- static UIWIDGET ui_box(UiObject* obj, UiContainerArgs args, UiBoxContainerType type) { UiObject* current = uic_current_obj(obj); UI_APPLY_LAYOUT1(current, args); Grid grid = Grid(); current->container->Add(grid, true); UIElement elm = grid; UiWidget* widget = new UiWidget(elm); UiObject* newobj = uic_object_new(obj, widget); newobj->container = new UiBoxContainer(grid, type, args.margin, args.spacing); uic_obj_add(obj, newobj); return widget; } UIWIDGET ui_vbox_create(UiObject* obj, UiContainerArgs args) { return ui_box(obj, args, UI_BOX_CONTAINER_VBOX); } UIWIDGET ui_hbox_create(UiObject* obj, UiContainerArgs args) { return ui_box(obj, args, UI_BOX_CONTAINER_HBOX); } UiBoxContainer::UiBoxContainer(Grid grid, enum UiBoxContainerType type, int margin, int spacing) { this->grid = grid; this->type = type; Thickness t = { (double)margin, (double)margin, (double)margin, (double)margin }; grid.Margin(t); grid.ColumnSpacing((double)spacing); grid.RowSpacing((double)spacing); GridLength gl; gl.Value = 1; gl.GridUnitType = GridUnitType::Star; // hbox needs one row def, vbox needs one col def // all other col/row defs are created when elements are added if (type == UI_BOX_CONTAINER_HBOX) { boxRowDef = RowDefinition(); boxRowDef.Height(gl); grid.RowDefinitions().Append(boxRowDef); } else { boxColDef = ColumnDefinition(); boxColDef.Width(gl); grid.ColumnDefinitions().Append(boxColDef); } ui_reset_layout(layout); } void UiBoxContainer::Add(FrameworkElement control, UiBool fill) { if (this->layout.fill != UI_LAYOUT_UNDEFINED) { fill = ui_lb2bool(this->layout.fill); } GridLength gl; if (fill) { gl.Value = 1; gl.GridUnitType = GridUnitType::Star; } else { gl.Value = 0; gl.GridUnitType = GridUnitType::Auto; } control.HorizontalAlignment(HorizontalAlignment::Stretch); control.VerticalAlignment(VerticalAlignment::Stretch); if (type == UI_CONTAINER_HBOX) { ColumnDefinition coldef = ColumnDefinition(); coldef.Width(gl); grid.ColumnDefinitions().Append(coldef); grid.SetColumn(control, grid.Children().Size()); grid.SetRow(control, 0); } else { RowDefinition rowdef = RowDefinition(); rowdef.Height(gl); grid.RowDefinitions().Append(rowdef); grid.SetRow(control, grid.Children().Size()); grid.SetColumn(control, 0); } grid.Children().Append(control); ui_reset_layout(layout); } // --------------------- UiGridContainer --------------------- UIWIDGET ui_grid_create(UiObject* obj, UiContainerArgs args) { UiObject* current = uic_current_obj(obj); UI_APPLY_LAYOUT1(current, args); Grid grid = Grid(); current->container->Add(grid, true); UIElement elm = grid; UiWidget* widget = new UiWidget(elm); UiObject* newobj = uic_object_new(obj, widget); newobj->container = new UiGridContainer(grid, args.margin, args.columnspacing, args.rowspacing); uic_obj_add(obj, newobj); return widget; } UiGridContainer::UiGridContainer(Grid grid, int margin, int columnspacing, int rowspacing) { this->grid = grid; Thickness t = { (double)margin, (double)margin, (double)margin, (double)margin }; grid.Margin(t); grid.ColumnSpacing((double)columnspacing); grid.RowSpacing((double)rowspacing); ui_reset_layout(layout); } void UiGridContainer::Add(FrameworkElement control, UiBool fill) { GridLength gl; int hexpand = FALSE; int vexpand = FALSE; if (layout.hexpand != UI_LAYOUT_UNDEFINED) { hexpand = layout.hexpand; } if (layout.vexpand != UI_LAYOUT_UNDEFINED) { vexpand = layout.vexpand; } // create new RowDefinition for the new line if (layout.newline || y == -1) { x = 0; y++; RowDefinition rowdef = RowDefinition(); if (vexpand) { gl.GridUnitType = GridUnitType::Star; gl.Value = 1; } else { gl.GridUnitType = GridUnitType::Auto; gl.Value = 0; } rowdef.Height(gl); grid.RowDefinitions().Append(rowdef); } // create new columndefinition, if a new column is added if (x == cols) { if (hexpand) { gl.GridUnitType = GridUnitType::Star; gl.Value = 1; } else { gl.GridUnitType = GridUnitType::Auto; gl.Value = 0; } ColumnDefinition coldef = ColumnDefinition(); coldef.Width(gl); grid.ColumnDefinitions().Append(coldef); cols++; } // add control control.HorizontalAlignment(HorizontalAlignment::Stretch); control.VerticalAlignment(VerticalAlignment::Stretch); if (layout.colspan > 0) { grid.SetColumnSpan(control, layout.colspan); } if (layout.rowspan > 0) { grid.SetRowSpan(control, layout.rowspan); } grid.SetRow(control, y); grid.SetColumn(control, x); grid.Children().Append(control); x++; ui_reset_layout(layout); } // --------------------- UI Frame --------------------- UIWIDGET ui_frame_create(UiObject* obj, UiFrameArgs args) { // create a grid for the frame, that contains the label and a sub-frame Grid frame = Grid(); GridLength gl; gl.GridUnitType = GridUnitType::Star; gl.Value = 1; ColumnDefinition coldef = ColumnDefinition(); coldef.Width(gl); frame.ColumnDefinitions().Append(coldef); RowDefinition rowdefFrame = RowDefinition(); rowdefFrame.Height(gl); // label int row = 0; if (args.label) { RowDefinition rowdefLabel = RowDefinition(); gl.GridUnitType = GridUnitType::Auto; gl.Value = 0; rowdefLabel.Height(gl); frame.RowDefinitions().Append(rowdefLabel); TextBlock label = TextBlock(); wchar_t* wlabel = str2wstr(args.label, nullptr); winrt::hstring hstr(wlabel); label.Text(hstr); free(wlabel); frame.SetRow(label, row++); frame.SetColumn(label, 0); frame.Children().Append(label); } // workarea frame frame.RowDefinitions().Append(rowdefFrame); Grid workarea = Grid(); frame.SetRow(workarea, row); frame.SetColumn(workarea, 0); frame.Children().Append(workarea); // some styling for the workarea winrt::Microsoft::UI::Xaml::Media::SolidColorBrush brush{ winrt::Microsoft::UI::ColorHelper::FromArgb(150, 150, 150, 150) }; workarea.BorderBrush(brush); CornerRadius radius{ 8, 8, 8, 8 }; Thickness t = { 1, 1, 1, 1 }; workarea.CornerRadius(radius); workarea.BorderThickness(t); Thickness padding = { 10, 10, 10, 10 }; workarea.Padding(padding); // add frame to the parent container UiObject* current = uic_current_obj(obj); UI_APPLY_LAYOUT1(current, args); current->container->Add(frame, true); UIElement elm = frame; UiWidget* widget = new UiWidget(elm); // sub container UiContainer* ctn = nullptr; switch (args.subcontainer) { default: case UI_CONTAINER_VBOX: { ctn = new UiBoxContainer(workarea, UI_BOX_CONTAINER_VBOX, args.margin, args.spacing); break; } case UI_CONTAINER_HBOX: { ctn = new UiBoxContainer(workarea, UI_BOX_CONTAINER_HBOX, args.margin, args.spacing); break; } case UI_CONTAINER_GRID: { ctn = new UiGridContainer(workarea, args.margin, args.columnspacing, args.rowspacing); break; } } UiObject* newobj = uic_object_new(obj, widget); newobj->container = ctn; uic_obj_add(obj, newobj); return widget; } // --------------------- UI Expander --------------------- UIWIDGET ui_expander_create(UiObject* obj, UiFrameArgs args) { Expander expander = Expander(); if (args.label) { wchar_t* wlabel = str2wstr(args.label, nullptr); expander.Header(box_value(wlabel)); free(wlabel); } expander.IsExpanded(args.isexpanded); // add frame to the parent container UiObject* current = uic_current_obj(obj); UI_APPLY_LAYOUT1(current, args); current->container->Add(expander, true); UIElement elm = expander; UiWidget* widget = new UiWidget(elm); Grid content = Grid(); expander.Content(content); UiContainer* ctn = nullptr; switch (args.subcontainer) { default: case UI_CONTAINER_VBOX: { ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_VBOX, args.margin, args.spacing); break; } case UI_CONTAINER_HBOX: { ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_HBOX, args.margin, args.spacing); break; } case UI_CONTAINER_GRID: { ctn = new UiGridContainer(content, args.margin, args.columnspacing, args.rowspacing); break; } } UiObject* newobj = uic_object_new(obj, widget); newobj->container = ctn; uic_obj_add(obj, newobj); return widget; } // --------------------- UI ScrolledWindow --------------------- UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) { ScrollViewer scrollW = ScrollViewer(); // add frame to the parent container UiObject* current = uic_current_obj(obj); UI_APPLY_LAYOUT1(current, args); current->container->Add(scrollW, true); UIElement elm = scrollW; UiWidget* widget = new UiWidget(elm); // create child container Grid content = Grid(); scrollW.Content(content); UiContainer* ctn = nullptr; switch (args.subcontainer) { default: case UI_CONTAINER_VBOX: { ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_VBOX, args.margin, args.spacing); break; } case UI_CONTAINER_HBOX: { ctn = new UiBoxContainer(content, UI_BOX_CONTAINER_HBOX, args.margin, args.spacing); break; } case UI_CONTAINER_GRID: { ctn = new UiGridContainer(content, args.margin, args.columnspacing, args.rowspacing); break; } } UiObject* newobj = uic_object_new(obj, widget); newobj->container = ctn; uic_obj_add(obj, newobj); return widget; } /* * -------------------- Layout Functions -------------------- * * functions for setting layout attributes for the current container * */ void ui_layout_fill(UiObject* obj, UiBool fill) { UiContainer* ct = uic_get_current_container(obj); ct->layout.fill = ui_bool2lb(fill); } void ui_layout_hexpand(UiObject* obj, UiBool expand) { UiContainer* ct = uic_get_current_container(obj); ct->layout.hexpand = expand; } void ui_layout_vexpand(UiObject* obj, UiBool expand) { UiContainer* ct = uic_get_current_container(obj); ct->layout.vexpand = expand; } void ui_layout_width(UiObject* obj, int width) { UiContainer* ct = uic_get_current_container(obj); ct->layout.width = width; } void ui_layout_height(UiObject* obj, int height) { UiContainer* ct = uic_get_current_container(obj); ct->layout.height = height; } void ui_layout_colspan(UiObject* obj, int cols) { UiContainer* ct = uic_get_current_container(obj); ct->layout.colspan = cols; } void ui_layout_rowspan(UiObject* obj, int rows) { UiContainer* ct = uic_get_current_container(obj); ct->layout.rowspan = rows; } void ui_newline(UiObject* obj) { UiContainer* ct = uic_get_current_container(obj); ct->layout.newline = TRUE; }