import {
  Box,
  StateNode,
  moveCameraWhenCloseToEdge,
  pointInPolygon,
  polygonsIntersect
} from "@tldraw/editor";
class Brushing extends StateNode {
  static id = "brushing";
  info = {};
  initialSelectedShapeIds = [];
  excludedShapeIds = /* @__PURE__ */ new Set();
  isWrapMode = false;
  // The shape that the brush started on
  initialStartShape = null;
  onEnter = (info) => {
    const { altKey, currentPagePoint } = this.editor.inputs;
    this.isWrapMode = this.editor.user.getIsWrapMode();
    if (altKey) {
      this.parent.transition("scribble_brushing", info);
      return;
    }
    this.excludedShapeIds = new Set(
      this.editor.getCurrentPageShapes().filter(
        (shape) => this.editor.isShapeOfType(shape, "group") || this.editor.isShapeOrAncestorLocked(shape)
      ).map((shape) => shape.id)
    );
    this.info = info;
    this.initialSelectedShapeIds = this.editor.getSelectedShapeIds().slice();
    this.initialStartShape = this.editor.getShapesAtPoint(currentPagePoint)[0];
    this.hitTestShapes();
  };
  onExit = () => {
    this.initialSelectedShapeIds = [];
    this.editor.updateInstanceState({ brush: null });
  };
  onTick = () => {
    moveCameraWhenCloseToEdge(this.editor);
  };
  onPointerMove = () => {
    this.hitTestShapes();
  };
  onPointerUp = () => {
    this.complete();
  };
  onComplete = () => {
    this.complete();
  };
  onCancel = (info) => {
    this.editor.setSelectedShapes(this.initialSelectedShapeIds);
    this.parent.transition("idle", info);
  };
  onKeyDown = (info) => {
    if (this.editor.inputs.altKey) {
      this.parent.transition("scribble_brushing", info);
    } else {
      this.hitTestShapes();
    }
  };
  onKeyUp = () => {
    this.hitTestShapes();
  };
  complete() {
    this.hitTestShapes();
    this.parent.transition("idle");
  }
  hitTestShapes() {
    const { editor, excludedShapeIds, isWrapMode } = this;
    const {
      inputs: { originPagePoint, currentPagePoint, shiftKey, ctrlKey }
    } = editor;
    const results = new Set(shiftKey ? this.initialSelectedShapeIds : []);
    const isWrapping = isWrapMode ? !ctrlKey : ctrlKey;
    const brush = Box.FromPoints([originPagePoint, currentPagePoint]);
    const { corners } = brush;
    let A, B, shape, pageBounds, pageTransform, localCorners;
    const currentPageShapes = editor.getCurrentPageShapes();
    const currentPageId = editor.getCurrentPageId();
    testAllShapes:
      for (let i = 0, n = currentPageShapes.length; i < n; i++) {
        shape = currentPageShapes[i];
        if (excludedShapeIds.has(shape.id) || results.has(shape.id))
          continue testAllShapes;
        pageBounds = editor.getShapePageBounds(shape);
        if (!pageBounds)
          continue testAllShapes;
        if (brush.contains(pageBounds)) {
          this.handleHit(shape, currentPagePoint, currentPageId, results, corners);
          continue testAllShapes;
        }
        if (isWrapping || editor.isShapeOfType(shape, "frame")) {
          continue testAllShapes;
        }
        if (brush.collides(pageBounds)) {
          pageTransform = editor.getShapePageTransform(shape);
          if (!pageTransform)
            continue testAllShapes;
          localCorners = pageTransform.clone().invert().applyToPoints(corners);
          const geometry = editor.getShapeGeometry(shape);
          hitTestBrushEdges:
            for (let i2 = 0; i2 < 4; i2++) {
              A = localCorners[i2];
              B = localCorners[(i2 + 1) % 4];
              if (geometry.hitTestLineSegment(A, B, 0)) {
                this.handleHit(shape, currentPagePoint, currentPageId, results, corners);
                break hitTestBrushEdges;
              }
            }
        }
      }
    editor.getInstanceState().isCoarsePointer;
    const currentBrush = editor.getInstanceState().brush;
    if (!currentBrush || !brush.equals(currentBrush)) {
      editor.updateInstanceState({ brush: { ...brush.toJson() } });
    }
    const current = editor.getSelectedShapeIds();
    if (current.length !== results.size || current.some((id) => !results.has(id))) {
      editor.setSelectedShapes(Array.from(results));
    }
  }
  onInterrupt = () => {
    this.editor.updateInstanceState({ brush: null });
  };
  handleHit(shape, currentPagePoint, currentPageId, results, corners) {
    if (shape.parentId === currentPageId) {
      results.add(shape.id);
      return;
    }
    const selectedShape = this.editor.getOutermostSelectableShape(shape);
    const pageMask = this.editor.getShapeMask(selectedShape.id);
    if (pageMask && !polygonsIntersect(pageMask, corners) && !pointInPolygon(currentPagePoint, pageMask)) {
      return;
    }
    results.add(selectedShape.id);
  }
}
export {
  Brushing
};
//# sourceMappingURL=Brushing.mjs.map
