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

Types

clicks()

@type clicks() ::
  :idle
  | {:pressed,
     %{time: integer(), pos: {integer(), integer()}, count: pos_integer()}}

drag()

@type drag() ::
  :idle
  | {:active,
     %{
       anchor: {non_neg_integer(), non_neg_integer()},
       origin_window: MingaEditor.Window.id() | nil,
       click_count: pos_integer()
     }}

hover()

@type hover() :: :idle | {:active, {integer(), integer()}, reference() | nil}

resize()

@type resize() ::
  :idle
  | {:active,
     {MingaEditor.WindowTree.direction() | :agent_separator, non_neg_integer()}}

t()

@type t() :: %MingaEditor.State.Mouse{
  clicks: clicks(),
  drag: drag(),
  hover: hover(),
  resize: resize()
}

Functions

accept_hover_timer(mouse, timer)

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

active_drag(mouse)

@spec active_drag(t()) ::
  {:active, {non_neg_integer(), non_neg_integer()},
   MingaEditor.Window.id() | nil, pos_integer()}
  | :idle

clear_hover(mouse)

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

click_count(mouse)

@spec click_count(t()) :: non_neg_integer()

double_click_ms()

@spec double_click_ms() :: pos_integer()

dragging?(mouse)

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

hover_delay_ms()

@spec hover_delay_ms() :: pos_integer()

hover_position(mouse)

@spec hover_position(t()) :: {integer(), integer()} | nil

prepare_clear_hover(mouse)

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

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

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

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 the effective click count set.

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

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

resizing?(mouse)

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

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

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

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()

stop_drag(mouse)

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

stop_resize(mouse)

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

update_resize(mouse, direction, new_position)

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