MingaEditor.State.Mouse (Minga v0.1.0)

Copy Markdown View Source

Mouse interaction state: drag tracking, anchor position, separator resize, multi-click detection, and hover tracking.

Multi-click detection

The TUI always sends click_count: 1 because libvaxis doesn't track multi-clicks. The BEAM detects double/triple-clicks by comparing press timestamps and positions. GUI frontends send the native click count directly, so BEAM detection is skipped when click_count > 1.

Two presses within @double_click_ms milliseconds at the same position (within @click_distance cells) increment the click count. The count resets on motion, timeout, or a click at a different position.

Summary

Functions

Records a timer reference created by the mouse workflow.

Clears hover state and returns any timer for the owning workflow to cancel.

Returns the double-click timing window in milliseconds (for testing).

Returns the hover debounce delay in milliseconds (for testing).

Prepares hover clearing without touching the process timer API.

Prepares hover state without touching the process timer API.

Records a mouse press and computes the effective click count.

Records a mouse press using a timestamp supplied by the input workflow.

Returns true if a separator resize drag is active.

Records hover position and returns timer work for the owning workflow.

Begins a content drag from the given buffer position.

Begins a content drag from the given buffer position and originating window.

Begins a separator resize drag in the given direction at the given position.

Ends an active drag, clearing the anchor.

Ends a separator resize drag.

Updates the separator position during an active resize drag.

Types

t()

@type t() :: %MingaEditor.State.Mouse{
  anchor: {non_neg_integer(), non_neg_integer()} | nil,
  click_count: non_neg_integer(),
  drag_click_count: pos_integer(),
  drag_origin_window: MingaEditor.Window.id() | nil,
  dragging: boolean(),
  hover_pos: {integer(), integer()} | nil,
  hover_timer: reference() | nil,
  last_press_pos: {integer(), integer()} | nil,
  last_press_time: integer() | nil,
  resize_dragging:
    {MingaEditor.WindowTree.direction() | :agent_separator, non_neg_integer()}
    | nil
}

Functions

accept_hover_timer(mouse, timer)

@spec accept_hover_timer(t(), reference()) :: t()

Records a timer reference created by the mouse workflow.

clear_hover(mouse)

@spec clear_hover(t()) :: t()

Clears hover state and returns any timer for the owning workflow to cancel.

double_click_ms()

@spec double_click_ms() :: pos_integer()

Returns the double-click timing window in milliseconds (for testing).

hover_delay_ms()

@spec hover_delay_ms() :: pos_integer()

Returns the hover debounce delay in milliseconds (for testing).

prepare_clear_hover(mouse)

@spec prepare_clear_hover(t()) :: {t(), reference() | nil}

Prepares hover clearing without touching the process timer API.

prepare_hover(mouse, row, col, opts \\ [])

@spec prepare_hover(t(), integer(), integer(), keyword()) ::
  {t(), reference() | nil, boolean()}

Prepares hover state without touching the process timer API.

record_press(mouse, row, col, native_click_count)

@spec record_press(t(), integer(), integer(), pos_integer()) :: t()

Records a mouse press and computes the effective click count.

If native_click_count > 1, uses that directly (GUI frontend). Otherwise, detects multi-clicks by timing and position (TUI fallback).

Returns the updated mouse state with click_count set.

record_press_at(mouse, row, col, native_click_count, now)

@spec record_press_at(t(), integer(), integer(), pos_integer(), integer()) :: t()

Records a mouse press using a timestamp supplied by the input workflow.

resizing?(mouse)

@spec resizing?(t()) :: boolean()

Returns true if a separator resize drag is active.

set_hover(mouse, row, col, opts \\ [])

@spec set_hover(t(), integer(), integer(), keyword()) :: t()

Records hover position and returns timer work for the owning workflow.

start_drag(mouse, anchor)

@spec start_drag(
  t(),
  {non_neg_integer(), non_neg_integer()}
) :: t()

Begins a content drag from the given buffer position.

start_drag(mouse, anchor, origin_window)

@spec start_drag(
  t(),
  {non_neg_integer(), non_neg_integer()},
  MingaEditor.Window.id() | nil
) :: t()

Begins a content drag from the given buffer position and originating window.

start_resize(mouse, direction, position)

@spec start_resize(
  t(),
  MingaEditor.WindowTree.direction() | :agent_separator,
  non_neg_integer()
) :: t()

Begins a separator resize drag in the given direction at the given position.

stop_drag(mouse)

@spec stop_drag(t()) :: t()

Ends an active drag, clearing the anchor.

stop_resize(mouse)

@spec stop_resize(t()) :: t()

Ends a separator resize drag.

update_resize(mouse, direction, new_position)

@spec update_resize(
  t(),
  MingaEditor.WindowTree.direction() | :agent_separator,
  non_neg_integer()
) ::
  t()

Updates the separator position during an active resize drag.