Add PopupMenu method set_item_index

This commit is contained in:
kit
2026-01-25 10:43:51 -05:00
parent f8444475ac
commit 01839942fc
10 changed files with 145 additions and 5 deletions

View File

@@ -216,7 +216,7 @@
<param index="0" name="rid" type="RID" />
<param index="1" name="submenu_rid" type="RID" />
<description>
Returns the index of the item with the submenu specified by [param submenu_rid]. Indices are automatically assigned to each item by the engine, and cannot be set manually.
Returns the index of the item with the submenu specified by [param submenu_rid]. Indices are automatically assigned to each item by the engine.
[b]Note:[/b] This method is implemented on macOS and Windows.
</description>
</method>
@@ -225,7 +225,7 @@
<param index="0" name="rid" type="RID" />
<param index="1" name="tag" type="Variant" />
<description>
Returns the index of the item with the specified [param tag]. Indices are automatically assigned to each item by the engine, and cannot be set manually.
Returns the index of the item with the specified [param tag]. Indices are automatically assigned to each item by the engine.
[b]Note:[/b] This method is implemented on macOS and Windows.
</description>
</method>
@@ -234,7 +234,7 @@
<param index="0" name="rid" type="RID" />
<param index="1" name="text" type="String" />
<description>
Returns the index of the item with the specified [param text]. Indices are automatically assigned to each item by the engine, and cannot be set manually.
Returns the index of the item with the specified [param text]. Indices are automatically assigned to each item by the engine.
[b]Note:[/b] This method is implemented on macOS and Windows.
</description>
</method>
@@ -618,6 +618,18 @@
[b]Note:[/b] This method is implemented only on macOS.
</description>
</method>
<method name="set_item_index">
<return type="int" />
<param index="0" name="rid" type="RID" />
<param index="1" name="idx" type="int" />
<param index="2" name="target_idx" type="int" />
<description>
Changes the index of the item at index [param idx] to be at index [param target_idx]. This can be used to move an item above other items.
Returns the new index of the moved item, it's not guaranteed to be the same as [param target_idx].
[b]Note:[/b] The indices of any items between index [param idx] and index [param target_idx] will be shifted by one.
[b]Note:[/b] This method is implemented on macOS and Windows.
</description>
</method>
<method name="set_item_key_callback">
<return type="void" />
<param index="0" name="rid" type="RID" />

View File

@@ -270,7 +270,7 @@
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the ID of the item at the given [param index]. [code]id[/code] can be manually assigned, while index can not.
Returns the ID of the item at the given [param index].
</description>
</method>
<method name="get_item_indent" qualifiers="const">
@@ -284,7 +284,7 @@
<return type="int" />
<param index="0" name="id" type="int" />
<description>
Returns the index of the item containing the specified [param id]. Index is automatically assigned to each item by the engine and can not be set manually.
Returns the index of the item containing the specified [param id]. The index is automatically assigned to each item by the engine when added and represents the order items will be displayed.
</description>
</method>
<method name="get_item_language" qualifiers="const">
@@ -536,6 +536,15 @@
Sets the horizontal offset of the item at the given [param index].
</description>
</method>
<method name="set_item_index">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="target_index" type="int" />
<description>
Changes the index of the item at index [param index] to be at index [param target_index]. This can be used to move an item above other items. The moved item will keep the same ID, even if it was generated from the original index.
[b]Note:[/b] The indices of any items between index [param index] and index [param target_index] will be shifted by one.
</description>
</method>
<method name="set_item_language">
<return type="void" />
<param index="0" name="index" type="int" />

View File

@@ -152,6 +152,7 @@ public:
virtual void set_item_max_states(const RID &p_rid, int p_idx, int p_max_states) override;
virtual void set_item_icon(const RID &p_rid, int p_idx, const Ref<Texture2D> &p_icon) override;
virtual void set_item_indentation_level(const RID &p_rid, int p_idx, int p_level) override;
virtual int set_item_index(const RID &p_rid, int p_idx, int p_target_idx) override;
virtual int get_item_count(const RID &p_rid) const override;
virtual bool is_system_menu(const RID &p_rid) const override;

