Allow negative indexes in ItemList and PopupMenu

This commit is contained in:
kobewi 2022-03-12 01:06:45 +01:00
parent d5076439e4
commit 42078dec9f
25 changed files with 163 additions and 59 deletions

View file

@ -7,6 +7,7 @@
This control provides a selectable list of items that may be in a single (or multiple columns) with option of text, icons, or both text and icon. Tooltips are supported and may be different for every item in the list.
Selectable items in the list may be selected or deselected and multiple selection may be enabled. Selection with right mouse button may also be enabled to allow use of popup context menus. Items may also be "activated" by double-clicking them or by pressing [kbd]Enter[/kbd].
Item text only supports single-line strings, newline characters (e.g. [code]\n[/code]) in the string won't produce a newline. Text wrapping is enabled in [constant ICON_MODE_TOP] mode, but column's width is adjusted to fully fit its content by default. You need to set [member fixed_column_width] greater than zero to wrap the text.
All [code]set_*[/code] methods allow negative item index, which makes the item accessed from the last one.
</description>
<tutorials>
</tutorials>

View file

@ -7,6 +7,7 @@
[PopupMenu] is a modal window used to display a list of options. They are popular in toolbars or context menus.
The size of a [PopupMenu] can be limited by using [member Window.max_size]. If the height of the list of items is larger than the maximum height of the [PopupMenu], a [ScrollContainer] within the popup will allow the user to scroll the contents.
If no maximum size is set, or if it is set to 0, the [PopupMenu] height will be limited by its parent rect.
All [code]set_*[/code] methods allow negative item index, which makes the item accessed from the last one.
</description>
<tutorials>
</tutorials>

View file

@ -925,7 +925,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
String name = E.operator String().replace("AudioEffect", "");
effect_options->add_item(name);
effect_options->set_item_metadata(effect_options->get_item_count() - 1, E);
effect_options->set_item_metadata(-1, E);
}
bus_options = memnew(MenuButton);

View file

