You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-06 12:20:30 +00:00
Merge pull request #98926 from YeldhamDev/out_all_of_you
Add toggle to hide filtered out parents in the "SceneTree" dock
This commit is contained in:
@@ -241,6 +241,9 @@
|
|||||||
<member name="docks/scene_tree/center_node_on_reparent" type="bool" setter="" getter="">
|
<member name="docks/scene_tree/center_node_on_reparent" type="bool" setter="" getter="">
|
||||||
If [code]true[/code], new node created when reparenting node(s) will be positioned at the average position of the selected node(s).
|
If [code]true[/code], new node created when reparenting node(s) will be positioned at the average position of the selected node(s).
|
||||||
</member>
|
</member>
|
||||||
|
<member name="docks/scene_tree/hide_filtered_out_parents" type="bool" setter="" getter="">
|
||||||
|
If [code]true[/code], the scene tree dock will only show nodes that match the filter, without showing parents that don't. This settings can also be changed in the Scene dock's top menu.
|
||||||
|
</member>
|
||||||
<member name="docks/scene_tree/start_create_dialog_fully_expanded" type="bool" setter="" getter="">
|
<member name="docks/scene_tree/start_create_dialog_fully_expanded" type="bool" setter="" getter="">
|
||||||
If [code]true[/code], the Create dialog (Create New Node/Create New Resource) will start with all its sections expanded. Otherwise, sections will be collapsed until the user starts searching (which will automatically expand sections as needed).
|
If [code]true[/code], the Create dialog (Create New Node/Create New Resource) will start with all its sections expanded. Otherwise, sections will be collapsed until the user starts searching (which will automatically expand sections as needed).
|
||||||
</member>
|
</member>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "editor/debugger/editor_debugger_node.h"
|
#include "editor/debugger/editor_debugger_node.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
#include "editor/gui/editor_file_dialog.h"
|
#include "editor/gui/editor_file_dialog.h"
|
||||||
#include "editor/scene_tree_dock.h"
|
#include "editor/scene_tree_dock.h"
|
||||||
@@ -146,24 +147,50 @@ void EditorDebuggerTree::_scene_tree_rmb_selected(const Vector2 &p_position, Mou
|
|||||||
/// |-E
|
/// |-E
|
||||||
///
|
///
|
||||||
void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger) {
|
void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger) {
|
||||||
|
set_hide_root(false);
|
||||||
|
|
||||||
updating_scene_tree = true;
|
updating_scene_tree = true;
|
||||||
const String last_path = get_selected_path();
|
const String last_path = get_selected_path();
|
||||||
const String filter = SceneTreeDock::get_singleton()->get_filter();
|
const String filter = SceneTreeDock::get_singleton()->get_filter();
|
||||||
|
TreeItem *select_item = nullptr;
|
||||||
|
bool hide_filtered_out_parents = EDITOR_GET("docks/scene_tree/hide_filtered_out_parents");
|
||||||
|
|
||||||
bool should_scroll = scrolling_to_item || filter != last_filter;
|
bool should_scroll = scrolling_to_item || filter != last_filter;
|
||||||
scrolling_to_item = false;
|
scrolling_to_item = false;
|
||||||
TreeItem *scroll_item = nullptr;
|
TreeItem *scroll_item = nullptr;
|
||||||
|
|
||||||
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
|
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
|
||||||
List<Pair<TreeItem *, int>> parents;
|
List<ParentItem> parents;
|
||||||
for (const SceneDebuggerTree::RemoteNode &node : p_tree->nodes) {
|
for (const SceneDebuggerTree::RemoteNode &node : p_tree->nodes) {
|
||||||
TreeItem *parent = nullptr;
|
TreeItem *parent = nullptr;
|
||||||
|
Pair<TreeItem *, TreeItem *> move_from_to;
|
||||||
if (parents.size()) { // Find last parent.
|
if (parents.size()) { // Find last parent.
|
||||||
Pair<TreeItem *, int> &p = parents.front()->get();
|
ParentItem &p = parents.front()->get();
|
||||||
parent = p.first;
|
parent = p.tree_item;
|
||||||
if (!(--p.second)) { // If no child left, remove it.
|
if (!(--p.child_count)) { // If no child left, remove it.
|
||||||
parents.pop_front();
|
parents.pop_front();
|
||||||
|
|
||||||
|
if (hide_filtered_out_parents && !filter.is_subsequence_ofn(parent->get_text(0))) {
|
||||||
|
if (parent == get_root()) {
|
||||||
|
set_hide_root(true);
|
||||||
|
} else {
|
||||||
|
move_from_to.first = parent;
|
||||||
|
// Find the closest ancestor that matches the filter.
|
||||||
|
for (const ParentItem p2 : parents) {
|
||||||
|
move_from_to.second = p2.tree_item;
|
||||||
|
if (p2.matches_filter || move_from_to.second == get_root()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!move_from_to.second) {
|
||||||
|
move_from_to.second = get_root();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add this node.
|
// Add this node.
|
||||||
TreeItem *item = create_item(parent);
|
TreeItem *item = create_item(parent);
|
||||||
item->set_text(0, node.name);
|
item->set_text(0, node.name);
|
||||||
@@ -178,12 +205,17 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||||||
}
|
}
|
||||||
item->set_metadata(0, node.id);
|
item->set_metadata(0, node.id);
|
||||||
|
|
||||||
// Set current item as collapsed if necessary (root is never collapsed).
|
String current_path;
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
current_path += (String)parent->get_meta("node_path");
|
||||||
|
|
||||||
|
// Set current item as collapsed if necessary (root is never collapsed).
|
||||||
if (!unfold_cache.has(node.id)) {
|
if (!unfold_cache.has(node.id)) {
|
||||||
item->set_collapsed(true);
|
item->set_collapsed(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
item->set_meta("node_path", current_path + "/" + item->get_text(0));
|
||||||
|
|
||||||
// Select previously selected node.
|
// Select previously selected node.
|
||||||
if (debugger_id == p_debugger) { // Can use remote id.
|
if (debugger_id == p_debugger) { // Can use remote id.
|
||||||
if (node.id == inspected_object_id) {
|
if (node.id == inspected_object_id) {
|
||||||
@@ -196,21 +228,18 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||||||
updating_scene_tree = true;
|
updating_scene_tree = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
item->select(0);
|
select_item = item;
|
||||||
|
|
||||||
if (should_scroll) {
|
if (should_scroll) {
|
||||||
scroll_item = item;
|
scroll_item = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Must use path
|
} else if (last_path == (String)item->get_meta("node_path")) { // Must use path.
|
||||||
if (last_path == _get_path(item)) {
|
updating_scene_tree = false; // Force emission of new selection.
|
||||||
updating_scene_tree = false; // Force emission of new selection.
|
select_item = item;
|
||||||
item->select(0);
|
if (should_scroll) {
|
||||||
if (should_scroll) {
|
scroll_item = item;
|
||||||
scroll_item = item;
|
|
||||||
}
|
|
||||||
updating_scene_tree = true;
|
|
||||||
}
|
}
|
||||||
|
updating_scene_tree = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add buttons.
|
// Add buttons.
|
||||||
@@ -242,7 +271,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||||||
|
|
||||||
// Add in front of the parents stack if children are expected.
|
// Add in front of the parents stack if children are expected.
|
||||||
if (node.child_count) {
|
if (node.child_count) {
|
||||||
parents.push_front(Pair<TreeItem *, int>(item, node.child_count));
|
parents.push_front(ParentItem(item, node.child_count, filter.is_subsequence_ofn(item->get_text(0))));
|
||||||
} else {
|
} else {
|
||||||
// Apply filters.
|
// Apply filters.
|
||||||
while (parent) {
|
while (parent) {
|
||||||
@@ -250,31 +279,60 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
|||||||
if (filter.is_subsequence_ofn(item->get_text(0))) {
|
if (filter.is_subsequence_ofn(item->get_text(0))) {
|
||||||
break; // Filter matches, must survive.
|
break; // Filter matches, must survive.
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->remove_child(item);
|
parent->remove_child(item);
|
||||||
memdelete(item);
|
memdelete(item);
|
||||||
if (scroll_item == item) {
|
if (select_item == item || scroll_item == item) {
|
||||||
|
select_item = nullptr;
|
||||||
scroll_item = nullptr;
|
scroll_item = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (had_siblings) {
|
if (had_siblings) {
|
||||||
break; // Parent must survive.
|
break; // Parent must survive.
|
||||||
}
|
}
|
||||||
|
|
||||||
item = parent;
|
item = parent;
|
||||||
parent = item->get_parent();
|
parent = item->get_parent();
|
||||||
// Check if parent expects more children.
|
// Check if parent expects more children.
|
||||||
for (const Pair<TreeItem *, int> &pair : parents) {
|
for (ParentItem &pair : parents) {
|
||||||
if (pair.first == item) {
|
if (pair.tree_item == item) {
|
||||||
parent = nullptr;
|
parent = nullptr;
|
||||||
break; // Might have more children.
|
break; // Might have more children.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move all children to the ancestor that matches the filter, if picked.
|
||||||
|
if (move_from_to.first) {
|
||||||
|
TreeItem *from = move_from_to.first;
|
||||||
|
TypedArray<TreeItem> children = from->get_children();
|
||||||
|
if (!children.is_empty()) {
|
||||||
|
for (Variant &c : children) {
|
||||||
|
TreeItem *ti = Object::cast_to<TreeItem>(c);
|
||||||
|
from->remove_child(ti);
|
||||||
|
move_from_to.second->add_child(ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
from->get_parent()->remove_child(from);
|
||||||
|
memdelete(from);
|
||||||
|
if (select_item == from || scroll_item == from) {
|
||||||
|
select_item = nullptr;
|
||||||
|
scroll_item = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
|
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
|
||||||
|
|
||||||
|
if (select_item) {
|
||||||
|
select_item->select(0);
|
||||||
|
}
|
||||||
if (scroll_item) {
|
if (scroll_item) {
|
||||||
scroll_to_item(scroll_item, false);
|
scroll_to_item(scroll_item, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
last_filter = filter;
|
last_filter = filter;
|
||||||
updating_scene_tree = false;
|
updating_scene_tree = false;
|
||||||
}
|
}
|
||||||
@@ -338,22 +396,7 @@ String EditorDebuggerTree::get_selected_path() {
|
|||||||
if (!get_selected()) {
|
if (!get_selected()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return _get_path(get_selected());
|
return get_selected()->get_meta("node_path");
|
||||||
}
|
|
||||||
|
|
||||||
String EditorDebuggerTree::_get_path(TreeItem *p_item) {
|
|
||||||
ERR_FAIL_NULL_V(p_item, "");
|
|
||||||
|
|
||||||
if (p_item->get_parent() == nullptr) {
|
|
||||||
return "/root";
|
|
||||||
}
|
|
||||||
String text = p_item->get_text(0);
|
|
||||||
TreeItem *cur = p_item->get_parent();
|
|
||||||
while (cur) {
|
|
||||||
text = cur->get_text(0) + "/" + text;
|
|
||||||
cur = cur->get_parent();
|
|
||||||
}
|
|
||||||
return "/" + text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
|
void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
|
||||||
|
|||||||
@@ -40,6 +40,18 @@ class EditorDebuggerTree : public Tree {
|
|||||||
GDCLASS(EditorDebuggerTree, Tree);
|
GDCLASS(EditorDebuggerTree, Tree);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ParentItem {
|
||||||
|
TreeItem *tree_item;
|
||||||
|
int child_count;
|
||||||
|
bool matches_filter;
|
||||||
|
|
||||||
|
ParentItem(TreeItem *p_tree_item = nullptr, int p_child_count = 0, bool p_matches_filter = false) {
|
||||||
|
tree_item = p_tree_item;
|
||||||
|
child_count = p_child_count;
|
||||||
|
matches_filter = p_matches_filter;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum ItemMenu {
|
enum ItemMenu {
|
||||||
ITEM_MENU_SAVE_REMOTE_NODE,
|
ITEM_MENU_SAVE_REMOTE_NODE,
|
||||||
ITEM_MENU_COPY_NODE_PATH,
|
ITEM_MENU_COPY_NODE_PATH,
|
||||||
@@ -56,7 +68,6 @@ private:
|
|||||||
EditorFileDialog *file_dialog = nullptr;
|
EditorFileDialog *file_dialog = nullptr;
|
||||||
String last_filter;
|
String last_filter;
|
||||||
|
|
||||||
String _get_path(TreeItem *p_item);
|
|
||||||
void _scene_tree_folded(Object *p_obj);
|
void _scene_tree_folded(Object *p_obj);
|
||||||
void _scene_tree_selected();
|
void _scene_tree_selected();
|
||||||
void _scene_tree_rmb_selected(const Vector2 &p_position, MouseButton p_button);
|
void _scene_tree_rmb_selected(const Vector2 &p_position, MouseButton p_button);
|
||||||
|
|||||||
@@ -633,6 +633,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
|
|||||||
_initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false);
|
_initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false);
|
||||||
_initial_set("docks/scene_tree/auto_expand_to_selected", true);
|
_initial_set("docks/scene_tree/auto_expand_to_selected", true);
|
||||||
_initial_set("docks/scene_tree/center_node_on_reparent", false);
|
_initial_set("docks/scene_tree/center_node_on_reparent", false);
|
||||||
|
_initial_set("docks/scene_tree/hide_filtered_out_parents", true);
|
||||||
|
|
||||||
// FileSystem
|
// FileSystem
|
||||||
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "docks/filesystem/thumbnail_size", 64, "32,128,16")
|
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "docks/filesystem/thumbnail_size", 64, "32,128,16")
|
||||||
|
|||||||
@@ -957,49 +957,62 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now find other reasons to keep this Node, too.
|
||||||
|
PackedStringArray terms = filter.to_lower().split_spaces();
|
||||||
|
bool keep = _item_matches_all_terms(p_parent, terms);
|
||||||
|
|
||||||
|
bool selectable = keep;
|
||||||
|
bool is_root = p_parent == tree->get_root();
|
||||||
|
|
||||||
|
if (keep) {
|
||||||
|
Node *n = get_node(p_parent->get_metadata(0));
|
||||||
|
if (!p_parent->is_visible() || (is_root && tree->is_root_hidden())) {
|
||||||
|
// Place back moved out children from when this item has hidden.
|
||||||
|
HashMap<Node *, CachedNode>::Iterator I = node_cache.get(n, false);
|
||||||
|
if (I && I->value.has_moved_children) {
|
||||||
|
_update_node_subtree(I->value.node, nullptr, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid_types.is_empty()) {
|
||||||
|
selectable = false;
|
||||||
|
for (const StringName &E : valid_types) {
|
||||||
|
if (n->is_class(E) ||
|
||||||
|
EditorNode::get_singleton()->is_object_of_custom_type(n, E)) {
|
||||||
|
selectable = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
Ref<Script> node_script = n->get_script();
|
||||||
|
while (node_script.is_valid()) {
|
||||||
|
if (node_script->get_path() == E) {
|
||||||
|
selectable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node_script = node_script->get_base_script();
|
||||||
|
}
|
||||||
|
if (selectable) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool keep_for_children = false;
|
bool keep_for_children = false;
|
||||||
for (TreeItem *child = p_parent->get_first_child(); child; child = child->get_next()) {
|
for (TreeItem *child = p_parent->get_first_child(); child; child = child->get_next()) {
|
||||||
// Always keep if at least one of the children are kept.
|
// Always keep if at least one of the children are kept.
|
||||||
keep_for_children = _update_filter(child, p_scroll_to_selected) || keep_for_children;
|
keep_for_children = _update_filter(child, p_scroll_to_selected) || keep_for_children;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now find other reasons to keep this Node, too.
|
if (!is_root) {
|
||||||
PackedStringArray terms = filter.to_lower().split_spaces();
|
if (show_all_nodes) {
|
||||||
bool keep = _item_matches_all_terms(p_parent, terms);
|
p_parent->set_visible(keep_for_children || keep);
|
||||||
|
} else {
|
||||||
bool selectable = keep;
|
// Show only selectable nodes, or parents of selectable.
|
||||||
if (keep && !valid_types.is_empty()) {
|
p_parent->set_visible(keep_for_children || selectable);
|
||||||
selectable = false;
|
|
||||||
Node *n = get_node(p_parent->get_metadata(0));
|
|
||||||
|
|
||||||
for (const StringName &E : valid_types) {
|
|
||||||
if (n->is_class(E) ||
|
|
||||||
EditorNode::get_singleton()->is_object_of_custom_type(n, E)) {
|
|
||||||
selectable = true;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
Ref<Script> node_script = n->get_script();
|
|
||||||
while (node_script.is_valid()) {
|
|
||||||
if (node_script->get_path() == E) {
|
|
||||||
selectable = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
node_script = node_script->get_base_script();
|
|
||||||
}
|
|
||||||
if (selectable) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_all_nodes) {
|
|
||||||
p_parent->set_visible(keep_for_children || keep);
|
|
||||||
} else {
|
|
||||||
// Show only selectable nodes, or parents of selectable.
|
|
||||||
p_parent->set_visible(keep_for_children || selectable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectable) {
|
if (selectable) {
|
||||||
Color custom_color = p_parent->get_meta(SNAME("custom_color"), Color(0, 0, 0, 0));
|
Color custom_color = p_parent->get_meta(SNAME("custom_color"), Color(0, 0, 0, 0));
|
||||||
if (custom_color == Color(0, 0, 0, 0)) {
|
if (custom_color == Color(0, 0, 0, 0)) {
|
||||||
@@ -1007,24 +1020,67 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
|
|||||||
} else {
|
} else {
|
||||||
p_parent->set_custom_color(0, custom_color);
|
p_parent->set_custom_color(0, custom_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
p_parent->set_selectable(0, true);
|
p_parent->set_selectable(0, true);
|
||||||
} else if (keep_for_children) {
|
} else if (keep_for_children) {
|
||||||
p_parent->set_custom_color(0, get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
|
p_parent->set_visible(!hide_filtered_out_parents || is_root);
|
||||||
p_parent->set_selectable(0, false);
|
|
||||||
p_parent->deselect(0);
|
if (!p_parent->is_visible()) {
|
||||||
|
TreeItem *filtered_parent = p_parent->get_parent();
|
||||||
|
while (filtered_parent) {
|
||||||
|
if (filtered_parent == tree->get_root() || (filtered_parent->is_selectable(0) && filtered_parent->is_visible())) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
filtered_parent = filtered_parent->get_parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtered_parent) {
|
||||||
|
for (Variant &item : p_parent->get_children()) {
|
||||||
|
TreeItem *ti = Object::cast_to<TreeItem>(item);
|
||||||
|
bool is_selected = ti->is_selected(0);
|
||||||
|
|
||||||
|
p_parent->remove_child(ti);
|
||||||
|
filtered_parent->add_child(ti);
|
||||||
|
TreeItem *prev = p_parent->get_prev();
|
||||||
|
if (prev) {
|
||||||
|
ti->move_after(prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_selected) {
|
||||||
|
ti->select(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<Node *, CachedNode>::Iterator I = node_cache.get(get_node(p_parent->get_metadata(0)), false);
|
||||||
|
if (I) {
|
||||||
|
I->value.has_moved_children = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p_parent->set_custom_color(0, get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
|
||||||
|
p_parent->set_selectable(0, false);
|
||||||
|
p_parent->deselect(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_root) {
|
||||||
|
tree->set_hide_root(hide_filtered_out_parents && !selectable);
|
||||||
|
if (tree->is_root_hidden()) {
|
||||||
|
p_parent->set_collapsed(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editor_selection) {
|
if (editor_selection) {
|
||||||
Node *n = get_node(p_parent->get_metadata(0));
|
Node *n = get_node(p_parent->get_metadata(0));
|
||||||
if (selectable) {
|
if (selectable) {
|
||||||
if (p_scroll_to_selected && n && editor_selection->is_selected(n)) {
|
if (p_scroll_to_selected && n && editor_selection->is_selected(n)) {
|
||||||
tree->scroll_to_item(p_parent);
|
// Needs to be deferred to account for possible root visibility change.
|
||||||
}
|
callable_mp(tree, &Tree::scroll_to_item).call_deferred(p_parent, false);
|
||||||
} else {
|
|
||||||
if (n && p_parent->is_selected(0)) {
|
|
||||||
editor_selection->remove_node(n);
|
|
||||||
p_parent->deselect(0);
|
|
||||||
}
|
}
|
||||||
|
} else if (n && p_parent->is_selected(0)) {
|
||||||
|
editor_selection->remove_node(n);
|
||||||
|
p_parent->deselect(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1894,19 +1950,37 @@ void SceneTreeEditor::set_auto_expand_selected(bool p_auto, bool p_update_settin
|
|||||||
auto_expand_selected = p_auto;
|
auto_expand_selected = p_auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SceneTreeEditor::set_hide_filtered_out_parents(bool p_hide, bool p_update_settings) {
|
||||||
|
if (p_hide == hide_filtered_out_parents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_update_settings) {
|
||||||
|
EditorSettings::get_singleton()->set("docks/scene_tree/hide_filtered_out_parents", p_hide);
|
||||||
|
}
|
||||||
|
hide_filtered_out_parents = p_hide;
|
||||||
|
|
||||||
|
if (hide_filtered_out_parents) {
|
||||||
|
_update_filter();
|
||||||
|
} else {
|
||||||
|
node_cache.force_update = true;
|
||||||
|
_update_tree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SceneTreeEditor::set_connect_to_script_mode(bool p_enable) {
|
void SceneTreeEditor::set_connect_to_script_mode(bool p_enable) {
|
||||||
connect_to_script_mode = p_enable;
|
connect_to_script_mode = p_enable;
|
||||||
update_tree();
|
_update_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeEditor::set_connecting_signal(bool p_enable) {
|
void SceneTreeEditor::set_connecting_signal(bool p_enable) {
|
||||||
connecting_signal = p_enable;
|
connecting_signal = p_enable;
|
||||||
update_tree();
|
_update_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeEditor::set_update_when_invisible(bool p_enable) {
|
void SceneTreeEditor::set_update_when_invisible(bool p_enable) {
|
||||||
update_when_invisible = p_enable;
|
update_when_invisible = p_enable;
|
||||||
update_tree();
|
_update_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeEditor::_bind_methods() {
|
void SceneTreeEditor::_bind_methods() {
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ class SceneTreeEditor : public Control {
|
|||||||
Node *revoke_node = nullptr;
|
Node *revoke_node = nullptr;
|
||||||
|
|
||||||
bool auto_expand_selected = true;
|
bool auto_expand_selected = true;
|
||||||
|
bool hide_filtered_out_parents = false;
|
||||||
bool connect_to_script_mode = false;
|
bool connect_to_script_mode = false;
|
||||||
bool connecting_signal = false;
|
bool connecting_signal = false;
|
||||||
bool update_when_invisible = true;
|
bool update_when_invisible = true;
|
||||||
@@ -243,9 +244,10 @@ public:
|
|||||||
void set_show_enabled_subscene(bool p_show) { show_enabled_subscene = p_show; }
|
void set_show_enabled_subscene(bool p_show) { show_enabled_subscene = p_show; }
|
||||||
void set_valid_types(const Vector<StringName> &p_valid);
|
void set_valid_types(const Vector<StringName> &p_valid);
|
||||||
|
|
||||||
void update_tree() { _update_tree(); }
|
inline void update_tree() { _update_tree(); }
|
||||||
|
|
||||||
void set_auto_expand_selected(bool p_auto, bool p_update_settings);
|
void set_auto_expand_selected(bool p_auto, bool p_update_settings);
|
||||||
|
void set_hide_filtered_out_parents(bool p_hide, bool p_update_settings);
|
||||||
void set_connect_to_script_mode(bool p_enable);
|
void set_connect_to_script_mode(bool p_enable);
|
||||||
void set_connecting_signal(bool p_enable);
|
void set_connecting_signal(bool p_enable);
|
||||||
void set_update_when_invisible(bool p_enable);
|
void set_update_when_invisible(bool p_enable);
|
||||||
|
|||||||
@@ -1242,6 +1242,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||||||
case TOOL_CENTER_PARENT: {
|
case TOOL_CENTER_PARENT: {
|
||||||
EditorSettings::get_singleton()->set("docks/scene_tree/center_node_on_reparent", !EDITOR_GET("docks/scene_tree/center_node_on_reparent"));
|
EditorSettings::get_singleton()->set("docks/scene_tree/center_node_on_reparent", !EDITOR_GET("docks/scene_tree/center_node_on_reparent"));
|
||||||
} break;
|
} break;
|
||||||
|
case TOOL_HIDE_FILTERED_OUT_PARENTS: {
|
||||||
|
scene_tree->set_hide_filtered_out_parents(!EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"), true);
|
||||||
|
} break;
|
||||||
case TOOL_SCENE_EDITABLE_CHILDREN: {
|
case TOOL_SCENE_EDITABLE_CHILDREN: {
|
||||||
if (!profile_allow_editing) {
|
if (!profile_allow_editing) {
|
||||||
break;
|
break;
|
||||||
@@ -1667,6 +1670,7 @@ void SceneTreeDock::_notification(int p_what) {
|
|||||||
case NOTIFICATION_ENTER_TREE: {
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
clear_inherit_confirm->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM, false));
|
clear_inherit_confirm->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM, false));
|
||||||
scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
|
scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
|
||||||
|
scene_tree->set_hide_filtered_out_parents(EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"), false);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
@@ -1676,6 +1680,7 @@ void SceneTreeDock::_notification(int p_what) {
|
|||||||
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
||||||
if (EditorSettings::get_singleton()->check_changed_settings_in_group("docks/scene_tree")) {
|
if (EditorSettings::get_singleton()->check_changed_settings_in_group("docks/scene_tree")) {
|
||||||
scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
|
scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
|
||||||
|
scene_tree->set_hide_filtered_out_parents(EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"), false);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -3961,12 +3966,16 @@ void SceneTreeDock::_update_tree_menu() {
|
|||||||
|
|
||||||
tree_menu->add_separator();
|
tree_menu->add_separator();
|
||||||
tree_menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
|
tree_menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
|
||||||
tree_menu->set_item_checked(tree_menu->get_item_index(TOOL_AUTO_EXPAND), EDITOR_GET("docks/scene_tree/auto_expand_to_selected"));
|
tree_menu->set_item_checked(-1, EDITOR_GET("docks/scene_tree/auto_expand_to_selected"));
|
||||||
|
|
||||||
tree_menu->add_check_item(TTR("Center Node on Reparent"), TOOL_CENTER_PARENT);
|
tree_menu->add_check_item(TTR("Center Node on Reparent"), TOOL_CENTER_PARENT);
|
||||||
tree_menu->set_item_checked(tree_menu->get_item_index(TOOL_CENTER_PARENT), EDITOR_GET("docks/scene_tree/center_node_on_reparent"));
|
tree_menu->set_item_checked(-1, EDITOR_GET("docks/scene_tree/center_node_on_reparent"));
|
||||||
tree_menu->set_item_tooltip(tree_menu->get_item_index(TOOL_CENTER_PARENT), TTR("If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible."));
|
tree_menu->set_item_tooltip(-1, TTR("If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible."));
|
||||||
|
|
||||||
|
tree_menu->add_check_item(TTR("Hide Filtered Out Parents"), TOOL_HIDE_FILTERED_OUT_PARENTS);
|
||||||
|
tree_menu->set_item_checked(-1, EDITOR_GET("docks/scene_tree/hide_filtered_out_parents"));
|
||||||
|
|
||||||
|
tree_menu->add_separator();
|
||||||
PopupMenu *resource_list = memnew(PopupMenu);
|
PopupMenu *resource_list = memnew(PopupMenu);
|
||||||
resource_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
resource_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||||
resource_list->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_list_all_subresources).bind(resource_list));
|
resource_list->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_list_all_subresources).bind(resource_list));
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ class SceneTreeDock : public VBoxContainer {
|
|||||||
TOOL_CREATE_USER_INTERFACE,
|
TOOL_CREATE_USER_INTERFACE,
|
||||||
TOOL_CREATE_FAVORITE,
|
TOOL_CREATE_FAVORITE,
|
||||||
TOOL_CENTER_PARENT,
|
TOOL_CENTER_PARENT,
|
||||||
|
TOOL_HIDE_FILTERED_OUT_PARENTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|||||||
Reference in New Issue
Block a user