diff -r 0f2e69873875 -r 320d85f3cd14 ui/winui/list.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/winui/list.cpp Mon Oct 02 19:31:06 2023 +0200 @@ -0,0 +1,165 @@ +/* + * 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 "list.h" +#include "container.h" +#include "util.h" + +#include "../common/context.h" +#include "../common/object.h" + +#include + +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; + +UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args) { + UiObject* current = uic_current_obj(obj); + + // create listview and toolkit wrapper + ListView listview = ListView(); + if (args.multiselection) { + listview.SelectionMode(ListViewSelectionMode::Extended); + } + + bool clickEnabled = listview.IsItemClickEnabled(); + listview.IsItemClickEnabled(true); + + + UIElement elm = listview; + UiWidget* widget = new UiWidget(elm); + widget->data1 = args.model; + widget->data2 = args.getvalue; + 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_simple_list_update; + list->obj = widget; + ui_simple_list_update(list, 0); + } + + if (args.onselection) { + ui_callback onselection = args.onselection; + void* cbdata = args.onselectiondata; + listview.SelectionChanged([onselection, cbdata, obj](IInspectable const& sender, RoutedEventArgs evtargs) { + std::vector selectedRows = ui_create_listview_selection(sender.as()); + + UiListSelection selection; + selection.rows = selectedRows.data(); + selection.count = selectedRows.size(); + + UiEvent evt; + evt.obj = obj; + evt.window = obj->window; + evt.document = obj->ctx->document; + evt.eventdata = &selection; + evt.intval = 0; + onselection(&evt, cbdata); + }); + } + if (args.onactivate) { + ui_callback cb = args.onactivate; + void* cbdata = args.onactivatedata; + listview.ItemClick([cb, cbdata, obj](IInspectable const& sender, RoutedEventArgs evtargs) { + std::vector selectedRows = ui_create_listview_selection(sender.as()); + UiListSelection selection; + selection.rows = selectedRows.data(); + selection.count = selectedRows.size(); + + UiEvent evt; + evt.obj = obj; + evt.window = obj->window; + evt.document = obj->ctx->document; + evt.eventdata = &selection; + evt.intval = 0; + cb(&evt, cbdata); + }); + } + + // add listview to current container + UI_APPLY_LAYOUT1(current, args); + + current->container->Add(listview, false); + + return widget; +} + +static void* getstrvalue(void* elm, int ignore) { + return elm; +} + +void ui_simple_list_update(UiList* list, int i) { + UiWidget* widget = (UiWidget*)list->obj; + UiModel* model = (UiModel*)widget->data1; + ui_getvaluefunc getvalue = (ui_getvaluefunc)widget->data2; + ListView listview = widget->uielement.as(); + auto items = listview.Items(); + + // priority: getvalue, model.getvalue, getstrvalue (fallback) + if (getvalue == nullptr) { + if (model && model->getvalue) { + getvalue = model->getvalue; + } else { + getvalue = getstrvalue; + } + } + + // add list elements to listview.Items + items.Clear(); + void* elm = list->first(list); + while (elm) { + char* value = (char*)getvalue(elm, 0); + wchar_t* wstr = str2wstr(value, nullptr); + items.Append(box_value(wstr)); + free(wstr); + + elm = list->next(list); + } +} + +std::vector ui_create_listview_selection(ListView listview) { + std::vector selection; + int p = 0; + auto ranges = listview.SelectedRanges(); + for (auto range : ranges) { + int begin = range.FirstIndex(); + int end = range.LastIndex(); + for (int i = begin; i <= end; i++) { + selection.push_back(i); + } + } + return selection; +} +