|
@@ -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();
|
|
|
|
- parent = p.first;
|
|
|
|
- if (!(--p.second)) { // If no child left, remove it.
|
|
|
|
|
|
+ ParentItem &p = parents.front()->get();
|
|
|
|
+ parent = p.tree_item;
|
|
|
|
+ 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
|
|
|
|
- if (last_path == _get_path(item)) {
|
|
|
|
- updating_scene_tree = false; // Force emission of new selection.
|
|
|
|
- item->select(0);
|
|
|
|
- if (should_scroll) {
|
|
|
|
- scroll_item = item;
|
|
|
|
- }
|
|
|
|
- updating_scene_tree = true;
|
|
|
|
|
|
+ } else if (last_path == (String)item->get_meta("node_path")) { // Must use path.
|
|
|
|
+ updating_scene_tree = false; // Force emission of new selection.
|
|
|
|
+ select_item = item;
|
|
|
|
+ if (should_scroll) {
|
|
|
|
+ scroll_item = item;
|
|
}
|
|
}
|
|
|
|
+ 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) {
|
|
|
|
- if (pair.first == item) {
|
|
|
|
|
|
+ for (ParentItem &pair : parents) {
|
|
|
|
+ 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());
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-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;
|
|
|
|
|
|
+ return get_selected()->get_meta("node_path");
|
|
}
|
|
}
|
|
|
|
|
|
void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
|
|
void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
|