update method

({Cmd? cmd, bool consumed, DebugOverlayModel model}) update(
  1. Msg msg
)

Updates overlay state and reports whether the message was consumed.

Implementation

({DebugOverlayModel model, Cmd? cmd, bool consumed}) update(Msg msg) {
  switch (msg) {
    case RenderMetricsMsg(:final metrics):
      return (model: copyWith(metrics: metrics), cmd: null, consumed: false);

    case WindowSizeMsg(:final width, :final height):
      final next = copyWith(terminalWidth: width, terminalHeight: height);
      // Clamp stored position if set.
      if (next.panelX != null || next.panelY != null) {
        final (:x, :y, :w, :h) = next._panelRect();
        final clampedX = x.clamp(0, (width - w).clamp(0, width));
        final clampedY = y.clamp(0, (height - h).clamp(0, height));
        return (
          model: next.copyWith(panelX: clampedX, panelY: clampedY),
          cmd: null,
          consumed: false,
        );
      }
      return (model: next, cmd: null, consumed: false);

    case MouseMsg(:final x, :final y, :final button, :final action):
      if (!enabled) return (model: this, cmd: null, consumed: false);

      // When dragging, consume ALL mouse events to prevent selection bleed.
      if (dragging) {
        if (action == MouseAction.release) {
          return (
            model: copyWith(dragging: false, pointerCaptured: false),
            cmd: null,
            consumed: true,
          );
        }
        if (action == MouseAction.motion) {
          final bounds = panelBounds;
          final maxX = (terminalWidth - bounds.w).clamp(0, terminalWidth);
          final maxY = (terminalHeight - bounds.h).clamp(0, terminalHeight);
          final nx = (x - dragOffsetX).clamp(0, maxX);
          final ny = (y - dragOffsetY).clamp(0, maxY);
          return (
            model: copyWith(panelX: nx, panelY: ny),
            cmd: null,
            consumed: true,
          );
        }
        return (model: this, cmd: null, consumed: true);
      }

      if (pointerCaptured) {
        return (
          model: action == MouseAction.release
              ? copyWith(pointerCaptured: false)
              : this,
          cmd: null,
          consumed: true,
        );
      }

      // Tabs and the title bar have distinct pointer actions. Neither takes
      // keyboard focus from the application.
      if (action == MouseAction.press && button == MouseButton.left) {
        final tab = _tabAt(x, y);
        if (tab != null) {
          return (
            model: selectMode(tab).copyWith(pointerCaptured: true),
            cmd: null,
            consumed: true,
          );
        }
        final bounds = panelBounds;
        if (containsPoint(x, y) && y == bounds.y) {
          return (
            model: copyWith(
              panelX: bounds.x,
              panelY: bounds.y,
              dragging: true,
              pointerCaptured: true,
              dragOffsetX: x - bounds.x,
              dragOffsetY: y - bounds.y,
            ),
            cmd: null,
            consumed: true,
          );
        }
      }

      // Do not activate application buttons hidden behind the opaque panel.
      if (action == MouseAction.press &&
          button == MouseButton.left &&
          containsPoint(x, y)) {
        return (
          model: copyWith(pointerCaptured: true),
          cmd: null,
          consumed: true,
        );
      }
      return (model: this, cmd: null, consumed: false);

    default:
      return (model: this, cmd: null, consumed: false);
  }
}