⌨️Handling User Interaction
A UI is more than just a static display; it's a conversation with the user. Paper provides a comprehensive event system to handle mouse and keyboard input, allowing you to respond with ease.
1. Integrating Your Input System
Paper is engine-agnostic, which means it doesn't know how to get input from your specific application window (be it Raylib, OpenTK, or something else). Your first step is to forward your application's raw input events to Paper's input system.
This should be done every frame before you begin defining your UI (i.e., before Paper.BeginFrame()
).
Here is a simplified example of the necessary calls:
// Call this every frame before your UI code
void UpdatePaperInput()
{
// 1. Update mouse/pointer position
paper.SetPointerPosition(yourMousePositionVector);
// 2. Forward mouse button states (true for down, false for up)
if (IsMouseButtonPressed(MouseButton.Left))
paper.SetPointerState(PaperMouseBtn.Left, yourMousePositionVector, true);
if (IsMouseButtonReleased(MouseButton.Left))
paper.SetPointerState(PaperMouseBtn.Left, yourMousePositionVector, false);
// Repeat for Right & Middle buttons...
// 3. Forward mouse wheel scroll changes
float wheelDelta = GetMouseWheelMove();
if (wheelDelta != 0)
paper.SetPointerWheel(wheelDelta);
// 4. Forward keyboard character input for text fields
int charCode = GetCharPressed();
while (charCode > 0)
{
paper.AddInputCharacter(((char)charCode).ToString());
charCode = GetCharPressed();
}
// 5. Forward key states for shortcuts, etc.
if (IsKeyPressed(YourKeys.Enter))
paper.SetKeyState(PaperKey.Enter, true);
if (IsKeyReleased(YourKeys.Enter))
paper.SetKeyState(PaperKey.Enter, false);
// Repeat for other keys like Ctrl, Shift, A, B, C, etc.
}
Once you have this bridge in place, Paper can process the raw input and dispatch events to your UI elements.
2. The Event Handling API
You can attach event handlers to any element using a fluent, lambda-based API. This makes your interaction logic clean and co-located with the element's definition.
Click and Hover Events
These are the most common events you'll use.
OnClick((rect) => { ... })
: Fires when the left mouse button is pressed and released on the element.OnRightClick((rect) => { ... })
: Fires for the right mouse button.OnDoubleClick((rect) => { ... })
: Fires on a quick double-click.OnHover((rect) => { ... })
: Fires every frame the mouse is over the element.OnEnter((rect) => { ... })
: Fires on the single frame the mouse first enters the element's bounds.OnLeave((rect) => { ... })
: Fires on the single frame the mouse first leaves the element's bounds.
paper.Box("MyButton")
.Text(Text.Center("Click Me!", myFont, Color.White))
.OnClick((rect) => Console.WriteLine("Button was clicked!"))
.OnEnter((rect) => Console.WriteLine("Mouse entered the button area."))
.OnLeave((rect) => Console.WriteLine("Mouse left the button area."));
Drag Events
Paper has built-in support for detecting drag-and-drop gestures.
OnDragStart((rect) => { ... })
: Fires on the frame a drag begins (mouse is pressed and moves beyond a small threshold).OnDragging((start, rect) => { ... })
: Fires every frame the mouse is moving while dragging. Thestart
parameter is the initial drag position.OnDragEnd((start, total, rect) => { ... })
: Fires when the mouse button is released, ending the drag.total
is the total vector of the drag.
// A simple draggable element
paper.Box("Draggable")
.OnDragging((start, rect) => {
// 'rect' contains the delta of the mouse movement
myElementPosition += rect.Delta;
});
Scroll and Keyboard Events
OnScroll((delta, rect) => { ... })
: Fires when the mouse wheel is scrolled while the cursor is over the element.delta
is the amount scrolled.OnKeyPressed((keyEvent) => { ... })
: Fires when a key is pressed while the element is focused.OnTextInput((textEvent) => { ... })
: Fires when character input is received while the element is focused, useful for text fields.
3. Event Bubbling
Events in Paper bubble up the hierarchy. This means that if you click on a child element, the OnClick
event for its parent (and grandparent, and so on) will also be called.
This is incredibly useful. For example, you can have a single OnClick
handler on a list container to react to a click on any of its items, rather than adding a handler to every single item.
// One handler on the parent
using (paper.Column("MyList").OnClick((r) => Console.WriteLine("List was clicked!")).Enter())
{
// Clicking this will trigger the parent's OnClick
paper.Box("Item1").Text(Text.Left("First Item", myFont, Color.Black));
// Clicking this will ALSO trigger the parent's OnClick
paper.Box("Item2").Text(Text.Left("Second Item", myFont, Color.Black));
}
If you need to stop an event from traveling further up the hierarchy, you can set StopPropagation
to true
on the element.
Paper.Box("ChildThatStopsEvents")
.StopPropagation(true)
.OnClick((r) => { /* This event will not bubble to the parent */ });
Last updated