# HG changeset patch # User Olaf Wintermann # Date 1697733019 -7200 # Node ID a82d9beaa94a827623828e16e22469ec25c15d19 # Parent e377456302df3c65ee658e6f298f4720a342897c add semi-functional pathbar (WinUI3) diff -r e377456302df -r a82d9beaa94a make/vs/testapp/main.c --- a/make/vs/testapp/main.c Tue Oct 17 21:50:48 2023 +0200 +++ b/make/vs/testapp/main.c Thu Oct 19 18:30:19 2023 +0200 @@ -47,6 +47,7 @@ UiList* list2; UiList* list3; UiDouble* progress; + UiInteger* spinner; } WindowData; static UiIcon* folder_icon; @@ -62,6 +63,9 @@ double d = wdata->progress->get(wdata->progress); wdata->progress->set(wdata->progress, d + 1); + + int spinner_active = wdata->spinner->get(wdata->spinner); + wdata->spinner->set(wdata->spinner, !spinner_active); } void action_set_checkbox(UiEvent* event, void* data) { @@ -155,6 +159,7 @@ wdata->t2 = ui_string_new(obj->ctx, "t2"); wdata->t3 = ui_string_new(obj->ctx, "t3"); wdata->progress = ui_double_new(obj->ctx, "progress"); + wdata->spinner = ui_int_new(obj->ctx, "spinner"); ui_list_append(wdata->list, "Hello"); ui_list_append(wdata->list, "World"); @@ -221,6 +226,10 @@ ui_togglebutton(obj, .label = "Option 2", .value = wdata->toggle); ui_newline(obj); + ui_label(obj, .label = "Progress"); + ui_progressspinner(obj, .value = wdata->spinner); + ui_newline(obj); + ui_hbox(obj, .colspan = 3) { ui_radiobutton(obj, .label = "Radio 1", .value = wdata->radio); ui_radiobutton(obj, .label = "Radio 2", .value = wdata->radio); @@ -231,7 +240,8 @@ ui_switch(obj, .label = "test", .onchange = action_switch); ui_newline(obj); - ui_breadcrumbbar(obj, .list = wdata->list3, .onactivate=action_breadcrumb); + //ui_breadcrumbbar(obj, .list = wdata->list3, .onactivate=action_breadcrumb); + ui_pathbar(obj, .colspan = 3, .list = wdata->list3, .onactivate = action_breadcrumb); ui_newline(obj); ui_textfield(obj, .value = wdata->text); @@ -283,7 +293,8 @@ UiModel* model = ui_model(obj->ctx, UI_ICON_TEXT, "Col 1", UI_STRING, "Col 2", UI_STRING, "Col 3", -1); model->getvalue = table_getvalue; - ui_table(obj, .colspan = 3, .model = model, .list = wdata->list2, .onactivate = action_onactivate, .onselection = action_listselection_changed); + ui_table(obj, .colspan = 3, .model = model, .list = wdata->list2, .onactivate = action_onactivate, + .onselection = action_listselection_changed, .enabledrag = true, .enabledrop = true); ui_model_free(obj->ctx, model); } } diff -r e377456302df -r a82d9beaa94a make/vs/uicommon/uicommon.vcxproj.filters --- a/make/vs/uicommon/uicommon.vcxproj.filters Tue Oct 17 21:50:48 2023 +0200 +++ b/make/vs/uicommon/uicommon.vcxproj.filters Thu Oct 19 18:30:19 2023 +0200 @@ -5,61 +5,61 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source - Source + Ressourcendateien\Source \ No newline at end of file diff -r e377456302df -r a82d9beaa94a ui/ui/display.h --- a/ui/ui/display.h Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/ui/display.h Thu Oct 19 18:30:19 2023 +0200 @@ -75,6 +75,17 @@ const char* varname; } UiProgressbarArgs; +typedef struct UiProgressbarSpinnerArgs { + UiTri fill; + UiBool hexpand; + UiBool vexpand; + int colspan; + int rowspan; + + UiInteger* value; + const char* varname; +} UiProgressbarSpinnerArgs; + /* label widgets */ #define ui_label(obj, ...) ui_label_create(obj, (UiLabelArgs) { __VA_ARGS__ }) @@ -89,11 +100,13 @@ UIWIDGET ui_space(UiObject *obj); UIWIDGET ui_separator(UiObject *obj); -/* progress bar */ +/* progress bar/spinner */ #define ui_progressbar(obj, ...) ui_progressbar_create(obj, (UiProgressbarArgs) { __VA_ARGS__ } ) +#define ui_progressspinner(obj, ...) ui_progressspinner_create(obj, (UiProgressbarSpinnerArgs) { __VA_ARGS__ } ) UIEXPORT UIWIDGET ui_progressbar_create(UiObject *obj, UiProgressbarArgs args); +UIEXPORT UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args); #ifdef __cplusplus diff -r e377456302df -r a82d9beaa94a ui/ui/tree.h --- a/ui/ui/tree.h Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/ui/tree.h Thu Oct 19 18:30:19 2023 +0200 @@ -40,6 +40,7 @@ typedef struct UiListSelection UiListSelection; typedef struct UiListArgs UiListArgs; +typedef struct UiPathBarArgs UiPathBarArgs; typedef enum UiModelType { UI_STRING = 0, @@ -125,7 +126,40 @@ void* onactivatedata; ui_callback onselection; void* onselectiondata; + ui_callback ondragstart; + void* ondragstartdata; + ui_callback ondragcomplete; + void* ondragcompletedata; + ui_callback ondrop; + void* ondropsdata; UiBool multiselection; + UiBool enabledrag; + UiBool enabledrop; +}; + +struct UiPathBarArgs { + UiTri fill; + UiBool hexpand; + UiBool vexpand; + int colspan; + int rowspan; + + UiList* list; + const char* varname; + UiModel* model; + ui_getvaluefunc getvalue; + ui_callback onactivate; + void* onactivatedata; + ui_callback ontextinput; + void* ontextinputdata; + ui_callback ondragstart; + void* ondragstartdata; + ui_callback ondragcomplete; + void* ondragcompletedata; + ui_callback ondrop; + void* ondropsdata; + UiBool enabledrag; + UiBool enabledrop; }; UIEXPORT UiModel* ui_model(UiContext *ctx, ...); @@ -136,11 +170,13 @@ #define ui_table(obj, ...) ui_table_create(obj, (UiListArgs) { __VA_ARGS__ } ) #define ui_combobox(obj, ...) ui_combobox_create(obj, (UiListArgs) { __VA_ARGS__ } ) #define ui_breadcrumbbar(obj, ...) ui_breadcrumbbar_create(obj, (UiListArgs) { __VA_ARGS__ } ) +#define ui_pathbar(obj, ...) ui_pathbar_create(obj, (UiPathBarArgs) { __VA_ARGS__ } ) UIEXPORT UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args); UIEXPORT UIWIDGET ui_table_create(UiObject* obj, UiListArgs args); UIEXPORT UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs args); UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs args); +UIEXPORT UIWIDGET ui_pathbar_create(UiObject* obj, UiPathBarArgs args); void ui_table_dragsource(UIWIDGET tablewidget, int actions, char *target0, ...); diff -r e377456302df -r a82d9beaa94a ui/winui/MainWindow.xaml --- a/ui/winui/MainWindow.xaml Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/MainWindow.xaml Thu Oct 19 18:30:19 2023 +0200 @@ -14,7 +14,7 @@ - + diff -r e377456302df -r a82d9beaa94a ui/winui/container.cpp --- a/ui/winui/container.cpp Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/container.cpp Thu Oct 19 18:30:19 2023 +0200 @@ -534,8 +534,8 @@ static UiTabView* tabview_main_create(UiObject* obj, UiTabViewArgs args) { TabView tabview = TabView(); tabview.IsAddTabButtonVisible(false); - tabview.CanDragTabs(false); - tabview.CanReorderTabs(false); + //tabview.CanDragTabs(false); + //tabview.CanReorderTabs(false); UiMainTabView* uitabview = new UiMainTabView(obj, tabview, args); return uitabview; diff -r e377456302df -r a82d9beaa94a ui/winui/label.cpp --- a/ui/winui/label.cpp Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/label.cpp Thu Oct 19 18:30:19 2023 +0200 @@ -153,3 +153,47 @@ d->value = newvalue; progressbar.Value(newvalue); } + +UIWIDGET ui_progressspinner_create(UiObject* obj, UiProgressbarSpinnerArgs args) { + UiObject* current = uic_current_obj(obj); + + // create textbox and toolkit wrapper + ProgressRing spinner = ProgressRing(); + spinner.IsActive(false); + + UIElement elm = spinner; + UiWidget* widget = new UiWidget(elm); + ui_context_add_widget_destructor(current->ctx, widget); + + UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_DOUBLE); + if (var) { + UiInteger* value = (UiInteger*)var->value; + value->obj = widget; + value->get = ui_progressspinner_get; + value->set = ui_progressspinner_set; + + // listener for notifying observers + // TODO: + } + + // add button to current container + UI_APPLY_LAYOUT1(current, args); + + current->container->Add(spinner, false); + + return widget; +} + +int64_t ui_progressspinner_get(UiInteger * i) { + UiWidget* widget = (UiWidget*)i->obj; + ProgressRing spinner = widget->uielement.as(); + i->value = spinner.IsActive(); + return i->value; +} + +void ui_progressspinner_set(UiInteger * i, int64_t newvalue) { + UiWidget* widget = (UiWidget*)i->obj; + ProgressRing spinner = widget->uielement.as(); + i->value = newvalue != 0 ? 1 : 0; + spinner.IsActive(i->value); +} diff -r e377456302df -r a82d9beaa94a ui/winui/label.h --- a/ui/winui/label.h Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/label.h Thu Oct 19 18:30:19 2023 +0200 @@ -37,3 +37,6 @@ extern "C" double ui_progressbar_get(UiDouble *d); extern "C" void ui_progressbar_set(UiDouble *d, double newvalue); + +extern "C" int64_t ui_progressspinner_get(UiInteger * i); +extern "C" void ui_progressspinner_set(UiInteger * i, int64_t newvalue); diff -r e377456302df -r a82d9beaa94a ui/winui/list.cpp --- a/ui/winui/list.cpp Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/list.cpp Thu Oct 19 18:30:19 2023 +0200 @@ -41,6 +41,8 @@ using namespace Microsoft::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Interop; using namespace winrt::Windows::Foundation; +using namespace Microsoft::UI::Xaml::Markup; +using namespace Microsoft::UI::Xaml::Media; using namespace winrt::Microsoft::UI::Xaml::Controls::Primitives; UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args) { @@ -209,6 +211,113 @@ return widget; } + +extern "C" static void destroy_ui_pathbar(void* ptr) { + UiPathBar* pb = (UiPathBar*)ptr; + delete pb; +} + +static void ui_context_add_pathbar_destructor(UiContext* ctx, UiPathBar* pb) { + cxMempoolRegister(ctx->mp, pb, destroy_ui_pathbar); +} + +UIEXPORT UIWIDGET ui_pathbar_create(UiObject* obj, UiPathBarArgs args) { + UiObject* current = uic_current_obj(obj); + + // create view and toolkit wrapper + Border pathbar = Border(); + + IInspectable bgRes = Application::Current().Resources().Lookup(box_value(L"TextControlBackground")); + IInspectable borderThicknessRes = Application::Current().Resources().Lookup(box_value(L"TextControlBorderThemeThickness")); + IInspectable borderBrushRes = Application::Current().Resources().Lookup(box_value(L"TextControlBorderBrush")); + // IInspectable cornerRes = Application::Current().Resources().Lookup(box_value(L"TextControlCornerRadius")); + + Brush bgBrush = unbox_value(bgRes); + Thickness border = unbox_value(borderThicknessRes); + Brush borderBrush = unbox_value(borderBrushRes); + CornerRadius cornerRadius = { 4, 4, 4, 4 }; //unbox_value(cornerRes); + + pathbar.Background(bgBrush); + pathbar.BorderBrush(borderBrush); + pathbar.BorderThickness(border); + pathbar.CornerRadius(cornerRadius); + + Grid content = Grid(); + pathbar.Child(content); + + GridLength gl; + gl.Value = 1; + gl.GridUnitType = GridUnitType::Star; + + ColumnDefinition coldef = ColumnDefinition(); + coldef.Width(gl); + content.ColumnDefinitions().Append(coldef); + + TextBox pathTextBox = TextBox(); + Thickness t = { 0, 0, 0, 0 }; + CornerRadius c = { 0 ,0, 0, 0 }; + pathTextBox.BorderThickness(t); + //pathTextBox.CornerRadius(c); + + + pathTextBox.HorizontalAlignment(HorizontalAlignment::Stretch); + content.SetColumn(pathTextBox, 0); + + content.Children().Append(pathTextBox); + + // stackpanel for buttons + StackPanel buttons = StackPanel(); + buttons.Orientation(Orientation::Horizontal); + buttons.Visibility(Visibility::Collapsed); + content.SetColumn(buttons, 0); + content.Children().Append(buttons); + + if (args.ontextinput) { + // TODO + } + + //pathTextBox.Visibility(Visibility::Collapsed); + + UiPathBar* uipathbar = new UiPathBar; + ui_context_add_pathbar_destructor(current->ctx, uipathbar); + uipathbar->grid = content; + uipathbar->buttons = buttons; + uipathbar->textbox = pathTextBox; + uipathbar->enabledrag = args.enabledrag; + uipathbar->enabledrop = args.enabledrop; + uipathbar->getvalue = args.getvalue; + uipathbar->model = args.model; + uipathbar->onactivate = args.onactivate; + uipathbar->onactivatedata = args.onactivatedata; + uipathbar->ondragstart = args.ondragstart; + uipathbar->ondragstartdata = args.ondragstartdata; + uipathbar->ondragcomplete = args.ondragcomplete; + uipathbar->ondragcompletedata = args.ondragcompletedata; + uipathbar->ondrop = args.ondrop; + uipathbar->ondropdata = args.ondropsdata; + + UIElement elm = pathbar; + UiWidget* widget = new UiWidget(elm); + widget->data1 = uipathbar; + ui_context_add_widget_destructor(current->ctx, widget); + + // 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_pathbar_update; + list->obj = widget; + ui_pathbar_update(list, 0); + } + + // add listview to current container + UI_APPLY_LAYOUT1(current, args); + + current->container->Add(pathbar, false); + + return widget; +} + static void* getstrvalue(void* elm, int ignore) { return elm; } @@ -273,6 +382,58 @@ bar.ItemsSource(items); } +static void ui_pathbar_clear(StackPanel &buttons) { + for (int i = buttons.Children().Size() - 1; i >= 0; i--) { + buttons.Children().RemoveAt(i); + } +} + +extern "C" void ui_pathbar_update(UiList * list, int i) { + UiWidget* widget = (UiWidget*)list->obj; + UiPathBar* pb = (UiPathBar*)widget->data1; + Grid grid = pb->grid; + + UiModel* model = pb->model; + ui_getvaluefunc getvalue = pb->getvalue; + + // priority: getvalue, model.getvalue, getstrvalue (fallback) + if (getvalue == nullptr) { + if (model && model->getvalue) { + getvalue = model->getvalue; + } + else { + getvalue = getstrvalue; + } + } + + // hide textbox, show button panel + pb->textbox.Visibility(Visibility::Collapsed); + pb->buttons.Visibility(Visibility::Visible); + + // clear old buttons + ui_pathbar_clear(pb->buttons); + + // add new buttons + void* elm = list->first(list); + while (elm) { + char* value = (char*)getvalue(elm, 0); + wchar_t* wstr = str2wstr(value, nullptr); + Button button = Button(); + button.Content(box_value(wstr)); + free(wstr); + + Thickness t = { 0, 0, 1, 0 }; + CornerRadius c = { 0 ,0, 0, 0 }; + button.BorderThickness(t); + button.CornerRadius(c); + + pb->buttons.Children().Append(button); + + elm = list->next(list); + } +} + + std::vector ui_create_listview_selection(ListView listview) { std::vector selection; int p = 0; diff -r e377456302df -r a82d9beaa94a ui/winui/list.h --- a/ui/winui/list.h Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/list.h Thu Oct 19 18:30:19 2023 +0200 @@ -33,9 +33,33 @@ #include "../ui/container.h" +struct UiPathBar { + winrt::Microsoft::UI::Xaml::Controls::Grid grid = { nullptr }; + winrt::Microsoft::UI::Xaml::Controls::StackPanel buttons = { nullptr }; + winrt::Microsoft::UI::Xaml::Controls::TextBox textbox = { nullptr }; + + UiModel* model; + ui_getvaluefunc getvalue; + ui_callback onactivate; + void* onactivatedata; + ui_callback ontextinput; + void* ontextinputdata; + ui_callback ondragstart; + void* ondragstartdata; + ui_callback ondragcomplete; + void* ondragcompletedata; + ui_callback ondrop; + void* ondropdata; + UiBool enabledrag; + UiBool enabledrop; +}; + + extern "C" void ui_simple_list_update(UiList * list, int i); extern "C" void ui_breadcrumbbar_update(UiList * list, int i); +extern "C" void ui_pathbar_update(UiList * list, int i); + std::vector ui_create_listview_selection(winrt::Microsoft::UI::Xaml::Controls::ListView listview); diff -r e377456302df -r a82d9beaa94a ui/winui/table.cpp --- a/ui/winui/table.cpp Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/table.cpp Thu Oct 19 18:30:19 2023 +0200 @@ -41,6 +41,8 @@ #include #include #include +#include +#include using namespace winrt; using namespace Microsoft::UI::Xaml; @@ -76,6 +78,13 @@ uitable->onselectiondata = args.onselectiondata; uitable->onactivate = args.onactivate; uitable->onactivatedata = args.onactivatedata; + uitable->ondragstart = args.ondragstart; + uitable->ondragstartdata = args.ondragstartdata; + uitable->ondragcomplete = args.ondragcomplete; + uitable->ondrop = args.ondrop; + uitable->ondropdata = args.ondropsdata; + uitable->enabledrag = args.enabledrag; + uitable->enabledrop = args.enabledrop; // grid styling winrt::Windows::UI::Color bg = { 255, 255, 255, 255 }; // test color @@ -259,6 +268,17 @@ cellBorder.BorderThickness(b2); } + // dnd + if (enabledrag) { + cellBorder.CanDrag(enabledrag); + cellBorder.DragStarting([](IInspectable const& sender, DragStartingEventArgs args) { + //args.Data().SetText(L"test"); + }); + } + if (enabledrop) { + cellBorder.AllowDrop(enabledrop); + } + // set the cell value // depending on the type, we create different cell controls UiModelType type = model->types[col]; @@ -269,6 +289,7 @@ cell.VerticalAlignment(VerticalAlignment::Stretch); textblock_set_str(cell, (char*)getvalue(elm, model_col)); cellBorder.Child(cell); + break; } case UI_INTEGER: { diff -r e377456302df -r a82d9beaa94a ui/winui/table.h --- a/ui/winui/table.h Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/table.h Thu Oct 19 18:30:19 2023 +0200 @@ -51,6 +51,12 @@ void* onactivatedata; ui_callback onselection; void* onselectiondata; + ui_callback ondragstart; + void* ondragstartdata; + ui_callback ondragcomplete; + void* ondragcompletedata; + ui_callback ondrop; + void* ondropdata; UiModel* model = nullptr; std::vector header; ui_getvaluefunc getvalue = nullptr; @@ -58,6 +64,8 @@ int lastSelection = 0; ULONG64 lastPointerPress = 0; std::vector selection; + bool enabledrag = false; + bool enabledrop = false; UiTable(UiObject *obj, winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid); diff -r e377456302df -r a82d9beaa94a ui/winui/toolkit.cpp --- a/ui/winui/toolkit.cpp Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/toolkit.cpp Thu Oct 19 18:30:19 2023 +0200 @@ -180,6 +180,7 @@ } void ui_main() { + /* init_apartment(); //Application::Start([](auto&&) {make(); }); @@ -188,6 +189,28 @@ { ::winrt::make<::winrt::winui::implementation::App>(); }); + */ + { + void (WINAPI * pfnXamlCheckProcessRequirements)(); + auto module = ::LoadLibrary(L"Microsoft.ui.xaml.dll"); + if (module) + { + pfnXamlCheckProcessRequirements = reinterpret_cast(GetProcAddress(module, "XamlCheckProcessRequirements")); + if (pfnXamlCheckProcessRequirements) + { + (*pfnXamlCheckProcessRequirements)(); + } + + ::FreeLibrary(module); + } + } + + winrt::init_apartment(winrt::apartment_type::single_threaded); + ::winrt::Microsoft::UI::Xaml::Application::Start( + [](auto&&) + { + ::winrt::make<::winrt::winui::implementation::App>(); + }); } class UiWin { diff -r e377456302df -r a82d9beaa94a ui/winui/window.cpp --- a/ui/winui/window.cpp Tue Oct 17 21:50:48 2023 +0200 +++ b/ui/winui/window.cpp Thu Oct 19 18:30:19 2023 +0200 @@ -47,6 +47,7 @@ using namespace winrt; using namespace Microsoft::UI::Xaml; using namespace Microsoft::UI::Xaml::Controls; +using namespace Microsoft::UI::Xaml::Controls::Primitives; using namespace Microsoft::UI::Xaml::XamlTypeInfo; using namespace Microsoft::UI::Xaml::Markup; using namespace Windows::UI::Xaml::Interop; @@ -61,8 +62,12 @@ obj->ctx = uic_context(obj, mp); obj->window = window_data; - //Window window = Window(); - Window window = make(); + Window window = Window(); + //Window window = make(); + + winrt::Windows::Foundation::Uri resourceLocator{ L"ms-appx:///MainWindow.xaml" }; + Application::LoadComponent(window, resourceLocator, ComponentResourceLocation::Nested); + window.ExtendsContentIntoTitleBar(true); Grid grid = Grid();