77#include < initializer_list>
88#include < string>
99#include < type_traits>
10+ #include < Geode/loader/Dispatch.hpp>
11+ #define MY_MOD_ID " geode.devtools"
1012
1113namespace devtools {
1214 template <typename T>
@@ -22,36 +24,23 @@ namespace devtools {
2224 std::is_same_v<T, cocos2d::CCSize> ||
2325 std::is_same_v<T, cocos2d::CCRect>;
2426
25- struct RegisterNodeEvent final : geode::Event {
26- RegisterNodeEvent (std::function<void (cocos2d::CCNode*)>&& callback)
27- : callback(std::move(callback)) {}
28- std::function<void (cocos2d::CCNode*)> callback;
29- };
30-
3127 template <typename T>
32- struct PropertyFnEvent final : geode::Event {
33- PropertyFnEvent () {}
34- using Fn = bool (const char * name, T&);
35- Fn* fn = nullptr ;
36- };
28+ concept UnderlyingIntegral = std::is_integral_v<T> || std::is_integral_v<std::underlying_type_t <T>>;
3729
38- struct DrawLabelFnEvent final : geode::Event {
39- DrawLabelFnEvent () {}
40- using Fn = void (const char * text);
41- Fn* fn = nullptr ;
30+ struct RegisterNodeEvent final : geode::Event<RegisterNodeEvent, bool (geode::Function<void (cocos2d::CCNode*)>&)> {
31+ using Event::Event;
4232 };
4333
4434 template <typename T>
45- struct EnumerableFnEvent final : geode::Event {
46- EnumerableFnEvent () {}
47- using Fn = bool (const char * label, T* value, std::span<std::pair<T, const char *> const > items);
48- Fn* fn = nullptr ;
35+ struct PropertyFnEvent final : geode::Event<PropertyFnEvent<T>, bool (bool (*&)(geode::ZStringView name, T&))> {
36+ using Fn = bool (geode::ZStringView name, T&);
37+ using geode::Event<PropertyFnEvent, bool (Fn*&)>::Event;
4938 };
5039
51- struct ButtonFnEvent final : geode::Event {
52- ButtonFnEvent () {}
53- using Fn = bool (const char * label );
54- Fn* fn = nullptr ;
40+ template < typename T>
41+ struct EnumerableFnEvent final : geode::Event<EnumerableFnEvent<T>, bool ( bool (*&)(geode::ZStringView label, T* value, std::span<std::pair<T, geode::ZStringView> const >))> {
42+ using Fn = bool (geode::ZStringView label, T* value, std::span<std::pair<T, geode::ZStringView> const > );
43+ using geode::Event<EnumerableFnEvent, bool (Fn*&)>::Event ;
5544 };
5645
5746 // / @brief Checks if DevTools is currently loaded.
@@ -60,6 +49,10 @@ namespace devtools {
6049 return geode::Loader::get ()->getLoadedMod (" geode.devtools" ) != nullptr ;
6150 }
6251
52+ // / @brief Checks if DevTools is currently open.
53+ // / @return True if DevTools is open, false otherwise.
54+ inline bool isOpen () GEODE_EVENT_EXPORT_NORES(&isOpen, ());
55+
6356 // / @brief Waits for DevTools to be loaded and then calls the provided callback.
6457 // / @param callback The function to call once DevTools is loaded.
6558 template <typename F>
@@ -70,12 +63,11 @@ namespace devtools {
7063 auto devtools = geode::Loader::get ()->getInstalledMod (" geode.devtools" );
7164 if (!devtools) return ;
7265
73- new geode::EventListener (
74- [callback = std::forward<F>(callback)](geode::ModStateEvent* ) {
66+ geode::ModStateEvent (geode::ModEventType::Loaded, devtools). listen (
67+ [callback = std::forward<F>(callback)]() {
7568 callback ();
76- },
77- geode::ModStateFilter (devtools, geode::ModEventType::Loaded)
78- );
69+ }
70+ ).leak ();
7971 }
8072 }
8173
@@ -84,11 +76,13 @@ namespace devtools {
8476 // / @see `devtools::property`, `devtools::label`, `devtools::enumerable`, `devtools::button`
8577 template <typename T, std::invocable<std::remove_pointer_t <T>*> F> requires IsCCNode<T>
8678 void registerNode (F&& callback) {
87- RegisterNodeEvent ( [callback = std::forward<F>(callback)](cocos2d::CCNode* node) {
79+ geode::Function< void (cocos2d::CCNode*)> func = [callback = std::forward<F>(callback)](cocos2d::CCNode* node) {
8880 if (auto casted = geode::cast::typeinfo_cast<std::remove_pointer_t <T>*>(node)) {
8981 callback (casted);
9082 }
91- }).post ();
83+ };
84+
85+ RegisterNodeEvent ().send (func);
9286 }
9387
9488 // / @brief Renders a property editor for the given value in the DevTools UI.
@@ -97,47 +91,40 @@ namespace devtools {
9791 // / @return True if the property was changed, false otherwise.
9892 // / @warning This function should only ever be called from within a registered node callback.
9993 template <typename T> requires SupportedProperty<T>
100- bool property (const char * name, T& prop) {
94+ bool property (geode::ZStringView name, T& prop) {
10195 static auto fn = ([] {
102- PropertyFnEvent<T> event ;
103- event. post ( );
104- return event. fn ;
96+ typename PropertyFnEvent<T>::Fn* fnPtr = nullptr ;
97+ PropertyFnEvent<T>(). send (fnPtr );
98+ return fnPtr ;
10599 })();
106100 return fn ? fn (name, prop) : false ;
107101 }
108102
109103 // / @brief Renders a label in the DevTools UI.
110104 // / @param text The text to display in the label.
111105 // / @warning This function should only ever be called from within a registered node callback.
112- inline void label (const char * text) {
113- static auto fn = ([] {
114- DrawLabelFnEvent event;
115- event.post ();
116- return event.fn ;
117- })();
118- if (fn) fn (text);
119- }
106+ inline void label (geode::ZStringView text) GEODE_EVENT_EXPORT_NORES(&label, (text));
120107
121108 // / @brief Renders an enumerable property editor using radio buttons for the given value in the DevTools UI.
122109 // / @param label The label for the enumerable property.
123110 // / @param value The value to edit, which should be an enum or integral type.
124111 // / @param items A list of pairs where each pair contains a value and its corresponding label.
125112 // / @return True if the value was changed, false otherwise.
126113 // / @warning This function should only ever be called from within a registered node callback.
127- template <typename T> requires std::is_integral_v<std:: underlying_type_t <T> >
128- bool enumerable (const char * label, T& value, std::initializer_list<std::pair<T, const char * >> items) {
114+ template <UnderlyingIntegral T >
115+ bool enumerable (geode::ZStringView label, T& value, std::initializer_list<std::pair<T, geode::ZStringView >> items) {
129116 using ValueType = std::underlying_type_t <T>;
130117 static auto fn = ([] {
131- EnumerableFnEvent<ValueType> event ;
132- event. post ( );
133- return event. fn ;
118+ typename EnumerableFnEvent<ValueType>::Fn* fnPtr = nullptr ;
119+ EnumerableFnEvent<ValueType>(). send (fnPtr );
120+ return fnPtr ;
134121 })();
135122 return fn ? fn (
136123 label,
137124 reinterpret_cast <ValueType*>(&value),
138125 std::span (
139- reinterpret_cast <std::pair<ValueType, const char * > const *>(&*items.begin ()),
140- reinterpret_cast <std::pair<ValueType, const char * > const *>(&*items.end ())
126+ reinterpret_cast <std::pair<ValueType, geode::ZStringView > const *>(&*items.begin ()),
127+ reinterpret_cast <std::pair<ValueType, geode::ZStringView > const *>(&*items.end ())
141128 )
142129 ) : false ;
143130 }
@@ -146,23 +133,52 @@ namespace devtools {
146133 // / @param label The label for the button.
147134 // / @return True if the button was clicked, false otherwise.
148135 // / @warning This function should only ever be called from within a registered node callback.
149- inline bool button (const char * label) {
150- static auto fn = ([] {
151- ButtonFnEvent event;
152- event.post ();
153- return event.fn ;
154- })();
155- return fn ? fn (label) : false ;
156- }
136+ inline bool button (geode::ZStringView label) GEODE_EVENT_EXPORT_NORES(&button, (label));
157137
158138 // / @brief Renders a button in the DevTools UI and calls the provided callback if the button is clicked.
159139 // / @param label The label for the button.
160140 // / @param callback The function to call when the button is clicked.
161141 // / @warning This function should only ever be called from within a registered node callback.
162142 template <typename F>
163- void button (const char * label, F&& callback) {
143+ void button (geode::ZStringView label, F&& callback) {
164144 if (button (label)) {
165145 callback ();
166146 }
167147 }
168- }
148+
149+ inline void newLine () GEODE_EVENT_EXPORT_NORES(&newLine, ());
150+ inline void sameLine () GEODE_EVENT_EXPORT_NORES(&sameLine, ());
151+ inline void separator () GEODE_EVENT_EXPORT_NORES(&separator, ());
152+ inline void nextItemWidth (float width) GEODE_EVENT_EXPORT_NORES(&nextItemWidth, (width));
153+ inline void indent () GEODE_EVENT_EXPORT_NORES(&indent, ());
154+ inline void unindent () GEODE_EVENT_EXPORT_NORES(&unindent, ());
155+
156+ inline bool combo (
157+ geode::ZStringView label,
158+ int & current,
159+ std::span<char const *> items,
160+ int maxHeight = -1
161+ ) GEODE_EVENT_EXPORT_NORES(&combo, (label, current, items, maxHeight));
162+
163+ template <UnderlyingIntegral T, typename R = std::initializer_list<geode::ZStringView>>
164+ requires
165+ std::ranges::range<R> &&
166+ std::same_as<std::remove_pointer_t <decltype (&*std::declval<R>().begin())> const , geode::ZStringView const >
167+ bool combo (geode::ZStringView label, T& current, R&& range, int maxHeight = -1 ) {
168+ return combo (
169+ label,
170+ reinterpret_cast <int &>(current),
171+ std::span (const_cast <geode::ZStringView*>(&*range.begin ()), const_cast <geode::ZStringView*>(&*range.end ())),
172+ maxHeight
173+ );
174+ }
175+
176+ inline bool radio (geode::ZStringView label, int & current, int num) GEODE_EVENT_EXPORT_NORES(&radio, (label, current, num));
177+
178+ template <UnderlyingIntegral T, UnderlyingIntegral U>
179+ bool radio (geode::ZStringView label, T& current, U value) {
180+ return radio (label, reinterpret_cast <int &>(current), reinterpret_cast <int &>(value));
181+ }
182+
183+ inline void inputMultiline (geode::ZStringView label, std::string& text) GEODE_EVENT_EXPORT_NORES(&inputMultiline, (label, text));
184+ }
0 commit comments