Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/platform/windows/native_menu_windows.cpp
10277 views
1
/**************************************************************************/
2
/* native_menu_windows.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "native_menu_windows.h"
32
33
#include "display_server_windows.h"
34
35
#include "scene/resources/image_texture.h"
36
37
HBITMAP NativeMenuWindows::_make_bitmap(const Ref<Image> &p_img) const {
38
p_img->convert(Image::FORMAT_RGBA8);
39
40
Vector2i texture_size = p_img->get_size();
41
UINT image_size = texture_size.width * texture_size.height;
42
43
COLORREF *buffer = nullptr;
44
45
BITMAPV5HEADER bi;
46
ZeroMemory(&bi, sizeof(bi));
47
bi.bV5Size = sizeof(bi);
48
bi.bV5Width = texture_size.width;
49
bi.bV5Height = -texture_size.height;
50
bi.bV5Planes = 1;
51
bi.bV5BitCount = 32;
52
bi.bV5Compression = BI_BITFIELDS;
53
bi.bV5RedMask = 0x00ff0000;
54
bi.bV5GreenMask = 0x0000ff00;
55
bi.bV5BlueMask = 0x000000ff;
56
bi.bV5AlphaMask = 0xff000000;
57
58
HDC dc = GetDC(nullptr);
59
HBITMAP bitmap = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&buffer), nullptr, 0);
60
for (UINT index = 0; index < image_size; index++) {
61
int row_index = std::floor(index / texture_size.width);
62
int column_index = (index % int(texture_size.width));
63
const Color &c = p_img->get_pixel(column_index, row_index);
64
*(buffer + index) = c.to_argb32();
65
}
66
ReleaseDC(nullptr, dc);
67
68
return bitmap;
69
}
70
71
void NativeMenuWindows::_menu_activate(HMENU p_menu, int p_index) const {
72
if (menu_lookup.has(p_menu)) {
73
MenuData *md = menus.get_or_null(menu_lookup[p_menu]);
74
if (md) {
75
int count = GetMenuItemCount(md->menu);
76
if (p_index >= 0 && p_index < count) {
77
MENUITEMINFOW item;
78
ZeroMemory(&item, sizeof(item));
79
item.cbSize = sizeof(item);
80
item.fMask = MIIM_STATE | MIIM_DATA;
81
if (GetMenuItemInfoW(md->menu, p_index, true, &item)) {
82
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
83
if (item_data) {
84
if (item_data->callback.is_valid()) {
85
Variant ret;
86
Callable::CallError ce;
87
const Variant *args[1] = { &item_data->meta };
88
89
item_data->callback.callp(args, 1, ret, ce);
90
if (ce.error != Callable::CallError::CALL_OK) {
91
ERR_PRINT(vformat("Failed to execute menu callback: %s.", Variant::get_callable_error_text(item_data->callback, args, 1, ce)));
92
}
93
}
94
}
95
}
96
}
97
}
98
}
99
}
100
101
bool NativeMenuWindows::has_feature(Feature p_feature) const {
102
switch (p_feature) {
103
// case FEATURE_GLOBAL_MENU:
104
// case FEATURE_OPEN_CLOSE_CALLBACK:
105
// case FEATURE_HOVER_CALLBACK:
106
// case FEATURE_KEY_CALLBACK:
107
case FEATURE_POPUP_MENU:
108
return true;
109
default:
110
return false;
111
}
112
}
113
114
bool NativeMenuWindows::has_system_menu(SystemMenus p_menu_id) const {
115
return false;
116
}
117
118
RID NativeMenuWindows::get_system_menu(SystemMenus p_menu_id) const {
119
return RID();
120
}
121
122
RID NativeMenuWindows::create_menu() {
123
MenuData *md = memnew(MenuData);
124
md->menu = CreatePopupMenu();
125
126
MENUINFO menu_info;
127
ZeroMemory(&menu_info, sizeof(menu_info));
128
menu_info.cbSize = sizeof(menu_info);
129
menu_info.fMask = MIM_STYLE;
130
menu_info.dwStyle = MNS_NOTIFYBYPOS;
131
SetMenuInfo(md->menu, &menu_info);
132
133
RID rid = menus.make_rid(md);
134
menu_lookup[md->menu] = rid;
135
return rid;
136
}
137
138
bool NativeMenuWindows::has_menu(const RID &p_rid) const {
139
return menus.owns(p_rid);
140
}
141
142
void NativeMenuWindows::free_menu(const RID &p_rid) {
143
MenuData *md = menus.get_or_null(p_rid);
144
if (md) {
145
clear(p_rid);
146
DestroyMenu(md->menu);
147
menus.free(p_rid);
148
menu_lookup.erase(md->menu);
149
memdelete(md);
150
}
151
}
152
153
Size2 NativeMenuWindows::get_size(const RID &p_rid) const {
154
const MenuData *md = menus.get_or_null(p_rid);
155
ERR_FAIL_NULL_V(md, Size2());
156
157
Size2 size;
158
int count = GetMenuItemCount(md->menu);
159
for (int i = 0; i < count; i++) {
160
RECT rect;
161
if (GetMenuItemRect(nullptr, md->menu, i, &rect)) {
162
size.x = MAX(size.x, rect.right - rect.left);
163
size.y += rect.bottom - rect.top;
164
}
165
}
166
return size;
167
}
168
169
void NativeMenuWindows::popup(const RID &p_rid, const Vector2i &p_position) {
170
const MenuData *md = menus.get_or_null(p_rid);
171
ERR_FAIL_NULL(md);
172
173
HWND hwnd = (HWND)DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::WINDOW_HANDLE, DisplayServer::MAIN_WINDOW_ID);
174
UINT flags = TPM_HORIZONTAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_VERPOSANIMATION;
175
if (md->is_rtl) {
176
flags |= TPM_LAYOUTRTL;
177
}
178
SetForegroundWindow(hwnd);
179
TrackPopupMenuEx(md->menu, flags, p_position.x, p_position.y, hwnd, nullptr);
180
181
if (md->close_cb.is_valid()) {
182
Variant ret;
183
Callable::CallError ce;
184
md->close_cb.callp(nullptr, 0, ret, ce);
185
if (ce.error != Callable::CallError::CALL_OK) {
186
ERR_PRINT(vformat("Failed to execute popup close callback: %s.", Variant::get_callable_error_text(md->close_cb, nullptr, 0, ce)));
187
}
188
}
189
190
PostMessage(hwnd, WM_NULL, 0, 0);
191
}
192
193
void NativeMenuWindows::set_interface_direction(const RID &p_rid, bool p_is_rtl) {
194
MenuData *md = menus.get_or_null(p_rid);
195
ERR_FAIL_NULL(md);
196
197
if (md->is_rtl == p_is_rtl) {
198
return;
199
}
200
md->is_rtl = p_is_rtl;
201
}
202
203
void NativeMenuWindows::set_popup_open_callback(const RID &p_rid, const Callable &p_callback) {
204
// Not supported.
205
}
206
207
Callable NativeMenuWindows::get_popup_open_callback(const RID &p_rid) const {
208
// Not supported.
209
return Callable();
210
}
211
212
void NativeMenuWindows::set_popup_close_callback(const RID &p_rid, const Callable &p_callback) {
213
MenuData *md = menus.get_or_null(p_rid);
214
ERR_FAIL_NULL(md);
215
216
md->close_cb = p_callback;
217
}
218
219
Callable NativeMenuWindows::get_popup_close_callback(const RID &p_rid) const {
220
const MenuData *md = menus.get_or_null(p_rid);
221
ERR_FAIL_NULL_V(md, Callable());
222
223
return md->close_cb;
224
}
225
226
void NativeMenuWindows::set_minimum_width(const RID &p_rid, float p_width) {
227
// Not supported.
228
}
229
230
float NativeMenuWindows::get_minimum_width(const RID &p_rid) const {
231
// Not supported.
232
return 0.f;
233
}
234
235
bool NativeMenuWindows::is_opened(const RID &p_rid) const {
236
// Not supported.
237
return false;
238
}
239
240
int NativeMenuWindows::add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag, int p_index) {
241
MenuData *md = menus.get_or_null(p_rid);
242
MenuData *md_sub = menus.get_or_null(p_submenu_rid);
243
ERR_FAIL_NULL_V(md, -1);
244
ERR_FAIL_NULL_V(md_sub, -1);
245
ERR_FAIL_COND_V_MSG(md->menu == md_sub->menu, -1, "Can't set submenu to self!");
246
247
if (p_index == -1) {
248
p_index = GetMenuItemCount(md->menu);
249
} else {
250
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
251
}
252
253
MenuItemData *item_data = memnew(MenuItemData);
254
item_data->meta = p_tag;
255
item_data->checkable_type = CHECKABLE_TYPE_NONE;
256
item_data->max_states = 0;
257
item_data->state = 0;
258
259
Char16String label = p_label.utf16();
260
MENUITEMINFOW item;
261
ZeroMemory(&item, sizeof(item));
262
item.cbSize = sizeof(item);
263
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU;
264
item.fType = MFT_STRING;
265
item.hSubMenu = md_sub->menu;
266
item.dwItemData = (ULONG_PTR)item_data;
267
item.dwTypeData = (LPWSTR)label.get_data();
268
269
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
270
memdelete(item_data);
271
return -1;
272
}
273
return p_index;
274
}
275
276
int NativeMenuWindows::add_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
277
const MenuData *md = menus.get_or_null(p_rid);
278
ERR_FAIL_NULL_V(md, -1);
279
280
if (p_index == -1) {
281
p_index = GetMenuItemCount(md->menu);
282
} else {
283
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
284
}
285
286
MenuItemData *item_data = memnew(MenuItemData);
287
item_data->callback = p_callback;
288
item_data->meta = p_tag;
289
item_data->checkable_type = CHECKABLE_TYPE_NONE;
290
item_data->max_states = 0;
291
item_data->state = 0;
292
293
Char16String label = p_label.utf16();
294
MENUITEMINFOW item;
295
ZeroMemory(&item, sizeof(item));
296
item.cbSize = sizeof(item);
297
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
298
item.fType = MFT_STRING;
299
item.dwItemData = (ULONG_PTR)item_data;
300
item.dwTypeData = (LPWSTR)label.get_data();
301
302
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
303
memdelete(item_data);
304
return -1;
305
}
306
return p_index;
307
}
308
309
int NativeMenuWindows::add_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
310
const MenuData *md = menus.get_or_null(p_rid);
311
ERR_FAIL_NULL_V(md, -1);
312
313
if (p_index == -1) {
314
p_index = GetMenuItemCount(md->menu);
315
} else {
316
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
317
}
318
319
MenuItemData *item_data = memnew(MenuItemData);
320
item_data->callback = p_callback;
321
item_data->meta = p_tag;
322
item_data->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
323
item_data->max_states = 0;
324
item_data->state = 0;
325
326
Char16String label = p_label.utf16();
327
MENUITEMINFOW item;
328
ZeroMemory(&item, sizeof(item));
329
item.cbSize = sizeof(item);
330
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
331
item.fType = MFT_STRING;
332
item.dwItemData = (ULONG_PTR)item_data;
333
item.dwTypeData = (LPWSTR)label.get_data();
334
335
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
336
memdelete(item_data);
337
return -1;
338
}
339
return p_index;
340
}
341
342
int NativeMenuWindows::add_icon_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
343
const MenuData *md = menus.get_or_null(p_rid);
344
ERR_FAIL_NULL_V(md, -1);
345
346
if (p_index == -1) {
347
p_index = GetMenuItemCount(md->menu);
348
} else {
349
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
350
}
351
352
MenuItemData *item_data = memnew(MenuItemData);
353
item_data->callback = p_callback;
354
item_data->meta = p_tag;
355
item_data->checkable_type = CHECKABLE_TYPE_NONE;
356
item_data->max_states = 0;
357
item_data->state = 0;
358
if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
359
item_data->img = p_icon->get_image();
360
item_data->img = item_data->img->duplicate();
361
if (item_data->img->is_compressed()) {
362
item_data->img->decompress();
363
}
364
item_data->bmp = _make_bitmap(item_data->img);
365
}
366
367
Char16String label = p_label.utf16();
368
MENUITEMINFOW item;
369
ZeroMemory(&item, sizeof(item));
370
item.cbSize = sizeof(item);
371
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
372
item.fType = MFT_STRING;
373
item.dwItemData = (ULONG_PTR)item_data;
374
item.dwTypeData = (LPWSTR)label.get_data();
375
item.hbmpItem = item_data->bmp;
376
377
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
378
memdelete(item_data);
379
return -1;
380
}
381
return p_index;
382
}
383
384
int NativeMenuWindows::add_icon_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
385
const MenuData *md = menus.get_or_null(p_rid);
386
ERR_FAIL_NULL_V(md, -1);
387
388
if (p_index == -1) {
389
p_index = GetMenuItemCount(md->menu);
390
} else {
391
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
392
}
393
394
MenuItemData *item_data = memnew(MenuItemData);
395
item_data->callback = p_callback;
396
item_data->meta = p_tag;
397
item_data->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
398
item_data->max_states = 0;
399
item_data->state = 0;
400
if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
401
item_data->img = p_icon->get_image();
402
item_data->img = item_data->img->duplicate();
403
if (item_data->img->is_compressed()) {
404
item_data->img->decompress();
405
}
406
item_data->bmp = _make_bitmap(item_data->img);
407
}
408
409
Char16String label = p_label.utf16();
410
MENUITEMINFOW item;
411
ZeroMemory(&item, sizeof(item));
412
item.cbSize = sizeof(item);
413
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
414
item.fType = MFT_STRING;
415
item.dwItemData = (ULONG_PTR)item_data;
416
item.dwTypeData = (LPWSTR)label.get_data();
417
item.hbmpItem = item_data->bmp;
418
419
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
420
memdelete(item_data);
421
return -1;
422
}
423
return p_index;
424
}
425
426
int NativeMenuWindows::add_radio_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
427
const MenuData *md = menus.get_or_null(p_rid);
428
ERR_FAIL_NULL_V(md, -1);
429
430
if (p_index == -1) {
431
p_index = GetMenuItemCount(md->menu);
432
} else {
433
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
434
}
435
436
MenuItemData *item_data = memnew(MenuItemData);
437
item_data->callback = p_callback;
438
item_data->meta = p_tag;
439
item_data->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
440
item_data->max_states = 0;
441
item_data->state = 0;
442
443
Char16String label = p_label.utf16();
444
MENUITEMINFOW item;
445
ZeroMemory(&item, sizeof(item));
446
item.cbSize = sizeof(item);
447
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
448
item.fType = MFT_STRING | MFT_RADIOCHECK;
449
item.dwItemData = (ULONG_PTR)item_data;
450
item.dwTypeData = (LPWSTR)label.get_data();
451
452
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
453
memdelete(item_data);
454
return -1;
455
}
456
return p_index;
457
}
458
459
int NativeMenuWindows::add_icon_radio_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
460
const MenuData *md = menus.get_or_null(p_rid);
461
ERR_FAIL_NULL_V(md, -1);
462
463
if (p_index == -1) {
464
p_index = GetMenuItemCount(md->menu);
465
} else {
466
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
467
}
468
469
MenuItemData *item_data = memnew(MenuItemData);
470
item_data->callback = p_callback;
471
item_data->meta = p_tag;
472
item_data->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
473
item_data->max_states = 0;
474
item_data->state = 0;
475
if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
476
item_data->img = p_icon->get_image();
477
item_data->img = item_data->img->duplicate();
478
if (item_data->img->is_compressed()) {
479
item_data->img->decompress();
480
}
481
item_data->bmp = _make_bitmap(item_data->img);
482
}
483
484
Char16String label = p_label.utf16();
485
MENUITEMINFOW item;
486
ZeroMemory(&item, sizeof(item));
487
item.cbSize = sizeof(item);
488
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
489
item.fType = MFT_STRING | MFT_RADIOCHECK;
490
item.dwItemData = (ULONG_PTR)item_data;
491
item.dwTypeData = (LPWSTR)label.get_data();
492
item.hbmpItem = item_data->bmp;
493
494
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
495
memdelete(item_data);
496
return -1;
497
}
498
return p_index;
499
}
500
501
int NativeMenuWindows::add_multistate_item(const RID &p_rid, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
502
const MenuData *md = menus.get_or_null(p_rid);
503
ERR_FAIL_NULL_V(md, -1);
504
505
if (p_index == -1) {
506
p_index = GetMenuItemCount(md->menu);
507
} else {
508
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
509
}
510
511
MenuItemData *item_data = memnew(MenuItemData);
512
item_data->callback = p_callback;
513
item_data->meta = p_tag;
514
item_data->checkable_type = CHECKABLE_TYPE_NONE;
515
item_data->max_states = p_max_states;
516
item_data->state = p_default_state;
517
518
Char16String label = p_label.utf16();
519
MENUITEMINFOW item;
520
ZeroMemory(&item, sizeof(item));
521
item.cbSize = sizeof(item);
522
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
523
item.fType = MFT_STRING;
524
item.dwItemData = (ULONG_PTR)item_data;
525
item.dwTypeData = (LPWSTR)label.get_data();
526
527
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
528
memdelete(item_data);
529
return -1;
530
}
531
return p_index;
532
}
533
534
int NativeMenuWindows::add_separator(const RID &p_rid, int p_index) {
535
const MenuData *md = menus.get_or_null(p_rid);
536
ERR_FAIL_NULL_V(md, -1);
537
538
if (p_index == -1) {
539
p_index = GetMenuItemCount(md->menu);
540
} else {
541
p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
542
}
543
544
MenuItemData *item_data = memnew(MenuItemData);
545
item_data->checkable_type = CHECKABLE_TYPE_NONE;
546
item_data->max_states = 0;
547
item_data->state = 0;
548
549
MENUITEMINFOW item;
550
ZeroMemory(&item, sizeof(item));
551
item.cbSize = sizeof(item);
552
item.fMask = MIIM_FTYPE | MIIM_DATA;
553
item.fType = MFT_SEPARATOR;
554
item.dwItemData = (ULONG_PTR)item_data;
555
556
if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
557
memdelete(item_data);
558
return -1;
559
}
560
return p_index;
561
}
562
563
int NativeMenuWindows::find_item_index_with_text(const RID &p_rid, const String &p_text) const {
564
const MenuData *md = menus.get_or_null(p_rid);
565
ERR_FAIL_NULL_V(md, -1);
566
567
MENUITEMINFOW item;
568
int count = GetMenuItemCount(md->menu);
569
for (int i = 0; i < count; i++) {
570
ZeroMemory(&item, sizeof(item));
571
item.cbSize = sizeof(item);
572
item.fMask = MIIM_STRING;
573
item.dwTypeData = nullptr;
574
if (GetMenuItemInfoW(md->menu, i, true, &item)) {
575
item.cch++;
576
Char16String str;
577
str.resize_uninitialized(item.cch);
578
item.dwTypeData = (LPWSTR)str.ptrw();
579
if (GetMenuItemInfoW(md->menu, i, true, &item)) {
580
if (String::utf16((const char16_t *)str.get_data()) == p_text) {
581
return i;
582
}
583
}
584
}
585
}
586
return -1;
587
}
588
589
int NativeMenuWindows::find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) const {
590
const MenuData *md = menus.get_or_null(p_rid);
591
ERR_FAIL_NULL_V(md, -1);
592
593
MENUITEMINFOW item;
594
int count = GetMenuItemCount(md->menu);
595
for (int i = 0; i < count; i++) {
596
ZeroMemory(&item, sizeof(item));
597
item.cbSize = sizeof(item);
598
item.fMask = MIIM_DATA;
599
if (GetMenuItemInfoW(md->menu, i, true, &item)) {
600
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
601
if (item_data) {
602
if (item_data->meta == p_tag) {
603
return i;
604
}
605
}
606
}
607
}
608
return -1;
609
}
610
611
bool NativeMenuWindows::is_item_checked(const RID &p_rid, int p_idx) const {
612
ERR_FAIL_COND_V(p_idx < 0, false);
613
const MenuData *md = menus.get_or_null(p_rid);
614
ERR_FAIL_NULL_V(md, false);
615
int count = GetMenuItemCount(md->menu);
616
ERR_FAIL_COND_V(p_idx >= count, false);
617
618
MENUITEMINFOW item;
619
ZeroMemory(&item, sizeof(item));
620
item.cbSize = sizeof(item);
621
item.fMask = MIIM_STATE | MIIM_DATA;
622
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
623
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
624
if (item_data) {
625
return item_data->checked;
626
}
627
}
628
return false;
629
}
630
631
bool NativeMenuWindows::is_item_checkable(const RID &p_rid, int p_idx) const {
632
ERR_FAIL_COND_V(p_idx < 0, false);
633
const MenuData *md = menus.get_or_null(p_rid);
634
ERR_FAIL_NULL_V(md, false);
635
int count = GetMenuItemCount(md->menu);
636
ERR_FAIL_COND_V(p_idx >= count, false);
637
638
MENUITEMINFOW item;
639
ZeroMemory(&item, sizeof(item));
640
item.cbSize = sizeof(item);
641
item.fMask = MIIM_DATA;
642
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
643
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
644
if (item_data) {
645
return item_data->checkable_type == CHECKABLE_TYPE_CHECK_BOX;
646
}
647
}
648
return false;
649
}
650
651
bool NativeMenuWindows::is_item_radio_checkable(const RID &p_rid, int p_idx) const {
652
ERR_FAIL_COND_V(p_idx < 0, false);
653
const MenuData *md = menus.get_or_null(p_rid);
654
ERR_FAIL_NULL_V(md, false);
655
int count = GetMenuItemCount(md->menu);
656
ERR_FAIL_COND_V(p_idx >= count, false);
657
658
MENUITEMINFOW item;
659
ZeroMemory(&item, sizeof(item));
660
item.cbSize = sizeof(item);
661
item.fMask = MIIM_DATA;
662
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
663
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
664
if (item_data) {
665
return item_data->checkable_type == CHECKABLE_TYPE_RADIO_BUTTON;
666
}
667
}
668
return false;
669
}
670
671
Callable NativeMenuWindows::get_item_callback(const RID &p_rid, int p_idx) const {
672
ERR_FAIL_COND_V(p_idx < 0, Callable());
673
const MenuData *md = menus.get_or_null(p_rid);
674
ERR_FAIL_NULL_V(md, Callable());
675
int count = GetMenuItemCount(md->menu);
676
ERR_FAIL_COND_V(p_idx >= count, Callable());
677
678
MENUITEMINFOW item;
679
ZeroMemory(&item, sizeof(item));
680
item.cbSize = sizeof(item);
681
item.fMask = MIIM_DATA;
682
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
683
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
684
if (item_data) {
685
return item_data->callback;
686
}
687
}
688
return Callable();
689
}
690
691
Callable NativeMenuWindows::get_item_key_callback(const RID &p_rid, int p_idx) const {
692
// Not supported.
693
return Callable();
694
}
695
696
Variant NativeMenuWindows::get_item_tag(const RID &p_rid, int p_idx) const {
697
ERR_FAIL_COND_V(p_idx < 0, Variant());
698
const MenuData *md = menus.get_or_null(p_rid);
699
ERR_FAIL_NULL_V(md, Variant());
700
int count = GetMenuItemCount(md->menu);
701
ERR_FAIL_COND_V(p_idx >= count, Variant());
702
703
MENUITEMINFOW item;
704
ZeroMemory(&item, sizeof(item));
705
item.cbSize = sizeof(item);
706
item.fMask = MIIM_DATA;
707
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
708
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
709
if (item_data) {
710
return item_data->meta;
711
}
712
}
713
return Variant();
714
}
715
716
String NativeMenuWindows::get_item_text(const RID &p_rid, int p_idx) const {
717
ERR_FAIL_COND_V(p_idx < 0, String());
718
const MenuData *md = menus.get_or_null(p_rid);
719
ERR_FAIL_NULL_V(md, String());
720
int count = GetMenuItemCount(md->menu);
721
ERR_FAIL_COND_V(p_idx >= count, String());
722
723
MENUITEMINFOW item;
724
ZeroMemory(&item, sizeof(item));
725
item.cbSize = sizeof(item);
726
item.fMask = MIIM_STRING;
727
item.dwTypeData = nullptr;
728
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
729
item.cch++;
730
Char16String str;
731
str.resize_uninitialized(item.cch);
732
item.dwTypeData = (LPWSTR)str.ptrw();
733
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
734
return String::utf16((const char16_t *)str.get_data());
735
}
736
}
737
return String();
738
}
739
740
RID NativeMenuWindows::get_item_submenu(const RID &p_rid, int p_idx) const {
741
ERR_FAIL_COND_V(p_idx < 0, RID());
742
const MenuData *md = menus.get_or_null(p_rid);
743
ERR_FAIL_NULL_V(md, RID());
744
int count = GetMenuItemCount(md->menu);
745
ERR_FAIL_COND_V(p_idx >= count, RID());
746
747
MENUITEMINFOW item;
748
ZeroMemory(&item, sizeof(item));
749
item.cbSize = sizeof(item);
750
item.fMask = MIIM_SUBMENU;
751
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
752
if (menu_lookup.has(item.hSubMenu)) {
753
return menu_lookup[item.hSubMenu];
754
}
755
}
756
return RID();
757
}
758
759
Key NativeMenuWindows::get_item_accelerator(const RID &p_rid, int p_idx) const {
760
// Not supported.
761
return Key::NONE;
762
}
763
764
bool NativeMenuWindows::is_item_disabled(const RID &p_rid, int p_idx) const {
765
ERR_FAIL_COND_V(p_idx < 0, false);
766
const MenuData *md = menus.get_or_null(p_rid);
767
ERR_FAIL_NULL_V(md, false);
768
int count = GetMenuItemCount(md->menu);
769
ERR_FAIL_COND_V(p_idx >= count, false);
770
771
MENUITEMINFOW item;
772
ZeroMemory(&item, sizeof(item));
773
item.cbSize = sizeof(item);
774
item.fMask = MIIM_STATE;
775
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
776
return (item.fState & MFS_DISABLED) == MFS_DISABLED;
777
}
778
return false;
779
}
780
781
bool NativeMenuWindows::is_item_hidden(const RID &p_rid, int p_idx) const {
782
// Not supported.
783
return false;
784
}
785
786
String NativeMenuWindows::get_item_tooltip(const RID &p_rid, int p_idx) const {
787
// Not supported.
788
return String();
789
}
790
791
int NativeMenuWindows::get_item_state(const RID &p_rid, int p_idx) const {
792
ERR_FAIL_COND_V(p_idx < 0, -1);
793
const MenuData *md = menus.get_or_null(p_rid);
794
ERR_FAIL_NULL_V(md, -1);
795
int count = GetMenuItemCount(md->menu);
796
ERR_FAIL_COND_V(p_idx >= count, -1);
797
798
MENUITEMINFOW item;
799
ZeroMemory(&item, sizeof(item));
800
item.cbSize = sizeof(item);
801
item.fMask = MIIM_DATA;
802
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
803
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
804
if (item_data) {
805
return item_data->state;
806
}
807
}
808
return -1;
809
}
810
811
int NativeMenuWindows::get_item_max_states(const RID &p_rid, int p_idx) const {
812
ERR_FAIL_COND_V(p_idx < 0, -1);
813
const MenuData *md = menus.get_or_null(p_rid);
814
ERR_FAIL_NULL_V(md, -1);
815
int count = GetMenuItemCount(md->menu);
816
ERR_FAIL_COND_V(p_idx >= count, -1);
817
818
MENUITEMINFOW item;
819
ZeroMemory(&item, sizeof(item));
820
item.cbSize = sizeof(item);
821
item.fMask = MIIM_DATA;
822
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
823
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
824
if (item_data) {
825
return item_data->max_states;
826
}
827
}
828
return -1;
829
}
830
831
Ref<Texture2D> NativeMenuWindows::get_item_icon(const RID &p_rid, int p_idx) const {
832
ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
833
const MenuData *md = menus.get_or_null(p_rid);
834
ERR_FAIL_NULL_V(md, Ref<Texture2D>());
835
int count = GetMenuItemCount(md->menu);
836
ERR_FAIL_COND_V(p_idx >= count, Ref<Texture2D>());
837
838
MENUITEMINFOW item;
839
ZeroMemory(&item, sizeof(item));
840
item.cbSize = sizeof(item);
841
item.fMask = MIIM_DATA;
842
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
843
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
844
if (item_data) {
845
return ImageTexture::create_from_image(item_data->img);
846
}
847
}
848
return Ref<Texture2D>();
849
}
850
851
int NativeMenuWindows::get_item_indentation_level(const RID &p_rid, int p_idx) const {
852
// Not supported.
853
return 0;
854
}
855
856
void NativeMenuWindows::set_item_checked(const RID &p_rid, int p_idx, bool p_checked) {
857
ERR_FAIL_COND(p_idx < 0);
858
const MenuData *md = menus.get_or_null(p_rid);
859
ERR_FAIL_NULL(md);
860
int count = GetMenuItemCount(md->menu);
861
ERR_FAIL_COND(p_idx >= count);
862
863
MENUITEMINFOW item;
864
ZeroMemory(&item, sizeof(item));
865
item.cbSize = sizeof(item);
866
item.fMask = MIIM_STATE | MIIM_DATA;
867
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
868
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
869
if (item_data) {
870
item_data->checked = p_checked;
871
if (p_checked) {
872
item.fState |= MFS_CHECKED;
873
} else {
874
item.fState &= ~MFS_CHECKED;
875
}
876
}
877
SetMenuItemInfoW(md->menu, p_idx, true, &item);
878
}
879
}
880
881
void NativeMenuWindows::set_item_checkable(const RID &p_rid, int p_idx, bool p_checkable) {
882
ERR_FAIL_COND(p_idx < 0);
883
const MenuData *md = menus.get_or_null(p_rid);
884
ERR_FAIL_NULL(md);
885
int count = GetMenuItemCount(md->menu);
886
ERR_FAIL_COND(p_idx >= count);
887
888
MENUITEMINFOW item;
889
ZeroMemory(&item, sizeof(item));
890
item.cbSize = sizeof(item);
891
item.fMask = MIIM_FTYPE | MIIM_DATA;
892
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
893
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
894
if (item_data) {
895
item.fType &= ~MFT_RADIOCHECK;
896
item_data->checkable_type = (p_checkable) ? CHECKABLE_TYPE_CHECK_BOX : CHECKABLE_TYPE_NONE;
897
SetMenuItemInfoW(md->menu, p_idx, true, &item);
898
}
899
}
900
}
901
902
void NativeMenuWindows::set_item_radio_checkable(const RID &p_rid, int p_idx, bool p_checkable) {
903
ERR_FAIL_COND(p_idx < 0);
904
const MenuData *md = menus.get_or_null(p_rid);
905
ERR_FAIL_NULL(md);
906
int count = GetMenuItemCount(md->menu);
907
ERR_FAIL_COND(p_idx >= count);
908
909
MENUITEMINFOW item;
910
ZeroMemory(&item, sizeof(item));
911
item.cbSize = sizeof(item);
912
item.fMask = MIIM_FTYPE | MIIM_DATA;
913
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
914
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
915
if (item_data) {
916
if (p_checkable) {
917
item.fType |= MFT_RADIOCHECK;
918
item_data->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
919
} else {
920
item.fType &= ~MFT_RADIOCHECK;
921
item_data->checkable_type = CHECKABLE_TYPE_NONE;
922
}
923
SetMenuItemInfoW(md->menu, p_idx, true, &item);
924
}
925
}
926
}
927
928
void NativeMenuWindows::set_item_callback(const RID &p_rid, int p_idx, const Callable &p_callback) {
929
ERR_FAIL_COND(p_idx < 0);
930
const MenuData *md = menus.get_or_null(p_rid);
931
ERR_FAIL_NULL(md);
932
int count = GetMenuItemCount(md->menu);
933
ERR_FAIL_COND(p_idx >= count);
934
935
MENUITEMINFOW item;
936
ZeroMemory(&item, sizeof(item));
937
item.cbSize = sizeof(item);
938
item.fMask = MIIM_DATA;
939
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
940
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
941
if (item_data) {
942
item_data->callback = p_callback;
943
}
944
}
945
}
946
947
void NativeMenuWindows::set_item_key_callback(const RID &p_rid, int p_idx, const Callable &p_key_callback) {
948
// Not supported.
949
}
950
951
void NativeMenuWindows::set_item_hover_callbacks(const RID &p_rid, int p_idx, const Callable &p_callback) {
952
// Not supported.
953
}
954
955
void NativeMenuWindows::set_item_tag(const RID &p_rid, int p_idx, const Variant &p_tag) {
956
ERR_FAIL_COND(p_idx < 0);
957
const MenuData *md = menus.get_or_null(p_rid);
958
ERR_FAIL_NULL(md);
959
int count = GetMenuItemCount(md->menu);
960
ERR_FAIL_COND(p_idx >= count);
961
962
MENUITEMINFOW item;
963
ZeroMemory(&item, sizeof(item));
964
item.cbSize = sizeof(item);
965
item.fMask = MIIM_DATA;
966
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
967
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
968
if (item_data) {
969
item_data->meta = p_tag;
970
}
971
}
972
}
973
974
void NativeMenuWindows::set_item_text(const RID &p_rid, int p_idx, const String &p_text) {
975
ERR_FAIL_COND(p_idx < 0);
976
const MenuData *md = menus.get_or_null(p_rid);
977
ERR_FAIL_NULL(md);
978
int count = GetMenuItemCount(md->menu);
979
ERR_FAIL_COND(p_idx >= count);
980
981
Char16String label = p_text.utf16();
982
MENUITEMINFOW item;
983
ZeroMemory(&item, sizeof(item));
984
item.cbSize = sizeof(item);
985
item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
986
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
987
item.dwTypeData = (LPWSTR)label.get_data();
988
SetMenuItemInfoW(md->menu, p_idx, true, &item);
989
}
990
}
991
992
void NativeMenuWindows::set_item_submenu(const RID &p_rid, int p_idx, const RID &p_submenu_rid) {
993
ERR_FAIL_COND(p_idx < 0);
994
const MenuData *md = menus.get_or_null(p_rid);
995
ERR_FAIL_NULL(md);
996
int count = GetMenuItemCount(md->menu);
997
ERR_FAIL_COND(p_idx >= count);
998
999
MenuData *md_sub = menus.get_or_null(p_submenu_rid);
1000
ERR_FAIL_COND_MSG(md->menu == md_sub->menu, "Can't set submenu to self!");
1001
1002
MENUITEMINFOW item;
1003
ZeroMemory(&item, sizeof(item));
1004
item.cbSize = sizeof(item);
1005
item.fMask = MIIM_SUBMENU;
1006
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
1007
if (p_submenu_rid.is_valid()) {
1008
item.hSubMenu = md_sub->menu;
1009
} else {
1010
item.hSubMenu = nullptr;
1011
}
1012
SetMenuItemInfoW(md->menu, p_idx, true, &item);
1013
}
1014
}
1015
1016
void NativeMenuWindows::set_item_accelerator(const RID &p_rid, int p_idx, Key p_keycode) {
1017
// Not supported.
1018
}
1019
1020
void NativeMenuWindows::set_item_disabled(const RID &p_rid, int p_idx, bool p_disabled) {
1021
ERR_FAIL_COND(p_idx < 0);
1022
const MenuData *md = menus.get_or_null(p_rid);
1023
ERR_FAIL_NULL(md);
1024
int count = GetMenuItemCount(md->menu);
1025
ERR_FAIL_COND(p_idx >= count);
1026
1027
MENUITEMINFOW item;
1028
ZeroMemory(&item, sizeof(item));
1029
item.cbSize = sizeof(item);
1030
item.fMask = MIIM_STATE;
1031
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
1032
if (p_disabled) {
1033
item.fState |= MFS_DISABLED;
1034
} else {
1035
item.fState &= ~MFS_DISABLED;
1036
}
1037
SetMenuItemInfoW(md->menu, p_idx, true, &item);
1038
}
1039
}
1040
1041
void NativeMenuWindows::set_item_hidden(const RID &p_rid, int p_idx, bool p_hidden) {
1042
// Not supported.
1043
}
1044
1045
void NativeMenuWindows::set_item_tooltip(const RID &p_rid, int p_idx, const String &p_tooltip) {
1046
// Not supported.
1047
}
1048
1049
void NativeMenuWindows::set_item_state(const RID &p_rid, int p_idx, int p_state) {
1050
ERR_FAIL_COND(p_idx < 0);
1051
const MenuData *md = menus.get_or_null(p_rid);
1052
ERR_FAIL_NULL(md);
1053
int count = GetMenuItemCount(md->menu);
1054
ERR_FAIL_COND(p_idx >= count);
1055
1056
MENUITEMINFOW item;
1057
ZeroMemory(&item, sizeof(item));
1058
item.cbSize = sizeof(item);
1059
item.fMask = MIIM_DATA;
1060
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
1061
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
1062
if (item_data) {
1063
item_data->state = p_state;
1064
}
1065
}
1066
}
1067
1068
void NativeMenuWindows::set_item_max_states(const RID &p_rid, int p_idx, int p_max_states) {
1069
ERR_FAIL_COND(p_idx < 0);
1070
const MenuData *md = menus.get_or_null(p_rid);
1071
ERR_FAIL_NULL(md);
1072
int count = GetMenuItemCount(md->menu);
1073
ERR_FAIL_COND(p_idx >= count);
1074
1075
MENUITEMINFOW item;
1076
ZeroMemory(&item, sizeof(item));
1077
item.cbSize = sizeof(item);
1078
item.fMask = MIIM_DATA;
1079
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
1080
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
1081
if (item_data) {
1082
item_data->max_states = p_max_states;
1083
}
1084
}
1085
}
1086
1087
void NativeMenuWindows::set_item_icon(const RID &p_rid, int p_idx, const Ref<Texture2D> &p_icon) {
1088
ERR_FAIL_COND(p_idx < 0);
1089
const MenuData *md = menus.get_or_null(p_rid);
1090
ERR_FAIL_NULL(md);
1091
int count = GetMenuItemCount(md->menu);
1092
ERR_FAIL_COND(p_idx >= count);
1093
1094
MENUITEMINFOW item;
1095
ZeroMemory(&item, sizeof(item));
1096
item.cbSize = sizeof(item);
1097
item.fMask = MIIM_DATA | MIIM_BITMAP;
1098
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
1099
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
1100
if (item_data) {
1101
if (item_data->bmp) {
1102
DeleteObject(item_data->bmp);
1103
}
1104
if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
1105
item_data->img = p_icon->get_image();
1106
item_data->img = item_data->img->duplicate();
1107
if (item_data->img->is_compressed()) {
1108
item_data->img->decompress();
1109
}
1110
item_data->bmp = _make_bitmap(item_data->img);
1111
} else {
1112
item_data->img = Ref<Image>();
1113
item_data->bmp = nullptr;
1114
}
1115
item.hbmpItem = item_data->bmp;
1116
SetMenuItemInfoW(md->menu, p_idx, true, &item);
1117
}
1118
}
1119
}
1120
1121
void NativeMenuWindows::set_item_indentation_level(const RID &p_rid, int p_idx, int p_level) {
1122
// Not supported.
1123
}
1124
1125
int NativeMenuWindows::get_item_count(const RID &p_rid) const {
1126
const MenuData *md = menus.get_or_null(p_rid);
1127
ERR_FAIL_NULL_V(md, 0);
1128
1129
return GetMenuItemCount(md->menu);
1130
}
1131
1132
bool NativeMenuWindows::is_system_menu(const RID &p_rid) const {
1133
return false;
1134
}
1135
1136
void NativeMenuWindows::remove_item(const RID &p_rid, int p_idx) {
1137
ERR_FAIL_COND(p_idx < 0);
1138
const MenuData *md = menus.get_or_null(p_rid);
1139
ERR_FAIL_NULL(md);
1140
int count = GetMenuItemCount(md->menu);
1141
ERR_FAIL_COND(p_idx >= count);
1142
1143
MENUITEMINFOW item;
1144
ZeroMemory(&item, sizeof(item));
1145
item.cbSize = sizeof(item);
1146
item.fMask = MIIM_DATA;
1147
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
1148
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
1149
if (item_data) {
1150
if (item_data->bmp) {
1151
DeleteObject(item_data->bmp);
1152
}
1153
memdelete(item_data);
1154
}
1155
}
1156
RemoveMenu(md->menu, p_idx, MF_BYPOSITION);
1157
}
1158
1159
void NativeMenuWindows::clear(const RID &p_rid) {
1160
const MenuData *md = menus.get_or_null(p_rid);
1161
ERR_FAIL_NULL(md);
1162
1163
MENUITEMINFOW item;
1164
int count = GetMenuItemCount(md->menu);
1165
for (int i = 0; i < count; i++) {
1166
ZeroMemory(&item, sizeof(item));
1167
item.cbSize = sizeof(item);
1168
item.fMask = MIIM_DATA;
1169
if (GetMenuItemInfoW(md->menu, 0, true, &item)) {
1170
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
1171
if (item_data) {
1172
if (item_data->bmp) {
1173
DeleteObject(item_data->bmp);
1174
}
1175
memdelete(item_data);
1176
}
1177
}
1178
RemoveMenu(md->menu, 0, MF_BYPOSITION);
1179
}
1180
}
1181
1182
NativeMenuWindows::NativeMenuWindows() {}
1183
1184
NativeMenuWindows::~NativeMenuWindows() {}
1185
1186