8#ifndef MALENA_SCENEMANAGER_H
9#define MALENA_SCENEMANAGER_H
16#include <unordered_map>
111 template<
typename StateEnum>
120 std::function<
Core*()> factory;
121 std::unique_ptr<Core> owned;
123 bool isLazy()
const {
return static_cast<bool>(factory); }
124 bool isActive()
const {
return scene !=
nullptr; }
127 Core* get()
const {
return scene; }
133 inline static std::unordered_map<StateEnum, SceneEntry, EnumClassHash> _bindings;
134 inline static std::vector<StateEnum> _history;
135 inline static StateEnum _current{};
136 inline static bool _started =
false;
137 inline static bool _attached =
false;
140 inline static std::function<void(
Core&)> _add;
143 inline static std::function<void(
Core&)> _remove;
146 inline static std::function<void(StateEnum)> _setter;
164 _bindings[state] = SceneEntry{ &scene,
nullptr,
nullptr };
184 template<
typename SceneType,
typename... Args>
185 static void bindLazy(StateEnum state, Args&&... args)
187 static_assert(std::is_base_of_v<Core, SceneType>,
188 "[SceneManager] bindLazy: SceneType must derive from ml::Core.");
191 _bindings[state] = SceneEntry
194 [capturedArgs = std::make_tuple(std::forward<Args>(args)...)]()
mutable ->
Core*
196 return std::apply([](
auto&&... a) ->
Core*
198 return new SceneType(std::forward<
decltype(a)>(a)...);
226 template<
typename App>
232 _setter = [&app](StateEnum s) { app.setState(s); };
233 _add = [&app](
Core& s) { app.addComponent(s); };
237 _remove = [&app](
Core& s)
239 if constexpr (
requires { app.removeComponent(s); })
240 app.removeComponent(s);
246 app.onStateExit([](StateEnum leaving)
248 SceneManager::deactivate(leaving);
251 app.onStateEnter([](StateEnum entering)
253 SceneManager::activate(entering);
289 if (_history.empty())
return;
291 StateEnum previous = _history.back();
308 static StateEnum
current() {
return _current; }
314 static bool isActive(StateEnum state) {
return _started && _current == state; }
320 static bool has(StateEnum state) {
return _bindings.count(state) > 0; }
353 static void activate(StateEnum state)
355 auto it = _bindings.find(state);
356 if (it == _bindings.end())
return;
358 SceneEntry& entry = it->second;
365 entry.owned.reset(entry.factory());
366 entry.scene = entry.owned.get();
370 if (entry.scene && _add)
382 static void deactivate(StateEnum state)
384 auto it = _bindings.find(state);
385 if (it == _bindings.end())
return;
387 SceneEntry& entry = it->second;
389 if (entry.scene && _remove)
390 _remove(*entry.scene);
393 _history.push_back(state);
399 entry.scene =
nullptr;
Virtual base class for all Malena framework objects.
bool removeComponent(T &component)
Unregister a T object by reference.
State-driven scene router for Malena applications.
static void bind(StateEnum state, Core &scene)
Bind an existing scene instance to a state (eager).
static void attach(App &app)
Wire SceneManager into the application's state machine.
static void back()
Navigate to the previously visited state.
static void clear()
Clear all bindings and history.
static bool isActive(StateEnum state)
Return true if state is currently the active scene.
static StateEnum current()
Return the currently active state.
static void bindLazy(StateEnum state, Args &&... args)
Bind a lazily-constructed scene type to a state.
static void start(StateEnum state)
Activate the initial scene without recording a history entry.
static bool has(StateEnum state)
Return true if a scene has been bound to state.