Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NativeMenu] Do not auto toggle check/multi-state items. Add is_native_menu method. #94061

Merged
merged 1 commit into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/classes/PopupMenu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,12 @@
Returns [code]true[/code] if the specified item's shortcut is disabled.
</description>
</method>
<method name="is_native_menu" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the system native menu is supported and currently used by this [PopupMenu].
</description>
</method>
<method name="is_system_menu" qualifiers="const">
<return type="bool" />
<description>
Expand Down Expand Up @@ -636,6 +642,7 @@
</member>
<member name="prefer_native_menu" type="bool" setter="set_prefer_native_menu" getter="is_prefer_native_menu" default="false">
If [code]true[/code], [MenuBar] will use native menu when supported.
[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.
</member>
<member name="submenu_popup_delay" type="float" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay" default="0.3">
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.
Expand Down
16 changes: 0 additions & 16 deletions platform/macos/display_server_macos.mm
Original file line number Diff line number Diff line change
Expand Up @@ -568,23 +568,7 @@
}

GodotMenuItem *value = [p_sender representedObject];

if (value) {
if (value->max_states > 0) {
value->state++;
if (value->state >= value->max_states) {
value->state = 0;
}
}

if (value->checkable_type == CHECKABLE_TYPE_CHECK_BOX) {
if ([p_sender state] == NSControlStateValueOff) {
[p_sender setState:NSControlStateValueOn];
} else {
[p_sender setState:NSControlStateValueOff];
}
}

if (value->callback.is_valid()) {
MenuCall mc;
mc.tag = value->meta;
Expand Down
1 change: 1 addition & 0 deletions platform/macos/godot_menu_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum GlobalMenuCheckType {
Callable hover_callback;
Variant meta;
GlobalMenuCheckType checkable_type;
bool checked;
int max_states;
int state;
Ref<Image> img;
Expand Down
14 changes: 14 additions & 0 deletions platform/macos/godot_menu_item.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,18 @@
#include "godot_menu_item.h"

@implementation GodotMenuItem

- (id)init {
self = [super init];

self->callback = Callable();
self->key_callback = Callable();
self->checkable_type = GlobalMenuCheckType::CHECKABLE_TYPE_NONE;
self->checked = false;
self->max_states = 0;
self->state = 0;

return self;
}

@end
37 changes: 12 additions & 25 deletions platform/macos/native_menu_macos.mm
Original file line number Diff line number Diff line change
Expand Up @@ -373,12 +373,7 @@
menu_item = [md->menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];

GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = Callable();
obj->key_callback = Callable();
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = 0;
obj->state = 0;
[menu_item setRepresentedObject:obj];

[md_sub->menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]];
Expand Down Expand Up @@ -417,9 +412,6 @@
obj->callback = p_callback;
obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = 0;
obj->state = 0;
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
Expand All @@ -438,8 +430,6 @@
obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
obj->max_states = 0;
obj->state = 0;
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
Expand All @@ -457,9 +447,6 @@
obj->callback = p_callback;
obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = 0;
obj->state = 0;
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
obj->img = p_icon->get_image();
Expand Down Expand Up @@ -489,8 +476,6 @@
obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
obj->max_states = 0;
obj->state = 0;
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
obj->img = p_icon->get_image();
Expand Down Expand Up @@ -520,8 +505,6 @@
obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
obj->max_states = 0;
obj->state = 0;
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
Expand All @@ -540,8 +523,6 @@
obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
obj->max_states = 0;
obj->state = 0;
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (ds && p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
obj->img = p_icon->get_image();
Expand Down Expand Up @@ -570,7 +551,6 @@
obj->callback = p_callback;
obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = p_max_states;
obj->state = p_default_state;
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
Expand Down Expand Up @@ -640,7 +620,10 @@
ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
const NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
if (menu_item) {
return ([menu_item state] == NSControlStateValueOn);
const GodotMenuItem *obj = [menu_item representedObject];
if (obj) {
return obj->checked;
}
}
return false;
}
Expand Down Expand Up @@ -958,10 +941,14 @@
ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
if (menu_item) {
if (p_checked) {
[menu_item setState:NSControlStateValueOn];
} else {
[menu_item setState:NSControlStateValueOff];
GodotMenuItem *obj = [menu_item representedObject];
if (obj) {
obj->checked = p_checked;
if (p_checked) {
[menu_item setState:NSControlStateValueOn];
} else {
[menu_item setState:NSControlStateValueOff];
}
}
}
}
Expand Down
37 changes: 14 additions & 23 deletions platform/windows/native_menu_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,6 @@ void NativeMenuWindows::_menu_activate(HMENU p_menu, int p_index) const {
if (GetMenuItemInfoW(md->menu, p_index, true, &item)) {
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
if (item_data) {
if (item_data->max_states > 0) {
item_data->state++;
if (item_data->state >= item_data->max_states) {
item_data->state = 0;
}
}

if (item_data->checkable_type == CHECKABLE_TYPE_CHECK_BOX) {
if ((item.fState & MFS_CHECKED) == MFS_CHECKED) {
item.fState &= ~MFS_CHECKED;
} else {
item.fState |= MFS_CHECKED;
}
SetMenuItemInfoW(md->menu, p_index, true, &item);
}

if (item_data->callback.is_valid()) {
Variant ret;
Callable::CallError ce;
Expand Down Expand Up @@ -619,9 +603,12 @@ bool NativeMenuWindows::is_item_checked(const RID &p_rid, int p_idx) const {
MENUITEMINFOW item;
ZeroMemory(&item, sizeof(item));
item.cbSize = sizeof(item);
item.fMask = MIIM_STATE;
item.fMask = MIIM_STATE | MIIM_DATA;
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
return (item.fState & MFS_CHECKED) == MFS_CHECKED;
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
if (item_data) {
return item_data->checked;
}
}
return false;
}
Expand Down Expand Up @@ -861,12 +848,16 @@ void NativeMenuWindows::set_item_checked(const RID &p_rid, int p_idx, bool p_che
MENUITEMINFOW item;
ZeroMemory(&item, sizeof(item));
item.cbSize = sizeof(item);
item.fMask = MIIM_STATE;
item.fMask = MIIM_STATE | MIIM_DATA;
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
if (p_checked) {
item.fState |= MFS_CHECKED;
} else {
item.fState &= ~MFS_CHECKED;
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
if (item_data) {
item_data->checked = p_checked;
if (p_checked) {
item.fState |= MFS_CHECKED;
} else {
item.fState &= ~MFS_CHECKED;
}
}
SetMenuItemInfoW(md->menu, p_idx, true, &item);
}
Expand Down
1 change: 1 addition & 0 deletions platform/windows/native_menu_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class NativeMenuWindows : public NativeMenu {
Callable callback;
Variant meta;
GlobalMenuCheckType checkable_type;
bool checked = false;
int max_states = 0;
int state = 0;
Ref<Image> img;
Expand Down
11 changes: 11 additions & 0 deletions scene/gui/popup_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2314,6 +2314,16 @@ bool PopupMenu::is_prefer_native_menu() const {
return prefer_native;
}

bool PopupMenu::is_native_menu() const {
#ifdef TOOLS_ENABLED
if (is_part_of_edited_scene()) {
return false;
}
#endif

return global_menu.is_valid();
}

bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only) {
ERR_FAIL_COND_V(p_event.is_null(), false);
Key code = Key::NONE;
Expand Down Expand Up @@ -2643,6 +2653,7 @@ void PopupMenu::_bind_methods() {

ClassDB::bind_method(D_METHOD("set_prefer_native_menu", "enabled"), &PopupMenu::set_prefer_native_menu);
ClassDB::bind_method(D_METHOD("is_prefer_native_menu"), &PopupMenu::is_prefer_native_menu);
ClassDB::bind_method(D_METHOD("is_native_menu"), &PopupMenu::is_native_menu);

ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0));
Expand Down
2 changes: 2 additions & 0 deletions scene/gui/popup_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,8 @@ class PopupMenu : public Popup {
void set_prefer_native_menu(bool p_enabled);
bool is_prefer_native_menu() const;

bool is_native_menu() const;

void scroll_to_item(int p_idx);

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