Repository navigation
Events
Each Component has an EventListener, which manages incoming Events and forwarding of those events to sub-components. An event listener also contains a StateHandler, which manages the state of the component using the incoming events. Event callbacks can be added to the event listener by using the operator+=(). And state callbacks can be added to the state handler by calling the StateHandler& State(const StateSettings&) method, which also comes with some StateSettings.
struct StateSettings
{
State state; // State to link.
int limit = -1; // Limit on amount of sub-components with this state.
bool visible = true; // Must the sub-component be visible?
}An event listener manages incoming events, by calling the registered event callbacks, and by forwarding it to sub-components.
EventListener::operator+=(auto lambda)An event callback can be registered using the += operator, a callback must be a lambda with no return and a single argument, which should be a const reference to a derived class from Event.
An example on how to register a callback for a MousePress event.
listener += [](const MousePress& e) {
// handle event here
};NOTE: An event listener does not copy the callbacks when it is copy constructed or copy assigned! This is because the callbacks might capture references or this-pointers, which may become invalid. This means it is important to register event callbacks inside of the (copy/move) constructor of a component.
StateHandler& State(const StateSettings&);Registering state handlers is a bit more involved, since there are a bit more settings involved. When calling the State() function it will return a reference to a StateHandler that will be linked to the state given in the StateSettings. You can then call the operator+=() on that StateHandler to register callbacks. Those callbacks must return an integer and take in a const reference to a class derived from Event, a reference to a class derived from or equal to Component, and an int.
The final int parameter will be set to the available amount of slots for this state, which is linked to the given limit in the StateSettings. So for example, if a single component has returned 1 for the state Pressed, all subsequent calls to the callback will have that int parameter set to 0, because the limit has been reached. You can still choose to return any number to set the state, the limit is only used as an indication that can be used inside these callbacks.
An example of how to register a state handler for pressed:
auto& _stateHandler = listener.State({.state = Pressed, .limit = 1 });
_stateHandler += [](const MousePress& e, Component& c, int l) -> int { if (l && c.Hitbox(e.pos)) return 1; };
_stateHandler += [](const MouseRelease& e, Component& c, int) -> int { return 0; };The event base class can be extended to make custom events. The constructor expects a bool, which determines whether the event will be forwarded to the sub-components before or after the state handler. It also contains a pure virtual Forward method that must be overriden, which determines whether this event should be forwarded to the given component.
Event(bool beforeStateHandler);
virtual bool Forward(const Component&) const;Because of the way the event listener works, it means it is very easy to create custom events. But some standard events are given:
struct MouseMove
{
Vec2<float> pos; // Position of the cursor
};
struct MouseDrag
{
Vec2<float> source; // Press position of the cursor
Vec2<float> pos; // Position of the cursor
int buttons; // All buttons that are held down (bits)
int mod; // Mods (shift/ctrl etc.)
};
struct MousePress
{
Vec2<float> pos; // Position of the cursor
int button; // Button that was clicked
int mod; // Mods (shift/ctrl etc.)
};
struct MouseClick
{
Vec2<float> pos; // Position of the cursor
int button; // Button that was clicked
int mod; // Mods (shift/ctrl etc.)
};
struct MouseWheel
{
Vec2<float> pos; // Position of the cursor
int amount; // Scrolled amount
int mod; // Mods (shift/ctrl etc.)
};
struct MouseRelease
{
Vec2<float> pos; // Position of the cursor
int button; // Button that was released
int mod; // Mods (shift/ctrl etc.)
};
struct KeyPress
{
int keycode; // Key code
int mod; // Mods (shift/ctrl etc.)
bool repeat; // true when event was fired because key was held down.
};
struct KeyType
{
char key; // Character typed
int mod; // Mods (shift/ctrl etc.)
bool coded; // Is it a coded character?
};
struct MouseExit {};
struct MouseEnter {};
struct Focus {};
struct Unfocus {};