Guides
Mouse Support
Rezi enables mouse routing when terminal capabilities report mouse support.
Rezi enables mouse routing when terminal capabilities report mouse support.
Mouse Input
Mouse kind values (ABI)
Mouse events use these fixed kind values:
move = 1drag = 2down = 3up = 4wheel = 5
Click model
- On mouse down, Rezi hit-tests and immediately moves focus to the hit widget if it is focusable and enabled.
- Activation uses a press/release model:
- Mouse down captures
pressedIdonly for pressable targets (currently button IDs). - Mouse up emits
action: "press"only if release lands on the same enabled pressable ID. - Releasing elsewhere (or disabling/removing the target) cancels the press.
- Mouse down captures
- Non-pressable focusable widgets still take focus on mouse down but do not emit the generic
"press"action. SplitPaneis intentionally not focusable; divider drag is handled by dedicated mouse logic.
Scroll routing and boundaries
Wheel routing order:
VirtualListunder cursor (hitTestTargetId), else focusedVirtualList.CodeEditorunder cursor, else focusedCodeEditor.LogsConsoleunder cursor, else focusedLogsConsole.DiffViewerunder cursor, else focusedDiffViewer.- Nearest generic
overflow: "scroll"container under cursor. - If none match, the wheel event is ignored.
Wheel step size (where implemented):
VirtualList:wheelY * 3lines- Default is
scrollDirection: "traditional"(wheel down moves viewport down). - With
scrollDirection: "natural", Rezi flipswheelYfor that virtual list.
- Default is
CodeEditor:wheelY * 3vertical lines,wheelX * 3horizontal columnsLogsConsole:wheelY * 3linesDiffViewer:wheelY * 3lines
Clamping:
VirtualList.scrollTop:[0, max(0, totalHeight - viewportHeight)]CodeEditor.scrollTop:[0, max(0, lineCount - viewportHeight)]CodeEditor.scrollLeft:>= 0LogsConsole.scrollTop/DiffViewer.scrollTop:[0, max(0, contentLines - viewportHeight)]- Generic
overflow: "scroll"containers clampscrollX/scrollYto content bounds.
Generic scroll containers
Boxes and other widgets configured with overflow: "scroll" are wheel-interactive.
Wheel deltas route to the nearest scrollable ancestor under the cursor.
SplitPane drag lifecycle
- Drag starts on primary-button mouse down in divider hit area (
dividerSizeplus 1-cell expansion on each side). - Runtime captures pointer start position and panel start sizes.
- On move/drag, delta is applied via
handleDividerDrag(...):- Only the two panels adjacent to the dragged divider resize.
- Delta is clamped against both panels'
minSizesandmaxSizes. - The panel-pair total size is preserved.
onChangefires on each drag update (absolute cells or percentages, based onsizeMode).- Mouse up ends drag and clears drag state. If pane metadata disappears mid-drag, drag state is canceled.
- When
collapsibleandonCollapseare set, divider double-click (\<= 500ms) toggles collapse for the side clicked.
FileTreeExplorer click routing
FileTreeExplorer supports full mouse-to-node click routing, following the same press/release pattern as Table:
- Mouse down (left button): Hit-tests the click position against the visible node rows. Computes the target node index from
scrollTop + localY. CallsonSelect(node)immediately to select the clicked node. Stores the pressed node index. - Mouse up: If the release lands on the same widget and same node index as the press:
- Checks for double-click (two clicks on the same node within 500ms)
- On double-click: calls
onPress(node)(open file, toggle directory, etc.) - On single click: selection already fired on mouse down, no additional action
- Right button: Skipped by the left-click handler; right-click context menu routing handles it separately.
- Drag/release elsewhere: Pressing state is cleared, no activation fires.
This enables natural mouse-driven file browsing: click to select, double-click to open.
Mouse + keyboard interaction
- Clicking transfers focus through the same focus state used by Tab/Shift+Tab.
- Focus transfer triggers normal blur behavior for the previously focused input (
onBlur). - Keybinding chord state is managed by key routing rules (key events, timeout, mode switch). Mouse events do not run the chord matcher directly.
Hit-testing priority
Mouse routing priority:
- Top open dropdown (consumes mouse input and blocks lower layers while open).
- Layer hit-test using resolved layer order (higher
zIndexfirst; ties resolved by later registration/order). - Base widget hit-test (
hitTestFocusable) with ancestor clip intersection and deterministic overlap tie-break:- depth-first preorder traversal (children left-to-right)
- later tree-order nodes win overlap ties
Modal/layer blocking invariants:
- The topmost modal blocks input to all lower layers and base widgets, including points outside modal bounds.
- Backdrop visual style (
none/dim/opaque) does not change blocking semantics. - If
closeOnBackdropis enabled andonCloseexists, backdrop mouse down closes the blocking layer.
Related
- Input & Focus
- Layers
- SplitPane
- FileTreeExplorer - File tree widget with mouse click support
- Table - Table widget (original click routing pattern)