140 lines
4.6 KiB
C++
140 lines
4.6 KiB
C++
// Copyright (c) 2023 Dominic Masters
|
|
//
|
|
// This software is released under the MIT License.
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
#pragma once
|
|
#include "StateEvent.hpp"
|
|
#include "StateProperty.hpp"
|
|
|
|
namespace Dawn {
|
|
class StateOwner : public IStateOwner {
|
|
private:
|
|
std::vector<IStateEvent*> eventsSubscribed;
|
|
|
|
/**
|
|
* Called by the state event when it is disposing (before the StateOwner
|
|
* itself is).
|
|
*
|
|
* @param evt Event that is being disposed.
|
|
*/
|
|
void _stateEventDisposed(IStateEvent *evt) override {
|
|
auto it = eventsSubscribed.begin();
|
|
while(it != eventsSubscribed.end()) {
|
|
if(*it == evt) {
|
|
it = eventsSubscribed.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Listen for changes to a state property and invoke the provided func
|
|
* when the value is changed.
|
|
*
|
|
* @param fn The callback to be invoked when the state value changes.
|
|
* @param property Property to listen for affect changees to.
|
|
* @return Returns callback that invokes the provided FN immediately.
|
|
*/
|
|
std::function<void()> useEffect(
|
|
const std::function<void()> &fn,
|
|
IStateProperty &property
|
|
) {
|
|
property._effectListners.push_back(fn);
|
|
return fn;
|
|
}
|
|
|
|
/**
|
|
* Listen for changes to a set of state properties and invoke the provided
|
|
* func when any of their values are changed.
|
|
*
|
|
* @param fn The callback to be invoked when the state value changes.
|
|
* @param property Vector list of properties to listen for changes to.
|
|
* @return Returns callback that invokes the provided FN immediately.
|
|
*/
|
|
std::function<void()> useEffect(
|
|
const std::function<void()> &fn,
|
|
std::vector<IStateProperty*> props
|
|
) {
|
|
auto itProp = props.begin();
|
|
while(itProp != props.end()) {
|
|
(*itProp)->_effectListners.push_back(fn);
|
|
++itProp;
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
/**
|
|
* Listen for changes to a state property and invoke the provided callback
|
|
* also, when state is changed this will run the returned teardown
|
|
* callback.
|
|
*
|
|
* @param fn The callback to be invoked when the state value changes.
|
|
* @param property Vector list of properties to listen for changes to.
|
|
* @return Returns callback that invokes the provided FN immediately.
|
|
*/
|
|
std::function<void()> useEffectWithTeardown(
|
|
const std::function<std::function<void()>()> &fn,
|
|
IStateProperty &property
|
|
) {
|
|
property._effectListnersWithTeardown.push_back(fn);
|
|
|
|
return std::bind([&](
|
|
std::function<std::function<void()>()> &callback,
|
|
IStateProperty *prop
|
|
) {
|
|
auto teardown = callback();
|
|
prop->_effectTeardowns.push_back(teardown);
|
|
}, fn, &property);
|
|
}
|
|
|
|
/**
|
|
* Listen for when an event is invoked by a state event. This is intended
|
|
* to allow for cross-state-owner communication in a simple and effective
|
|
* way.
|
|
*
|
|
* @tparam F The type of the callback function.
|
|
* @tparam A The arguments from the state event that are calledback.
|
|
* @param fn The function to be inokved on event trigger.
|
|
* @param event The event that is being subscribed to.
|
|
*/
|
|
template<typename F, typename... A>
|
|
std::function<void()> useEvent(F fn, StateEvent<A...> &event) {
|
|
// Create a listener structure
|
|
struct StateEventListener<A...> listener;
|
|
listener.listener = fn;
|
|
listener.owner = this;
|
|
listener.event = &event;
|
|
listener.unsubWithParams = [&](struct StateEventListener<A...> listener) {
|
|
auto itFound = listener.event->_eventListeners.begin();
|
|
while(itFound != listener.event->_eventListeners.end()) {
|
|
if(itFound->id == listener.id) {
|
|
listener.event->_eventListeners.erase(itFound);
|
|
break;
|
|
}
|
|
++itFound++;
|
|
}
|
|
};
|
|
listener.id = event.stateEventId++;
|
|
listener.unsub = std::bind(listener.unsubWithParams, listener);
|
|
|
|
// Put that listener structure on to the event stack
|
|
event._eventListeners.push_back(listener);
|
|
this->eventsSubscribed.push_back(&event);
|
|
|
|
return listener.unsub;
|
|
}
|
|
|
|
|
|
|
|
virtual ~StateOwner() {
|
|
auto it = this->eventsSubscribed.begin();
|
|
while(it != this->eventsSubscribed.end()) {
|
|
(*it)->_stateOwnerDestroyed(this);
|
|
++it;
|
|
}
|
|
}
|
|
};
|
|
} |