Thu, 12 Oct 2023 13:52:18 +0200
add custom titlebar (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 "pch.h" #include "table.h" #include "container.h" #include "util.h" #include "../common/context.h" #include "../common/object.h" #include <winrt/Microsoft.UI.Xaml.Data.h> #include <winrt/Microsoft.UI.Xaml.Media.h> #include <winrt/Microsoft.UI.Xaml.Input.h> using namespace winrt; using namespace Microsoft::UI::Xaml; using namespace Microsoft::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Interop; using namespace winrt::Windows::Foundation; using namespace winrt::Microsoft::UI::Xaml::Controls::Primitives; using namespace winrt::Microsoft::UI::Xaml::Media; using namespace winrt::Windows::UI::Xaml::Input; extern "C" void reg_table_destructor(UiContext * ctx, UiTable * table) { // TODO: } UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs args) { if (!args.model) { return nullptr; } UiObject* current = uic_current_obj(obj); // create widgets and wrapper obj ScrollViewer scrollW = ScrollViewer(); Grid grid = Grid(); scrollW.Content(grid); UiTable* uitable = new UiTable(scrollW, grid); reg_table_destructor(current->ctx, uitable); uitable->getvalue = args.model->getvalue ? args.model->getvalue : args.getvalue; // grid styling winrt::Windows::UI::Color bg = { 255, 255, 255, 255 }; // test color SolidColorBrush brush = SolidColorBrush(bg); grid.Background(brush); // add columns from args.model uitable->add_header(args.model); // bind var UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); if (var) { UiList* list = (UiList*)var->value; list->update = ui_table_update; list->obj = uitable; uitable->update(list, 0); } // create toolkit wrapper object and register destructor UIElement elm = scrollW; UiWidget* widget = new UiWidget(elm); ui_context_add_widget_destructor(current->ctx, widget); // add scrollW to current container UI_APPLY_LAYOUT1(current, args); current->container->Add(scrollW, false); return widget; } extern "C" void ui_table_update(UiList * list, int i) { UiTable* table = (UiTable*)list->obj; table->clear(); table->update(list, i); } UiTable::UiTable(winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid) { this->scrollw = scrollw; this->grid = grid; winrt::Windows::UI::Color highlightBg = { 255, 234, 234, 234 }; highlightBrush = SolidColorBrush(highlightBg); winrt::Windows::UI::Color defaultBg = { 0, 0, 0, 0 }; // default defaultBrush = SolidColorBrush(defaultBg); winrt::Windows::UI::Color selectedBg = { 255, 204, 232, 255 }; // test color selectedBrush = SolidColorBrush(selectedBg); winrt::Windows::UI::Color selectedFg = { 255, 0, 90, 158 }; // test color selectedBorderBrush = SolidColorBrush(selectedFg); } void UiTable::add_header(UiModel* model) { GridLength gl; gl.Value = 0; gl.GridUnitType = GridUnitType::Auto; // add header row definition auto headerRowDef = RowDefinition(); headerRowDef.Height(gl); grid.RowDefinitions().Append(headerRowDef); for (int i = 0; i < model->columns;i++) { char* title = model->titles[i]; UiModelType type = model->types[i]; // add grid column definition auto colDef = ColumnDefinition(); colDef.Width(gl); grid.ColumnDefinitions().Append(colDef); // add button auto button = Button(); wchar_t* wlabel = str2wstr(title, nullptr); button.Content(box_value(wlabel)); free(wlabel); // some styling for the button Thickness border = { 0,0,1,0 }; CornerRadius corner = { 0,0,0,0 }; button.BorderThickness(border); button.CornerRadius(corner); grid.SetColumn(button, i); grid.SetRow(button, 0); grid.Children().Append(button); UiTableColumn h; h.header = button; header.push_back(h); } maxrows = 1; } void UiTable::update(UiList* list, int i) { if (getvalue == nullptr) { return; } Thickness b1 = { 1, 1, 0, 1 }; // first col Thickness b2 = { 0, 1, 0, 1 }; // middle Thickness b3 = { 0, 1, 1, 1 }; // last col GridLength gl; gl.Value = 0; gl.GridUnitType = GridUnitType::Auto; int row = 1; void* elm = list->first(list); while (elm) { if (row >= maxrows) { auto rowdef = RowDefinition(); rowdef.Height(gl); grid.RowDefinitions().Append(rowdef); maxrows = row; } for (int col = 0; col < header.size(); col++) { Border cellBorder = Border(); cellBorder.Background(defaultBrush); TextBlock cell = TextBlock(); cellBorder.Child(cell); cellBorder.BorderBrush(defaultBrush); if (col == 0) { cellBorder.BorderThickness(b1); } else if (col + 1 == header.size()) { cellBorder.BorderThickness(b3); } else { cellBorder.BorderThickness(b2); } char* value = (char*)getvalue(elm, col); if (value) { wchar_t* wstr = str2wstr(value, nullptr); cell.Text(winrt::hstring(wstr)); free(wstr); } Thickness padding = { 10,0,4,0 }; cell.Padding(padding); cell.VerticalAlignment(VerticalAlignment::Stretch); // event handler cellBorder.PointerPressed( winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { if (selection > 0) { row_background(selection, defaultBrush, defaultBrush); } row_background(row, selectedBrush, selectedBorderBrush); selection = row; }) ); cellBorder.PointerReleased( winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { }) ); cellBorder.PointerEntered( winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { if (selection != row) { row_background(row, highlightBrush, highlightBrush); } }) ); cellBorder.PointerExited( winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { if (selection != row) { row_background(row, defaultBrush, defaultBrush); } }) ); grid.SetColumn(cellBorder, col); grid.SetRow(cellBorder, row); grid.Children().Append(cellBorder); } row++; elm = list->next(list); } } void UiTable::clear() { for (int i = grid.Children().Size()-1; i >= 0; i--) { FrameworkElement elm = grid.Children().GetAt(i).as<FrameworkElement>(); int child_row = grid.GetRow(elm); if (child_row > 0) { grid.Children().RemoveAt(i); } } } void UiTable::row_background(int row, winrt::Microsoft::UI::Xaml::Media::Brush brush, winrt::Microsoft::UI::Xaml::Media::Brush borderBrush) { Thickness b1 = { 1, 1, 0, 1 }; // first col Thickness b2 = { 0, 1, 0, 1 }; // middle Thickness b3 = { 0, 1, 1, 1 }; // last col for (auto child : grid.Children()) { FrameworkElement elm = child.as<FrameworkElement>(); int child_row = grid.GetRow(elm); if (child_row == row) { Border b = elm.as<Border>(); b.Background(brush); b.BorderBrush(borderBrush); } } }