@ -214,7 +214,7 @@ void EditorFileDialog::update_dir() {
if (dir_access->get_current_dir().is_network_share_path()) {
_update_drives(false);
drives->add_item(RTR("Network"));
drives->set_item_disabled(drives->get_item_count() - 1, true);
drives->set_item_disabled(-1, true);
drives->select(drives->get_item_count() - 1);
} else {
drives->select(dir_access->get_current_drive());
@ -314,8 +314,8 @@ void EditorFileDialog::_post_popup() {
recentd.remove_at(i--);
} else {
recent->add_item(name, folder);
recent->set_item_metadata(recent->get_item_count() - 1, recentd[i]);
recent->set_item_icon_modulate(recent->get_item_count() - 1, folder_color);
recent->set_item_metadata(-1, recentd[i]);
recent->set_item_icon_modulate(-1, folder_color);
}
}
EditorSettings::get_singleton()->set_recent_dirs(recentd);
@ -800,9 +800,9 @@ void EditorFileDialog::update_file_list() {
item_list->add_item(dir_name);
if (display_mode == DISPLAY_THUMBNAILS) {
item_list->set_item_icon(item_list->get_item_count() - 1, folder_thumbnail);
item_list->set_item_icon(-1, folder_thumbnail);
} else {
item_list->set_item_icon(item_list->get_item_count() - 1, folder);
item_list->set_item_icon(-1, folder);
}
Dictionary d;
@ -810,8 +810,8 @@ void EditorFileDialog::update_file_list() {
d["path"] = cdir.plus_file(dir_name);
d["dir"] = true;
item_list->set_item_metadata(item_list->get_item_count() - 1, d);
item_list->set_item_icon_modulate(item_list->get_item_count() - 1, folder_color);
item_list->set_item_metadata(-1, d);
item_list->set_item_icon_modulate(-1, folder_color);
dirs.pop_front();
}
@ -858,10 +858,10 @@ void EditorFileDialog::update_file_list() {
if (get_icon_func) {
Ref<Texture2D> icon = get_icon_func(cdir.plus_file(files.front()->get()));
if (display_mode == DISPLAY_THUMBNAILS) {
item_list->set_item_icon(item_list->get_item_count() - 1, file_thumbnail);
item_list->set_item_tag_icon(item_list->get_item_count() - 1, icon);
item_list->set_item_icon(-1, file_thumbnail);
item_list->set_item_tag_icon(-1, icon);
} else {
item_list->set_item_icon(item_list->get_item_count() - 1, icon);
item_list->set_item_icon(-1, icon);
}
}
@ -870,7 +870,7 @@ void EditorFileDialog::update_file_list() {
d["dir"] = false;
String fullpath = cdir.plus_file(files.front()->get());
d["path"] = fullpath;
item_list->set_item_metadata(item_list->get_item_count() - 1, d);
item_list->set_item_metadata(-1, d);
if (display_mode == DISPLAY_THUMBNAILS && previews_enabled) {
EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath, this, "_thumbnail_result", fullpath);
@ -1321,8 +1321,8 @@ void EditorFileDialog::_update_favorites() {
continue; // We don't handle favorite files here.
}
favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]);
favorites->set_item_icon_modulate(favorites->get_item_count() - 1, folder_color);
favorites->set_item_metadata(-1, favorited[i]);
favorites->set_item_icon_modulate(-1, folder_color);
if (setthis) {
favorite->set_pressed(true);

View file

@ -6516,7 +6516,7 @@ EditorNode::EditorNode() {
ED_SHORTCUT_OVERRIDE("editor/take_screenshot", "macos", KeyModifierMask::CMD | Key::F12);
p->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_SCREENSHOT);
p->set_item_tooltip(p->get_item_count() - 1, TTR("Screenshots are stored in the Editor Data/Settings Folder."));
p->set_item_tooltip(-1, TTR("Screenshots are stored in the Editor Data/Settings Folder."));
ED_SHORTCUT_AND_COMMAND("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KeyModifierMask::SHIFT | Key::F11);
ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::F);

View file

@ -83,7 +83,7 @@ void EditorRunNative::_notification(int p_what) {
mb->set_tooltip(eep->get_options_tooltip());
for (int i = 0; i < dc; i++) {
mb->get_popup()->add_icon_item(eep->get_option_icon(i), eep->get_option_label(i));
mb->get_popup()->set_item_tooltip(mb->get_popup()->get_item_count() - 1, eep->get_option_tooltip(i));
mb->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(i));
}
}
}

View file

@ -779,14 +779,14 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
icon = folder_icon;
if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) {
files->add_item(text, icon, true);
files->set_item_metadata(files->get_item_count() - 1, favorite);
files->set_item_metadata(-1, favorite);
}
} else if (favorite.ends_with("/")) {
text = favorite.substr(0, favorite.length() - 1).get_file();
icon = folder_icon;
if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) {
files->add_item(text, icon, true);
files->set_item_metadata(files->get_item_count() - 1, favorite);
files->set_item_metadata(-1, favorite);
}
} else {
int index;
@ -840,9 +840,9 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
bd += "/";
}
files->set_item_metadata(files->get_item_count() - 1, bd);
files->set_item_selectable(files->get_item_count() - 1, false);
files->set_item_icon_modulate(files->get_item_count() - 1, folder_color);
files->set_item_metadata(-1, bd);
files->set_item_selectable(-1, false);
files->set_item_icon_modulate(-1, folder_color);
}
bool reversed = file_sort == FILE_SORT_NAME_REVERSE;
@ -852,8 +852,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
String dname = efd->get_subdir(i)->get_name();
files->add_item(dname, folder_icon, true);
files->set_item_metadata(files->get_item_count() - 1, directory.plus_file(dname) + "/");
files->set_item_icon_modulate(files->get_item_count() - 1, folder_color);
files->set_item_metadata(-1, directory.plus_file(dname) + "/");
files->set_item_icon_modulate(-1, folder_color);
if (cselection.has(dname)) {
files->select(files->get_item_count() - 1, false);

View file

@ -128,7 +128,7 @@ void ImportDock::set_edit_path(const String &p_path) {
for (const Pair<String, String> &E : importer_names) {
import_as->add_item(E.first);
import_as->set_item_metadata(import_as->get_item_count() - 1, E.second);
import_as->set_item_metadata(-1, E.second);
if (E.second == importer_name) {
import_as->select(import_as->get_item_count() - 1);
}
@ -149,7 +149,7 @@ void ImportDock::set_edit_path(const String &p_path) {
void ImportDock::_add_keep_import_option(const String &p_importer_name) {
import_as->add_separator();
import_as->add_item(TTR("Keep File (No Import)"));
import_as->set_item_metadata(import_as->get_item_count() - 1, "keep");
import_as->set_item_metadata(-1, "keep");
if (p_importer_name == "keep") {
import_as->select(import_as->get_item_count() - 1);
}
@ -286,7 +286,7 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
for (const Pair<String, String> &E : importer_names) {
import_as->add_item(E.first);
import_as->set_item_metadata(import_as->get_item_count() - 1, E.second);
import_as->set_item_metadata(-1, E.second);
if (E.second == params->importer->get_importer_name()) {
import_as->select(import_as->get_item_count() - 1);
}

View file

@ -1670,11 +1670,11 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
onion_skinning->set_tooltip(TTR("Onion Skinning Options"));
onion_skinning->get_popup()->add_separator(TTR("Directions"));
onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST);
onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true);
onion_skinning->get_popup()->set_item_checked(-1, true);
onion_skinning->get_popup()->add_check_item(TTR("Future"), ONION_SKINNING_FUTURE);
onion_skinning->get_popup()->add_separator(TTR("Depth"));
onion_skinning->get_popup()->add_radio_check_item(TTR("1 step"), ONION_SKINNING_1_STEP);
onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true);
onion_skinning->get_popup()->set_item_checked(-1, true);
onion_skinning->get_popup()->add_radio_check_item(TTR("2 steps"), ONION_SKINNING_2_STEPS);
onion_skinning->get_popup()->add_radio_check_item(TTR("3 steps"), ONION_SKINNING_3_STEPS);
onion_skinning->get_popup()->add_separator();

View file

@ -1145,7 +1145,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
String name = cat["name"];
int id = cat["id"];
categories->add_item(name);
categories->set_item_metadata(categories->get_item_count() - 1, id);
categories->set_item_metadata(-1, id);
category_map[cat["id"]] = name;
}
}

View file

@ -63,30 +63,24 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
PopupMenu *p = debug_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
p->set_item_tooltip(
p->get_item_count() - 1,
p->set_item_tooltip(-1,
TTR("When this option is enabled, using one-click deploy will make the executable attempt to connect to this computer's IP so the running project can be debugged.\nThis option is intended to be used for remote debugging (typically with a mobile device).\nYou don't need to enable it to use the GDScript debugger locally."));
p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network Filesystem")), RUN_FILE_SERVER);
p->set_item_tooltip(
p->get_item_count() - 1,
p->set_item_tooltip(-1,
TTR("When this option is enabled, using one-click deploy for Android will only export an executable without the project data.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploying will use the USB cable for faster performance. This option speeds up testing for projects with large assets."));
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
p->set_item_tooltip(
p->get_item_count() - 1,
p->set_item_tooltip(-1,
TTR("When this option is enabled, collision shapes and raycast nodes (for 2D and 3D) will be visible in the running project."));
p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
p->set_item_tooltip(
p->get_item_count() - 1,
p->set_item_tooltip(-1,
TTR("When this option is enabled, navigation meshes and polygons will be visible in the running project."));
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
p->set_item_tooltip(
p->get_item_count() - 1,
p->set_item_tooltip(-1,
TTR("When this option is enabled, any changes made to the scene in the editor will be replicated in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Synchronize Script Changes")), RUN_RELOAD_SCRIPTS);
p->set_item_tooltip(
p->get_item_count() - 1,
p->set_item_tooltip(-1,
TTR("When this option is enabled, any script that is saved will be reloaded in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
// Multi-instance, start/stop

View file

@ -447,16 +447,16 @@ MeshInstance3DEditor::MeshInstance3DEditor() {
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MeshInstance3D"), SNAME("EditorIcons")));
options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a StaticBody3D and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection."));
options->get_popup()->set_item_tooltip(-1, TTR("Creates a StaticBody3D and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection."));
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection."));
options->get_popup()->set_item_tooltip(-1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection."));
options->get_popup()->add_item(TTR("Create Single Convex Collision Sibling"), MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE);
options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection."));
options->get_popup()->set_item_tooltip(-1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection."));
options->get_popup()->add_item(TTR("Create Simplified Convex Collision Sibling"), MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE);
options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a simplified convex collision shape.\nThis is similar to single collision shape, but can result in a simpler geometry in some cases, at the cost of accuracy."));
options->get_popup()->set_item_tooltip(-1, TTR("Creates a simplified convex collision shape.\nThis is similar to single collision shape, but can result in a simpler geometry in some cases, at the cost of accuracy."));
options->get_popup()->add_item(TTR("Create Multiple Convex Collision Siblings"), MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES);
options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between a single convex collision and a polygon-based collision."));
options->get_popup()->set_item_tooltip(-1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between a single convex collision and a polygon-based collision."));
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
options->get_popup()->add_separator();

View file

@ -1881,7 +1881,7 @@ void ScriptEditor::_update_members_overview() {
String name = functions[i].get_slice(":", 0);
if (filter.is_empty() || filter.is_subsequence_ofn(name)) {
members_overview->add_item(name);
members_overview->set_item_metadata(members_overview->get_item_count() - 1, functions[i].get_slice(":", 1).to_int() - 1);
members_overview->set_item_metadata(-1, functions[i].get_slice(":", 1).to_int() - 1);
}
}
@ -2139,7 +2139,7 @@ void ScriptEditor::_update_script_names() {
for (int i = 0; i < sedata_filtered.size(); i++) {
script_list->add_item(sedata_filtered[i].name, sedata_filtered[i].icon);
if (sedata_filtered[i].tool) {
script_list->set_item_icon_modulate(script_list->get_item_count() - 1, tool_color);
script_list->set_item_icon_modulate(-1, tool_color);
}
int index = script_list->get_item_count() - 1;

View file

@ -579,7 +579,7 @@ void ScriptTextEditor::_update_bookmark_list() {
}
bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - `" + line + "`");
bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]);
bookmarks_menu->set_item_metadata(-1, bookmark_list[i]);
}
}
@ -731,7 +731,7 @@ void ScriptTextEditor::_update_breakpoint_list() {
}
breakpoints_menu->add_item(String::num((int)breakpoint_list[i] + 1) + " - `" + line + "`");
breakpoints_menu->set_item_metadata(breakpoints_menu->get_item_count() - 1, breakpoint_list[i]);
breakpoints_menu->set_item_metadata(-1, breakpoint_list[i]);
}
}

View file

@ -647,7 +647,7 @@ void ShaderEditor::_update_bookmark_list() {
}
bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\"");
bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]);
bookmarks_menu->set_item_metadata(-1, bookmark_list[i]);
}
}

View file

@ -847,7 +847,7 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
at = at->get_atlas();
}
tree->set_item_tooltip(tree->get_item_count() - 1, tooltip);
tree->set_item_tooltip(-1, tooltip);
}
if (sel == i) {
tree->select(tree->get_item_count() - 1);

View file

@ -179,7 +179,7 @@ void TextEditor::_update_bookmark_list() {
}
bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\"");
bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]);
bookmarks_menu->set_item_metadata(-1, bookmark_list[i]);
}
}

