From 72855ac2b8b63a71f3aff55156398088ac522a27 Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:02:36 -0500 Subject: [PATCH 1/5] Fix drag button and macOS/iOS versions --- mod.json | 4 ++-- src/DevTools.cpp | 3 +-- src/main.cpp | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/mod.json b/mod.json index 5d4ff61..5d64c0c 100644 --- a/mod.json +++ b/mod.json @@ -4,8 +4,8 @@ "gd": { "win": "2.2081", "android": "*", - "mac": "2.2074", - "ios": "2.2074" + "mac": "2.2081", + "ios": "2.2081" }, "id": "geode.devtools", "name": "DevTools", diff --git a/src/DevTools.cpp b/src/DevTools.cpp index 762596d..fd35834 100644 --- a/src/DevTools.cpp +++ b/src/DevTools.cpp @@ -128,12 +128,11 @@ void DevTools::setupDragButton() { m_dragButton->setPosition(m_settings.buttonPos); m_dragButton->setZOrder(10000); m_dragButton->setID("devtools-button"_spr); - SceneManager::get()->keepAcrossScenes(m_dragButton); + OverlayManager::get()->addChild(m_dragButton); } void DevTools::removeDragButton() { if (m_dragButton) { - SceneManager::get()->forget(m_dragButton); m_dragButton->removeFromParent(); m_dragButton = nullptr; } diff --git a/src/main.cpp b/src/main.cpp index 1b3025f..f15380a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,4 @@ -#include "Geode/ui/SceneManager.hpp" #include "platform/platform.hpp" #include #include @@ -90,7 +89,7 @@ class $modify(CCDirector) { if (!DevTools::get()->shouldUseGDWindow()) { return CCDirector::drawScene(); } - + DevTools::get()->setup(); static GLRenderCtx* gdTexture = nullptr; From cb137e3e44adb26f2ff14c63694706a39cd76a7b Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:03:52 -0500 Subject: [PATCH 2/5] Match with some PR --- src/main.cpp | 1 - src/pages/Tree.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index f15380a..8b503ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,3 @@ - #include "platform/platform.hpp" #include #include diff --git a/src/pages/Tree.cpp b/src/pages/Tree.cpp index 37182ef..73eedcf 100644 --- a/src/pages/Tree.cpp +++ b/src/pages/Tree.cpp @@ -191,6 +191,7 @@ void DevTools::drawTree() { } this->drawTreeBranch(CCDirector::get()->getRunningScene(), 0, false, true); + this->drawTreeBranch(OverlayManager::get(), 1, false, true); if (auto* dragged = this->getDraggedNode()) { const auto name = formatNodeName(dragged, 0); From 22f6558c12493e34bd6f770242d84f6f0addce58 Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Sun, 1 Feb 2026 16:05:23 -0500 Subject: [PATCH 3/5] More of this? --- src/pages/Tree.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/Tree.cpp b/src/pages/Tree.cpp index 73eedcf..20eb203 100644 --- a/src/pages/Tree.cpp +++ b/src/pages/Tree.cpp @@ -2,6 +2,7 @@ #include #include "../DevTools.hpp" #include "../platform/utils.hpp" +#include #include #include #include "../ImGui.hpp" From 462f45cd664527a6c38de7bb5b27d9d94cdb68dd Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Sun, 8 Feb 2026 08:11:37 -0500 Subject: [PATCH 4/5] Event and mod changes --- include/API.hpp | 20 ++++++++++---------- src/main.cpp | 4 ++-- src/pages/Advanced.cpp | 18 +++--------------- 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/include/API.hpp b/include/API.hpp index c87f071..e5e34fe 100644 --- a/include/API.hpp +++ b/include/API.hpp @@ -27,30 +27,30 @@ namespace devtools { template concept UnderlyingIntegral = std::is_integral_v || std::is_integral_v>; - struct RegisterNodeEvent final : geode::SimpleEvent> { - using SimpleEvent::SimpleEvent; + struct RegisterNodeEvent final : geode::Event)> { + using Event::Event; }; template - struct PropertyFnEvent final : geode::SimpleEvent, bool(*&)(const char* name, T&)> { + struct PropertyFnEvent final : geode::Event, bool(bool(*&)(const char* name, T&))> { using Fn = bool(const char* name, T&); - using geode::SimpleEvent::SimpleEvent; + using geode::Event::Event; }; - struct DrawLabelFnEvent final : geode::SimpleEvent { + struct DrawLabelFnEvent final : geode::Event { using Fn = void(const char* text); - using SimpleEvent::SimpleEvent; + using Event::Event; }; template - struct EnumerableFnEvent final : geode::SimpleEvent, bool(*&)(const char* label, T* value, std::span const>)> { + struct EnumerableFnEvent final : geode::Event, bool(bool(*&)(const char* label, T* value, std::span const>))> { using Fn = bool(const char* label, T* value, std::span const>); - using geode::SimpleEvent::SimpleEvent; + using geode::Event::Event; }; - struct ButtonFnEvent final : geode::SimpleEvent { + struct ButtonFnEvent final : geode::Event { using Fn = bool(const char* label); - using SimpleEvent::SimpleEvent; + using Event::Event; }; /// @brief Checks if DevTools is currently loaded. diff --git a/src/main.cpp b/src/main.cpp index 71620b7..a210de8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -153,8 +153,8 @@ class $modify(CCEGLView) { }; // For the one eclipse shortcut -struct ToggleDevToolsEvent : SimpleEvent { - using SimpleEvent::SimpleEvent; +struct ToggleDevToolsEvent : Event { + using Event::Event; }; $execute { diff --git a/src/pages/Advanced.cpp b/src/pages/Advanced.cpp index c5e6c0c..3d2eb79 100644 --- a/src/pages/Advanced.cpp +++ b/src/pages/Advanced.cpp @@ -94,13 +94,7 @@ ModMetadata DevTools::inputMetadata(void* treePtr, ModMetadata metadata) { continue; } ImGui::Text("version: %s", item.getVersion().toString().c_str()); - const char* importance = ""; - switch (item.getImportance()) { - case geode::ModMetadata::Dependency::Importance::Required: importance = "required"; break; - case geode::ModMetadata::Dependency::Importance::Recommended: importance = "recommended"; break; - case geode::ModMetadata::Dependency::Importance::Suggested: importance = "suggested"; break; - } - ImGui::Text("importance: %s", importance); + ImGui::Text("required: %s", item.isRequired() ? "true" : "false"); ImGui::Text("isResolved: %s", item.isResolved() ? "true" : "false"); if (item.getMod()) drawModGraphNode(item.getMod()); @@ -120,13 +114,7 @@ ModMetadata DevTools::inputMetadata(void* treePtr, ModMetadata metadata) { continue; } ImGui::Text("version: %s", item.getVersion().toString().c_str()); - const char* importance = ""; - switch (item.getImportance()) { - case geode::ModMetadata::Incompatibility::Importance::Breaking: importance = "breaking"; break; - case geode::ModMetadata::Incompatibility::Importance::Conflicting: importance = "conflicting"; break; - case geode::ModMetadata::Incompatibility::Importance::Superseded: importance = "superseded"; break; - } - ImGui::Text("importance: %s", importance); + ImGui::Text("breaking: %s", item.isBreaking() ? "true" : "false"); ImGui::Text("isResolved: %s", item.isResolved() ? "true" : "false"); if (item.getMod()) drawModGraphNode(item.getMod()); @@ -165,7 +153,7 @@ void DevTools::drawModGraphNode(Mod* node) { ImColor color = ImColor(1.f, 1.f, 1.f); if (node->isUninstalled()) color = ImColor(0.1f, 0.1f, 0.1f); - else if (!node->isEnabled()) + else if (!node->isLoaded()) color = ImColor(0.7f, 0.7f, 0.7f); ImGui::PushStyleColor(ImGuiCol_Text, (ImU32)color); From f09ffd3078283c84d9cdb72548fe8efbc9e2bf9a Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Sun, 8 Feb 2026 08:31:13 -0500 Subject: [PATCH 5/5] ZStringView and event export --- include/API.hpp | 62 ++++++++++++--------------------------- src/API.cpp | 78 ++++++++++++++++++++++--------------------------- 2 files changed, 54 insertions(+), 86 deletions(-) diff --git a/include/API.hpp b/include/API.hpp index e5e34fe..23f93e0 100644 --- a/include/API.hpp +++ b/include/API.hpp @@ -32,27 +32,17 @@ namespace devtools { }; template - struct PropertyFnEvent final : geode::Event, bool(bool(*&)(const char* name, T&))> { - using Fn = bool(const char* name, T&); + struct PropertyFnEvent final : geode::Event, bool(bool(*&)(geode::ZStringView name, T&))> { + using Fn = bool(geode::ZStringView name, T&); using geode::Event::Event; }; - struct DrawLabelFnEvent final : geode::Event { - using Fn = void(const char* text); - using Event::Event; - }; - template - struct EnumerableFnEvent final : geode::Event, bool(bool(*&)(const char* label, T* value, std::span const>))> { - using Fn = bool(const char* label, T* value, std::span const>); + struct EnumerableFnEvent final : geode::Event, bool(bool(*&)(geode::ZStringView label, T* value, std::span const>))> { + using Fn = bool(geode::ZStringView label, T* value, std::span const>); using geode::Event::Event; }; - struct ButtonFnEvent final : geode::Event { - using Fn = bool(const char* label); - using Event::Event; - }; - /// @brief Checks if DevTools is currently loaded. /// @return True if DevTools is loaded, false otherwise. inline bool isLoaded() { @@ -95,7 +85,7 @@ namespace devtools { /// @return True if the property was changed, false otherwise. /// @warning This function should only ever be called from within a registered node callback. template requires SupportedProperty - bool property(const char* name, T& prop) { + bool property(geode::ZStringView name, T& prop) { static auto fn = ([] { typename PropertyFnEvent::Fn* fnPtr = nullptr; PropertyFnEvent().send(fnPtr); @@ -107,14 +97,7 @@ namespace devtools { /// @brief Renders a label in the DevTools UI. /// @param text The text to display in the label. /// @warning This function should only ever be called from within a registered node callback. - inline void label(const char* text) { - static auto fn = ([] { - DrawLabelFnEvent::Fn* fnPtr = nullptr; - DrawLabelFnEvent().send(fnPtr); - return fnPtr; - })(); - if (fn) fn(text); - } + inline void label(geode::ZStringView text) GEODE_EVENT_EXPORT_NORES(&label, (text)); /// @brief Renders an enumerable property editor using radio buttons for the given value in the DevTools UI. /// @param label The label for the enumerable property. @@ -123,7 +106,7 @@ namespace devtools { /// @return True if the value was changed, false otherwise. /// @warning This function should only ever be called from within a registered node callback. template - bool enumerable(const char* label, T& value, std::initializer_list> items) { + bool enumerable(geode::ZStringView label, T& value, std::initializer_list> items) { using ValueType = std::underlying_type_t; static auto fn = ([] { typename EnumerableFnEvent::Fn* fnPtr = nullptr; @@ -134,8 +117,8 @@ namespace devtools { label, reinterpret_cast(&value), std::span( - reinterpret_cast const*>(&*items.begin()), - reinterpret_cast const*>(&*items.end()) + reinterpret_cast const*>(&*items.begin()), + reinterpret_cast const*>(&*items.end()) ) ) : false; } @@ -144,21 +127,14 @@ namespace devtools { /// @param label The label for the button. /// @return True if the button was clicked, false otherwise. /// @warning This function should only ever be called from within a registered node callback. - inline bool button(const char* label) { - static auto fn = ([] { - ButtonFnEvent::Fn* fnPtr = nullptr; - ButtonFnEvent().send(fnPtr); - return fnPtr; - })(); - return fn ? fn(label) : false; - } + inline bool button(geode::ZStringView label) GEODE_EVENT_EXPORT_NORES(&button, (label)); /// @brief Renders a button in the DevTools UI and calls the provided callback if the button is clicked. /// @param label The label for the button. /// @param callback The function to call when the button is clicked. /// @warning This function should only ever be called from within a registered node callback. template - void button(const char* label, F&& callback) { + void button(geode::ZStringView label, F&& callback) { if (button(label)) { callback(); } @@ -172,31 +148,31 @@ namespace devtools { inline void unindent() GEODE_EVENT_EXPORT_NORES(&unindent, ()); inline bool combo( - char const* label, + geode::ZStringView label, int& current, std::span items, int maxHeight = -1 ) GEODE_EVENT_EXPORT_NORES(&combo, (label, current, items, maxHeight)); - template > + template > requires std::ranges::range && - std::same_as().begin())> const, char const* const> - bool combo(char const* label, T& current, R&& range, int maxHeight = -1) { + std::same_as().begin())> const, geode::ZStringView const> + bool combo(geode::ZStringView label, T& current, R&& range, int maxHeight = -1) { return combo( label, reinterpret_cast(current), - std::span(const_cast(&*range.begin()), const_cast(&*range.end())), + std::span(const_cast(&*range.begin()), const_cast(&*range.end())), maxHeight ); } - inline bool radio(char const* label, int& current, int num) GEODE_EVENT_EXPORT_NORES(&radio, (label, current, num)); + inline bool radio(geode::ZStringView label, int& current, int num) GEODE_EVENT_EXPORT_NORES(&radio, (label, current, num)); template - bool radio(char const* label, T& current, U value) { + bool radio(geode::ZStringView label, T& current, U value) { return radio(label, reinterpret_cast(current), reinterpret_cast(value)); } - inline void inputMultiline(char const* label, std::string& text) GEODE_EVENT_EXPORT_NORES(&inputMultiline, (label, text)); + inline void inputMultiline(geode::ZStringView label, std::string& text) GEODE_EVENT_EXPORT_NORES(&inputMultiline, (label, text)); } diff --git a/src/API.cpp b/src/API.cpp index 7634cda..3e77335 100644 --- a/src/API.cpp +++ b/src/API.cpp @@ -17,19 +17,19 @@ static void handleType() { sizeof(T) == 2 ? (isSigned ? ImGuiDataType_S16 : ImGuiDataType_U16) : sizeof(T) == 4 ? (isSigned ? ImGuiDataType_S32 : ImGuiDataType_U32) : isSigned ? ImGuiDataType_S64 : ImGuiDataType_U64; - fnPtr = +[](const char* name, T& prop) { - return ImGui::DragScalar(name, dataType, &prop); + fnPtr = +[](ZStringView name, T& prop) { + return ImGui::DragScalar(name.c_str(), dataType, &prop); }; return ListenerResult::Stop; }).leak(); devtools::EnumerableFnEvent().listen([](typename devtools::EnumerableFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* label, T* value, std::span const> items) { - ImGui::Text("%s:", label); + fnPtr = +[](ZStringView label, T* value, std::span const> items) { + ImGui::Text("%s:", label.c_str()); size_t i = 0; bool changed = false; for (auto& [itemValue, itemLabel] : items) { - if (ImGui::RadioButton(itemLabel, *value == itemValue)) { + if (ImGui::RadioButton(itemLabel.c_str(), *value == itemValue)) { *value = itemValue; changed = true; } @@ -62,20 +62,28 @@ void devtools::indent() { void devtools::unindent() { ImGui::Unindent(16.f); } -bool devtools::combo(char const* label, int& current, std::span items, int maxHeight) { +bool devtools::combo(ZStringView label, int& current, std::span items, int maxHeight) { return ImGui::Combo( - label, + label.c_str(), ¤t, &*items.begin(), static_cast(items.size()), maxHeight ); } -bool devtools::radio(const char* label, int& current, int num) { - return ImGui::RadioButton(label, ¤t, num); +bool devtools::radio(ZStringView label, int& current, int num) { + return ImGui::RadioButton(label.c_str(), ¤t, num); } -void devtools::inputMultiline(const char* label, std::string& str) { - ImGui::InputTextMultiline(label, &str); +void devtools::inputMultiline(ZStringView label, std::string& str) { + ImGui::InputTextMultiline(label.c_str(), &str); +} + +void devtools::label(ZStringView text) { + ImGui::Text("%s", text.c_str()); +} + +bool devtools::button(ZStringView label) { + return ImGui::Button(label.c_str()); } $execute { @@ -100,30 +108,30 @@ void devtools::inputMultiline(const char* label, std::string& str) { // checkbox devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, bool& prop) { - return ImGui::Checkbox(name, &prop); + fnPtr = +[](ZStringView name, bool& prop) { + return ImGui::Checkbox(name.c_str(), &prop); }; return ListenerResult::Stop; }).leak(); // string devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, std::string& prop) { - return ImGui::InputText(name, &prop); + fnPtr = +[](ZStringView name, std::string& prop) { + return ImGui::InputText(name.c_str(), &prop); }; return ListenerResult::Stop; }).leak(); // colors devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, ccColor3B& prop) { + fnPtr = +[](ZStringView name, ccColor3B& prop) { auto color = ImVec4( prop.r / 255.f, prop.g / 255.f, prop.b / 255.f, 1.0f ); - if (ImGui::ColorEdit3(name, &color.x)) { + if (ImGui::ColorEdit3(name.c_str(), &color.x)) { prop.r = static_cast(color.x * 255); prop.g = static_cast(color.y * 255); prop.b = static_cast(color.z * 255); @@ -134,14 +142,14 @@ void devtools::inputMultiline(const char* label, std::string& str) { return ListenerResult::Stop; }).leak(); devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, ccColor4B& prop) { + fnPtr = +[](ZStringView name, ccColor4B& prop) { auto color = ImVec4( prop.r / 255.f, prop.g / 255.f, prop.b / 255.f, prop.a / 255.f ); - if (ImGui::ColorEdit4(name, &color.x)) { + if (ImGui::ColorEdit4(name.c_str(), &color.x)) { prop.r = static_cast(color.x * 255); prop.g = static_cast(color.y * 255); prop.b = static_cast(color.z * 255); @@ -153,45 +161,29 @@ void devtools::inputMultiline(const char* label, std::string& str) { return ListenerResult::Stop; }).leak(); devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, ccColor4F& prop) { - return ImGui::ColorEdit4(name, reinterpret_cast(&prop)); + fnPtr = +[](ZStringView name, ccColor4F& prop) { + return ImGui::ColorEdit4(name.c_str(), reinterpret_cast(&prop)); }; return ListenerResult::Stop; }).leak(); // points/sizes devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, CCPoint& prop) { - return ImGui::DragFloat2(name, reinterpret_cast(&prop)); + fnPtr = +[](ZStringView name, CCPoint& prop) { + return ImGui::DragFloat2(name.c_str(), reinterpret_cast(&prop)); }; return ListenerResult::Stop; }).leak(); devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, CCSize& prop) { - return ImGui::DragFloat2(name, reinterpret_cast(&prop)); + fnPtr = +[](ZStringView name, CCSize& prop) { + return ImGui::DragFloat2(name.c_str(), reinterpret_cast(&prop)); }; return ListenerResult::Stop; }).leak(); devtools::PropertyFnEvent().listen([](devtools::PropertyFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* name, CCRect& prop) { - return ImGui::DragFloat4(name, reinterpret_cast(&prop)); - }; - return ListenerResult::Stop; - }).leak(); - - // label - devtools::DrawLabelFnEvent().listen([](devtools::DrawLabelFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* text) { - ImGui::Text("%s", text); - }; - return ListenerResult::Stop; - }).leak(); - - // button - devtools::ButtonFnEvent().listen([](devtools::ButtonFnEvent::Fn*& fnPtr) { - fnPtr = +[](const char* label) { - return ImGui::Button(label); + fnPtr = +[](ZStringView name, CCRect& prop) { + return ImGui::DragFloat4(name.c_str(), reinterpret_cast(&prop)); }; return ListenerResult::Stop; }).leak();