I got the next hierarchy of structers:
Event -> MouseEvent -> MouseButtonEvent
-> MouseWheelEvent
-> ...
-> KeyboardEvent -> KeyEvent
-> InputEvent
-> ...
-> ...
Potentially there could be a lot of different event types. There is also a components heirarchy. The base class is Component
:
Component.h:
how i want it to be
class Component
{
...
/* These could be overriden in derived to handle this events. */
virtual void handleEvent(const MouseButtonEvent&);
virtual void handleEvent(const MouseWheelEvent&);
virtual void handleEvent(const KeyEvent&);
virtual void handleEvent(const InputEvent&);
...
...
template<typename GMouseEvent>
void handleMouseEvent(const GMouseEvent& e)
{
if (!children.empty())
{
// Pay attention: I need to cast to real Event type to be able to use event properties here.
const auto& eMouse = static_cast<const MouseEvent&>(e);
auto eCopy = eMouse;
for (auto child : children)
{
// point is a property of MouseEvent
eCopy.point = child->transformPointToLocal(eMouse.point);
if (child->predicateOnMouseEventPropery(eMouse.point))
return child->handleEvent(static_cast<GMouseEvent&>(eCopy)); // Need to save GMouseEvent type to call proper virtual handler
}
}
}
template<typename GNonMouseEvent>
void handleNonMouseEvent(const GNonMouseEvent& e)
{
for (auto child : children)
child->handleEvent(e); // Also need to preserve original call type to call virtual method
}
...
std::vector<Component*> children;
}
...
void Component::handleEvent(const MouseButtonEvent& e)
{
handleMouseEvent<MouseButtonEvent>(e);
}
void Component::handleEvent(const MouseWheelEvent& e)
{
handleMouseEvent<MouseWheelEvent>(e);
}
void Component::handleEvent(const KeyEvent& e)
{
handleNonMouseEvent<KeyEvent>(e);
}
void Component::handleEvent(const InputEvent& e)
{
handleNonMouseEvent<InputEvent>(e);
}
Component.h:
how it is actually
class Component
{
...
/* These could be overriden in derived to handle this events. */
virtual void handleEvent(const MouseButtonEvent&);
virtual void handleEvent(const MouseWheelEvent&);
virtual void handleEvent(const KeyEvent&);
virtual void handleEvent(const InputEvent&);
...
std::vector<Component*> children;
}
...
void Component::handleEvent(const MouseButtonEvent& e)
{
if (!children.empty())
{
auto eCopy = e;
for (auto child : children)
{
// point is a property of MouseEvent that is the base of MouseButtonEvent
eCopy.point = child->transformPointToLocal(e.point);
if (child->predicateOnMouseEventPropery(e.point))
return child->handleEvent(eCopy);
}
}
}
void Component::handleEvent(const MouseWheelEvent& e)
{
if (!children.empty())
{
auto eCopy = e;
for (auto child : children)
{
// point is a property of MouseEvent that is the base of MouseWheelEvent
eCopy.point = child->transformPointToLocal(e.point);
if (child->predicateOnMouseEventPropery(e.point))
return child->handleEvent(eCopy);
}
}
}
void Component::handleEvent(const KeyEvent& e)
{
for (auto child : children)
child->handleEvent(e);
}
void Component::handleEvent(const InputEvent& e)
{
for (auto child : children)
child->handleEvent(e);
}
MyComponent.h:
class MyComponent : public Component
{
virtual void handleEvent(const MouseButtonEvent& e);
virtual void handleEvent(const KeyEvent& e);
...
}
void MyComponent::handleEvent(const MouseButtonEvent& e)
{
// Calling for virtual void Component::handleEvent(const MouseButtonEvent&)
Component::handleEvent(e);
... // doing other stuff
}
void MyComponent::handleEvent(const KeyEvent& e)
{
// Calling for virtual void Component::handleEvent(const KeyEvent&)
Component::handleEvent(e);
... // doing stuff
}
Somewhere else:
...
Component* c = myComponentPointer;
MouseButtonEvent e = {};
e.point = {10, 20};
e.foo = "bar";
// Just call virtual overloaded function here to be as simple from the side as possible
// Calling here virtual void MyComponent::handleEvent(const MouseButtonEvent&);
c->handleEvent(e);
...
I want to save this calling pattern when I nicely just call virtual functions that are implemented for end nodes of event heirarchy. But I want to put some code inside Component::handleEvent
for each of this virtual functions that just needs neither end nodes nor root node event. How can I rewrite template<typename GMouseEvent> void handleMouseEvent(const GMouseEvent& e)
and template<typename GNonMouseEvent> void handleNonMouseEvent(const GMouseNonEvent& e)
?
I found a way to do what I want.
Component.h
:
class Component
{
...
template<typename GMouseEvent>
ShouldParentHandleEvent handleMouseEvent(const GMouseEvent& e)
{
if (!children.empty())
{
/*
There is a trick: I cast unknown const reference to const MouseEvent&
to be able then read it as MouseEvent. I also need a copy of the original
event. So I copy it and cast it to a reference of MouseEvent&.
*/
const auto& eMouseEvent = static_cast<const MouseEvent&>(e);
auto eCopy = e;
auto& eMouse = static_cast<MouseEvent&>(eCopy);
for (const auto& child : children)
{
/*
There magic happens: eMouse is a reference to eCopy (original event).
We need it just only to write. Then we need to preserve event type
when we will call child->handleEvent(eCopy) with modified event of the
original type. So the right overloaded virtual function is called.
*/
eMouse.point = child->transformToLocalPoint(eMouseEvent.point);
if (child->predicateOnMouseEventProperty(eMouseEvent.point))
{
return child->handleEvent(eCopy);
}
}
}
return true;
}
template<typename GNonMouseEvent>
ShouldParentHandleEvent handleNonMouseEvent(const GNonMouseEvent& e)
{
bool shouldComponentHandleEvent = true;
for (const auto& child : children)
shouldComponentHandleEvent = child->handleEvent(e) && shouldComponentHandleEvent;
return shouldComponentHandleEvent;
}
...
}