aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/InkControls.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/InkControls.tsx')
-rw-r--r--src/client/views/InkControls.tsx118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx
new file mode 100644
index 000000000..eeddfce4c
--- /dev/null
+++ b/src/client/views/InkControls.tsx
@@ -0,0 +1,118 @@
+import React = require("react");
+import { observable, action } from "mobx";
+import { observer } from "mobx-react";
+import { InkStrokeProperties } from "./InkStrokeProperties";
+import { setupMoveUpEvents, emptyFunction } from "../../Utils";
+import { UndoManager } from "../util/UndoManager";
+import { ControlPoint, InkData, PointData } from "../../fields/InkField";
+import { Transform } from "../util/Transform";
+
+export interface InkControlProps {
+ data: InkData;
+ addedPoints: PointData[];
+ format: number[];
+ ScreenToLocalTransform: () => Transform;
+}
+
+@observer
+export class InkControls extends React.Component<InkControlProps> {
+ // @observable private _controlPoints: ControlPoint[] = [];
+ @observable private _overControl = -1;
+ @observable private _overAddPoint = -1;
+
+ /**
+ * Handles the movement of a selected control point when the user clicks and drags.
+ * @param controlNum The index of the currently selected control point.
+ */
+ @action
+ onControlDown = (e: React.PointerEvent, controlNum: number): void => {
+ if (InkStrokeProperties.Instance) {
+ InkStrokeProperties.Instance.moveControl(0, 0, 1);
+ const controlUndo = UndoManager.StartBatch("DocDecs set radius");
+ const screenScale = this.props.ScreenToLocalTransform().Scale;
+ setupMoveUpEvents(this, e,
+ (e: PointerEvent, down: number[], delta: number[]) => {
+ InkStrokeProperties.Instance?.moveControl(-delta[0] * screenScale, -delta[1] * screenScale, controlNum);
+ return false;
+ },
+ () => controlUndo?.end(), emptyFunction);
+ }
+ }
+
+ /**
+ * Deletes the currently selected point.
+ */
+ @action
+ onDelete = (e: KeyboardEvent) => {
+ if (["-", "Backspace", "Delete"].includes(e.key)) {
+ if (InkStrokeProperties.Instance?.deletePoints()) e.stopPropagation();
+ }
+ }
+
+ /**
+ * Changes the current selected control point.
+ */
+ @action
+ changeCurrPoint = (i: number) => {
+ if (InkStrokeProperties.Instance) {
+ InkStrokeProperties.Instance._currentPoint = i;
+ document.addEventListener("keydown", this.onDelete, true);
+ }
+ }
+
+ @action onEnterControl = (i: number) => { this._overControl = i; };
+ @action onLeaveControl = () => { this._overControl = -1; };
+ @action onEnterAddPoint = (i: number) => { this._overAddPoint = i; };
+ @action onLeaveAddPoint = () => { this._overAddPoint = -1; };
+
+ render() {
+ const data = this.props.data;
+ const controlPoints: ControlPoint[] = [];
+ if (data.length >= 4) {
+ for (let i = 0; i <= data.length - 4; i += 4) {
+ controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
+ controlPoints.push({ X: data[i + 3].X, Y: data[i + 3].Y, I: i + 3 });
+ }
+ }
+ const addedPoints = this.props.addedPoints;
+ const [left, top, scaleX, scaleY, strokeWidth, dotsize] = this.props.format;
+
+ return (
+ <>
+ {addedPoints.map((pts, i) =>
+ <svg height="10" width="10" key={`add${i}`}>
+ <circle
+ cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2}
+ cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
+ r={strokeWidth / 2}
+ stroke={this._overAddPoint === i ? "#1F85DE" : "transparent"}
+ strokeWidth={dotsize / 4} fill={this._overAddPoint === i ? "#1F85DE" : "transparent"}
+ onPointerDown={() => { InkStrokeProperties.Instance?.addPoints(pts.X, pts.Y, addedPoints, i, controlPoints); }}
+ onMouseEnter={() => this.onEnterAddPoint(i)}
+ onMouseLeave={this.onLeaveAddPoint}
+ pointerEvents="all"
+ cursor="all-scroll"
+ />
+ </svg>
+ )}
+ {controlPoints.map((control, i) =>
+ <svg height="10" width="10" key={`ctrl${i}`}>
+ <rect
+ x={(control.X - left - strokeWidth / 2) * scaleX}
+ y={(control.Y - top - strokeWidth / 2) * scaleY}
+ height={this._overControl === i ? strokeWidth * 1.5 : strokeWidth}
+ width={this._overControl === i ? strokeWidth * 1.5 : strokeWidth}
+ strokeWidth={strokeWidth / 6} stroke="#1F85DE"
+ fill={InkStrokeProperties.Instance?._currentPoint === control.I ? "#1F85DE" : "white"}
+ onPointerDown={(e) => { this.changeCurrPoint(control.I); this.onControlDown(e, control.I); }}
+ onMouseEnter={() => this.onEnterControl(i)}
+ onMouseLeave={this.onLeaveControl}
+ pointerEvents="all"
+ cursor="default"
+ />
+ </svg>
+ )}
+ </>
+ );
+ }
+} \ No newline at end of file