Open richardeakin opened 6 years ago
I'm not familiar with touch phases. Could you give an example?
The common phases are 'began', 'moved', and 'ended'. UIkit / Appkit also define 'stationary' and 'cancelled' (which you can see descriptions of here.
I think the three common ones would also map to MouseEvent
phases if needed, being 'down', 'drag', and 'up'.
Ah, OK, I get it.
Would you consider doing the following?
// Current definition of MouseEvent in Cinder. Will serve as a base class.
class ci::app::MouseEvent : public ci::app::Event { ... };
// Derived class will designate phase:
class ci::app::MouseMoveEvent : public ci::app::MouseEvent { ... };
class ci::app::MouseDownEvent : public ci::app::MouseEvent { ... };
class ci::app::MouseDragEvent : public ci::app::MouseEvent { ... };
class ci::app::MouseUpEvent : public ci::app::MouseEvent { ... };
class ci::app::MouseWheelEvent : public ci::app::MouseEvent { ... };
This is how I have done it in my toolkit, making it possible to handle events based on their type using templates (at compile time, as long as the class and its derived class have no virtual functions).
template <typename T>
bool Node::sendEvent( const T &event ) const
{
const auto &eventId = typeid( T ).hash_code();
if( mEvents.count( eventId ) == 0 )
return false;
auto &listeners = mEvents.at( eventId );
if( listeners && !listeners->empty() )
return listeners->call<T>( event );
}
// Example of adding listeners:
connectEvent<MouseDownEvent>( &MyClass::onMouseDown, this );
You can still use void mouseDown( MouseEvent event );
(unless I am too tired to remember that polymorphism only works with pointers and references), but you can also use void mouseDown( MouseDownEvent event );
.
If an event needs more data to describe something, it can do so in its own private member variables. The generic stuff goes into the base class. We'd do something similar for touch events, key events, filedrop events, etc.
I think this is a bit of a different design than what cinder currently uses, whichs maps pretty close to UIKit / App Kit already. It'd also require storing active touches in separate containers (one for each type) or as shared pointers, and we'd have to change public API like Window::getActiveTouches()
.
I feel like the data in the mouse or touch events are all consistent across the different phases, so I do feel like apple has a nice design on this one where they use a single mouse or touch event type that contains a phase property. Also, phase would give us extra room for cancelled and possible stationary, which I'm finding more and more useful when building out UI controls.
I see. Yeah, a phase property would be a solution. Are you thinking of something like:
class MouseEvent : public Event {
public:
enum class Phase { Move, Down, Drag, Up, Wheel };
...
Phase getPhase() const { return mPhase; }
private:
Phase mPhase;
}
This would work in my scenario as well. I'd do a connectEvent<MouseEvent>( &MyClass::onMouse, this );
and the function would look like:
bool onMouse( const MouseEvent &event )
{
switch( event.getPhase() )
{
case MouseEvent::Move: ... break;
}
return false; // Specific to my code: return true to capture event, false to continue propagating it.
}
I'm in a situation where I'm doing some more involved touch event processing, where I'm storing the Event to handle it within the next update loop. In this case, it would be handy to know what the 'phase' is of the event, similar to iOS's
UITouch.phase
property.I think this information would be fairly easy to set as an additional enum value on the
TouchEvent
itself. Not sure I can see the need to store the phase on theTouch
itself, which is where bothUITouch
andNSTouch
store it (and I believe from reading our MSW impl code that it is per touch too). Do others have an opinion here?One other thing that I think would be nice about knowing the phase, is that is some cases it is nice to convey that a touch has been 'cancelled' rather than just 'ended'. If we were to add a phase enum we could include this information here without needing an additional virtual method + signal.