View file

@ -241,7 +241,7 @@ void AtlasMergingDialog::update_tile_set(Ref<TileSet> p_tile_set) {
if (texture.is_valid()) {
String item_text = vformat("%s (id:%d)", texture->get_path().get_file(), source_id);
atlas_merging_atlases_list->add_item(item_text, texture);
atlas_merging_atlases_list->set_item_metadata(atlas_merging_atlases_list->get_item_count() - 1, source_id);
atlas_merging_atlases_list->set_item_metadata(-1, source_id);
}
}
}

View file

@ -188,7 +188,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() {
}
sources_list->add_item(item_text, texture);
sources_list->set_item_metadata(sources_list->get_item_count() - 1, source_id);
sources_list->set_item_metadata(-1, source_id);
}
if (sources_list->get_item_count() > 0) {

View file

@ -182,7 +182,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) {
}
sources_list->add_item(item_text, texture);
sources_list->set_item_metadata(sources_list->get_item_count() - 1, source_id);
sources_list->set_item_metadata(-1, source_id);
}
// Set again the current selected item if needed.

View file

@ -2551,7 +2551,7 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_
menu_properties->clear();
for (const String &p : valid_properties) {
menu_properties->add_item(capitalize ? p.capitalize() : p);
menu_properties->set_item_metadata(menu_properties->get_item_count() - 1, p);
menu_properties->set_item_metadata(-1, p);
}
menu_properties->reset_size();

