From 1f5bf8d5ea07912d7f79f61b82eb92945a49c052 Mon Sep 17 00:00:00 2001 From: undefined06855 Date: Fri, 1 May 2026 16:40:43 +0100 Subject: [PATCH 1/4] add extra-children user object --- src/DevTools.hpp | 2 +- src/pages/Tree.cpp | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/DevTools.hpp b/src/DevTools.hpp index 3838f37..8a04927 100644 --- a/src/DevTools.hpp +++ b/src/DevTools.hpp @@ -66,7 +66,7 @@ class DevTools { void setupPlatform(); void drawTree(); - void drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible); + void drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake); void drawSettings(); void drawAdvancedSettings(); void drawNodeAttributes(CCNode* node); diff --git a/src/pages/Tree.cpp b/src/pages/Tree.cpp index af2c284..47422f4 100644 --- a/src/pages/Tree.cpp +++ b/src/pages/Tree.cpp @@ -13,8 +13,8 @@ using namespace geode::prelude; -std::string formatNodeName(CCNode* node, size_t index) { - std::string name = fmt::format("[{}] {} ", index, geode::cocos::getObjectName(node)); +std::string formatNodeName(CCNode* node, size_t index, bool fake) { + std::string name = fmt::format("[{}{}] {} ", index, fake ? "*" : "", geode::cocos::getObjectName(node)); if (node->getTag() != -1) { name += fmt::format("({}) ", node->getTag()); } @@ -36,7 +36,7 @@ bool isNodeParentOf(CCNode* parent, CCNode* child) { return false; } -void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible) { +void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake) { if (!this->searchBranch(node)) { return; } @@ -58,7 +58,7 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl bool drawSeparator = false; - if (auto dragged = this->getDraggedNode(); dragged && dragged != node && !drag) { + if (auto dragged = this->getDraggedNode(); dragged && dragged != node && !drag && !fake) { float mouseY = ImGui::GetMousePos().y; float cursorY = ImGui::GetCursorPosY() + ImGui::GetWindowPos().y - ImGui::GetScrollY(); float height = ImGui::GetTextLineHeight(); @@ -112,7 +112,7 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl ImGui::BeginDisabled(!visible); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, false); // Bypass iteract blocking in imgui - const auto name = formatNodeName(node, index); + const auto name = formatNodeName(node, index, fake); // The order here is unusual due to imgui weirdness; see the second-to-last paragraph in https://kahwei.dev/2022/06/20/imgui-tree-node/ bool expanded = ImGui::TreeNodeEx(node, flags, "%s", name.c_str()); float height = ImGui::GetItemRectSize().y; @@ -164,10 +164,19 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl if (m_settings.attributesInTree) { this->drawNodeAttributes(node); } + size_t i = 0; for (auto& child : CCArrayExt(node->getChildren())) { - this->drawTreeBranch(child, i++, drag || isDrag, visible); + this->drawTreeBranch(child, i++, drag || isDrag, visible, false); } + + i = 0; + if (auto fakeChildren = typeinfo_cast(node->getUserObject("extra-children"_spr))) { + for (auto& child : CCArrayExt(fakeChildren)) { + this->drawTreeBranch(child, i++, drag || isDrag, visible, true); + } + } + ImGui::TreePop(); } // on leaf nodes expanded is true @@ -191,11 +200,11 @@ void DevTools::drawTree() { m_searchQuery.clear(); } - this->drawTreeBranch(CCDirector::get()->getRunningScene(), 0, false, true); - this->drawTreeBranch(OverlayManager::get(), 1, false, true); + this->drawTreeBranch(CCDirector::get()->getRunningScene(), 0, false, true, false); + this->drawTreeBranch(OverlayManager::get(), 1, false, true, false); if (auto* dragged = this->getDraggedNode()) { - const auto name = formatNodeName(dragged, 0); + const auto name = formatNodeName(dragged, 0, false); auto bgColor = ImGui::GetColorU32(ImGui::GetStyle().Colors[ImGuiCol_Header]); auto textColor = ImGui::GetColorU32(ImGui::GetStyle().Colors[ImGuiCol_Text]); From 84c60170bb9cd9d52d9037db65b822c4d656a3de Mon Sep 17 00:00:00 2001 From: undefined06855 Date: Fri, 1 May 2026 19:11:28 +0100 Subject: [PATCH 2/4] add hide user flag --- src/DevTools.hpp | 4 +++- src/pages/Settings.cpp | 8 +++++++ src/pages/Tree.cpp | 48 ++++++++++++++++++++++++++---------------- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/DevTools.hpp b/src/DevTools.hpp index 8a04927..58c8856 100644 --- a/src/DevTools.hpp +++ b/src/DevTools.hpp @@ -36,6 +36,7 @@ struct Settings { bool buttonInGame = false; bool buttonEnabled = false; bool treeDragReorder = false; + bool hideFlaggedNodes = false; }; class DevTools { @@ -66,7 +67,8 @@ class DevTools { void setupPlatform(); void drawTree(); - void drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake); + void drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake, bool parentHidden); + void drawNodeChildren(CCNode* node, bool drag, bool visible, bool parentHidden); void drawSettings(); void drawAdvancedSettings(); void drawNodeAttributes(CCNode* node); diff --git a/src/pages/Settings.cpp b/src/pages/Settings.cpp index 57f4b4e..6768650 100644 --- a/src/pages/Settings.cpp +++ b/src/pages/Settings.cpp @@ -64,6 +64,14 @@ void DevTools::drawSettings() { "(Experimental)\nAllows you to drag/drop nodes in the node tree, changing\ntheir parents or ordering." ); } + ImGui::Checkbox("Hide Flagged Nodes", &m_settings.hideFlaggedNodes); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip( + "If enabled, hides nodes in the node tree with the \"geode.devtools/hide\"\n" + "user flag set. Allows for hiding nodes irrelevant to debugging, such as containers.\n" + "This will keep the children of those nodes visible in the node tree." + ); + } ImGui::Checkbox("Advanced Settings", &m_settings.advancedSettings); if (ImGui::IsItemHovered()) { ImGui::SetTooltip( diff --git a/src/pages/Tree.cpp b/src/pages/Tree.cpp index 47422f4..afc4e69 100644 --- a/src/pages/Tree.cpp +++ b/src/pages/Tree.cpp @@ -13,8 +13,11 @@ using namespace geode::prelude; -std::string formatNodeName(CCNode* node, size_t index, bool fake) { - std::string name = fmt::format("[{}{}] {} ", index, fake ? "*" : "", geode::cocos::getObjectName(node)); +std::string formatNodeName(CCNode* node, size_t index, bool fake, bool parentHidden) { + std::string prefix = ""; + if (fake) prefix += "*"; + if (parentHidden) prefix += "..."; + std::string name = fmt::format("[{}{}] {} ", prefix, index, geode::cocos::getObjectName(node)); if (node->getTag() != -1) { name += fmt::format("({}) ", node->getTag()); } @@ -36,11 +39,16 @@ bool isNodeParentOf(CCNode* parent, CCNode* child) { return false; } -void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake) { +void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake, bool parentHidden) { if (!this->searchBranch(node)) { return; } + if (node->getUserFlag("hide"_spr) && m_settings.hideFlaggedNodes) { + this->drawNodeChildren(node, drag, visible, true); + return; + } + visible = node->isVisible() && visible; auto selected = DevTools::get()->getSelectedNode() == node; @@ -112,7 +120,7 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl ImGui::BeginDisabled(!visible); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, false); // Bypass iteract blocking in imgui - const auto name = formatNodeName(node, index, fake); + const auto name = formatNodeName(node, index, fake, parentHidden); // The order here is unusual due to imgui weirdness; see the second-to-last paragraph in https://kahwei.dev/2022/06/20/imgui-tree-node/ bool expanded = ImGui::TreeNodeEx(node, flags, "%s", name.c_str()); float height = ImGui::GetItemRectSize().y; @@ -165,17 +173,7 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl this->drawNodeAttributes(node); } - size_t i = 0; - for (auto& child : CCArrayExt(node->getChildren())) { - this->drawTreeBranch(child, i++, drag || isDrag, visible, false); - } - - i = 0; - if (auto fakeChildren = typeinfo_cast(node->getUserObject("extra-children"_spr))) { - for (auto& child : CCArrayExt(fakeChildren)) { - this->drawTreeBranch(child, i++, drag || isDrag, visible, true); - } - } + this->drawNodeChildren(node, drag || isDrag, visible, false); ImGui::TreePop(); } @@ -185,6 +183,20 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl } } +void DevTools::drawNodeChildren(CCNode* node, bool drag, bool visible, bool parentHidden) { + size_t i = 0; + for (auto& child : CCArrayExt(node->getChildren())) { + this->drawTreeBranch(child, i++, drag, visible, false, parentHidden); + } + + i = 0; + if (auto fakeChildren = typeinfo_cast(node->getUserObject("extra-children"_spr))) { + for (auto& child : CCArrayExt(fakeChildren)) { + this->drawTreeBranch(child, i++, drag, visible, true, parentHidden); + } + } +} + void DevTools::drawTree() { #ifdef GEODE_IS_MOBILE ImGui::Dummy({0.f, 60.f}); @@ -200,11 +212,11 @@ void DevTools::drawTree() { m_searchQuery.clear(); } - this->drawTreeBranch(CCDirector::get()->getRunningScene(), 0, false, true, false); - this->drawTreeBranch(OverlayManager::get(), 1, false, true, false); + this->drawTreeBranch(CCDirector::get()->getRunningScene(), 0, false, true, false, false); + this->drawTreeBranch(OverlayManager::get(), 1, false, true, false, false); if (auto* dragged = this->getDraggedNode()) { - const auto name = formatNodeName(dragged, 0, false); + const auto name = formatNodeName(dragged, 0, false, false); auto bgColor = ImGui::GetColorU32(ImGui::GetStyle().Colors[ImGuiCol_Header]); auto textColor = ImGui::GetColorU32(ImGui::GetStyle().Colors[ImGuiCol_Text]); From 25c439d371964f76b00ff7688bf57d3096d726b9 Mon Sep 17 00:00:00 2001 From: undefined06855 Date: Fri, 1 May 2026 19:21:05 +0100 Subject: [PATCH 3/4] change long unreadable parameter count into a struct --- src/DevTools.hpp | 17 +++++++++++++++-- src/pages/Tree.cpp | 46 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/DevTools.hpp b/src/DevTools.hpp index 58c8856..3007e83 100644 --- a/src/DevTools.hpp +++ b/src/DevTools.hpp @@ -39,6 +39,19 @@ struct Settings { bool hideFlaggedNodes = false; }; +struct TreeBranchOptions { + bool drag = true; + bool visible = true; + bool fake = false; + bool flagHidden = false; +}; + +struct ParentNodeInformation { + bool drag = true; + bool visible = true; + bool flagHidden = false; +}; + class DevTools { protected: bool m_visible = false; @@ -67,8 +80,8 @@ class DevTools { void setupPlatform(); void drawTree(); - void drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake, bool parentHidden); - void drawNodeChildren(CCNode* node, bool drag, bool visible, bool parentHidden); + void drawTreeBranch(CCNode* node, size_t index, TreeBranchOptions options); + void drawNodeChildren(CCNode* node, ParentNodeInformation info); void drawSettings(); void drawAdvancedSettings(); void drawNodeAttributes(CCNode* node); diff --git a/src/pages/Tree.cpp b/src/pages/Tree.cpp index afc4e69..c0586c0 100644 --- a/src/pages/Tree.cpp +++ b/src/pages/Tree.cpp @@ -13,10 +13,10 @@ using namespace geode::prelude; -std::string formatNodeName(CCNode* node, size_t index, bool fake, bool parentHidden) { +std::string formatNodeName(CCNode* node, size_t index, bool fake, bool flagHidden) { std::string prefix = ""; if (fake) prefix += "*"; - if (parentHidden) prefix += "..."; + if (flagHidden) prefix += "..."; std::string name = fmt::format("[{}{}] {} ", prefix, index, geode::cocos::getObjectName(node)); if (node->getTag() != -1) { name += fmt::format("({}) ", node->getTag()); @@ -39,17 +39,21 @@ bool isNodeParentOf(CCNode* parent, CCNode* child) { return false; } -void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visible, bool fake, bool parentHidden) { +void DevTools::drawTreeBranch(CCNode* node, size_t index, TreeBranchOptions options) { if (!this->searchBranch(node)) { return; } if (node->getUserFlag("hide"_spr) && m_settings.hideFlaggedNodes) { - this->drawNodeChildren(node, drag, visible, true); + this->drawNodeChildren(node, { + .drag = options.drag, + .visible = options.visible, + .flagHidden = true + }); return; } - visible = node->isVisible() && visible; + options.visible = node->isVisible() && options.visible; auto selected = DevTools::get()->getSelectedNode() == node; @@ -66,7 +70,7 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl bool drawSeparator = false; - if (auto dragged = this->getDraggedNode(); dragged && dragged != node && !drag && !fake) { + if (auto dragged = this->getDraggedNode(); dragged && dragged != node && !options.drag && !options.fake) { float mouseY = ImGui::GetMousePos().y; float cursorY = ImGui::GetCursorPosY() + ImGui::GetWindowPos().y - ImGui::GetScrollY(); float height = ImGui::GetTextLineHeight(); @@ -117,10 +121,10 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl auto alpha = ImGui::GetStyle().DisabledAlpha; ImGui::GetStyle().DisabledAlpha = node->isVisible() ? alpha + 0.15f : alpha; - ImGui::BeginDisabled(!visible); + ImGui::BeginDisabled(!options.visible); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, false); // Bypass iteract blocking in imgui - const auto name = formatNodeName(node, index, fake, parentHidden); + const auto name = formatNodeName(node, index, options.fake, options.flagHidden); // The order here is unusual due to imgui weirdness; see the second-to-last paragraph in https://kahwei.dev/2022/06/20/imgui-tree-node/ bool expanded = ImGui::TreeNodeEx(node, flags, "%s", name.c_str()); float height = ImGui::GetItemRectSize().y; @@ -173,7 +177,11 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl this->drawNodeAttributes(node); } - this->drawNodeChildren(node, drag || isDrag, visible, false); + this->drawNodeChildren(node, { + .drag = options.drag || isDrag, + .visible = options.visible, + .flagHidden = false + }); ImGui::TreePop(); } @@ -183,16 +191,26 @@ void DevTools::drawTreeBranch(CCNode* node, size_t index, bool drag, bool visibl } } -void DevTools::drawNodeChildren(CCNode* node, bool drag, bool visible, bool parentHidden) { +void DevTools::drawNodeChildren(CCNode* node, ParentNodeInformation info) { size_t i = 0; for (auto& child : CCArrayExt(node->getChildren())) { - this->drawTreeBranch(child, i++, drag, visible, false, parentHidden); + this->drawTreeBranch(child, i++, { + .drag = info.drag, + .visible = info.visible, + .fake = false, + .flagHidden = info.flagHidden + }); } i = 0; if (auto fakeChildren = typeinfo_cast(node->getUserObject("extra-children"_spr))) { for (auto& child : CCArrayExt(fakeChildren)) { - this->drawTreeBranch(child, i++, drag, visible, true, parentHidden); + this->drawTreeBranch(child, i++, { + .drag = info.drag, + .visible = info.visible, + .fake = true, + .flagHidden = info.flagHidden + }); } } } @@ -212,8 +230,8 @@ void DevTools::drawTree() { m_searchQuery.clear(); } - this->drawTreeBranch(CCDirector::get()->getRunningScene(), 0, false, true, false, false); - this->drawTreeBranch(OverlayManager::get(), 1, false, true, false, false); + this->drawTreeBranch(CCDirector::get()->getRunningScene(), 0, { .drag = false }); + this->drawTreeBranch(OverlayManager::get(), 1, { .drag = false }); if (auto* dragged = this->getDraggedNode()) { const auto name = formatNodeName(dragged, 0, false, false); From 1ca9589f913b9230cdede61d8f267301c42dcaec Mon Sep 17 00:00:00 2001 From: undefined06855 <98057141+undefined06855@users.noreply.github.com> Date: Fri, 8 May 2026 12:52:31 +0100 Subject: [PATCH 4/4] serialise hideFlaggedNodes (british serialiSation) --- src/DevTools.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/DevTools.cpp b/src/DevTools.cpp index ffe7243..dbc3d40 100644 --- a/src/DevTools.cpp +++ b/src/DevTools.cpp @@ -36,6 +36,7 @@ struct matjson::Serialize { assign(value["button_game"], s.buttonInGame); assign(value["button_enabled"], s.buttonEnabled); assign(value["tree_drag_reorder"], s.treeDragReorder); + assign(value["hide_flagged_nodes"], s.hideFlaggedNodes); return Ok(s); } @@ -58,7 +59,8 @@ struct matjson::Serialize { { "button_editor", settings.buttonInEditor }, { "button_game", settings.buttonInGame }, { "button_enabled", settings.buttonEnabled }, - { "tree_drag_reorder", settings.treeDragReorder } + { "tree_drag_reorder", settings.treeDragReorder }, + { "hide_flagged_nodes", settings.hideFlaggedNodes }, }); } };