"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var Drawing_exports = {};
__export(Drawing_exports, {
  Drawing: () => Drawing
});
module.exports = __toCommonJS(Drawing_exports);
var import_editor = require("@tldraw/editor");
var import_default_shape_constants = require("../../shared/default-shape-constants");
class Drawing extends import_editor.StateNode {
  static id = "drawing";
  info = {};
  initialShape;
  shapeType = this.parent.id === "highlight" ? "highlight" : "draw";
  util = this.editor.getShapeUtil(this.shapeType);
  isPen = false;
  isPenOrStylus = false;
  segmentMode = "free";
  didJustShiftClickToExtendPreviousShapeLine = false;
  pagePointWhereCurrentSegmentChanged = {};
  pagePointWhereNextSegmentChanged = null;
  lastRecordedPoint = {};
  mergeNextPoint = false;
  currentLineLength = 0;
  // Cache for current segment's points to avoid repeated b64 decode/encode
  currentSegmentPoints = [];
  markId = null;
  onEnter(info) {
    this.markId = null;
    this.info = info;
    this.lastRecordedPoint = this.editor.inputs.getCurrentPagePoint().clone();
    this.startShape();
  }
  onPointerMove() {
    const { inputs } = this.editor;
    const isPen = inputs.getIsPen();
    if (this.isPen && !isPen) {
      if (this.markId) {
        this.editor.bailToMark(this.markId);
        this.startShape();
        return;
      }
    }
    if (this.isPenOrStylus) {
      const currentPagePoint = inputs.getCurrentPagePoint();
      if (import_editor.Vec.Dist(currentPagePoint, this.lastRecordedPoint) >= 1 / this.editor.getZoomLevel()) {
        this.lastRecordedPoint = currentPagePoint.clone();
        this.mergeNextPoint = false;
      } else {
        this.mergeNextPoint = true;
      }
    } else {
      this.mergeNextPoint = false;
    }
    this.updateDrawingShape();
  }
  onKeyDown(info) {
    if (info.key === "Shift") {
      switch (this.segmentMode) {
        case "free": {
          this.segmentMode = "starting_straight";
          this.pagePointWhereNextSegmentChanged = this.editor.inputs.getCurrentPagePoint().clone();
          break;
        }
        case "starting_free": {
          this.segmentMode = "starting_straight";
        }
      }
    }
    this.updateDrawingShape();
  }
  onKeyUp(info) {
    if (info.key === "Shift") {
      this.editor.snaps.clearIndicators();
      switch (this.segmentMode) {
        case "straight": {
          this.segmentMode = "starting_free";
          this.pagePointWhereNextSegmentChanged = this.editor.inputs.getCurrentPagePoint().clone();
          break;
        }
        case "starting_straight": {
          this.pagePointWhereNextSegmentChanged = null;
          this.segmentMode = "free";
          break;
        }
      }
    }
    this.updateDrawingShape();
  }
  onExit() {
    this.editor.snaps.clearIndicators();
    this.pagePointWhereCurrentSegmentChanged = this.editor.inputs.getCurrentPagePoint().clone();
  }
  canClose() {
    return this.shapeType !== "highlight";
  }
  getIsClosed(segments, size, scale) {
    if (!this.canClose()) return false;
    const strokeWidth = import_default_shape_constants.STROKE_SIZES[size];
    const firstPoint = import_editor.b64Vecs.decodeFirstPoint(segments[0].points);
    const lastSegment = segments[segments.length - 1];
    const lastPoint = import_editor.b64Vecs.decodeLastPoint(lastSegment.points);
    return firstPoint !== null && lastPoint !== null && firstPoint !== lastPoint && this.currentLineLength > strokeWidth * 4 * scale && import_editor.Vec.DistMin(firstPoint, lastPoint, strokeWidth * 2 * scale);
  }
  startShape() {
    const inputs = this.editor.inputs;
    const originPagePoint = inputs.getOriginPagePoint();
    const isPen = inputs.getIsPen();
    this.markId = this.editor.markHistoryStoppingPoint("draw start");
    const { z = 0.5 } = this.info.point;
    this.isPen = isPen;
    this.isPenOrStylus = isPen || z > 0 && z < 0.5 || z > 0.5 && z < 1;
    const pressure = this.isPenOrStylus ? z * 1.25 : 0.5;
    this.segmentMode = this.editor.inputs.getShiftKey() ? "straight" : "free";
    this.didJustShiftClickToExtendPreviousShapeLine = false;
    this.lastRecordedPoint = originPagePoint.clone();
    if (this.initialShape) {
      const shape2 = this.editor.getShape(this.initialShape.id);
      if (shape2 && this.segmentMode === "straight") {
        this.didJustShiftClickToExtendPreviousShapeLine = true;
        const prevSegment = (0, import_editor.last)(shape2.props.segments);
        if (!prevSegment) throw Error("Expected a previous segment!");
        const prevPoint = import_editor.b64Vecs.decodeLastPoint(prevSegment.points);
        if (!prevPoint) throw Error("Expected a previous point!");
        const { x, y } = this.editor.getPointInShapeSpace(shape2, originPagePoint).toFixed();
        const newSegment = {
          type: this.segmentMode,
          points: import_editor.b64Vecs.encodePoints([
            { x: prevPoint.x, y: prevPoint.y, z: +pressure.toFixed(2) },
            { x, y, z: +pressure.toFixed(2) }
          ])
        };
        const prevPointPageSpace = import_editor.Mat.applyToPoint(
          this.editor.getShapePageTransform(shape2.id),
          prevPoint
        );
        this.pagePointWhereCurrentSegmentChanged = prevPointPageSpace;
        this.pagePointWhereNextSegmentChanged = null;
        const segments = [...shape2.props.segments, newSegment];
        if (this.currentLineLength < import_default_shape_constants.STROKE_SIZES[shape2.props.size] * 4) {
          this.currentLineLength = this.getLineLength(segments);
        }
        const shapePartial = {
          id: shape2.id,
          type: this.shapeType,
          props: {
            segments
          }
        };
        if (this.canClose()) {
          ;
          shapePartial.props.isClosed = this.getIsClosed(
            segments,
            shape2.props.size,
            shape2.props.scale
          );
        }
        this.editor.updateShapes([shapePartial]);
        return;
      }
    }
    this.pagePointWhereCurrentSegmentChanged = originPagePoint.clone();
    const id = (0, import_editor.createShapeId)();
    const initialPoint = new import_editor.Vec(0, 0, +pressure.toFixed(2));
    this.currentSegmentPoints = [initialPoint];
    this.editor.createShape({
      id,
      type: this.shapeType,
      x: originPagePoint.x,
      y: originPagePoint.y,
      props: {
        isPen: this.isPenOrStylus,
        scale: this.editor.user.getIsDynamicResizeMode() ? 1 / this.editor.getZoomLevel() : 1,
        segments: [
          {
            type: this.segmentMode,
            points: import_editor.b64Vecs.encodePoints([initialPoint])
          }
        ]
      }
    });
    const shape = this.editor.getShape(id);
    if (!shape) {
      this.cancel();
      return;
    }
    this.currentLineLength = 0;
    this.initialShape = this.editor.getShape(id);
  }
  updateDrawingShape() {
    const { initialShape } = this;
    const { inputs } = this.editor;
    if (!initialShape) return;
    const {
      id,
      props: { size, scale }
    } = initialShape;
    const shape = this.editor.getShape(id);
    if (!shape) return;
    const { segments } = shape.props;
    const currentPagePoint = inputs.getCurrentPagePoint();
    const { x, y, z } = this.editor.getPointInShapeSpace(shape, currentPagePoint).toFixed();
    const pressure = this.isPenOrStylus ? +(currentPagePoint.z * 1.25).toFixed(2) : 0.5;
    const newPoint = { x, y, z: pressure };
    switch (this.segmentMode) {
      case "starting_straight": {
        const { pagePointWhereNextSegmentChanged } = this;
        if (pagePointWhereNextSegmentChanged === null) {
          throw Error("We should have a point where the segment changed");
        }
        const hasMovedFarEnough = import_editor.Vec.Dist2(pagePointWhereNextSegmentChanged, inputs.getCurrentPagePoint()) > this.editor.options.dragDistanceSquared;
        if (hasMovedFarEnough) {
          this.pagePointWhereCurrentSegmentChanged = this.pagePointWhereNextSegmentChanged.clone();
          this.pagePointWhereNextSegmentChanged = null;
          this.segmentMode = "straight";
          const prevSegment = (0, import_editor.last)(segments);
          if (!prevSegment) throw Error("Expected a previous segment!");
          const prevLastPoint = import_editor.b64Vecs.decodeLastPoint(prevSegment.points);
          if (!prevLastPoint) throw Error("Expected a previous last point!");
          let newSegment;
          const newLastPoint = this.editor.getPointInShapeSpace(shape, this.pagePointWhereCurrentSegmentChanged).toFixed().toJson();
          if (prevSegment.type === "straight") {
            this.currentLineLength += import_editor.Vec.Dist(prevLastPoint, newLastPoint);
            newSegment = {
              type: "straight",
              points: import_editor.b64Vecs.encodePoints([prevLastPoint, newLastPoint])
            };
            const transform = this.editor.getShapePageTransform(shape);
            this.pagePointWhereCurrentSegmentChanged = import_editor.Mat.applyToPoint(transform, prevLastPoint);
          } else {
            newSegment = {
              type: "straight",
              points: import_editor.b64Vecs.encodePoints([newLastPoint, newPoint])
            };
          }
          const shapePartial = {
            id,
            type: this.shapeType,
            props: {
              segments: [...segments, newSegment]
            }
          };
          if (this.canClose()) {
            ;
            shapePartial.props.isClosed = this.getIsClosed(
              segments,
              size,
              scale
            );
          }
          this.editor.updateShapes([shapePartial]);
        }
        break;
      }
      case "starting_free": {
        const { pagePointWhereNextSegmentChanged } = this;
        if (pagePointWhereNextSegmentChanged === null) {
          throw Error("We should have a point where the segment changed");
        }
        const hasMovedFarEnough = import_editor.Vec.Dist2(pagePointWhereNextSegmentChanged, inputs.getCurrentPagePoint()) > this.editor.options.dragDistanceSquared;
        if (hasMovedFarEnough) {
          this.pagePointWhereCurrentSegmentChanged = this.pagePointWhereNextSegmentChanged.clone();
          this.pagePointWhereNextSegmentChanged = null;
          this.segmentMode = "free";
          const newSegments = segments.slice();
          const prevStraightSegment = newSegments[newSegments.length - 1];
          const prevPoint = import_editor.b64Vecs.decodeLastPoint(prevStraightSegment.points);
          if (!prevPoint) {
            throw Error("No previous point!");
          }
          const interpolatedPoints = import_editor.Vec.PointsBetween(prevPoint, newPoint, 6).map(
            (p) => new import_editor.Vec((0, import_editor.toFixed)(p.x), (0, import_editor.toFixed)(p.y), (0, import_editor.toFixed)(p.z))
          );
          this.currentSegmentPoints = interpolatedPoints;
          const newFreeSegment = {
            type: "free",
            points: import_editor.b64Vecs.encodePoints(interpolatedPoints)
          };
          const finalSegments = [...newSegments, newFreeSegment];
          if (this.currentLineLength < import_default_shape_constants.STROKE_SIZES[shape.props.size] * 4) {
            this.currentLineLength = this.getLineLength(finalSegments);
          }
          const shapePartial = {
            id,
            type: this.shapeType,
            props: {
              segments: finalSegments
            }
          };
          if (this.canClose()) {
            ;
            shapePartial.props.isClosed = this.getIsClosed(
              finalSegments,
              size,
              scale
            );
          }
          this.editor.updateShapes([shapePartial]);
        }
        break;
      }
      case "straight": {
        const newSegments = segments.slice();
        const newSegment = newSegments[newSegments.length - 1];
        const { pagePointWhereCurrentSegmentChanged } = this;
        const inputs2 = this.editor.inputs;
        const ctrlKey = inputs2.getCtrlKey();
        const currentPagePoint2 = inputs2.getCurrentPagePoint();
        if (!pagePointWhereCurrentSegmentChanged)
          throw Error("We should have a point where the segment changed");
        let pagePoint;
        let shouldSnapToAngle = false;
        if (this.didJustShiftClickToExtendPreviousShapeLine) {
          if (this.editor.inputs.getIsDragging()) {
            shouldSnapToAngle = !ctrlKey;
            this.didJustShiftClickToExtendPreviousShapeLine = false;
          } else {
          }
        } else {
          shouldSnapToAngle = !ctrlKey;
        }
        let newPoint2 = this.editor.getPointInShapeSpace(shape, currentPagePoint2).toFixed().toJson();
        let didSnap = false;
        let snapSegment = void 0;
        const shouldSnap = this.editor.user.getIsSnapMode() ? !ctrlKey : ctrlKey;
        if (shouldSnap) {
          if (newSegments.length > 2) {
            let nearestPoint = void 0;
            let minDistance = 8 / this.editor.getZoomLevel();
            for (let i = 0, n = segments.length - 2; i < n; i++) {
              const segment = segments[i];
              if (!segment) break;
              if (segment.type === "free") continue;
              const first = import_editor.b64Vecs.decodeFirstPoint(segment.points);
              const lastPoint = import_editor.b64Vecs.decodeLastPoint(segment.points);
              if (!(first && lastPoint)) continue;
              const nearestPointOnSegment = import_editor.Vec.NearestPointOnLineSegment(
                first,
                lastPoint,
                newPoint2
              );
              if (import_editor.Vec.DistMin(nearestPointOnSegment, newPoint2, minDistance)) {
                nearestPoint = nearestPointOnSegment.toFixed().toJson();
                minDistance = import_editor.Vec.Dist(nearestPointOnSegment, newPoint2);
                snapSegment = segment;
                break;
              }
            }
            if (nearestPoint) {
              didSnap = true;
              newPoint2 = nearestPoint;
            }
          }
        }
        if (didSnap && snapSegment) {
          const transform = this.editor.getShapePageTransform(shape);
          const first = import_editor.b64Vecs.decodeFirstPoint(snapSegment.points);
          const lastPoint = import_editor.b64Vecs.decodeLastPoint(snapSegment.points);
          if (!first || !lastPoint) throw Error("Expected a last point!");
          const A = import_editor.Mat.applyToPoint(transform, first);
          const B = import_editor.Mat.applyToPoint(transform, lastPoint);
          const snappedPoint = import_editor.Mat.applyToPoint(transform, newPoint2);
          this.editor.snaps.setIndicators([
            {
              id: (0, import_editor.uniqueId)(),
              type: "points",
              points: [A, snappedPoint, B]
            }
          ]);
        } else {
          this.editor.snaps.clearIndicators();
          if (shouldSnapToAngle) {
            const currentAngle = import_editor.Vec.Angle(pagePointWhereCurrentSegmentChanged, currentPagePoint2);
            const snappedAngle = (0, import_editor.snapAngle)(currentAngle, 24);
            const angleDiff = snappedAngle - currentAngle;
            pagePoint = import_editor.Vec.RotWith(
              currentPagePoint2,
              pagePointWhereCurrentSegmentChanged,
              angleDiff
            );
          } else {
            pagePoint = currentPagePoint2.clone();
          }
          newPoint2 = this.editor.getPointInShapeSpace(shape, pagePoint).toFixed().toJson();
        }
        this.currentLineLength += newSegments.length && import_editor.b64Vecs.decodeFirstPoint(newSegment.points) ? import_editor.Vec.Dist(import_editor.b64Vecs.decodeFirstPoint(newSegment.points), import_editor.Vec.From(newPoint2)) : 0;
        newSegments[newSegments.length - 1] = {
          ...newSegment,
          type: "straight",
          points: import_editor.b64Vecs.encodePoints([
            import_editor.b64Vecs.decodeFirstPoint(newSegment.points),
            import_editor.Vec.From(newPoint2)
          ])
        };
        const shapePartial = {
          id,
          type: this.shapeType,
          props: {
            segments: newSegments
          }
        };
        if (this.canClose()) {
          ;
          shapePartial.props.isClosed = this.getIsClosed(
            segments,
            size,
            scale
          );
        }
        this.editor.updateShapes([shapePartial]);
        break;
      }
      case "free": {
        const cachedPoints = this.currentSegmentPoints;
        if (cachedPoints.length && this.mergeNextPoint) {
          const lastPoint = cachedPoints[cachedPoints.length - 1];
          lastPoint.x = newPoint.x;
          lastPoint.y = newPoint.y;
          lastPoint.z = lastPoint.z ? Math.max(lastPoint.z, newPoint.z) : newPoint.z;
        } else {
          this.currentLineLength += cachedPoints.length ? import_editor.Vec.Dist(cachedPoints[cachedPoints.length - 1], newPoint) : 0;
          cachedPoints.push(new import_editor.Vec(newPoint.x, newPoint.y, newPoint.z));
        }
        const newSegments = segments.slice();
        const newSegment = newSegments[newSegments.length - 1];
        newSegments[newSegments.length - 1] = {
          ...newSegment,
          points: import_editor.b64Vecs.encodePoints(cachedPoints)
        };
        if (this.currentLineLength < import_default_shape_constants.STROKE_SIZES[shape.props.size] * 4) {
          this.currentLineLength = this.getLineLength(newSegments);
        }
        const shapePartial = {
          id,
          type: this.shapeType,
          props: {
            segments: newSegments
          }
        };
        if (this.canClose()) {
          ;
          shapePartial.props.isClosed = this.getIsClosed(
            newSegments,
            size,
            scale
          );
        }
        this.editor.updateShapes([shapePartial]);
        if (cachedPoints.length > this.util.options.maxPointsPerShape) {
          this.editor.updateShapes([{ id, type: this.shapeType, props: { isComplete: true } }]);
          const newShapeId = (0, import_editor.createShapeId)();
          const props = this.editor.getShape(id).props;
          if (!this.editor.canCreateShapes([newShapeId])) return this.cancel();
          const currentPagePoint2 = inputs.getCurrentPagePoint();
          const initialPoint = new import_editor.Vec(0, 0, this.isPenOrStylus ? +(z * 1.25).toFixed() : 0.5);
          this.currentSegmentPoints = [initialPoint];
          this.editor.createShape({
            id: newShapeId,
            type: this.shapeType,
            x: (0, import_editor.toFixed)(currentPagePoint2.x),
            y: (0, import_editor.toFixed)(currentPagePoint2.y),
            props: {
              isPen: this.isPenOrStylus,
              scale: props.scale,
              segments: [
                {
                  type: "free",
                  points: import_editor.b64Vecs.encodePoints([initialPoint])
                }
              ]
            }
          });
          const shape2 = this.editor.getShape(newShapeId);
          if (!shape2) {
            return this.cancel();
          }
          this.initialShape = (0, import_editor.structuredClone)(shape2);
          this.mergeNextPoint = false;
          this.lastRecordedPoint = currentPagePoint2.clone();
          this.currentLineLength = 0;
        }
        break;
      }
    }
  }
  getLineLength(segments) {
    let length = 0;
    for (let j = 0; j < segments.length; j++) {
      const points = import_editor.b64Vecs.decodePoints(segments[j].points);
      for (let i = 0; i < points.length - 1; i++) {
        length += import_editor.Vec.Dist2(points[i], points[i + 1]);
      }
    }
    return Math.sqrt(length);
  }
  onPointerUp() {
    this.complete();
  }
  onCancel() {
    this.cancel();
  }
  onComplete() {
    this.complete();
  }
  onInterrupt() {
    if (this.editor.inputs.getIsDragging()) {
      return;
    }
    if (this.markId) {
      this.editor.bailToMark(this.markId);
    }
    this.cancel();
  }
  complete() {
    const { initialShape } = this;
    if (!initialShape) return;
    this.editor.updateShapes([
      { id: initialShape.id, type: initialShape.type, props: { isComplete: true } }
    ]);
    this.parent.transition("idle");
  }
  cancel() {
    this.parent.transition("idle", this.info);
  }
}
//# sourceMappingURL=Drawing.js.map
