Merge pull request #62666 from AThousandShips/tree_folding
Tree recursive folding (like Scene Tree Dock)
This commit is contained in:
commit
057dd292e4
7 changed files with 107 additions and 78 deletions
|
@ -312,6 +312,9 @@
|
|||
The drop mode as an OR combination of flags. See [enum DropModeFlags] constants. Once dropping is done, reverts to [constant DROP_MODE_DISABLED]. Setting this during [method Control._can_drop_data] is recommended.
|
||||
This controls the drop sections, i.e. the decision and drawing of possible drop locations based on the mouse position.
|
||||
</member>
|
||||
<member name="enable_recursive_folding" type="bool" setter="set_enable_recursive_folding" getter="is_recursive_folding_enabled" default="true">
|
||||
If [code]true[/code], recursive folding is enabled for this [Tree]. Holding down Shift while clicking the fold arrow collapses or uncollapses the [TreeItem] and all its descendants.
|
||||
</member>
|
||||
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
|
||||
<member name="hide_folding" type="bool" setter="set_hide_folding" getter="is_folding_hidden" default="false">
|
||||
If [code]true[/code], the folding arrow is hidden.
|
||||
|
|
|
@ -321,6 +321,14 @@
|
|||
Returns the [Tree] that owns this TreeItem.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_any_collapsed">
|
||||
<return type="bool" />
|
||||
<param index="0" name="only_visible" type="bool" default="false" />
|
||||
<description>
|
||||
Returns [code]true[/code] if this [TreeItem], or any of its descendants, is collapsed.
|
||||
If [param only_visible] is [code]true[/code] it ignores non-visible [TreeItem]s.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_button_disabled" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="column" type="int" />
|
||||
|
@ -442,6 +450,13 @@
|
|||
If [code]true[/code], the given [param column] is checked. Clears column's indeterminate status.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_collapsed_recursive">
|
||||
<return type="void" />
|
||||
<param index="0" name="enable" type="bool" />
|
||||
<description>
|
||||
Collapses or uncollapses this [TreeItem] and all the descendants of this item.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_custom_as_button">
|
||||
<return type="void" />
|
||||
<param index="0" name="column" type="int" />
|
||||
|
|
|
@ -1751,22 +1751,7 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
|
|||
case FOLDER_COLLAPSE_ALL: {
|
||||
// Expand or collapse the folder
|
||||
if (selected_strings.size() == 1) {
|
||||
bool is_collapsed = (p_option == FOLDER_COLLAPSE_ALL);
|
||||
|
||||
Vector<TreeItem *> needs_check;
|
||||
needs_check.push_back(tree->get_selected());
|
||||
|
||||
while (needs_check.size()) {
|
||||
needs_check[0]->set_collapsed(is_collapsed);
|
||||
|
||||
TreeItem *child = needs_check[0]->get_first_child();
|
||||
while (child) {
|
||||
needs_check.push_back(child);
|
||||
child = child->get_next();
|
||||
}
|
||||
|
||||
needs_check.remove_at(0);
|
||||
}
|
||||
tree->get_selected()->set_collapsed_recursive(p_option == FOLDER_COLLAPSE_ALL);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
|
|
|
@ -441,8 +441,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||
}
|
||||
}
|
||||
|
||||
bool collapsed = _is_collapsed_recursive(selected_item);
|
||||
_set_collapsed_recursive(selected_item, !collapsed);
|
||||
bool collapsed = selected_item->is_any_collapsed();
|
||||
selected_item->set_collapsed_recursive(!collapsed);
|
||||
|
||||
tree->ensure_cursor_is_visible();
|
||||
|
||||
|
@ -1223,17 +1223,6 @@ void SceneTreeDock::add_root_node(Node *p_node) {
|
|||
editor_data->get_undo_redo()->commit_action();
|
||||
}
|
||||
|
||||
void SceneTreeDock::_node_collapsed(Object *p_obj) {
|
||||
TreeItem *ti = Object::cast_to<TreeItem>(p_obj);
|
||||
if (!ti) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
|
||||
_set_collapsed_recursive(ti, ti->is_collapsed());
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTreeDock::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_READY: {
|
||||
|
@ -1945,48 +1934,6 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
|||
editor_data->get_undo_redo()->commit_action();
|
||||
}
|
||||
|
||||
bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
|
||||
bool is_branch_collapsed = false;
|
||||
|
||||
List<TreeItem *> needs_check;
|
||||
needs_check.push_back(p_item);
|
||||
|
||||
while (!needs_check.is_empty()) {
|
||||
TreeItem *item = needs_check.back()->get();
|
||||
needs_check.pop_back();
|
||||
|
||||
TreeItem *child = item->get_first_child();
|
||||
is_branch_collapsed = item->is_collapsed() && child;
|
||||
|
||||
if (is_branch_collapsed) {
|
||||
break;
|
||||
}
|
||||
while (child) {
|
||||
needs_check.push_back(child);
|
||||
child = child->get_next();
|
||||
}
|
||||
}
|
||||
return is_branch_collapsed;
|
||||
}
|
||||
|
||||
void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) {
|
||||
List<TreeItem *> to_collapse;
|
||||
to_collapse.push_back(p_item);
|
||||
|
||||
while (!to_collapse.is_empty()) {
|
||||
TreeItem *item = to_collapse.back()->get();
|
||||
to_collapse.pop_back();
|
||||
|
||||
item->set_collapsed(p_collapsed);
|
||||
|
||||
TreeItem *child = item->get_first_child();
|
||||
while (child) {
|
||||
to_collapse.push_back(child);
|
||||
child = child->get_next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTreeDock::_script_created(Ref<Script> p_script) {
|
||||
List<Node *> selected = editor_selection->get_selected_node_list();
|
||||
|
||||
|
@ -3532,7 +3479,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
|
|||
scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin));
|
||||
|
||||
scene_tree->get_scene_tree()->connect("item_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node));
|
||||
scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed));
|
||||
|
||||
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
|
||||
|
||||
|
|
|
@ -137,7 +137,6 @@ class SceneTreeDock : public VBoxContainer {
|
|||
HBoxContainer *tool_hbc = nullptr;
|
||||
void _tool_selected(int p_tool, bool p_confirm_override = false);
|
||||
void _property_selected(int p_idx);
|
||||
void _node_collapsed(Object *p_obj);
|
||||
|
||||
Node *property_drop_node = nullptr;
|
||||
String resource_drop_path;
|
||||
|
@ -188,9 +187,6 @@ class SceneTreeDock : public VBoxContainer {
|
|||
void _node_reparent(NodePath p_path, bool p_keep_global_xform);
|
||||
void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform);
|
||||
|
||||
bool _is_collapsed_recursive(TreeItem *p_item) const;
|
||||
void _set_collapsed_recursive(TreeItem *p_item, bool p_collapsed);
|
||||
|
||||
void _set_owners(Node *p_owner, const Array &p_nodes);
|
||||
|
||||
enum ReplaceOwnerMode {
|
||||
|
|
|
@ -563,6 +563,57 @@ bool TreeItem::is_collapsed() {
|
|||
return collapsed;
|
||||
}
|
||||
|
||||
void TreeItem::set_collapsed_recursive(bool p_collapsed) {
|
||||
if (!tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_collapsed(p_collapsed);
|
||||
|
||||
TreeItem *child = get_first_child();
|
||||
while (child) {
|
||||
child->set_collapsed_recursive(p_collapsed);
|
||||
child = child->get_next();
|
||||
}
|
||||
}
|
||||
|
||||
bool TreeItem::_is_any_collapsed(bool p_only_visible) {
|
||||
TreeItem *child = get_first_child();
|
||||
|
||||
// Check on children directly first (avoid recursing if possible).
|
||||
while (child) {
|
||||
if (child->get_first_child() && child->is_collapsed() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count()))) {
|
||||
return true;
|
||||
}
|
||||
child = child->get_next();
|
||||
}
|
||||
|
||||
child = get_first_child();
|
||||
|
||||
// Otherwise recurse on children.
|
||||
while (child) {
|
||||
if (child->get_first_child() && (!p_only_visible || (child->is_visible() && child->get_visible_child_count())) && child->_is_any_collapsed(p_only_visible)) {
|
||||
return true;
|
||||
}
|
||||
child = child->get_next();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TreeItem::is_any_collapsed(bool p_only_visible) {
|
||||
if (p_only_visible && !is_visible()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Collapsed if this is collapsed and it has children (only considers visible if only visible is set).
|
||||
if (is_collapsed() && get_first_child() && (!p_only_visible || get_visible_child_count())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return _is_any_collapsed(p_only_visible);
|
||||
}
|
||||
|
||||
void TreeItem::set_visible(bool p_visible) {
|
||||
if (visible == p_visible) {
|
||||
return;
|
||||
|
@ -1406,6 +1457,9 @@ void TreeItem::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed);
|
||||
ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_collapsed_recursive", "enable"), &TreeItem::set_collapsed_recursive);
|
||||
ClassDB::bind_method(D_METHOD("is_any_collapsed", "only_visible"), &TreeItem::is_any_collapsed, DEFVAL(false));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_visible", "enable"), &TreeItem::set_visible);
|
||||
ClassDB::bind_method(D_METHOD("is_visible"), &TreeItem::is_visible);
|
||||
|
||||
|
@ -2572,7 +2626,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
|
|||
}
|
||||
|
||||
if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + theme_cache.item_margin))) {
|
||||
p_item->set_collapsed(!p_item->is_collapsed());
|
||||
if (enable_recursive_folding && p_mod->is_shift_pressed()) {
|
||||
p_item->set_collapsed_recursive(!p_item->is_collapsed());
|
||||
} else {
|
||||
p_item->set_collapsed(!p_item->is_collapsed());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -2623,7 +2681,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
|
|||
}
|
||||
|
||||
if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) {
|
||||
p_item->set_collapsed(!p_item->is_collapsed());
|
||||
if (enable_recursive_folding && p_mod->is_shift_pressed()) {
|
||||
p_item->set_collapsed_recursive(!p_item->is_collapsed());
|
||||
} else {
|
||||
p_item->set_collapsed(!p_item->is_collapsed());
|
||||
}
|
||||
return -1; //collapse/uncollapse because nothing can be done with item
|
||||
}
|
||||
|
||||
|
@ -5026,6 +5088,14 @@ bool Tree::is_folding_hidden() const {
|
|||
return hide_folding;
|
||||
}
|
||||
|
||||
void Tree::set_enable_recursive_folding(bool p_enable) {
|
||||
enable_recursive_folding = p_enable;
|
||||
}
|
||||
|
||||
bool Tree::is_recursive_folding_enabled() const {
|
||||
return enable_recursive_folding;
|
||||
}
|
||||
|
||||
void Tree::set_drop_mode_flags(int p_flags) {
|
||||
if (drop_mode_flags == p_flags) {
|
||||
return;
|
||||
|
@ -5129,6 +5199,9 @@ void Tree::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_hide_folding", "hide"), &Tree::set_hide_folding);
|
||||
ClassDB::bind_method(D_METHOD("is_folding_hidden"), &Tree::is_folding_hidden);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_enable_recursive_folding", "enable"), &Tree::set_enable_recursive_folding);
|
||||
ClassDB::bind_method(D_METHOD("is_recursive_folding_enabled"), &Tree::is_recursive_folding_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_drop_mode_flags", "flags"), &Tree::set_drop_mode_flags);
|
||||
ClassDB::bind_method(D_METHOD("get_drop_mode_flags"), &Tree::get_drop_mode_flags);
|
||||
|
||||
|
@ -5143,6 +5216,7 @@ void Tree::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_folding"), "set_hide_folding", "is_folding_hidden");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_recursive_folding"), "set_enable_recursive_folding", "is_recursive_folding_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_root"), "set_hide_root", "is_root_hidden");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In Between"), "set_drop_mode_flags", "get_drop_mode_flags");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Row,Multi"), "set_select_mode", "get_select_mode");
|
||||
|
|
|
@ -173,6 +173,8 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
bool _is_any_collapsed(bool p_only_visible);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
|
@ -272,6 +274,9 @@ public:
|
|||
void set_collapsed(bool p_collapsed);
|
||||
bool is_collapsed();
|
||||
|
||||
void set_collapsed_recursive(bool p_collapsed);
|
||||
bool is_any_collapsed(bool p_only_visible = false);
|
||||
|
||||
void set_visible(bool p_visible);
|
||||
bool is_visible();
|
||||
|
||||
|
@ -613,6 +618,8 @@ private:
|
|||
|
||||
bool hide_folding = false;
|
||||
|
||||
bool enable_recursive_folding = true;
|
||||
|
||||
int _count_selected_items(TreeItem *p_from) const;
|
||||
bool _is_branch_selected(TreeItem *p_from) const;
|
||||
bool _is_sibling_branch_selected(TreeItem *p_from) const;
|
||||
|
@ -712,6 +719,9 @@ public:
|
|||
void set_hide_folding(bool p_hide);
|
||||
bool is_folding_hidden() const;
|
||||
|
||||
void set_enable_recursive_folding(bool p_enable);
|
||||
bool is_recursive_folding_enabled() const;
|
||||
|
||||
void set_drop_mode_flags(int p_flags);
|
||||
int get_drop_mode_flags() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue