Magnum::Ui::EventLayer class new in Git master

Event handling layer.

Provides signal/slot-like functionality, connecting events happening on nodes with arbitrary functions handling them.

Setting up an event layer instance

If you create a UserInterfaceGL instance with a style and don't exclude StyleFeature::EventLayer, an implicit instance is already provided and available through UserInterface::eventLayer(). If you don't, or if you want to set up a custom event layer, pass its instance to AbstractUserInterface::setLayerInstance():

Ui::EventLayer& layer = ui.setLayerInstance(
    Containers::pointer<Ui::EventLayer>(ui.createLayer()));

Creating event handlers

An event handler is created by calling one of the on*() APIs with a NodeHandle to react on (or any Widget instance, since it's implicitly convertible to a NodeHandle as well) and a desired function. For example, using onTapOrClick() to print a message to standard output when a button is tapped or clicked:

Ui::NodeHandle button = ;

layer.onTapOrClick(button, []{
    Debug{} << "Click!";
});

By default the event handler is tied to lifetime of the node it's added to. You can use the returned DataHandle to remove() it earlier, if needed. As an alternative, all APIs have on*Scoped() variants that return a RAII EventConnection instance that removes the handler when destructed, which is useful for example when the lifetime is tied to a concrete class instance. In the following snippet, the onTapOrClickScoped() in addition uses a Containers::Function created from a member function instead of a lambda:

class Observer {
    public:
        explicit Observer(Ui::EventLayer& layer, Ui::NodeHandle button):
            _c{layer.onTapOrClickScoped(button, {*this, &Observer::call})} {}

        void call() {
            
        }

    private:
        Ui::EventConnection _c;
};

Tap or click, press & release

A function passed to onTapOrClick() gets called when a Pointer::MouseLeft, primary Pointer::Finger or Pointer::Pen (i.e., a pointer type that's understood as performing the primary action) is pressed and subsequently released on the same node. Relying on pointer capture being implicitly enabled on a press, the pointer is allowed to leave the area when being pressed. If a release then happens with the pointer back over the node, it's still recognized as a tap or click, which improves reliability especially with imprecise touch input. On the other hand, releasing with a pointer outside of the node will not be recognized as a tap or click, which is a common usage pattern for canceling accidental UI actions.

Accepted Accepted Rejected

The onMiddleClick() and onRightClick() APIs then expose the same functionality for Pointer::MouseMiddle or Pointer::MouseRight. Right now, Pointer::Eraser doesn't have any matching event handler. Finally, the onPress() and onRelease() counterparts get called when Pointer::MouseLeft, primary Pointer::Finger or Pointer::Pen gets pressed or released.

All these functions have additional overloads that pass a node-relative position to the handler, useful in case the position matters. For example to calculate a concrete color when pressing on a color picker:

Ui::NodeHandle picker = ;

layer.onPress(picker, [&ui, picker, ](const Vector2& position) {
    Vector2 normalized = position/ui.nodeSize(picker);
    Color3 color = Color3::fromHsv({, normalized.x(), 1.0f - normalized.y()});
    
});

Pointer drag

The onDrag() API calls a function when Pointer::MouseLeft, primary Pointer::Finger or Pointer::Pen is dragged over a node, passing a relative movement position to it. The handler is called only if the event is captured on the node, i.e. when the drag started on it in the first place. Which prevents accidental action, such as when dragging from outside of the active UI area, however at the same time it also allows the pointer to leave the node when dragging without the action being aborted. Such behavior is useful especially when interacting with narrow UI elements such as scrollbars or sliders.

Accepted Accepted Rejected

Below is an example of a (vertical) scrollbar implementation affecting a scrollable view. At its core, a scroll area is a node with NodeFlag::Clip enabled, containing another larger node within, and the scrolling is performed by adjusting offset of the inner node with AbstractUserInterface::setNodeOffset(). Additionally the code makes sure it doesn't scroll beyond either of the edges.

Ui::NodeHandle scrollbar = ;
Ui::NodeHandle scrollarea = ui.createNode(, Ui::NodeFlag::Clip);
Ui::NodeHandle contents = ui.createNode(scrollarea, );

layer.onDrag(scrollbar, [&ui, scrollarea, contents](const Vector2& relativePosition) {
    Vector2 offset = ui.nodeOffset(contents);
    offset.y() = Math::clamp(offset.y() - relativePosition.y(),
        ui.nodeSize(scrollarea).y() - ui.nodeSize(contents).y(), 0.0f);
    ui.setNodeOffset(contents, offset);
});

As with other pointer event handlers, there's also an overload taking both a movement delta and a position within a node.

Scrolling using pointer drag

A common touch interface pattern for scrollable views is to drag on the view itself, without any scroll bars. Compared to above, the following implements scrolling using drag in both directions, with onDrag() set up on the scrollarea itself:

layer.onDrag(scrollarea, [&ui, scrollarea, contents](const Vector2& relativePosition) {
    ui.setNodeOffset(contents, Math::clamp(
        ui.nodeOffset(contents) + relativePosition,
        ui.nodeSize(scrollarea) - ui.nodeSize(contents), Vector2{0.0f}));
});

This however only works only as long as the drag isn't initiated on an inner node that itself accepts events, even if just for visual feedback. Because as shown for the tap or click above, as soon as a press gets accepted by an inner node, further events get captured on it and don't reach the scroll area. A solution is to enable NodeFlag::FallthroughPointerEvents on the scroll area containing the onDrag() handler. That'll cause it to receive also all events that were accepted on inner nodes.

ui.addNodeFlags(scrollarea, Ui::NodeFlag::FallthroughPointerEvents);

With this option it doesn't take over the drag events unconditionally because even just a tap where the pointer moves slightly between a press and a release would be interpreted as a drag of the whole area, making it almost impossible to interact with the inner contents. Instead, there's a distance threshold, configurable with setDragThreshold(), after which the press, move and release is no longer treated as a tap or click, but gets interpreted as a drag. Thus, after a press, the drag will be initially directed to items underneath, highlighting them for example, and only after reaching the threshold it'll jump and start scrolling instead of affecting the items underneath. See Pointer event fallthrough for a detailed description of this behavior.

Tap on inner node Drag on outer node Distance threshold

If the contents don't need to be interacted with in any way, an alternative is to enable NodeFlag::NoEvents on them. In that case there will be no scroll delay, as the events will always go directly to the scroll area.

Pinch zoom and rotation

On input devices supporting multi-touch, onPinch() calls a function as soon as two fingers are pressed and dragged relatively to each other, passing it a scale, rotation and translation delta. As with onDrag(), the gesture is only recognized when it started on given node but the pointers can leave the area when pressed. As an example, the following snippet implements two-finger panning in a drawing application while the single-pointer onDrag() would be used for drawing:

Ui::NodeHandle canvas = ;

layer.onDrag(canvas, [canvas](const Vector2& position, const Vector2& relativePosition) {
    // Draw ...
});
layer.onPinch(canvas, [&ui, canvas](const Vector2&, const Vector2& relativeTranslation, const Complex&, Float) {
    ui.setNodeOffset(canvas, ui.nodeOffset(canvas) + relativeTranslation);

    // Also discard any in-progress draw from onDrag() that may have been made
    // while just one finger of the two was down ...
});

Pointer enter and leave, focus and blur

With onEnter() and onLeave() you can implement various actions happening when the primary pointer enters or leaves the node area. Usually there's however just visual feedback, which is likely already handled by BaseLayer and TextLayer style transitions.

For nodes that have NodeFlag::Focusable enabled, onFocus() and onBlur() can attach actions to an input being focused and blurred again, for example to open a keypad or an autocompletion popup.

Base classes

class AbstractLayer new in Git master
Base for data layers.

Constructors, destructors, conversion operators

EventLayer(LayerHandle handle) explicit
Constructor.
EventLayer(const EventLayer&) deleted
Copying is not allowed.
EventLayer(EventLayer&&) noexcept
Move constructor.
~EventLayer() override
Destructor.

Public functions

auto operator=(const EventLayer&) -> EventLayer& deleted
Copying is not allowed.
auto operator=(EventLayer&&) -> EventLayer& noexcept
Move assignment.
auto usedScopedConnectionCount() const -> UnsignedInt
Count of currently active EventConnection instances.
auto usedAllocatedConnectionCount() const -> UnsignedInt
Count of allocated connections.
auto dragThreshold() const -> Float
Distance threshold for fallthrough drag.
auto setDragThreshold(Float distance) -> EventLayer&
Set a distance threshold for fallthrough drag.
auto onPress(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a finger / pen tap or left mouse press.
auto onPress(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> DataHandle
auto onPressScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a finger / pen tap or left mouse press.
auto onPressScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> EventConnection
auto onRelease(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a finger / pen tap or left mouse release.
auto onRelease(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> DataHandle
auto onReleaseScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a finger / pen tap or left mouse release.
auto onReleaseScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> EventConnection
auto onTapOrClick(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a finger / pen tap or left mouse click.
auto onTapOrClick(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> DataHandle
auto onTapOrClickScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a finger / pen tap or left mouse click.
auto onTapOrClickScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> EventConnection
auto onMiddleClick(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a middle mouse click.
auto onMiddleClick(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> DataHandle
auto onMiddleClickScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a middle mouse click.
auto onMiddleClickScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> EventConnection
auto onRightClick(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a right mouse click.
auto onRightClick(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> DataHandle
auto onRightClickScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a right mouse click.
auto onRightClickScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot) -> EventConnection
auto onDrag(NodeHandle node, Containers::Function<void(const Vector2&relativePosition)>&& slot) -> DataHandle
Connect to a drag.
auto onDrag(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativePosition)>&& slot) -> DataHandle
auto onDragScoped(NodeHandle node, Containers::Function<void(const Vector2&relativePosition)>&& slot) -> EventConnection
Scoped connection to a drag.
auto onDragScoped(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativePosition)>&& slot) -> EventConnection
auto onPinch(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativeTranslation, const Complex&relativeRotation, Float relativeScaling)>&& slot) -> DataHandle
Connect to a two-finger pinch, zoom or pan gesture.
auto onPinchScoped(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativeTranslation, const Complex&relativeRotation, Float relativeScaling)>&& slot) -> EventConnection
Scoped connection to a two-finger pinch, zoom or pan gesture.
auto onEnter(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a pointer enter.
auto onEnterScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a pointer enter.
auto onLeave(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a pointer leave.
auto onLeaveScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a pointer leave.
auto onFocus(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a focus.
auto onFocusScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a focus.
auto onBlur(NodeHandle node, Containers::Function<void()>&& slot) -> DataHandle
Connect to a blur.
auto onBlurScoped(NodeHandle node, Containers::Function<void()>&& slot) -> EventConnection
Scoped connection to a pointer leave.
void remove(DataHandle handle)
Remove a connection.
void remove(LayerDataHandle handle)
Remove a connection assuming it belongs to this layer.

Function documentation

Magnum::Ui::EventLayer::EventLayer(LayerHandle handle) explicit

Constructor.

Parameters
handle Layer handle returned from AbstractUserInterface::createLayer()

Magnum::Ui::EventLayer::EventLayer(EventLayer&&) noexcept

Move constructor.

Performs a destructive move, i.e. the original object isn't usable afterwards anymore.

Magnum::Ui::EventLayer::~EventLayer() override

Destructor.

Expects that usedScopedConnectionCount() is 0.

UnsignedInt Magnum::Ui::EventLayer::usedScopedConnectionCount() const

Count of currently active EventConnection instances.

Always at most usedCount(). The layer is only allowed to be destroyed after all scoped connections are removed, as the EventConnection destructors would then access a dangling layer pointer.

UnsignedInt Magnum::Ui::EventLayer::usedAllocatedConnectionCount() const

Count of allocated connections.

Always at most usedCount(). Counts all connections that capture non-trivially-destructible state or state that's too large to be stored in-place. The operation is done with a $ \mathcal{O}(n) $ complexity where $ n $ is capacity().

EventLayer& Magnum::Ui::EventLayer::setDragThreshold(Float distance)

Set a distance threshold for fallthrough drag.

When onDrag() is set up on a node with NodeFlag::FallthroughPointerEvents, pointer events that are accepted by child nodes are only interpreted as a drag after the total drag distance exceeds distance. Default is 16.0f.

DataHandle Magnum::Ui::EventLayer::onPress(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a finger / pen tap or left mouse press.

The slot, optionally receiving a node-relative position of the press, is called when a Pointer::MouseLeft, primary Pointer::Finger or Pointer::Pen press happens on the node, and it isn't a fallthrough event from a child node. Expects that the slot is not nullptr.

Use onTapOrClick() for a combined press and release. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onPressScoped() for a scoped alternative.

DataHandle Magnum::Ui::EventLayer::onPress(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

EventConnection Magnum::Ui::EventLayer::onPressScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a finger / pen tap or left mouse press.

Compared to onPress() the connection is removed automatically when the returned EventConnection gets destroyed.

EventConnection Magnum::Ui::EventLayer::onPressScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

DataHandle Magnum::Ui::EventLayer::onRelease(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a finger / pen tap or left mouse release.

The slot, optionally receiving a node-relative position of the release, is called when a Pointer::MouseLeft, primary Pointer::Finger or Pointer::Pen release happens on the node, and it isn't a fallthrough event from a child node. Expects that the slot is not nullptr.

Use onTapOrClick() for a combined press and release. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onReleaseScoped() for a scoped alternative.

DataHandle Magnum::Ui::EventLayer::onRelease(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

EventConnection Magnum::Ui::EventLayer::onReleaseScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a finger / pen tap or left mouse release.

Compared to onRelease() the connection is removed automatically when the returned EventConnection gets destroyed.

EventConnection Magnum::Ui::EventLayer::onReleaseScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

DataHandle Magnum::Ui::EventLayer::onTapOrClick(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a finger / pen tap or left mouse click.

The slot, optionally receiving a node-relative position of the tap or click, is called when a Pointer::MouseLeft, primary Pointer::Finger or Pointer::Pen release happens on the node after a previous primary pointer press, and it isn't a fallthrough event from a child node. If event capture is disabled by any event handler on given node, the slot is called only if the pointer didn't leave the node area between a press and a release. Expects that the slot is not nullptr.

Use onRightClick() and onMiddleClick() to handle Pointer::MouseRight and Pointer::MouseMiddle clicks. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onTapOrClickScoped() for a scoped alternative.

DataHandle Magnum::Ui::EventLayer::onTapOrClick(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

EventConnection Magnum::Ui::EventLayer::onTapOrClickScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a finger / pen tap or left mouse click.

Compared to onTapOrClick() the connection is removed automatically when the returned EventConnection gets destroyed.

EventConnection Magnum::Ui::EventLayer::onTapOrClickScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

DataHandle Magnum::Ui::EventLayer::onMiddleClick(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a middle mouse click.

The slot, optionally receiving a node-relative position of the click, is called when a Pointer::MouseMiddle release happens on the node after a previous pointer press, and it isn't a fallthrough event from a child node. If event capture is disabled by any event handler on given node, the slot is called only if the pointer didn't leave the node area between a press and a release. Expects that the slot is not nullptr.

Use onTapOrClick() and onRightClick() to handle Pointer::MouseLeft / Pointer::Finger / Pointer::Pen and Pointer::MouseRight clicks. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onMiddleClickScoped() for a scoped alternative.

DataHandle Magnum::Ui::EventLayer::onMiddleClick(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

EventConnection Magnum::Ui::EventLayer::onMiddleClickScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a middle mouse click.

Compared to onMiddleClick() the connection is removed automatically when the returned EventConnection gets destroyed.

EventConnection Magnum::Ui::EventLayer::onMiddleClickScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

DataHandle Magnum::Ui::EventLayer::onRightClick(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a right mouse click.

The slot, optionally receiving a node-relative position of the click, is called when a Pointer::MouseRight release happens on the node after a previous pointer press, and it isn't a fallthrough event from a child node. If event capture is disabled by any event handler on given node, the slot is called only if the pointer didn't leave the node area between a press and a release. Expects that the slot is not nullptr.

Use onTapOrClick() and onRightClick() to handle Pointer::MouseLeft / Pointer::Finger / Pointer::Pen and Pointer::MouseRight clicks. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onMiddleClickScoped() for a scoped alternative.

DataHandle Magnum::Ui::EventLayer::onRightClick(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

EventConnection Magnum::Ui::EventLayer::onRightClickScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a right mouse click.

Compared to onRightClick() the connection is removed automatically when the returned EventConnection gets destroyed.

EventConnection Magnum::Ui::EventLayer::onRightClickScoped(NodeHandle node, Containers::Function<void(const Vector2&position)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

DataHandle Magnum::Ui::EventLayer::onDrag(NodeHandle node, Containers::Function<void(const Vector2&relativePosition)>&& slot)

Connect to a drag.

The slot, receiving the movement delta and optionally also a node-relative position at which the move happened, is called when a Pointer::MouseLeft, primary Pointer::Finger or Pointer::Pen move happens on the node. To prevent the slot from being triggered by drags that originated outside of node, it's called only if the move event is captured on given node. Expects that the slot is not nullptr.

See Scrolling using pointer drag for additional considerations when implementing scrollable views. In particular, if the event is originating on given node, the slot gets called immediately. If it's a fallthrough event from a child node, the slot gets called after the distance reaches the threshold configurable with setDragThreshold(), at which point which the event capture is transferred to node.

Use onPinch() to handle two-finger gestures. In particular, if onPinch() is handled by the layer as well, only one of onDrag() and onPinch() is called depending on whether a two-finger gesture is recognized, never both at the same time.

The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onDragScoped() for a scoped alternative.

DataHandle Magnum::Ui::EventLayer::onDrag(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativePosition)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

EventConnection Magnum::Ui::EventLayer::onDragScoped(NodeHandle node, Containers::Function<void(const Vector2&relativePosition)>&& slot)

Scoped connection to a drag.

Compared to onDrag() the connection is removed automatically when the returned EventConnection gets destroyed.

EventConnection Magnum::Ui::EventLayer::onDragScoped(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativePosition)>&& slot)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

DataHandle Magnum::Ui::EventLayer::onPinch(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativeTranslation, const Complex&relativeRotation, Float relativeScaling)>&& slot)

Connect to a two-finger pinch, zoom or pan gesture.

The slot is called when two or more Pointer::Finger are pressed and move over the node area, and it isn't a fallthrough event from a child node. It receives a node-relative centroid position between the two presses, translation of the centroid relative to previous state of the two fingers, their relative rotation and scaling. Platform::TwoFingerGesture is used internally, see its documentation for more information. Expects that the slot is not nullptr.

By default, the gesture is tracked as long as the primary finger is pressed, even if the fingers are outside of the node area. If event capture is disabled by any event handler on given node, the gesture stops being tracked when any of the fingers leave the node area. The gesture also stops being tracked when given node loses visibility to events.

Use onDrag() to handle a regular single-finger, mouse or pen drag. In particular, if onDrag() is handled by the layer as well, only one of onDrag() and onPinch() is called depending on whether a two-finger gesture is recognized, never both at the same time.

The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onPinchScoped() for a scoped alternative.

EventConnection Magnum::Ui::EventLayer::onPinchScoped(NodeHandle node, Containers::Function<void(const Vector2&position, const Vector2&relativeTranslation, const Complex&relativeRotation, Float relativeScaling)>&& slot)

Scoped connection to a two-finger pinch, zoom or pan gesture.

Compared to onPinch() the connection is removed automatically when the returned EventConnection gets destroyed.

DataHandle Magnum::Ui::EventLayer::onEnter(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a pointer enter.

The slot is called when a primary pointer moves over the node area, and it isn't a fallthrough event from a child node. Expects that the slot is not nullptr.

Use onLeave() to hadle the opposite case. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onEnterScoped() for a scoped alternative.

EventConnection Magnum::Ui::EventLayer::onEnterScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a pointer enter.

Compared to onEnter() the connection is removed automatically when the returned EventConnection gets destroyed.

DataHandle Magnum::Ui::EventLayer::onLeave(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a pointer leave.

The slot is called when a primary pointer moves out of the node area, and it isn't a fallthrough event from a child node. Expects that the slot is not nullptr.

Use onEnter() to hadle the opposite case. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onLeaveScoped() for a scoped alternative.

EventConnection Magnum::Ui::EventLayer::onLeaveScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a pointer leave.

Compared to onLeave() the connection is removed automatically when the returned EventConnection gets destroyed.

DataHandle Magnum::Ui::EventLayer::onFocus(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a focus.

The slot is called when a node is focused. Expects that the slot is not nullptr.

Use onBlur() to hadle the opposite case. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onFocusScoped() for a scoped alternative.

EventConnection Magnum::Ui::EventLayer::onFocusScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a focus.

Compared to onFocus() the connection is removed automatically when the returned EventConnection gets destroyed.

DataHandle Magnum::Ui::EventLayer::onBlur(NodeHandle node, Containers::Function<void()>&& slot)

Connect to a blur.

The slot is called when the node is blurred. Expects that the slot is not nullptr.

Use onFocus() to hadle the opposite case. The returned DataHandle is automatically removed once node or any of its parents is removed, it's the caller responsibility to ensure it doesn't outlive the state captured in the slot. See onBlurScoped() for a scoped alternative.

EventConnection Magnum::Ui::EventLayer::onBlurScoped(NodeHandle node, Containers::Function<void()>&& slot)

Scoped connection to a pointer leave.

Compared to onBlur() the connection is removed automatically when the returned EventConnection gets destroyed.

void Magnum::Ui::EventLayer::remove(DataHandle handle)

Remove a connection.

Delegates to AbstractLayer::remove(DataHandle) and additionally calls a destructor on the captured function state, if it's not trivially destructible. The handle becomes invalid, which means that any existing EventConnection instance for it will not attempt to remove it again.

void Magnum::Ui::EventLayer::remove(LayerDataHandle handle)

Remove a connection assuming it belongs to this layer.

Delegates to AbstractLayer::remove(LayerDataHandle) and additionally calls a destructor on the captured function state, if it's not trivially destructible. The handle becomes invalid, which means that any existing EventConnection instance for it will not attempt to remove it again.