ui/winui/list.cpp

changeset 431
bb7da585debc
parent 382
de653b07050b
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2023 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 "pch.h"
30
31 #include "list.h"
32 #include "container.h"
33 #include "util.h"
34
35 #include "../common/context.h"
36 #include "../common/object.h"
37
38
39 using namespace winrt;
40 using namespace Microsoft::UI::Xaml;
41 using namespace Microsoft::UI::Xaml::Controls;
42 using namespace Windows::UI::Xaml::Interop;
43 using namespace winrt::Windows::Foundation;
44 using namespace Microsoft::UI::Xaml::Markup;
45 using namespace Microsoft::UI::Xaml::Media;
46 using namespace winrt::Microsoft::UI::Xaml::Controls::Primitives;
47
48
49 UIWIDGET ui_listview_create(UiObject* obj, UiListArgs args) {
50 UiObject* current = uic_current_obj(obj);
51
52 // create listview and toolkit wrapper
53 ListView listview = ListView();
54 if (args.multiselection) {
55 listview.SelectionMode(ListViewSelectionMode::Extended);
56 }
57
58 bool clickEnabled = listview.IsItemClickEnabled();
59 listview.IsItemClickEnabled(true);
60
61
62 UIElement elm = listview;
63 UiWidget* widget = new UiWidget(elm);
64 widget->data1 = args.model;
65 widget->data2 = args.getvalue;
66 ui_context_add_widget_destructor(current->ctx, widget);
67 ui_set_widget_groups(current->ctx, widget, args.groups);
68
69 // bind var
70 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
71 if (var) {
72 UiList* list = (UiList*)var->value;
73 list->update = ui_simple_list_update;
74 list->getselection = ui_listview_getselection;
75 list->setselection = ui_listview_setselection;
76 list->obj = widget;
77
78 ui_simple_list_update(list, 0);
79 }
80
81 if (args.onselection) {
82 ui_callback onselection = args.onselection;
83 void* cbdata = args.onselectiondata;
84 listview.SelectionChanged([onselection, cbdata, obj](IInspectable const& sender, RoutedEventArgs evtargs) {
85 std::vector<int> selectedRows = ui_create_listview_selection(sender.as<ListView>());
86
87 UiListSelection selection;
88 selection.rows = selectedRows.data();
89 selection.count = selectedRows.size();
90
91 UiEvent evt;
92 evt.obj = obj;
93 evt.window = obj->window;
94 evt.document = obj->ctx->document;
95 evt.eventdata = &selection;
96 evt.intval = 0;
97 onselection(&evt, cbdata);
98 });
99 }
100 if (args.onactivate) {
101 ui_callback cb = args.onactivate;
102 void* cbdata = args.onactivatedata;
103 listview.ItemClick([cb, cbdata, obj](IInspectable const& sender, RoutedEventArgs evtargs) {
104 std::vector<int> selectedRows = ui_create_listview_selection(sender.as<ListView>());
105 UiListSelection selection;
106 selection.rows = selectedRows.data();
107 selection.count = selectedRows.size();
108
109 UiEvent evt;
110 evt.obj = obj;
111 evt.window = obj->window;
112 evt.document = obj->ctx->document;
113 evt.eventdata = &selection;
114 evt.intval = 0;
115 cb(&evt, cbdata);
116 });
117 }
118
119 // add listview to current container
120 UI_APPLY_LAYOUT1(current, args);
121
122 current->container->Add(listview, false);
123
124 return widget;
125 }
126
127
128 UIWIDGET ui_combobox_create(UiObject* obj, UiListArgs args) {
129 UiObject* current = uic_current_obj(obj);
130
131 // create listview and toolkit wrapper
132 ComboBox combobox = ComboBox();
133
134 UIElement elm = combobox;
135 UiWidget* widget = new UiWidget(elm);
136 widget->data1 = args.model;
137 widget->data2 = args.getvalue;
138 ui_context_add_widget_destructor(current->ctx, widget);
139 ui_set_widget_groups(current->ctx, widget, args.groups);
140
141 // bind var
142 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
143 if (var) {
144 UiList* list = (UiList*)var->value;
145 list->update = ui_simple_list_update;
146 list->getselection = ui_dropdown_getselection;
147 list->setselection = ui_dropdown_setselection;
148 list->obj = widget;
149 ui_simple_list_update(list, 0);
150 }
151
152 if (args.onactivate) {
153 ui_callback cb = args.onactivate;
154 void* cbdata = args.onactivatedata;
155 combobox.SelectionChanged([cb, cbdata, obj](IInspectable const& sender, RoutedEventArgs evtargs) {
156 int selectedrow = sender.as<ComboBox>().SelectedIndex();
157 UiListSelection selection;
158 selection.count = 1;
159 selection.rows = &selectedrow;
160
161 UiEvent evt;
162 evt.obj = obj;
163 evt.window = obj->window;
164 evt.document = obj->ctx->document;
165 evt.eventdata = &selection;
166 evt.intval = selectedrow;
167 cb(&evt, cbdata);
168 });
169 }
170
171 // add listview to current container
172 UI_APPLY_LAYOUT1(current, args);
173
174 current->container->Add(combobox, false);
175
176 return widget;
177 }
178
179 UiListSelection ui_listview_getselection(UiList *list) {
180 UiWidget *widget = (UiWidget*)list->obj;
181 ListView listview = widget->uielement.as<ListView>();
182 std::vector<int> selectedRows = ui_create_listview_selection(listview);
183
184 UiListSelection selection = { NULL, 0 };
185 if (selectedRows.size() > 0) {
186 selection.count = selectedRows.size();
187 int *data = selectedRows.data();
188 selection.rows = (int*)calloc(selection.count, sizeof(int));
189 memcpy(selection.rows, data, selection.count);
190 }
191
192 return selection;
193 }
194
195 void ui_listview_setselection(UiList *list, UiListSelection selection) {
196 UiWidget* widget = (UiWidget*)list->obj;
197 if (selection.count > 0) {
198 ListView listview = widget->uielement.as<ListView>();
199 listview.SelectedIndex(selection.rows[0]);
200 }
201 }
202
203 UiListSelection ui_dropdown_getselection(UiList *list) {
204 UiWidget* widget = (UiWidget*)list->obj;
205 ComboBox cb = widget->uielement.as<ComboBox>();
206 int index = cb.SelectedIndex();
207 UiListSelection selection = { NULL, 0 };
208 if (index >= 0) {
209 selection.rows = (int*)calloc(1, sizeof(int));
210 selection.count = 1;
211 selection.rows[0] = index;
212 }
213 return selection;
214 }
215
216 void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
217 UiWidget* widget = (UiWidget*)list->obj;
218 if (selection.count > 0) {
219 ComboBox cb = widget->uielement.as<ComboBox>();
220 cb.SelectedIndex(selection.rows[0]);
221 }
222 }
223
224 UIEXPORT UIWIDGET ui_breadcrumbbar_create(UiObject* obj, UiListArgs args) {
225 UiObject* current = uic_current_obj(obj);
226
227 // create listview and toolkit wrapper
228 BreadcrumbBar bcbar = BreadcrumbBar();
229
230 UIElement elm = bcbar;
231 UiWidget* widget = new UiWidget(elm);
232 widget->data1 = args.model;
233 widget->data2 = args.getvalue;
234 ui_context_add_widget_destructor(current->ctx, widget);
235 ui_set_widget_groups(current->ctx, widget, args.groups);
236
237 // bind var
238 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST);
239 if (var) {
240 UiList* list = (UiList*)var->value;
241 list->update = ui_breadcrumbbar_update;
242 list->obj = widget;
243 ui_breadcrumbbar_update(list, 0);
244 }
245
246 if (args.onactivate) {
247 ui_callback cb = args.onactivate;
248 void* cbdata = args.onactivatedata;
249 bcbar.ItemClicked([cb, cbdata, obj](IInspectable const& sender, BreadcrumbBarItemClickedEventArgs evtargs) {
250 UiEvent evt;
251 evt.obj = obj;
252 evt.window = obj->window;
253 evt.document = obj->ctx->document;
254 evt.eventdata = nullptr;
255 evt.intval = evtargs.Index();
256 cb(&evt, cbdata);
257 });
258 }
259
260 // add listview to current container
261 UI_APPLY_LAYOUT1(current, args);
262
263 current->container->Add(bcbar, false);
264
265 return widget;
266 }
267
268 static void* getstrvalue(void* elm, int ignore) {
269 return elm;
270 }
271
272 void ui_simple_list_update(UiList* list, int i) {
273 UiWidget* widget = (UiWidget*)list->obj;
274 UiModel* model = (UiModel*)widget->data1;
275 ui_getvaluefunc getvalue = (ui_getvaluefunc)widget->data2;
276 ItemsControl listview = widget->uielement.as<ItemsControl>();
277 auto items = listview.Items();
278
279 // priority: getvalue, model.getvalue, getstrvalue (fallback)
280 if (getvalue == nullptr) {
281 if (model && model->getvalue) {
282 getvalue = model->getvalue;
283 } else {
284 getvalue = getstrvalue;
285 }
286 }
287
288 // add list elements to listview.Items
289 items.Clear();
290 void* elm = list->first(list);
291 while (elm) {
292 char* value = (char*)getvalue(elm, 0);
293 wchar_t* wstr = str2wstr(value, nullptr);
294 items.Append(box_value(wstr));
295 free(wstr);
296
297 elm = list->next(list);
298 }
299 }
300
301 extern "C" void ui_breadcrumbbar_update(UiList * list, int i) {
302 UiWidget* widget = (UiWidget*)list->obj;
303 UiModel* model = (UiModel*)widget->data1;
304 ui_getvaluefunc getvalue = (ui_getvaluefunc)widget->data2;
305
306 // priority: getvalue, model.getvalue, getstrvalue (fallback)
307 if (getvalue == nullptr) {
308 if (model && model->getvalue) {
309 getvalue = model->getvalue;
310 }
311 else {
312 getvalue = getstrvalue;
313 }
314 }
315
316 BreadcrumbBar bar = widget->uielement.as<BreadcrumbBar>();
317
318 Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> items { winrt::single_threaded_vector<Windows::Foundation::IInspectable>() };
319 void* elm = list->first(list);
320 while (elm) {
321 char* value = (char*)getvalue(elm, 0);
322 wchar_t* wstr = str2wstr(value, nullptr);
323 items.Append(box_value(wstr));
324 free(wstr);
325
326 elm = list->next(list);
327 }
328
329 bar.ItemsSource(items);
330 }
331
332
333 std::vector<int> ui_create_listview_selection(ListView listview) {
334 std::vector<int> selection;
335 int p = 0;
336 auto ranges = listview.SelectedRanges();
337 for (auto range : ranges) {
338 int begin = range.FirstIndex();
339 int end = range.LastIndex();
340 for (int i = begin; i <= end; i++) {
341 selection.push_back(i);
342 }
343 }
344 return selection;
345 }
346

mercurial