From 5ab81f49a11bd8a74725228a887a90c88a3848ff Mon Sep 17 00:00:00 2001
From: vkalev <vjk1883@gmail.com>
Date: Tue, 6 Jul 2021 14:27:29 -0500
Subject: added breaking of tangent handle lines by holding 'Alt' key when
 moving

---
 src/client/views/InkHandles.tsx | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

(limited to 'src/client/views/InkHandles.tsx')

diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx
index c2163c124..993e427b3 100644
--- a/src/client/views/InkHandles.tsx
+++ b/src/client/views/InkHandles.tsx
@@ -15,6 +15,8 @@ export interface InkControlProps {
 
 @observer
 export class InkHandles extends React.Component<InkControlProps> {
+    @observable private _brokenIndices: number[] = [];
+
     /**
      * Handles the movement of a selected handle point when the user clicks and drags.
      * @param handleNum The index of the currently selected handle point.
@@ -24,13 +26,25 @@ export class InkHandles extends React.Component<InkControlProps> {
             InkStrokeProperties.Instance.moveControl(0, 0, 1);
             const controlUndo = UndoManager.StartBatch("DocDecs set radius");
             const screenScale = this.props.ScreenToLocalTransform().Scale;
+            document.addEventListener("keydown", (e: KeyboardEvent) => this.onBreakTangent(e, handleNum), true);
             setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => {
-                    InkStrokeProperties.Instance?.moveHandle(-delta[0] * screenScale, -delta[1] * screenScale, handleNum);
+                    InkStrokeProperties.Instance?.moveHandle(-delta[0] * screenScale, -delta[1] * screenScale, handleNum, this._brokenIndices);
                     return false;
                 }, () => controlUndo?.end(), emptyFunction
             );
         }
     }
+
+    @action
+    onBreakTangent = (e: KeyboardEvent, handleIndex: number) => {
+        if (["Alt"].includes(e.key)) {
+            const order = handleIndex % 4;
+            const oppositeHandleIndex = order === 1 ? handleIndex - 3 : handleIndex + 3;
+            if (!this._brokenIndices.includes(handleIndex) && !this._brokenIndices.includes(oppositeHandleIndex)) {
+                this._brokenIndices.push(handleIndex, oppositeHandleIndex);
+            }
+        }
+    }
  
     render() {
         const formatInstance = InkStrokeProperties.Instance;
@@ -39,15 +53,15 @@ export class InkHandles extends React.Component<InkControlProps> {
         const handlePoints: HandlePoint[] = [];
         const handleLines: HandleLine[] = [];
         if (data.length >= 4) {
-            // adding first and last (single) handle lines
-            handleLines.push({ X1: data[0].X, Y1: data[0].Y, X2: data[1].X, Y2: data[1].Y, dot1: 0, dot2: 0 });
-            handleLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[data.length - 1].X, Y2: data[data.length - 1].Y, dot1: data.length - 1, dot2: data.length - 1 });
             for (let i = 0; i <= data.length - 4; i += 4) {
                 handlePoints.push({ X: data[i + 1].X, Y: data[i + 1].Y, I: i + 1, dot1: i, dot2: i === 0 ? i : i - 1 });
                 handlePoints.push({ X: data[i + 2].X, Y: data[i + 2].Y, I: i + 2, dot1: i + 3, dot2: i === data.length ? i + 3 : i + 4 });
             }
+            // adding first and last (single) handle lines
+            handleLines.push({ X1: data[0].X, Y1: data[0].Y, X2: data[0].X, Y2: data[0].Y, X3: data[1].X, Y3: data[1].Y, dot1: 0, dot2: 0 });
+            handleLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[data.length - 1].X, Y2: data[data.length - 1].Y, X3: data[data.length - 1].X, Y3: data[data.length - 1].Y, dot1: data.length - 1, dot2: data.length - 1 });
             for (let i = 2; i < data.length - 4; i += 4) {
-                handleLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 3].X, Y2: data[i + 3].Y, dot1: i + 1, dot2: i + 2 });
+                handleLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 1].X, Y2: data[i + 1].Y, X3: data[i + 3].X, Y3: data[i + 3].Y, dot1: i + 1, dot2: i + 2 });
             }
         }
         const [left, top, scaleX, scaleY, strokeWidth, dotsize] = this.props.format;
@@ -77,6 +91,14 @@ export class InkHandles extends React.Component<InkControlProps> {
                             stroke="#1F85DE" 
                             strokeWidth={dotsize / 8}
                             display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} />
+                        <line 
+                            x1={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} 
+                            y1={(pts.Y2 - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
+                            x2={(pts.X3 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} 
+                            y2={(pts.Y3 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} 
+                            stroke="#1F85DE" 
+                            strokeWidth={dotsize / 8}
+                            display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} />
                     </svg>)}
             </>
         );
-- 
cgit v1.2.3-70-g09d2

