# `MingaEditor.State.Mouse`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/state/mouse.ex#L1)

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.

# `t`

```elixir
@type t() :: %MingaEditor.State.Mouse{
  anchor: {non_neg_integer(), non_neg_integer()} | nil,
  click_count: non_neg_integer(),
  drag_click_count: pos_integer(),
  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
}
```

# `clear_hover`

```elixir
@spec clear_hover(t()) :: t()
```

Clears hover state and cancels any pending timer.

# `double_click_ms`

```elixir
@spec double_click_ms() :: pos_integer()
```

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

# `record_press`

```elixir
@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.

# `resizing?`

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

Returns true if a separator resize drag is active.

# `set_hover`

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

Sets the hover position and starts a debounce timer.

# `start_drag`

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

Begins a content drag from the given buffer position.

# `start_resize`

```elixir
@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`

```elixir
@spec stop_drag(t()) :: t()
```

Ends an active drag, clearing the anchor.

# `stop_resize`

```elixir
@spec stop_resize(t()) :: t()
```

Ends a separator resize drag.

# `update_resize`

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

Updates the separator position during an active resize drag.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