View File

@@ -1319,6 +1319,29 @@ void NativeMenuMacOS::set_item_indentation_level(const RID &p_rid, int p_idx, in
}
}
int NativeMenuMacOS::set_item_index(const RID &p_rid, int p_idx, int p_target_idx) {
ERR_FAIL_COND_V(p_idx < 0, -1);
MenuData *md = menus.get_or_null(p_rid);
ERR_FAIL_NULL_V(md, -1);
int item_start = _get_system_menu_start(md->menu);
int item_count = _get_system_menu_count(md->menu);
p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= item_start + item_count, -1);
ERR_FAIL_INDEX_V(p_target_idx, item_count, -1);
p_target_idx += item_start;
NSMenuItem *menu_item = [md->menu itemAtIndex:p_idx];
if ([menu_item submenu] && _is_menu_opened([menu_item submenu])) {
ERR_FAIL_V_MSG(-1, "Can't move open menu!");
}
if (menu_item) {
[md->menu removeItemAtIndex:p_idx];
[md->menu insertItem:menu_item atIndex:p_target_idx];
}
return p_target_idx - item_start;
}
int NativeMenuMacOS::get_item_count(const RID &p_rid) const {
const MenuData *md = menus.get_or_null(p_rid);
ERR_FAIL_NULL_V(md, 0);

View File

@@ -1122,6 +1122,58 @@ void NativeMenuWindows::set_item_indentation_level(const RID &p_rid, int p_idx,
// Not supported.
}
int NativeMenuWindows::set_item_index(const RID &p_rid, int p_idx, int p_target_idx) {
ERR_FAIL_COND_V(p_idx < 0, -1);
const MenuData *md = menus.get_or_null(p_rid);
ERR_FAIL_NULL_V(md, -1);
int count = GetMenuItemCount(md->menu);
ERR_FAIL_COND_V(p_idx >= count, -1);
ERR_FAIL_INDEX_V(p_target_idx, count, -1);
// Get item text separately.
MENUITEMINFOW item;
ZeroMemory(&item, sizeof(item));
item.cbSize = sizeof(item);
item.fMask = MIIM_STRING;
item.dwTypeData = nullptr;
Char16String str;
if (!GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
return -1;
}
item.cch++;
str.resize_uninitialized(item.cch);
item.dwTypeData = (LPWSTR)str.ptrw();
if (!GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
return -1;
}
ZeroMemory(&item, sizeof(item));
item.cbSize = sizeof(item);
item.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU | MIIM_BITMAP;
if (!GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
return -1;
}
item.dwTypeData = (LPWSTR)str.get_data();
if (!RemoveMenu(md->menu, p_idx, MF_BYPOSITION)) {
return -1;
}
if (!InsertMenuItemW(md->menu, p_target_idx, true, &item)) {
// Delete item if failed to insert.
MenuItemData *item_data = (MenuItemData *)item.dwItemData;
if (item_data) {
if (item_data->bmp) {
DeleteObject(item_data->bmp);
}
memdelete(item_data);
}
return -1;
}
return p_target_idx;
}
int NativeMenuWindows::get_item_count(const RID &p_rid) const {
const MenuData *md = menus.get_or_null(p_rid);
ERR_FAIL_NULL_V(md, 0);

View File

@@ -142,6 +142,7 @@ public:
virtual void set_item_max_states(const RID &p_rid, int p_idx, int p_max_states) override;
virtual void set_item_icon(const RID &p_rid, int p_idx, const Ref<Texture2D> &p_icon) override;
virtual void set_item_indentation_level(const RID &p_rid, int p_idx, int p_level) override;
virtual int set_item_index(const RID &p_rid, int p_idx, int p_target_idx) override;
virtual int get_item_count(const RID &p_rid) const override;
virtual bool is_system_menu(const RID &p_rid) const override;

View File

@@ -2633,6 +2633,39 @@ void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
_menu_changed();
}
void PopupMenu::set_item_index(int p_idx, int p_target_idx) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
if (p_target_idx < 0) {
p_target_idx += get_item_count();
}
ERR_FAIL_INDEX(p_target_idx, items.size());
if (p_idx == p_target_idx) {
return;
}
Item item = items[p_idx];
items.remove_at(p_idx);
items.insert(p_target_idx, item);
if (global_menu.is_valid()) {
NativeMenu *nmenu = NativeMenu::get_singleton();
nmenu->set_item_index(global_menu, p_idx, p_target_idx);
// Update tags of all affected items to their new index.
for (int i = MIN(p_idx, p_target_idx); i <= MAX(p_idx, p_target_idx); i++) {
nmenu->set_item_tag(global_menu, i, i);
}
}
queue_accessibility_update();
control->queue_redraw();
_menu_changed();
}
void PopupMenu::toggle_item_multistate(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
if (0 >= items[p_idx].max_states) {
@@ -3189,6 +3222,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_multistate", "index", "state"), &PopupMenu::set_item_multistate);
ClassDB::bind_method(D_METHOD("set_item_multistate_max", "index", "max_states"), &PopupMenu::set_item_max_states);
ClassDB::bind_method(D_METHOD("set_item_shortcut_disabled", "index", "disabled"), &PopupMenu::set_item_shortcut_disabled);
ClassDB::bind_method(D_METHOD("set_item_index", "index", "target_index"), &PopupMenu::set_item_index);
ClassDB::bind_method(D_METHOD("toggle_item_checked", "index"), &PopupMenu::toggle_item_checked);
ClassDB::bind_method(D_METHOD("toggle_item_multistate", "index"), &PopupMenu::toggle_item_multistate);

View File

@@ -332,6 +332,7 @@ public:
void set_item_multistate(int p_idx, int p_state);
void toggle_item_multistate(int p_idx);
void set_item_shortcut_disabled(int p_idx, bool p_disabled);
void set_item_index(int p_idx, int p_target_idx);
void toggle_item_checked(int p_idx);

View File

@@ -109,6 +109,7 @@ void NativeMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_max_states", "rid", "idx", "max_states"), &NativeMenu::set_item_max_states);
ClassDB::bind_method(D_METHOD("set_item_icon", "rid", "idx", "icon"), &NativeMenu::set_item_icon);
ClassDB::bind_method(D_METHOD("set_item_indentation_level", "rid", "idx", "level"), &NativeMenu::set_item_indentation_level);
ClassDB::bind_method(D_METHOD("set_item_index", "rid", "idx", "target_idx"), &NativeMenu::set_item_index);
ClassDB::bind_method(D_METHOD("get_item_count", "rid"), &NativeMenu::get_item_count);
ClassDB::bind_method(D_METHOD("is_system_menu", "rid"), &NativeMenu::is_system_menu);
@@ -444,6 +445,11 @@ void NativeMenu::set_item_indentation_level(const RID &p_rid, int p_idx, int p_l
WARN_PRINT("Global menus are not supported on this platform.");
}
int NativeMenu::set_item_index(const RID &p_rid, int p_idx, int p_target_idx) {
WARN_PRINT("Global menus are not supported on this platform.");
return -1;
}
int NativeMenu::get_item_count(const RID &p_rid) const {
WARN_PRINT("Global menus are not supported on this platform.");
return 0;

View File

@@ -140,6 +140,7 @@ public:
virtual void set_item_max_states(const RID &p_rid, int p_idx, int p_max_states);
virtual void set_item_icon(const RID &p_rid, int p_idx, const Ref<Texture2D> &p_icon);
virtual void set_item_indentation_level(const RID &p_rid, int p_idx, int p_level);
virtual int set_item_index(const RID &p_rid, int p_idx, int p_target_idx);
virtual int get_item_count(const RID &p_rid) const;
virtual bool is_system_menu(const RID &p_rid) const;