Skip to content

Commit 9804a8e

Browse files
committed
Merge pull request #94061 from bruvzg/menu_is_native
[NativeMenu] Do not auto toggle check/multi-state items. Add `is_native_menu` method.
2 parents f4bf25c + eddc9ce commit 9804a8e

9 files changed

+62
-64
lines changed

doc/classes/PopupMenu.xml

+7
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,12 @@
395395
Returns [code]true[/code] if the specified item's shortcut is disabled.
396396
</description>
397397
</method>
398+
<method name="is_native_menu" qualifiers="const">
399+
<return type="bool" />
400+
<description>
401+
Returns [code]true[/code] if the system native menu is supported and currently used by this [PopupMenu].
402+
</description>
403+
</method>
398404
<method name="is_system_menu" qualifiers="const">
399405
<return type="bool" />
400406
<description>
@@ -636,6 +642,7 @@
636642
</member>
637643
<member name="prefer_native_menu" type="bool" setter="set_prefer_native_menu" getter="is_prefer_native_menu" default="false">
638644
If [code]true[/code], [MenuBar] will use native menu when supported.
645+
[b]Note:[/b] If [PopupMenu] is linked to [StatusIndicator], [MenuBar], or another [PopupMenu] item it can use native menu regardless of this property, use [method is_native_menu] to check it.
639646
</member>
640647
<member name="submenu_popup_delay" type="float" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay" default="0.3">
641648
Sets the delay time in seconds for the submenu item to popup on mouse hovering. If the popup menu is added as a child of another (acting as a submenu), it will inherit the delay time of the parent menu item.

platform/macos/display_server_macos.mm

-16
Original file line numberDiff line numberDiff line change
@@ -568,23 +568,7 @@
568568
}
569569

570570
GodotMenuItem *value = [p_sender representedObject];
571-
572571
if (value) {
573-
if (value->max_states > 0) {
574-
value->state++;
575-
if (value->state >= value->max_states) {
576-
value->state = 0;
577-
}
578-
}
579-
580-
if (value->checkable_type == CHECKABLE_TYPE_CHECK_BOX) {
581-
if ([p_sender state] == NSControlStateValueOff) {
582-
[p_sender setState:NSControlStateValueOn];
583-
} else {
584-
[p_sender setState:NSControlStateValueOff];
585-
}
586-
}
587-
588572
if (value->callback.is_valid()) {
589573
MenuCall mc;
590574
mc.tag = value->meta;

platform/macos/godot_menu_item.h

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum GlobalMenuCheckType {
5252
Callable hover_callback;
5353
Variant meta;
5454
GlobalMenuCheckType checkable_type;
55+
bool checked;
5556
int max_states;
5657
int state;
5758
Ref<Image> img;

platform/macos/godot_menu_item.mm

+14
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,18 @@
3131
#include "godot_menu_item.h"
3232

3333
@implementation GodotMenuItem
34+
35+
- (id)init {
36+
self = [super init];
37+
38+
self->callback = Callable();
39+
self->key_callback = Callable();
40+
self->checkable_type = GlobalMenuCheckType::CHECKABLE_TYPE_NONE;
41+
self->checked = false;
42+
self->max_states = 0;
43+
self->state = 0;
44+
45+
return self;
46+
}
47+
3448
@end

platform/macos/native_menu_macos.mm

+12-25
Original file line numberDiff line numberDiff line change
@@ -373,12 +373,7 @@
373373
menu_item = [md->menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];
374374

375375
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
376-
obj->callback = Callable();
377-
obj->key_callback = Callable();
378376
obj->meta = p_tag;
379-
obj->checkable_type = CHECKABLE_TYPE_NONE;
380-
obj->max_states = 0;
381-
obj->state = 0;
382377
[menu_item setRepresentedObject:obj];
383378

384379
[md_sub->menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]];
@@ -417,9 +412,6 @@
417412
obj->callback = p_callback;
418413
obj->key_callback = p_key_callback;
419414
obj->meta = p_tag;
420-
obj->checkable_type = CHECKABLE_TYPE_NONE;
421-
obj->max_states = 0;
422-
obj->state = 0;
423415
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
424416
[menu_item setRepresentedObject:obj];
425417
}
@@ -438,8 +430,6 @@
438430
obj->key_callback = p_key_callback;
439431
obj->meta = p_tag;
440432
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
441-
obj->max_states = 0;
442-
obj->state = 0;
443433
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
444434
[menu_item setRepresentedObject:obj];
445435
}
@@ -457,9 +447,6 @@
457447
obj->callback = p_callback;
458448
obj->key_callback = p_key_callback;
459449
obj->meta = p_tag;
460-
obj->checkable_type = CHECKABLE_TYPE_NONE;
461-
obj->max_states = 0;
462-
obj->state = 0;
463450
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
464451
if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
465452
obj->img = p_icon->get_image();
@@ -489,8 +476,6 @@
489476
obj->key_callback = p_key_callback;
490477
obj->meta = p_tag;
491478
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
492-
obj->max_states = 0;
493-
obj->state = 0;
494479
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
495480
if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
496481
obj->img = p_icon->get_image();
@@ -520,8 +505,6 @@
520505
obj->key_callback = p_key_callback;
521506
obj->meta = p_tag;
522507
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
523-
obj->max_states = 0;
524-
obj->state = 0;
525508
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
526509
[menu_item setRepresentedObject:obj];
527510
}
@@ -540,8 +523,6 @@
540523
obj->key_callback = p_key_callback;
541524
obj->meta = p_tag;
542525
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
543-
obj->max_states = 0;
544-
obj->state = 0;
545526
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
546527
if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
547528
obj->img = p_icon->get_image();
@@ -570,7 +551,6 @@
570551
obj->callback = p_callback;
571552
obj->key_callback = p_key_callback;
572553
obj->meta = p_tag;
573-
obj->checkable_type = CHECKABLE_TYPE_NONE;
574554
obj->max_states = p_max_states;
575555
obj->state = p_default_state;
576556
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
@@ -640,7 +620,10 @@
640620
ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
641621
const NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
642622
if (menu_item) {
643-
return ([menu_item state] == NSControlStateValueOn);
623+
const GodotMenuItem *obj = [menu_item representedObject];
624+
if (obj) {
625+
return obj->checked;
626+
}
644627
}
645628
return false;
646629
}
@@ -958,10 +941,14 @@
958941
ERR_FAIL_COND(p_idx >= item_start + item_count);
959942
NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
960943
if (menu_item) {
961-
if (p_checked) {
962-
[menu_item setState:NSControlStateValueOn];
963-
} else {
964-
[menu_item setState:NSControlStateValueOff];
944+
GodotMenuItem *obj = [menu_item representedObject];
945+
if (obj) {
946+
obj->checked = p_checked;
947+
if (p_checked) {
948+
[menu_item setState:NSControlStateValueOn];
949+
} else {
950+
[menu_item setState:NSControlStateValueOff];
951+
}
965952
}
966953
}
967954
}

