8#ifndef MALENA_SCENEMANAGER_H
9#define MALENA_SCENEMANAGER_H
16#include <unordered_map>
151 template<
typename StateEnum>
160 std::function<
Core*()> factory;
161 std::unique_ptr<Core> owned;
163 bool isLazy()
const {
return static_cast<bool>(factory); }
164 bool isActive()
const {
return scene !=
nullptr; }
167 Core* get()
const {
return scene; }
173 std::unordered_map<StateEnum, SceneEntry, EnumClassHash> _bindings;
174 std::vector<StateEnum> _history;
175 StateEnum _current{};
176 bool _started =
false;
177 bool _attached =
false;
180 std::function<void(
Core&)> _add;
183 std::function<void(
Core&)> _remove;
186 std::function<void(StateEnum)> _setter;
189 std::function<void(StateEnum)> _sync;
219 _bindings[state] = SceneEntry{ &scene,
nullptr,
nullptr };
239 template<
typename SceneType,
typename... Args>
242 static_assert(std::is_base_of_v<Core, SceneType>,
243 "[SceneManager] bindLazy: SceneType must derive from ml::Core.");
246 _bindings[state] = SceneEntry
249 [capturedArgs = std::make_tuple(std::forward<Args>(args)...)]()
mutable ->
Core*
251 return std::apply([](
auto&&... a) ->
Core*
253 return new SceneType(std::forward<
decltype(a)>(a)...);
285 template<
typename Owner>
291 _setter = [&owner](StateEnum s) { owner.setState(s); };
292 _sync = [&owner](StateEnum s) { owner.syncState(s); };
293 _add = [&owner](
Core& s) { owner.addComponent(s); };
294 _remove = [&owner](
Core& s) { owner.removeComponent(s); };
297 owner.onStateExit([
this](StateEnum leaving)
302 owner.onStateEnter([
this](StateEnum entering)
323 if (_sync) _sync(state);
341 if (_history.empty())
return;
343 StateEnum previous = _history.back();
360 StateEnum
current()
const {
return _current; }
366 bool isActive(StateEnum state)
const {
return _started && _current == state; }
372 bool has(StateEnum state)
const {
return _bindings.count(state) > 0; }
403 void activate(StateEnum state)
405 auto it = _bindings.find(state);
406 if (it == _bindings.end())
return;
408 SceneEntry& entry = it->second;
415 entry.owned.reset(entry.factory());
416 entry.scene = entry.owned.get();
420 if (entry.scene && _add)
422 entry.scene->setEnabled(
true);
435 void deactivate(StateEnum state)
437 auto it = _bindings.find(state);
438 if (it == _bindings.end())
return;
440 SceneEntry& entry = it->second;
442 if (entry.scene && _remove)
444 _remove(*entry.scene);
445 entry.scene->setEnabled(
false);
449 _history.push_back(state);
455 entry.scene =
nullptr;
Virtual base class for all Malena framework objects.
void setEnabled(bool enabled)
bool has(StateEnum state) const
Return true if a scene has been bound to state.
void bindLazy(StateEnum state, Args &&... args)
Bind a lazily-constructed scene type to a state.
void attach(Owner &owner)
Wire SceneManager into the owner's state machine.
SceneManager(SceneManager &&)=delete
void back()
Navigate to the previously visited state.
void bind(StateEnum state, Core &scene)
Bind an existing scene instance to a state (eager).
SceneManager(const SceneManager &)=delete
bool isActive(StateEnum state) const
Return true if state is currently the active scene.
SceneManager & operator=(SceneManager &&)=delete
void start(StateEnum state)
Activate the initial scene without recording a history entry.
StateEnum current() const
Return the currently active state.
SceneManager & operator=(const SceneManager &)=delete
void clear()
Clear all bindings and history.