|
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 "appmenu.h" |
|
32 |
|
33 #include <cx/linked_list.h> |
|
34 #include <cx/array_list.h> |
|
35 |
|
36 #include "../common/context.h" |
|
37 #include "../common/object.h" |
|
38 |
|
39 #include "util.h" |
|
40 |
|
41 |
|
42 using namespace winrt; |
|
43 using namespace Microsoft::UI::Xaml; |
|
44 using namespace Microsoft::UI::Xaml::Controls; |
|
45 using namespace Microsoft::UI::Xaml::XamlTypeInfo; |
|
46 using namespace Microsoft::UI::Xaml::Markup; |
|
47 using namespace Windows::UI::Xaml::Interop; |
|
48 |
|
49 static void add_top_menu_widget(MenuBar &parent, int i, UiMenuItemI* item, UiObject* obj); |
|
50 |
|
51 static void add_menu_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj); |
|
52 static void add_menuitem_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj); |
|
53 static void add_menuseparator_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj); |
|
54 static void add_checkitem_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj); |
|
55 static void add_radioitem_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj); |
|
56 static void add_menuitem_list_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj); |
|
57 |
|
58 static ui_menu_add_f createMenuItem[] = { |
|
59 /* UI_MENU */ add_menu_widget, |
|
60 /* UI_MENU_ITEM */ add_menuitem_widget, |
|
61 /* UI_MENU_CHECK_ITEM */ add_checkitem_widget, |
|
62 /* UI_MENU_RADIO_ITEM */ add_radioitem_widget, |
|
63 /* UI_MENU_ITEM_LIST */ add_menuitem_list_widget, |
|
64 /* UI_MENU_CHECKITEM_LIST */ add_menuitem_list_widget, |
|
65 /* UI_MENU_RADIOITEM_LIST */ add_menuitem_list_widget, |
|
66 /* UI_MENU_SEPARATOR */ add_menuseparator_widget |
|
67 }; |
|
68 |
|
69 winrt::Microsoft::UI::Xaml::Controls::MenuBar ui_create_menubar(UiObject* obj) { |
|
70 MenuBar mb = MenuBar(); |
|
71 |
|
72 UiMenu* menus_begin = uic_get_menu_list(); |
|
73 |
|
74 UiMenu* ls = menus_begin; |
|
75 while (ls) { |
|
76 UiMenu* menu = ls; |
|
77 add_top_menu_widget(mb, 0, &menu->item, obj); |
|
78 |
|
79 ls = (UiMenu*)ls->item.next; |
|
80 } |
|
81 |
|
82 return mb; |
|
83 } |
|
84 |
|
85 static void add_top_menu_widget(MenuBar& parent, int i, UiMenuItemI* item, UiObject* obj) { |
|
86 UiMenu* menu = (UiMenu*)item; |
|
87 |
|
88 MenuBarItem mi = MenuBarItem(); |
|
89 wchar_t* wlabel = str2wstr(menu->label, NULL); |
|
90 mi.Title(wlabel); |
|
91 free(wlabel); |
|
92 |
|
93 UiMenuItemI* it = menu->items_begin; |
|
94 int index = 0; |
|
95 while (it) { |
|
96 createMenuItem[it->type](mi.Items(), index, it, obj); |
|
97 |
|
98 it = it->next; |
|
99 index++; |
|
100 } |
|
101 |
|
102 parent.Items().Append(mi); |
|
103 } |
|
104 |
|
105 static void add_menu_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj) { |
|
106 UiMenu* menu = (UiMenu*)item; |
|
107 |
|
108 MenuFlyoutSubItem mi = MenuFlyoutSubItem(); |
|
109 wchar_t* wlabel = str2wstr(menu->label, NULL); |
|
110 mi.Text(wlabel); |
|
111 free(wlabel); |
|
112 |
|
113 parent.Append(mi); |
|
114 |
|
115 UiMenuItemI* it = menu->items_begin; |
|
116 int index = 0; |
|
117 while (it) { |
|
118 createMenuItem[it->type](mi.Items(), index, it, obj); |
|
119 |
|
120 it = it->next; |
|
121 index++; |
|
122 } |
|
123 |
|
124 |
|
125 } |
|
126 |
|
127 static void add_menuitem_widget(winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, int i, UiMenuItemI* item, UiObject* obj) { |
|
128 UiMenuItem* it = (UiMenuItem*)item; |
|
129 |
|
130 MenuFlyoutItem mi = MenuFlyoutItem(); |
|
131 wchar_t* wlabel = str2wstr(it->label, NULL); |
|
132 mi.Text(wlabel); |
|
133 free(wlabel); |
|
134 |
|
135 parent.Append(mi); |
|
136 } |
|
137 |
|
138 static void add_menuseparator_widget( |
|
139 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, |
|
140 int i, |
|
141 UiMenuItemI* item, |
|
142 UiObject* obj) |
|
143 { |
|
144 |
|
145 } |
|
146 |
|
147 static void add_checkitem_widget( |
|
148 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, |
|
149 int i, |
|
150 UiMenuItemI* item, |
|
151 UiObject* obj) |
|
152 { |
|
153 |
|
154 } |
|
155 |
|
156 static void add_radioitem_widget( |
|
157 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, |
|
158 int i, |
|
159 UiMenuItemI* item, |
|
160 UiObject* obj) |
|
161 { |
|
162 |
|
163 } |
|
164 |
|
165 |
|
166 class UiMenuList { |
|
167 public: |
|
168 UiObject *obj = nullptr; |
|
169 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent = { nullptr }; |
|
170 UiMenuItemType type; |
|
171 int prevSize = 0; |
|
172 int insertPos = 0; |
|
173 UiVar* var = nullptr; |
|
174 ui_getvaluefunc getvalue = nullptr; |
|
175 ui_callback callback = nullptr; |
|
176 void* userdata = nullptr; |
|
177 |
|
178 UiMenuList() { |
|
179 |
|
180 } |
|
181 |
|
182 void updateItems() { |
|
183 UiList* list = (UiList*)var->value; |
|
184 |
|
185 // delete previous items |
|
186 for (int i = 0; i < prevSize; i++) { |
|
187 parent.RemoveAt(insertPos); |
|
188 } |
|
189 |
|
190 // insert new items |
|
191 int count = 0; |
|
192 void* elm = list->first(list); |
|
193 while (elm) { |
|
194 char *menuItemLabel = (char*) (getvalue ? getvalue(elm, 0) : elm); |
|
195 |
|
196 MenuFlyoutItem mi = MenuFlyoutItem(); |
|
197 wchar_t* wlabel = str2wstr(menuItemLabel ? menuItemLabel : "", NULL); |
|
198 mi.Text(wlabel); |
|
199 free(wlabel); |
|
200 |
|
201 if (callback) { |
|
202 mi.Click([this, elm, count](Windows::Foundation::IInspectable const& sender, RoutedEventArgs const& e) |
|
203 { |
|
204 UiEvent evt; |
|
205 evt.obj = obj; |
|
206 evt.window = obj->window; |
|
207 evt.document = obj->ctx->document; |
|
208 evt.eventdata = elm; |
|
209 evt.intval = count; |
|
210 callback(&evt, userdata); |
|
211 }); |
|
212 } |
|
213 |
|
214 parent.InsertAt(insertPos + count, mi); |
|
215 |
|
216 elm = list->next(list); |
|
217 count++; |
|
218 } |
|
219 |
|
220 prevSize = count; |
|
221 } |
|
222 }; |
|
223 |
|
224 extern "C" void destroy_ui_menu_list(void* ptr) { |
|
225 UiMenuList* ls = (UiMenuList*)ptr; |
|
226 delete ls; |
|
227 } |
|
228 |
|
229 static void ui_context_add_menu_list_destructor(UiContext* ctx, UiMenuList* list) { |
|
230 cxMempoolRegister(ctx->mp, list, destroy_ui_menu_list); |
|
231 } |
|
232 |
|
233 static void ui_menulist_update(UiEvent* event, void* userdata) { |
|
234 UiMenuList* mlist = (UiMenuList*)userdata; |
|
235 mlist->updateItems(); |
|
236 } |
|
237 |
|
238 static void add_menuitem_list_widget( |
|
239 winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::UI::Xaml::Controls::MenuFlyoutItemBase> parent, |
|
240 int i, |
|
241 UiMenuItemI* item, |
|
242 UiObject* obj) |
|
243 { |
|
244 UiMenuItemList* it = (UiMenuItemList*)item; |
|
245 if (!it->varname) { |
|
246 return; |
|
247 } |
|
248 |
|
249 uint32_t size = parent.Size(); |
|
250 |
|
251 UiVar* var = uic_create_var(ui_global_context(), it->varname, UI_VAR_LIST); |
|
252 |
|
253 UiMenuList* mlist = new UiMenuList(); |
|
254 mlist->obj = obj; |
|
255 mlist->parent = parent; |
|
256 mlist->getvalue = it->getvalue; |
|
257 mlist->callback = it->callback; |
|
258 mlist->userdata = it->userdata; |
|
259 mlist->prevSize = 0; |
|
260 mlist->insertPos = size; |
|
261 mlist->type = item->type; |
|
262 mlist->var = var; |
|
263 ui_context_add_menu_list_destructor(obj->ctx, mlist); |
|
264 |
|
265 UiList* list = (UiList*)var->value; |
|
266 list->observers = ui_add_observer(list->observers, ui_menulist_update, mlist); |
|
267 |
|
268 mlist->updateItems(); |
|
269 } |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 winrt::Microsoft::UI::Xaml::Controls::MenuFlyout ui_create_menu_flyout(UiObject* obj, UiMenu* menudef) { |
|
275 MenuFlyout flyout = MenuFlyout(); |
|
276 |
|
277 UiMenuItemI* it = menudef->items_begin; |
|
278 int index = 0; |
|
279 while (it) { |
|
280 createMenuItem[it->type](flyout.Items(), index, it, obj); |
|
281 |
|
282 it = it->next; |
|
283 index++; |
|
284 } |
|
285 |
|
286 return flyout; |
|
287 } |
|
288 |
|
289 UIMENU ui_contextmenu_create(UiMenuBuilder *builder, UiObject *obj, UIWIDGET widget) { |
|
290 return NULL; |
|
291 } |
|
292 |
|
293 void ui_contextmenu_popup(UIMENU menu, UIWIDGET widget, int x, int y) { |
|
294 |
|
295 } |