View file

@ -641,7 +641,7 @@ void ScriptCreateDialog::_update_template_menu() {
if (!templates_found.is_empty()) {
if (!separator) {
template_menu->add_separator();
template_menu->set_item_text(template_menu->get_item_count() - 1, display_name);
template_menu->set_item_text(-1, display_name);
separator = true;
}
for (ScriptLanguage::ScriptTemplate &t : templates_found) {

View file

@ -176,7 +176,7 @@ void FileDialog::update_dir() {
if (dir_access->get_current_dir().is_network_share_path()) {
_update_drives(false);
drives->add_item(RTR("Network"));
drives->set_item_disabled(drives->get_item_count() - 1, true);
drives->set_item_disabled(-1, true);
drives->select(drives->get_item_count() - 1);
} else {
drives->select(dir_access->get_current_drive());

View file

@ -83,6 +83,9 @@ int ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) {
}
void ItemList::set_item_text(int p_idx, const String &p_text) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].text = p_text;
@ -97,6 +100,9 @@ String ItemList::get_item_text(int p_idx) const {
}
void ItemList::set_item_text_direction(int p_idx, Control::TextDirection p_text_direction) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
if (items[p_idx].text_direction != p_text_direction) {
@ -119,6 +125,9 @@ void ItemList::clear_item_opentype_features(int p_idx) {
}
void ItemList::set_item_opentype_feature(int p_idx, const String &p_name, int p_value) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
int32_t tag = TS->name_to_tag(p_name);
if (!items[p_idx].opentype_features.has(tag) || (int)items[p_idx].opentype_features[tag] != p_value) {
@ -138,6 +147,9 @@ int ItemList::get_item_opentype_feature(int p_idx, const String &p_name) const {
}
void ItemList::set_item_language(int p_idx, const String &p_language) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
if (items[p_idx].language != p_language) {
items.write[p_idx].language = p_language;
@ -152,6 +164,9 @@ String ItemList::get_item_language(int p_idx) const {
}
void ItemList::set_item_tooltip_enabled(int p_idx, const bool p_enabled) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].tooltip_enabled = p_enabled;
}
@ -162,6 +177,9 @@ bool ItemList::is_item_tooltip_enabled(int p_idx) const {
}
void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].tooltip = p_tooltip;
@ -175,6 +193,9 @@ String ItemList::get_item_tooltip(int p_idx) const {
}
void ItemList::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].icon = p_icon;
@ -189,6 +210,9 @@ Ref<Texture2D> ItemList::get_item_icon(int p_idx) const {
}
void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].icon_transposed = p_transposed;
@ -203,6 +227,9 @@ bool ItemList::is_item_icon_transposed(int p_idx) const {
}
void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].icon_region = p_region;
@ -217,6 +244,9 @@ Rect2 ItemList::get_item_icon_region(int p_idx) const {
}
void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].icon_modulate = p_modulate;
@ -230,6 +260,9 @@ Color ItemList::get_item_icon_modulate(int p_idx) const {
}
void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_color) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].custom_bg = p_custom_bg_color;
@ -243,6 +276,9 @@ Color ItemList::get_item_custom_bg_color(int p_idx) const {
}
void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_color) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].custom_fg = p_custom_fg_color;
@ -256,6 +292,9 @@ Color ItemList::get_item_custom_fg_color(int p_idx) const {
}
void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].tag_icon = p_tag_icon;
@ -270,6 +309,9 @@ Ref<Texture2D> ItemList::get_item_tag_icon(int p_idx) const {
}
void ItemList::set_item_selectable(int p_idx, bool p_selectable) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].selectable = p_selectable;
@ -281,6 +323,9 @@ bool ItemList::is_item_selectable(int p_idx) const {
}
void ItemList::set_item_disabled(int p_idx, bool p_disabled) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].disabled = p_disabled;
@ -293,6 +338,9 @@ bool ItemList::is_item_disabled(int p_idx) const {
}
void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].metadata = p_metadata;

