From e2278afdd36b7182a98cfee641e3294b6ff50ec5 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Sat, 9 May 2026 19:23:07 -0300 Subject: [PATCH] Fix and improve selection behavior in the Filesystem dock --- doc/classes/TreeItem.xml | 3 +- editor/debugger/editor_visual_profiler.cpp | 1 - editor/docks/filesystem_dock.cpp | 338 +++++++++--------- editor/docks/filesystem_dock.h | 6 +- editor/scene/scene_tree_editor.cpp | 5 +- editor/settings/editor_command_palette.cpp | 1 - .../4.6-stable/GH-119367.txt | 5 + scene/gui/tree.compat.inc | 5 + scene/gui/tree.cpp | 20 +- scene/gui/tree.h | 7 +- 10 files changed, 201 insertions(+), 190 deletions(-) create mode 100644 misc/extension_api_validation/4.6-stable/GH-119367.txt diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 82e4b61774..fdd5536736 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -530,8 +530,9 @@ + - Selects the given [param column]. + Selects the given [param column]. If [param set_as_cursor] is [code]true[/code], the [Tree]'s cursor will be moved to this item (only matters if [member Tree.select_mode] is set to [constant Tree.SELECT_MULTI]). diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index de171b4c36..8ed78a30dc 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -434,7 +434,6 @@ void EditorVisualProfiler::_update_frame(bool p_focus_selected) { node = node->get_parent(); } ensure_selected->select(0); - ensure_selected->set_as_cursor(0); variables->ensure_cursor_is_visible(); } updating_frame = false; diff --git a/editor/docks/filesystem_dock.cpp b/editor/docks/filesystem_dock.cpp index b2083843fc..bfa6b4939b 100644 --- a/editor/docks/filesystem_dock.cpp +++ b/editor/docks/filesystem_dock.cpp @@ -227,7 +227,7 @@ Ref FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String } } -void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) { +void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, const Vector &p_uncollapsed_paths, const Vector &p_selected_paths) { // Create a tree item for the subdirectory. TreeItem *subdirectory_item = tree->create_item(p_parent); String dname = p_dir->get_name(); @@ -271,25 +271,18 @@ void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->set_metadata(0, lpath); folder_map[lpath] = subdirectory_item; - if (!p_select_in_favorites && (current_path == lpath || ((display_mode != DISPLAY_MODE_TREE_ONLY) && current_path.get_base_dir() == lpath))) { - subdirectory_item->select(0); - // Keep select an item when re-created a tree - // To prevent crashing when nothing is selected. - subdirectory_item->set_as_cursor(0); + if (current_path == lpath || p_selected_paths.has(lpath) || ((display_mode != DISPLAY_MODE_TREE_ONLY) && (current_path.get_base_dir() == lpath))) { + subdirectory_item->select(0, current_path == lpath); } - if (p_unfold_path && current_path.begins_with(lpath) && current_path != lpath) { - subdirectory_item->set_collapsed(false); - } else { - subdirectory_item->set_collapsed(!uncollapsed_paths.has(lpath)); - } + subdirectory_item->set_collapsed(!p_uncollapsed_paths.has(lpath)); // Create items for all subdirectories. bool reversed = file_sort == FileSortOption::FILE_SORT_NAME_REVERSE; for (int i = reversed ? p_dir->get_subdir_count() - 1 : 0; reversed ? i >= 0 : i < p_dir->get_subdir_count(); reversed ? i-- : i++) { - _create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites, p_unfold_path); + _create_tree(subdirectory_item, p_dir->get_subdir(i), p_uncollapsed_paths, p_selected_paths); } // Create all items for the files in the subdirectory. @@ -339,20 +332,16 @@ void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory } file_item->set_metadata(0, file_metadata); file_item->set_accept_children(false); - if (!p_select_in_favorites && current_path == file_metadata) { - file_item->select(0); - file_item->set_as_cursor(0); + if (current_path == file_metadata || p_selected_paths.has(file_metadata)) { + file_item->select(0, current_path == file_metadata); } if (main_scene_path == file_metadata) { file_item->set_custom_color(0, get_theme_color(SNAME("accent_color"), EditorStringName(Editor))); } EditorResourcePreview::get_singleton()->queue_resource_preview(file_metadata, callable_mp(this, &FileSystemDock::_tree_thumbnail_done).bind(tree_update_id, file_item->get_instance_id())); } - } else { - if (lpath.get_base_dir() == current_path.get_base_dir()) { - subdirectory_item->select(0); - subdirectory_item->set_as_cursor(0); - } + } else if (lpath.get_base_dir() == current_path.get_base_dir()) { + subdirectory_item->select(0); } } @@ -388,7 +377,9 @@ Vector FileSystemDock::get_uncollapsed_paths() const { return uncollapsed_paths; } -void FileSystemDock::_update_tree(const Vector &p_uncollapsed_paths, bool p_uncollapse_root, bool p_scroll_to_selected) { +void FileSystemDock::_update_tree(const Vector &p_uncollapsed_paths, bool p_uncollapse_root, bool p_scroll_to_selected, const Vector &p_override_selection) { + const Vector previous_selection = p_override_selection.is_empty() ? _tree_get_selected(false) : p_override_selection; + // Recreate the tree. tree->clear(); tree_update_id++; @@ -479,7 +470,7 @@ void FileSystemDock::_update_tree(const Vector &p_uncollapsed_paths, boo } // Create the remaining of the tree. - _create_tree(root, EditorFileSystem::get_singleton()->get_filesystem(), uncollapsed_paths, false); + _create_tree(root, EditorFileSystem::get_singleton()->get_filesystem(), uncollapsed_paths, previous_selection); if (!searched_tokens.is_empty()) { _update_filtered_items(); } @@ -497,73 +488,91 @@ void FileSystemDock::set_display_mode(DisplayMode p_display_mode) { } void FileSystemDock::_update_display_mode(bool p_force) { - // Compute the new display mode. - if (p_force || old_display_mode != display_mode) { - switch (display_mode) { - case DISPLAY_MODE_TREE_ONLY: { - button_toggle_display_mode->set_button_icon(get_editor_theme_icon(SNAME("Panels1"))); - tree->show(); - tree->set_v_size_flags(SIZE_EXPAND_FILL); - tree->set_theme_type_variation(""); - if (horizontal) { - toolbar2_hbc->hide(); - - tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH); - tree_mc->set_theme_type_variation("NoBorderBottomPanel"); - } else { - toolbar2_hbc->show(); - - tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_TOP); - tree_mc->set_theme_type_variation("NoBorderHorizontalBottom"); - } - button_file_list_display_mode->hide(); - - _update_tree(get_uncollapsed_paths()); - file_list_vb->hide(); - } break; - - case DISPLAY_MODE_HSPLIT: - case DISPLAY_MODE_VSPLIT: { - const bool is_vertical = display_mode == DISPLAY_MODE_VSPLIT; - split_box->set_vertical(is_vertical); - - const int actual_offset = is_vertical ? split_box_offset_v : split_box_offset_h; - split_box->set_split_offset(actual_offset); - const StringName icon = is_vertical ? SNAME("Panels2") : SNAME("Panels2Alt"); - button_toggle_display_mode->set_button_icon(get_editor_theme_icon(icon)); - - tree->show(); - tree->set_v_size_flags(SIZE_EXPAND_FILL); - if (is_vertical) { - tree->set_theme_type_variation(""); - tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH); - tree_mc->set_theme_type_variation(horizontal ? "NoBorderBottomPanel" : "NoBorderHorizontal"); - - files->set_theme_type_variation(horizontal ? "ItemListSecondary" : ""); - files->set_scroll_hint_mode(horizontal ? ItemList::SCROLL_HINT_MODE_DISABLED : ItemList::SCROLL_HINT_MODE_TOP); - files_mc->set_theme_type_variation(horizontal ? "" : "NoBorderHorizontalBottom"); - } else { - tree->set_theme_type_variation("TreeSecondary"); - tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_DISABLED); - tree_mc->set_theme_type_variation(""); - - files->set_theme_type_variation("ItemListSecondary"); - files->set_scroll_hint_mode(ItemList::SCROLL_HINT_MODE_DISABLED); - files_mc->set_theme_type_variation(""); - } - tree->ensure_cursor_is_visible(); - - toolbar2_hbc->hide(); - button_file_list_display_mode->show(); - _update_tree(get_uncollapsed_paths()); - - file_list_vb->show(); - _update_file_list(true); - } break; - } - - old_display_mode = display_mode; + if (!p_force && old_display_mode == display_mode) { + return; } + + // Preserve the selection when switching modes. + Vector selected_paths; + if (old_display_mode != display_mode) { + selected_paths = get_selected_paths(); + } + + switch (display_mode) { + case DISPLAY_MODE_TREE_ONLY: { + button_toggle_display_mode->set_button_icon(get_editor_theme_icon(SNAME("Panels1"))); + tree->show(); + tree->set_v_size_flags(SIZE_EXPAND_FILL); + tree->set_theme_type_variation(""); + if (horizontal) { + toolbar2_hbc->hide(); + + tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH); + tree_mc->set_theme_type_variation("NoBorderBottomPanel"); + } else { + toolbar2_hbc->show(); + + tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_TOP); + tree_mc->set_theme_type_variation("NoBorderHorizontalBottom"); + } + button_file_list_display_mode->hide(); + + _update_tree(get_uncollapsed_paths(), false, true, selected_paths); + file_list_vb->hide(); + } break; + + case DISPLAY_MODE_HSPLIT: + case DISPLAY_MODE_VSPLIT: { + const bool is_vertical = display_mode == DISPLAY_MODE_VSPLIT; + split_box->set_vertical(is_vertical); + + const int actual_offset = is_vertical ? split_box_offset_v : split_box_offset_h; + split_box->set_split_offset(actual_offset); + const StringName icon = is_vertical ? SNAME("Panels2") : SNAME("Panels2Alt"); + button_toggle_display_mode->set_button_icon(get_editor_theme_icon(icon)); + + tree->show(); + tree->set_v_size_flags(SIZE_EXPAND_FILL); + if (is_vertical) { + tree->set_theme_type_variation(""); + tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH); + tree_mc->set_theme_type_variation(horizontal ? "NoBorderBottomPanel" : "NoBorderHorizontal"); + + files->set_theme_type_variation(horizontal ? "ItemListSecondary" : ""); + files->set_scroll_hint_mode(horizontal ? ItemList::SCROLL_HINT_MODE_DISABLED : ItemList::SCROLL_HINT_MODE_TOP); + files_mc->set_theme_type_variation(horizontal ? "" : "NoBorderHorizontalBottom"); + } else { + tree->set_theme_type_variation("TreeSecondary"); + tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_DISABLED); + tree_mc->set_theme_type_variation(""); + + files->set_theme_type_variation("ItemListSecondary"); + files->set_scroll_hint_mode(ItemList::SCROLL_HINT_MODE_DISABLED); + files_mc->set_theme_type_variation(""); + } + tree->ensure_cursor_is_visible(); + + // Properly allocate the selections between the views. + Vector selected_files; + for (int i = 0; i < selected_paths.size(); i++) { + const String &path = selected_paths[i]; + if (!path.ends_with("/")) { + selected_files.append(path); + selected_paths.remove_at(i); + i--; + } + } + + toolbar2_hbc->hide(); + button_file_list_display_mode->show(); + _update_tree(get_uncollapsed_paths(), false, true, selected_paths); + + file_list_vb->show(); + _update_file_list(true, selected_files); + } break; + } + + old_display_mode = display_mode; } void FileSystemDock::_notification(int p_what) { @@ -731,20 +740,26 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s // Update the file list. if (!updating_tree && display_mode != DISPLAY_MODE_TREE_ONLY) { - _update_file_list(false); + _update_file_list(true); } } Vector FileSystemDock::get_selected_paths() const { - if (display_mode == DISPLAY_MODE_TREE_ONLY) { + Vector selected_tree = _tree_get_selected(false); + // Use the old mode to help preserve selection between modes. + // That variable also gets updated shortly after, so it shouldn't cause issues. + if (old_display_mode == DISPLAY_MODE_TREE_ONLY) { return _tree_get_selected(false); - } else { - Vector selected = _file_list_get_selected(); - if (selected.is_empty()) { - selected.push_back(get_current_directory()); - } - return selected; } + + Vector selected_files = _file_list_get_selected(); + for (const String &file : selected_files) { + if (!selected_tree.has(file)) { + selected_tree.append(file); + } + } + + return selected_tree; } String FileSystemDock::get_current_path() const { @@ -995,18 +1010,15 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List * } } -void FileSystemDock::_update_file_list(bool p_keep_selection) { - // Register the previously current and selected items. - HashSet previous_selection; - HashSet valid_selection; +void FileSystemDock::_update_file_list(bool p_keep_selection, const Vector &p_override_selection) { + // Register the previously selected items. + Vector previous_selection; if (p_keep_selection) { - for (int i = 0; i < files->get_item_count(); i++) { - if (files->is_selected(i)) { - previous_selection.insert(files->get_item_text(i)); - } - } + previous_selection = p_override_selection.is_empty() ? _file_list_get_selected() : p_override_selection; } + HashSet valid_selection; + files->clear(); _set_current_path_line_edit_text(current_path); @@ -1170,7 +1182,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { } files->set_item_icon_modulate(-1, this_folder_color); - if (previous_selection.has(dname)) { + if (previous_selection.has(dpath)) { files->select(files->get_item_count() - 1, false); valid_selection.insert(files->get_item_count() - 1); } @@ -1239,8 +1251,11 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { } // Select the items. - if (previous_selection.has(fname)) { + if (previous_selection.has(fpath)) { files->select(item_index, false); + if (current_path == fpath) { + files->set_current(item_index); + } valid_selection.insert(item_index); } @@ -1258,8 +1273,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { files->set_item_tooltip(item_index, tooltip); } - // If we only have any selected items retained, we need to update the current idx. - if (!valid_selection.is_empty()) { + // If we have any selected items retained, one must be set as the current one. + if (files->get_current() == -1 && !valid_selection.is_empty()) { files->set_current(*valid_selection.begin()); } } @@ -3809,6 +3824,7 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) { String fpath = files->get_item_metadata(current); if (!fpath.ends_with("/")) { current_path = fpath; + current_path_line_edit->set_text(fpath); } } @@ -3912,7 +3928,7 @@ void FileSystemDock::_tree_gui_input(Ref p_event) { } if (custom_callback.is_valid()) { - PackedStringArray selected = _tree_get_selected(false); + Vector selected = _tree_get_selected(false); if (create) { if (selected.is_empty()) { selected.append("res://"); @@ -4226,10 +4242,8 @@ void FileSystemDock::save_layout_to_config(Ref &p_layout, const Stri p_layout->set_value(p_section, "display_mode", get_display_mode()); p_layout->set_value(p_section, "file_sort", (int)get_file_sort()); p_layout->set_value(p_section, "file_list_display_mode", get_file_list_display_mode()); - PackedStringArray selected_files = get_selected_paths(); - p_layout->set_value(p_section, "selected_paths", selected_files); - Vector uncollapsed_paths = get_uncollapsed_paths(); - p_layout->set_value(p_section, "uncollapsed_paths", searched_tokens.is_empty() ? uncollapsed_paths : uncollapsed_paths_before_search); + p_layout->set_value(p_section, "selected_paths", get_selected_paths()); + p_layout->set_value(p_section, "uncollapsed_paths", searched_tokens.is_empty() ? get_uncollapsed_paths() : uncollapsed_paths_before_search); } void FileSystemDock::load_layout_from_config(const Ref &p_layout, const String &p_section) { @@ -4258,50 +4272,58 @@ void FileSystemDock::load_layout_from_config(const Ref &p_layout, co set_file_list_display_mode(dock_filesystem_file_list_display_mode); } + PackedStringArray uncollapsed_tis; + if (p_layout->has_section_key(p_section, "uncollapsed_paths")) { + uncollapsed_tis = p_layout->get_value(p_section, "uncollapsed_paths"); + } + + get_tree_control()->deselect_all(); + files->deselect_all(); + current_path = ""; + if (p_layout->has_section_key(p_section, "selected_paths")) { PackedStringArray dock_filesystem_selected_paths = p_layout->get_value(p_section, "selected_paths"); if (dock_filesystem_selected_paths.size() > 1) { - get_tree_control()->deselect_all(); - Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - HashSet paths_to_select; + Vector files_to_select; + Vector dirs_to_select; + + // Properly allocate the selections between the views. for (const String &path : dock_filesystem_selected_paths) { - if (da->file_exists(path) || da->dir_exists(path)) { - paths_to_select.insert(path); + if (da->file_exists(path)) { + if (display_mode == DISPLAY_MODE_TREE_ONLY) { + dirs_to_select.append(path); + } else { + files_to_select.append(path); + } + } else if (da->dir_exists(path)) { + dirs_to_select.append(path); } } - if (paths_to_select.is_empty()) { - select_file("res://"); // No valid file to select, default to base folder. + if (files_to_select.is_empty() && dirs_to_select.is_empty()) { + select_file("res://"); // No valid file to select, default to root folder. } else { - // Simple BFS from "res://" node to prevent default selection in "Favorite". - TreeItem *res_ti = get_tree_control()->get_item_with_metadata("res://", 0); - LocalVector ti_visit; - ti_visit.push_back(res_ti); - while (!ti_visit.is_empty()) { - TreeItem *curr_ti = ti_visit[0]; + _update_tree(uncollapsed_tis, true, false, dirs_to_select); - const String &path = curr_ti->get_metadata(0); - if (paths_to_select.has(path)) { - curr_ti->select(0); - current_path = path; - - paths_to_select.erase(path); - - if (paths_to_select.is_empty()) { - break; - } + if (!dirs_to_select.is_empty()) { + TreeItem *item = tree->get_item_with_metadata(*dirs_to_select.begin()); + if (item) { + item->set_as_cursor(0); + current_path = item->get_metadata(0); } - - TreeItem *child_ti = curr_ti->get_first_child(); - while (child_ti) { - ti_visit.push_back(child_ti); - child_ti = child_ti->get_next(); - } - - ti_visit.remove_at(0); } + + if (display_mode != DISPLAY_MODE_TREE_ONLY) { + _update_file_list(true, files_to_select); + + if (files->is_anything_selected()) { + current_path = files->get_item_metadata(*files->get_selected_items().begin()); + } + } + + current_path_line_edit->set_text(current_path); } } else if (dock_filesystem_selected_paths.size() == 1) { Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); @@ -4310,32 +4332,9 @@ void FileSystemDock::load_layout_from_config(const Ref &p_layout, co if (da->file_exists(path) || da->dir_exists(path)) { select_file(path); } else { - select_file("res://"); // For single-selection, default to base folder. - } - } else { - get_tree_control()->deselect_all(); - current_path = ""; - } - - current_path_line_edit->set_text(current_path); - } - - // Restore collapsed state. - PackedStringArray uncollapsed_tis; - if (p_layout->has_section_key(p_section, "uncollapsed_paths")) { - uncollapsed_tis = p_layout->get_value(p_section, "uncollapsed_paths"); - } else { - uncollapsed_tis = { "res://" }; - } - - if (!uncollapsed_tis.is_empty()) { - for (int i = 0; i < uncollapsed_tis.size(); i++) { - TreeItem *uncollapsed_ti = get_tree_control()->get_item_with_metadata(uncollapsed_tis[i], 0); - if (uncollapsed_ti) { - uncollapsed_ti->set_collapsed(false); + select_file("res://"); // For single-selection, default to root folder. } } - get_tree_control()->queue_redraw(); } } @@ -4499,6 +4498,7 @@ FileSystemDock::FileSystemDock() { tree->set_hide_root(true); tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_TOP); SET_DRAG_FORWARDING_GCD(tree, FileSystemDock); + tree->set_allow_reselect(true); tree->set_allow_rmb_select(true); tree->set_select_mode(Tree::SELECT_MULTI); tree->set_custom_minimum_size(Size2(40 * EDSCALE, 15 * EDSCALE)); diff --git a/editor/docks/filesystem_dock.h b/editor/docks/filesystem_dock.h index 2cbf280298..bc687e4f3e 100644 --- a/editor/docks/filesystem_dock.h +++ b/editor/docks/filesystem_dock.h @@ -276,8 +276,8 @@ private: void _reselect_items_selected_on_drag_begin(bool reset = false); Ref _get_tree_item_icon(bool p_is_valid, const String &p_file_type, const String &p_icon_path); - void _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false); - void _update_tree(const Vector &p_uncollapsed_paths = Vector(), bool p_uncollapse_root = false, bool p_scroll_to_selected = true); + void _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, const Vector &p_uncollapsed_paths, const Vector &p_selected_paths); + void _update_tree(const Vector &p_uncollapsed_paths = Vector(), bool p_uncollapse_root = false, bool p_scroll_to_selected = true, const Vector &p_override_selection = Vector()); void _navigate_to_path(const String &p_path, bool p_select_in_favorites = false, bool p_grab_focus = false); bool _update_filtered_items(TreeItem *p_tree_item = nullptr); void _append_favorite_items(); @@ -287,7 +287,7 @@ private: HashSet _get_valid_conversions_for_file_paths(const Vector &p_paths); - void _update_file_list(bool p_keep_selection); + void _update_file_list(bool p_keep_selection, const Vector &p_override_selection = Vector()); void _toggle_file_display(); void _set_file_display(bool p_active); void _fs_changed(); diff --git a/editor/scene/scene_tree_editor.cpp b/editor/scene/scene_tree_editor.cpp index ceb2f9fceb..867a83b176 100644 --- a/editor/scene/scene_tree_editor.cpp +++ b/editor/scene/scene_tree_editor.cpp @@ -645,8 +645,9 @@ void SceneTreeEditor::_update_node(Node *p_node, TreeItem *p_item, bool p_part_o if (selected == p_node) { if (!editor_selection) { p_item->select(0); + } else { + p_item->set_as_cursor(0); } - p_item->set_as_cursor(0); } } @@ -1481,7 +1482,6 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) { node = node->get_parent(); } item->select(0); - item->set_as_cursor(0); tree->ensure_cursor_is_visible(); } else { // Ensure the node is selected and visible for the user if the node @@ -1497,7 +1497,6 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) { } if (!collapsed) { item->select(0); - item->set_as_cursor(0); tree->ensure_cursor_is_visible(); } } diff --git a/editor/settings/editor_command_palette.cpp b/editor/settings/editor_command_palette.cpp index f0505f969e..41c45a1e1c 100644 --- a/editor/settings/editor_command_palette.cpp +++ b/editor/settings/editor_command_palette.cpp @@ -150,7 +150,6 @@ void EditorCommandPalette::_update_command_search(const String &search_text) { TreeItem *to_select = first_section->get_first_child(); to_select->select(0); - to_select->set_as_cursor(0); search_options->ensure_cursor_is_visible(); } diff --git a/misc/extension_api_validation/4.6-stable/GH-119367.txt b/misc/extension_api_validation/4.6-stable/GH-119367.txt new file mode 100644 index 0000000000..840fcdc6d9 --- /dev/null +++ b/misc/extension_api_validation/4.6-stable/GH-119367.txt @@ -0,0 +1,5 @@ +GH-119367 +--------- +Validate extension JSON: Error: Field 'classes/TreeItem/methods/select/arguments': size changed value in new API, from 1 to 2. + +Optional argument added. Compatibility method registered. diff --git a/scene/gui/tree.compat.inc b/scene/gui/tree.compat.inc index ec15106dd4..2d36afdd1d 100644 --- a/scene/gui/tree.compat.inc +++ b/scene/gui/tree.compat.inc @@ -34,11 +34,16 @@ #include "core/object/class_db.h" +void TreeItem::_select_bind_compat_119367(int p_column) { + select(p_column, true); +} + void TreeItem::_add_button_bind_compat_76829(int p_column, const Ref &p_button, int p_id, bool p_disabled, const String &p_tooltip) { add_button(p_column, p_button, p_id, p_disabled, p_tooltip, String()); } void TreeItem::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("select", "column"), &TreeItem::_select_bind_compat_119367); ClassDB::bind_compatibility_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip_text"), &TreeItem::_add_button_bind_compat_76829, DEFVAL(-1), DEFVAL(false), DEFVAL("")); } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 01e0910b80..b992ce51df 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -97,9 +97,9 @@ void TreeItem::_changed_notify() { } } -void TreeItem::_cell_selected(int p_cell) { +void TreeItem::_cell_selected(int p_cell, bool p_set_as_cursor) { if (tree) { - tree->item_selected(p_cell, this); + tree->item_selected(p_cell, this, p_set_as_cursor); } } @@ -1358,9 +1358,9 @@ void TreeItem::set_as_cursor(int p_column) { tree->queue_redraw(); } -void TreeItem::select(int p_column) { +void TreeItem::select(int p_column, bool p_set_as_cursor) { ERR_FAIL_INDEX(p_column, cells.size()); - _cell_selected(p_column); + _cell_selected(p_column, p_set_as_cursor); } void TreeItem::deselect(int p_column) { @@ -1927,7 +1927,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("is_selectable", "column"), &TreeItem::is_selectable); ClassDB::bind_method(D_METHOD("is_selected", "column"), &TreeItem::is_selected); - ClassDB::bind_method(D_METHOD("select", "column"), &TreeItem::select); + ClassDB::bind_method(D_METHOD("select", "column", "set_as_cursor"), &TreeItem::select, DEFVAL(true)); ClassDB::bind_method(D_METHOD("deselect", "column"), &TreeItem::deselect); ClassDB::bind_method(D_METHOD("set_editable", "column", "enabled"), &TreeItem::set_editable); @@ -5667,7 +5667,7 @@ void Tree::item_changed(int p_column, TreeItem *p_item) { queue_redraw(); } -void Tree::item_selected(int p_column, TreeItem *p_item) { +void Tree::item_selected(int p_column, TreeItem *p_item, bool p_set_as_cursor) { if (select_mode == SELECT_MULTI) { if (!p_item->cells[p_column].selectable) { return; @@ -5676,9 +5676,11 @@ void Tree::item_selected(int p_column, TreeItem *p_item) { p_item->cells.write[p_column].selected = true; //emit_signal(SNAME("multi_selected"),p_item,p_column,true); - NO this is for `TreeItem::select` - selected_col = p_column; - selected_item = p_item; - selected_button = -1; + if (p_set_as_cursor) { + selected_col = p_column; + selected_item = p_item; + selected_button = -1; + } } else { select_single_item(p_item, root, p_column); } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 6bef6adfcb..9e01b52bfa 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -164,7 +164,7 @@ private: void _changed_notify(int p_cell); void _changed_notify(); - void _cell_selected(int p_cell); + void _cell_selected(int p_cell, bool p_set_as_cursor); void _cell_deselected(int p_cell); void _handle_visibility_changed(bool p_visible); void _propagate_visibility_changed(bool p_parent_visible_in_tree); @@ -224,6 +224,7 @@ protected: static void _bind_methods(); #ifndef DISABLE_DEPRECATED + void _select_bind_compat_119367(int p_column); void _add_button_bind_compat_76829(int p_column, const Ref &p_button, int p_id, bool p_disabled, const String &p_tooltip); static void _bind_compatibility_methods(); #endif @@ -376,7 +377,7 @@ public: bool is_selected(int p_column); bool is_any_column_selected() const; - void select(int p_column); + void select(int p_column, bool p_set_as_cursor = true); void deselect(int p_column); void set_as_cursor(int p_column); @@ -603,7 +604,7 @@ private: void item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index = MouseButton::NONE); void item_changed(int p_column, TreeItem *p_item); - void item_selected(int p_column, TreeItem *p_item); + void item_selected(int p_column, TreeItem *p_item, bool p_set_as_cursor); void item_deselected(int p_column, TreeItem *p_item); void update_min_size_for_item_change();