Fleury routes pointer input through widget bounds and keyboard input through
focus. Built-in controls combine both; gesture detectors and mouse regions add
pointer behavior to custom widgets. This guide covers press feedback, drag
capture, and nested targets, including the keyboard and semantic support custom
controls need.
Use CellStyle.interactive to style a button while it is held. The pressed
entry applies only while a primary pointer press is held, and Fleury clears it
on release or cancellation. Keyboard and semantic activation still work; they
run the action at once, without a pressed state.
For a custom tile, pass your own content with Button(child: …) and remove
the brackets with appearance: ButtonAppearance.plain; the pressed style and
actions work the same. The button reference also
covers onSecondaryPressed for secondary-click actions.
GestureDetector captures a drag until release or cancellation, including
movement outside the handle. Apply the reported horizontal delta to the pane’s
width.
Use the reported delta, in terminal cells, rather than comparing local
positions: resizing moves the handle’s origin. Apply it only in the update
callback; the first movement also fires drag start with the same delta.
Gesture detection doesn’t add keyboard or semantic actions. Put the arrow
bindings around a focusable handle and call the same resize function to share
its width limits. The full source also exposes the width and increment/decrement
actions through semantics. See focus management for
wiring custom controls into traversal.
Keep press feedback separate from app state
Use the press lifecycle when cancellation needs custom feedback. In Fleury,
moving to another terminal cell cancels a tap, even while the pointer remains
inside the target.
Keep press feedback separate from the preview state. The cancellation handler
clears the held appearance and reports cancellation without closing an already
open note.
Hit areas and clipping
A detector’s target is the area laid out for its child. Put padding inside the
detector to give a small handle a larger hit area. Clipping limits that area;
if the target disappears, the gesture is cancelled.
Wrap a row in MouseRegion when its hover state should include child controls.
This adds enter/exit callbacks without intercepting the children’s presses.
In a native terminal, hover needs TerminalMode(mouseMotion: true); the
bin/run_app.dart that fleury create generates sets only mouse: true, which
reports presses, drags, and the wheel but not plain motion. See
Enable mouse input in a terminal. Browser
demos receive pointer motion automatically.
A press goes to the innermost target that handles taps or drags, and only that
target’s onTap or onSecondaryTap fires on release. Wrapping a button in a
gesture detector therefore won’t observe its taps or add secondary-click
handling; use the button’s own callbacks. A drag that starts on the button goes
to the nearest ancestor that handles drags, which also receives onTapDown.
Hover remains active on containing mouse regions.
Wheel input can pass to an ancestor at a scroll edge; see
nested scrolling for containment.
Keep copied text separate from controls
In a terminal app, runApp makes ordinary text selectable. Use a
SelectionArea for a region with its own selection callback or options. Set
allowSelect: false on decorative text inside a control, such as a resize
handle’s │, so a selection dragged across it doesn’t copy the glyph. Dragging
the handle itself resizes: its detector is the nearest target that handles
drags, so the selection never sees that drag.
This enables clicks, drags, scrolling, and hover; mouse: true omits hover.
Reporting is opt-in because it takes over the terminal’s native text selection.