View file

@ -999,6 +999,9 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
/* Methods to modify existing items. */
void PopupMenu::set_item_text(int p_idx, const String &p_text) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].text = p_text;
items.write[p_idx].xl_text = atr(p_text);
@ -1009,6 +1012,9 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
}
void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_text_direction) {
if (p_item < 0) {
p_item += get_item_count();
}
ERR_FAIL_INDEX(p_item, items.size());
ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
if (items[p_item].text_direction != p_text_direction) {
@ -1019,6 +1025,9 @@ void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_tex
}
void PopupMenu::clear_item_opentype_features(int p_item) {
if (p_item < 0) {
p_item += get_item_count();
}
ERR_FAIL_INDEX(p_item, items.size());
items.write[p_item].opentype_features.clear();
items.write[p_item].dirty = true;
@ -1026,6 +1035,9 @@ void PopupMenu::clear_item_opentype_features(int p_item) {
}
void PopupMenu::set_item_opentype_feature(int p_item, const String &p_name, int p_value) {
if (p_item < 0) {
p_item += get_item_count();
}
ERR_FAIL_INDEX(p_item, items.size());
int32_t tag = TS->name_to_tag(p_name);
if (!items[p_item].opentype_features.has(tag) || (int)items[p_item].opentype_features[tag] != p_value) {
@ -1036,6 +1048,9 @@ void PopupMenu::set_item_opentype_feature(int p_item, const String &p_name, int
}
void PopupMenu::set_item_language(int p_item, const String &p_language) {
if (p_item < 0) {
p_item += get_item_count();
}
ERR_FAIL_INDEX(p_item, items.size());
if (items[p_item].language != p_language) {
items.write[p_item].language = p_language;
@ -1045,6 +1060,9 @@ void PopupMenu::set_item_language(int p_item, const String &p_language) {
}
void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].icon = p_icon;
@ -1053,6 +1071,9 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
}
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checked = p_checked;
@ -1062,6 +1083,9 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
}
void PopupMenu::set_item_id(int p_idx, int p_id) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].id = p_id;
@ -1070,6 +1094,9 @@ void PopupMenu::set_item_id(int p_idx, int p_id) {
}
void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].accel = p_accel;
items.write[p_idx].dirty = true;
@ -1079,6 +1106,9 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
}
void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].metadata = p_meta;
control->update();
@ -1086,6 +1116,9 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
}
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].disabled = p_disabled;
control->update();
@ -1093,6 +1126,9 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
}
void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].submenu = p_submenu;
control->update();
@ -1201,6 +1237,9 @@ int PopupMenu::get_item_state(int p_idx) const {
}
void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].separator = p_separator;
control->update();
@ -1212,24 +1251,36 @@ bool PopupMenu::is_item_separator(int p_idx) const {
}
void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
control->update();
}
void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
control->update();
}
void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].tooltip = p_tooltip;
control->update();
}
void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
if (items[p_idx].shortcut.is_valid()) {
_unref_shortcut(items[p_idx].shortcut);
@ -1246,6 +1297,9 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo
}
void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].h_ofs = p_offset;
control->update();
@ -1253,12 +1307,18 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
}
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].state = p_state;
control->update();
}
void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].shortcut_is_disabled = p_disabled;
control->update();