platform/windows/native_menu_windows.cpp

+14-23
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,6 @@ void NativeMenuWindows::_menu_activate(HMENU p_menu, int p_index) const {
8181
if (GetMenuItemInfoW(md->menu, p_index, true, &item)) {
8282
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
8383
if (item_data) {
84-
if (item_data->max_states > 0) {
85-
item_data->state++;
86-
if (item_data->state >= item_data->max_states) {
87-
item_data->state = 0;
88-
}
89-
}
90-
91-
if (item_data->checkable_type == CHECKABLE_TYPE_CHECK_BOX) {
92-
if ((item.fState & MFS_CHECKED) == MFS_CHECKED) {
93-
item.fState &= ~MFS_CHECKED;
94-
} else {
95-
item.fState |= MFS_CHECKED;
96-
}
97-
SetMenuItemInfoW(md->menu, p_index, true, &item);
98-
}
99-
10084
if (item_data->callback.is_valid()) {
10185
Variant ret;
10286
Callable::CallError ce;
@@ -619,9 +603,12 @@ bool NativeMenuWindows::is_item_checked(const RID &p_rid, int p_idx) const {
619603
MENUITEMINFOW item;
620604
ZeroMemory(&item, sizeof(item));
621605
item.cbSize = sizeof(item);
622-
item.fMask = MIIM_STATE;
606+
item.fMask = MIIM_STATE | MIIM_DATA;
623607
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
624-
return (item.fState & MFS_CHECKED) == MFS_CHECKED;
608+
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
609+
if (item_data) {
610+
return item_data->checked;
611+
}
625612
}
626613
return false;
627614
}
@@ -861,12 +848,16 @@ void NativeMenuWindows::set_item_checked(const RID &p_rid, int p_idx, bool p_che
861848
MENUITEMINFOW item;
862849
ZeroMemory(&item, sizeof(item));
863850
item.cbSize = sizeof(item);
864-
item.fMask = MIIM_STATE;
851+
item.fMask = MIIM_STATE | MIIM_DATA;
865852
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
866-
if (p_checked) {
867-
item.fState |= MFS_CHECKED;
868-
} else {
869-
item.fState &= ~MFS_CHECKED;
853+
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
854+
if (item_data) {
855+
item_data->checked = p_checked;
856+
if (p_checked) {
857+
item.fState |= MFS_CHECKED;
858+
} else {
859+
item.fState &= ~MFS_CHECKED;
860+
}
870861
}
871862
SetMenuItemInfoW(md->menu, p_idx, true, &item);
872863
}

platform/windows/native_menu_windows.h

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class NativeMenuWindows : public NativeMenu {
5151
Callable callback;
5252
Variant meta;
5353
GlobalMenuCheckType checkable_type;
54+
bool checked = false;
5455
int max_states = 0;
5556
int state = 0;
5657
Ref<Image> img;

scene/gui/popup_menu.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -2314,6 +2314,16 @@ bool PopupMenu::is_prefer_native_menu() const {
23142314
return prefer_native;
23152315
}
23162316

2317+
bool PopupMenu::is_native_menu() const {
2318+
#ifdef TOOLS_ENABLED
2319+
if (is_part_of_edited_scene()) {
2320+
return false;
2321+
}
2322+
#endif
2323+
2324+
return global_menu.is_valid();
2325+
}
2326+
23172327
bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only) {
23182328
ERR_FAIL_COND_V(p_event.is_null(), false);
23192329
Key code = Key::NONE;
@@ -2643,6 +2653,7 @@ void PopupMenu::_bind_methods() {
26432653

26442654
ClassDB::bind_method(D_METHOD("set_prefer_native_menu", "enabled"), &PopupMenu::set_prefer_native_menu);
26452655
ClassDB::bind_method(D_METHOD("is_prefer_native_menu"), &PopupMenu::is_prefer_native_menu);
2656+
ClassDB::bind_method(D_METHOD("is_native_menu"), &PopupMenu::is_native_menu);
26462657

26472658
ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0));
26482659
ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0));

scene/gui/popup_menu.h

+2
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ class PopupMenu : public Popup {
330330
void set_prefer_native_menu(bool p_enabled);
331331
bool is_prefer_native_menu() const;
332332

333+
bool is_native_menu() const;
334+
333335
void scroll_to_item(int p_idx);
334336

335337
bool activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only = false);

0 commit comments

Comments
 (0)