Merge pull request #94061 from bruvzg/menu_is_native
[NativeMenu] Do not auto toggle check/multi-state items. Add `is_native_menu` method.
This commit is contained in:
commit
9804a8eb30
|
@ -395,6 +395,12 @@
|
||||||
Returns [code]true[/code] if the specified item's shortcut is disabled.
|
Returns [code]true[/code] if the specified item's shortcut is disabled.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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">
|
<method name="is_system_menu" qualifiers="const">
|
||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<description>
|
<description>
|
||||||
|
@ -636,6 +642,7 @@
|
||||||
</member>
|
</member>
|
||||||
<member name="prefer_native_menu" type="bool" setter="set_prefer_native_menu" getter="is_prefer_native_menu" default="false">
|
<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.
|
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>
|
||||||
<member name="submenu_popup_delay" type="float" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay" default="0.3">
|
<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.
|
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.
|
||||||
|
|
|
@ -568,23 +568,7 @@ void DisplayServerMacOS::menu_callback(id p_sender) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GodotMenuItem *value = [p_sender representedObject];
|
GodotMenuItem *value = [p_sender representedObject];
|
||||||
|
|
||||||
if (value) {
|
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()) {
|
if (value->callback.is_valid()) {
|
||||||
MenuCall mc;
|
MenuCall mc;
|
||||||
mc.tag = value->meta;
|
mc.tag = value->meta;
|
||||||
|
|
|
@ -52,6 +52,7 @@ enum GlobalMenuCheckType {
|
||||||
Callable hover_callback;
|
Callable hover_callback;
|
||||||
Variant meta;
|
Variant meta;
|
||||||
GlobalMenuCheckType checkable_type;
|
GlobalMenuCheckType checkable_type;
|
||||||
|
bool checked;
|
||||||
int max_states;
|
int max_states;
|
||||||
int state;
|
int state;
|
||||||
Ref<Image> img;
|
Ref<Image> img;
|
||||||
|
|
|
@ -31,4 +31,18 @@
|
||||||
#include "godot_menu_item.h"
|
#include "godot_menu_item.h"
|
||||||
|
|
||||||
@implementation GodotMenuItem
|
@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
|
@end
|
||||||
|
|
|
@ -373,12 +373,7 @@ int NativeMenuMacOS::add_submenu_item(const RID &p_rid, const String &p_label, c
|
||||||
menu_item = [md->menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];
|
menu_item = [md->menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];
|
||||||
|
|
||||||
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
|
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
|
||||||
obj->callback = Callable();
|
|
||||||
obj->key_callback = Callable();
|
|
||||||
obj->meta = p_tag;
|
obj->meta = p_tag;
|
||||||
obj->checkable_type = CHECKABLE_TYPE_NONE;
|
|
||||||
obj->max_states = 0;
|
|
||||||
obj->state = 0;
|
|
||||||
[menu_item setRepresentedObject:obj];
|
[menu_item setRepresentedObject:obj];
|
||||||
|
|
||||||
[md_sub->menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]];
|
[md_sub->menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]];
|
||||||
|
@ -417,9 +412,6 @@ int NativeMenuMacOS::add_item(const RID &p_rid, const String &p_label, const Cal
|
||||||
obj->callback = p_callback;
|
obj->callback = p_callback;
|
||||||
obj->key_callback = p_key_callback;
|
obj->key_callback = p_key_callback;
|
||||||
obj->meta = p_tag;
|
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 setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
|
||||||
[menu_item setRepresentedObject:obj];
|
[menu_item setRepresentedObject:obj];
|
||||||
}
|
}
|
||||||
|
@ -438,8 +430,6 @@ int NativeMenuMacOS::add_check_item(const RID &p_rid, const String &p_label, con
|
||||||
obj->key_callback = p_key_callback;
|
obj->key_callback = p_key_callback;
|
||||||
obj->meta = p_tag;
|
obj->meta = p_tag;
|
||||||
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
|
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 setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
|
||||||
[menu_item setRepresentedObject:obj];
|
[menu_item setRepresentedObject:obj];
|
||||||
}
|
}
|
||||||
|
@ -457,9 +447,6 @@ int NativeMenuMacOS::add_icon_item(const RID &p_rid, const Ref<Texture2D> &p_ico
|
||||||
obj->callback = p_callback;
|
obj->callback = p_callback;
|
||||||
obj->key_callback = p_key_callback;
|
obj->key_callback = p_key_callback;
|
||||||
obj->meta = p_tag;
|
obj->meta = p_tag;
|
||||||
obj->checkable_type = CHECKABLE_TYPE_NONE;
|
|
||||||
obj->max_states = 0;
|
|
||||||
obj->state = 0;
|
|
||||||
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
|
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()) {
|
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();
|
obj->img = p_icon->get_image();
|
||||||
|
@ -489,8 +476,6 @@ int NativeMenuMacOS::add_icon_check_item(const RID &p_rid, const Ref<Texture2D>
|
||||||
obj->key_callback = p_key_callback;
|
obj->key_callback = p_key_callback;
|
||||||
obj->meta = p_tag;
|
obj->meta = p_tag;
|
||||||
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
|
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
|
||||||
obj->max_states = 0;
|
|
||||||
obj->state = 0;
|
|
||||||
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
|
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()) {
|
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();
|
obj->img = p_icon->get_image();
|
||||||
|
@ -520,8 +505,6 @@ int NativeMenuMacOS::add_radio_check_item(const RID &p_rid, const String &p_labe
|
||||||
obj->key_callback = p_key_callback;
|
obj->key_callback = p_key_callback;
|
||||||
obj->meta = p_tag;
|
obj->meta = p_tag;
|
||||||
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
|
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 setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
|
||||||
[menu_item setRepresentedObject:obj];
|
[menu_item setRepresentedObject:obj];
|
||||||
}
|
}
|
||||||
|
@ -540,8 +523,6 @@ int NativeMenuMacOS::add_icon_radio_check_item(const RID &p_rid, const Ref<Textu
|
||||||
obj->key_callback = p_key_callback;
|
obj->key_callback = p_key_callback;
|
||||||
obj->meta = p_tag;
|
obj->meta = p_tag;
|
||||||
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
|
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
|
||||||
obj->max_states = 0;
|
|
||||||
obj->state = 0;
|
|
||||||
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
|
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()) {
|
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();
|
obj->img = p_icon->get_image();
|
||||||
|
@ -570,7 +551,6 @@ int NativeMenuMacOS::add_multistate_item(const RID &p_rid, const String &p_label
|
||||||
obj->callback = p_callback;
|
obj->callback = p_callback;
|
||||||
obj->key_callback = p_key_callback;
|
obj->key_callback = p_key_callback;
|
||||||
obj->meta = p_tag;
|
obj->meta = p_tag;
|
||||||
obj->checkable_type = CHECKABLE_TYPE_NONE;
|
|
||||||
obj->max_states = p_max_states;
|
obj->max_states = p_max_states;
|
||||||
obj->state = p_default_state;
|
obj->state = p_default_state;
|
||||||
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
|
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
|
||||||
|
@ -640,7 +620,10 @@ bool NativeMenuMacOS::is_item_checked(const RID &p_rid, int p_idx) const {
|
||||||
ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
|
ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
|
||||||
const NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
|
const NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
|
||||||
if (menu_item) {
|
if (menu_item) {
|
||||||
return ([menu_item state] == NSControlStateValueOn);
|
const GodotMenuItem *obj = [menu_item representedObject];
|
||||||
|
if (obj) {
|
||||||
|
return obj->checked;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -958,12 +941,16 @@ void NativeMenuMacOS::set_item_checked(const RID &p_rid, int p_idx, bool p_check
|
||||||
ERR_FAIL_COND(p_idx >= item_start + item_count);
|
ERR_FAIL_COND(p_idx >= item_start + item_count);
|
||||||
NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
|
NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
|
||||||
if (menu_item) {
|
if (menu_item) {
|
||||||
|
GodotMenuItem *obj = [menu_item representedObject];
|
||||||
|
if (obj) {
|
||||||
|
obj->checked = p_checked;
|
||||||
if (p_checked) {
|
if (p_checked) {
|
||||||
[menu_item setState:NSControlStateValueOn];
|
[menu_item setState:NSControlStateValueOn];
|
||||||
} else {
|
} else {
|
||||||
[menu_item setState:NSControlStateValueOff];
|
[menu_item setState:NSControlStateValueOff];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeMenuMacOS::set_item_checkable(const RID &p_rid, int p_idx, bool p_checkable) {
|
void NativeMenuMacOS::set_item_checkable(const RID &p_rid, int p_idx, bool p_checkable) {
|
||||||
|
|
|
@ -81,22 +81,6 @@ void NativeMenuWindows::_menu_activate(HMENU p_menu, int p_index) const {
|
||||||
if (GetMenuItemInfoW(md->menu, p_index, true, &item)) {
|
if (GetMenuItemInfoW(md->menu, p_index, true, &item)) {
|
||||||
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
|
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
|
||||||
if (item_data) {
|
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()) {
|
if (item_data->callback.is_valid()) {
|
||||||
Variant ret;
|
Variant ret;
|
||||||
Callable::CallError ce;
|
Callable::CallError ce;
|
||||||
|
@ -619,9 +603,12 @@ bool NativeMenuWindows::is_item_checked(const RID &p_rid, int p_idx) const {
|
||||||
MENUITEMINFOW item;
|
MENUITEMINFOW item;
|
||||||
ZeroMemory(&item, sizeof(item));
|
ZeroMemory(&item, sizeof(item));
|
||||||
item.cbSize = 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 (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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -861,13 +848,17 @@ void NativeMenuWindows::set_item_checked(const RID &p_rid, int p_idx, bool p_che
|
||||||
MENUITEMINFOW item;
|
MENUITEMINFOW item;
|
||||||
ZeroMemory(&item, sizeof(item));
|
ZeroMemory(&item, sizeof(item));
|
||||||
item.cbSize = 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 (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
|
||||||
|
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
|
||||||
|
if (item_data) {
|
||||||
|
item_data->checked = p_checked;
|
||||||
if (p_checked) {
|
if (p_checked) {
|
||||||
item.fState |= MFS_CHECKED;
|
item.fState |= MFS_CHECKED;
|
||||||
} else {
|
} else {
|
||||||
item.fState &= ~MFS_CHECKED;
|
item.fState &= ~MFS_CHECKED;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
SetMenuItemInfoW(md->menu, p_idx, true, &item);
|
SetMenuItemInfoW(md->menu, p_idx, true, &item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ class NativeMenuWindows : public NativeMenu {
|
||||||
Callable callback;
|
Callable callback;
|
||||||
Variant meta;
|
Variant meta;
|
||||||
GlobalMenuCheckType checkable_type;
|
GlobalMenuCheckType checkable_type;
|
||||||
|
bool checked = false;
|
||||||
int max_states = 0;
|
int max_states = 0;
|
||||||
int state = 0;
|
int state = 0;
|
||||||
Ref<Image> img;
|
Ref<Image> img;
|
||||||
|
|
|
@ -2314,6 +2314,16 @@ bool PopupMenu::is_prefer_native_menu() const {
|
||||||
return prefer_native;
|
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) {
|
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);
|
ERR_FAIL_COND_V(p_event.is_null(), false);
|
||||||
Key code = Key::NONE;
|
Key code = Key::NONE;
|
||||||
|
@ -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("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_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_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));
|
ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0));
|
||||||
|
|
|
@ -330,6 +330,8 @@ public:
|
||||||
void set_prefer_native_menu(bool p_enabled);
|
void set_prefer_native_menu(bool p_enabled);
|
||||||
bool is_prefer_native_menu() const;
|
bool is_prefer_native_menu() const;
|
||||||
|
|
||||||
|
bool is_native_menu() const;
|
||||||
|
|
||||||
void scroll_to_item(int p_idx);
|
void scroll_to_item(int p_idx);
|
||||||
|
|
||||||
bool activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only = false);
|
bool activate_item_by_event(const Ref<InputEvent> &p_event, bool p_for_global_only = false);
|
||||||
|
|
Loading…
Reference in New Issue