From a22f9b3c98c11d1170d1b0548bab61fc73fbc44f Mon Sep 17 00:00:00 2001
From: usodhi <61431818+usodhi@users.noreply.github.com>
Date: Thu, 23 Jul 2020 22:20:49 +0530
Subject: groups bugfix

---
 src/client/views/DocumentDecorations.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index fec4ad9e0..46411c05b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -549,8 +549,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 <div className="documentDecorations-contextMenu" onPointerDown={this.onSettingsDown}>
                     <FontAwesomeIcon size="lg" icon="cog" />
                 </div></Tooltip>) : (
-                <Tooltip title={<><div className="dash-tooltip">Iconify</div></>} placement="top">
-                    <div className="documentDecorations-minimizeButton" onClick={this.onCloseClick}>
+                <Tooltip title={<><div className="dash-tooltip">Delete</div></>} placement="top">
+                    <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
                         {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
                         <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
                     </div></Tooltip>);
@@ -616,7 +616,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                             <div className="documentDecorations-iconifyButton" onPointerDown={this.onIconifyDown}>
                                 {"_"}
                             </div></Tooltip>}
-                    <Tooltip title={<><div className="dash-tooltip">Open Document In Tab</div></>} placement="top"><div className="documentDecorations-closeButton" onPointerDown={this.onMaximizeDown}>
+                    <Tooltip title={<><div className="dash-tooltip">Open Document In Tab</div></>} placement="top"><div className="documentDecorations-openInTab" onPointerDown={this.onMaximizeDown}>
                         {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
                     </div></Tooltip>
                     <div id="documentDecorations-rotation" className="documentDecorations-rotation"
-- 
cgit v1.2.3-70-g09d2


From c841982c0de733b49f22a6e0d04427c166aabcf1 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 25 Jul 2020 14:57:41 -0400
Subject: added ability to resize fixed aspect docusments with ctrlKey.  added
 menu item to hide linkButton

---
 src/client/views/DocumentDecorations.tsx | 14 ++++++++------
 src/client/views/nodes/DocumentView.tsx  |  1 +
 2 files changed, 9 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 46411c05b..8d63537e7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -438,8 +438,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     if (nwidth / nheight !== width / height) {
                         height = nheight / nwidth * width;
                     }
-                    if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
-                    else dW = dH * nwidth / nheight;
+                    if (!e.ctrlKey) {
+                        if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
+                        else dW = dH * nwidth / nheight;
+                    }
                 }
                 const actualdW = Math.max(width + (dW * scale), 20);
                 const actualdH = Math.max(height + (dH * scale), 20);
@@ -463,20 +465,20 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 }
                 else if (nwidth > 0 && nheight > 0) {
                     if (Math.abs(dW) > Math.abs(dH)) {
-                        if (!fixedAspect) {
+                        if (!fixedAspect || e.ctrlKey) {
                             doc._nativeWidth = actualdW / (doc._width || 1) * (doc._nativeWidth || 0);
                         }
                         doc._width = actualdW;
                         if (fixedAspect && !doc._fitWidth) doc._height = nheight / nwidth * doc._width;
-                        else doc._height = actualdH;
+                        else if (!fixedAspect || !e.ctrlKey) doc._height = actualdH;
                     }
                     else {
-                        if (!fixedAspect) {
+                        if (!fixedAspect || e.ctrlKey) {
                             doc._nativeHeight = actualdH / (doc._height || 1) * (doc._nativeHeight || 0);
                         }
                         doc._height = actualdH;
                         if (fixedAspect && !doc._fitWidth) doc._width = nwidth / nheight * doc._height;
-                        else doc._width = actualdW;
+                        else if (!fixedAspect || !e.ctrlKey) doc._width = actualdW;
                     }
                 } else {
                     dW && (doc._width = actualdW);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a56943f6f..8cadafccd 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -758,6 +758,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const appearance = cm.findByDescription("Appearance...");
         const appearanceItems: ContextMenuProps[] = appearance && "subitems" in appearance ? appearance.subitems : [];
         templateDoc && appearanceItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
+        appearanceItems.push({ description: `${this.layoutDoc.hideLinkButton ? "Show" : "Hide"} Link Button`, event: action(() => this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton), icon: "eye" });
         !appearance && cm.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "compass" });
 
         const options = cm.findByDescription("Options...");
-- 
cgit v1.2.3-70-g09d2


From efaf0a35e58c8099918c66481f75ed7ae07c7a37 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 27 Jul 2020 08:25:39 -0400
Subject: added vertical resie of fixedaspect when _fitWidth is on.  fixin
 webBox css to not clip contents.

---
 src/client/views/DocumentDecorations.tsx |  7 ++++---
 src/client/views/nodes/WebBox.scss       |  3 ++-
 src/client/views/nodes/WebBox.tsx        | 10 ++++++----
 3 files changed, 12 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8d63537e7..9a4df926c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -374,7 +374,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         move[1] = thisPt.thisY - this._snapY;
         this._snapX = thisPt.thisX;
         this._snapY = thisPt.thisY;
-
+        let dragBottom = false;
         let dX = 0, dY = 0, dW = 0, dH = 0;
         const unfreeze = () =>
             SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) =>
@@ -412,6 +412,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             case "documentDecorations-bottomResizer":
                 unfreeze();
                 dH = move[1];
+                dragBottom = true;
                 break;
             case "documentDecorations-leftResizer":
                 unfreeze();
@@ -438,7 +439,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     if (nwidth / nheight !== width / height) {
                         height = nheight / nwidth * width;
                     }
-                    if (!e.ctrlKey) {
+                    if (!e.ctrlKey && (!dragBottom || !element.layoutDoc._fitWidth)) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
                         if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
                         else dW = dH * nwidth / nheight;
                     }
@@ -473,7 +474,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                         else if (!fixedAspect || !e.ctrlKey) doc._height = actualdH;
                     }
                     else {
-                        if (!fixedAspect || e.ctrlKey) {
+                        if (!fixedAspect || e.ctrlKey || (dragBottom && element.layoutDoc._fitWidth)) {
                             doc._nativeHeight = actualdH / (doc._height || 1) * (doc._nativeHeight || 0);
                         }
                         doc._height = actualdH;
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index f5c8745e7..62657780d 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -23,10 +23,11 @@
         position: absolute;
         background-color: rgba(245, 230, 95, 0.616);
     }
-    .webBox-container, .webBox-container-dragging {
+    .webBox-container {
         transform-origin: top left;
         width: 100%;
         height: 100%;
+        overflow-x:hidden;
 
         .webBox-htmlSpan {
             position: absolute;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index bc30b15e6..fe48dfc6c 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -659,12 +659,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
     marqueeing = () => this._marqueeing;
     scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop));
     render() {
+        const noScalin = this.props.ContentScaling() < 1;
         return (<div className="webBox" ref={this._mainCont} >
             <div className={`webBox-container`}
                 style={{
-                    transform: `scale(${this.props.ContentScaling()})`,
-                    width: Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
-                    height: Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
+                    position: noScalin ? "absolute" : undefined,
+                    transform: noScalin ? undefined : `scale(${this.props.ContentScaling()})`,
+                    width: noScalin ? undefined : Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
+                    height: noScalin ? undefined : Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
                     pointerEvents: this.layoutDoc.isBackground ? "none" : undefined
                 }}
                 onContextMenu={this.specificContextMenu}>
@@ -672,7 +674,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                 {this.content}
                 <div className={"webBox-outerContent"} ref={this._outerRef}
                     style={{
-                        width: Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
+                        width: 5000,//Number.isFinite(this.props.ContentScaling()) ? `${100 / this.props.ContentScaling()}% ` : "100%",
                         pointerEvents: this.layoutDoc.isAnnotating && !this.layoutDoc.isBackground ? "all" : "none"
                     }}
                     onWheel={e => e.stopPropagation()}
-- 
cgit v1.2.3-70-g09d2


From 258ad0d8628737e01613341437eb0421359ad168 Mon Sep 17 00:00:00 2001
From: yunahi <60233430+yunahi@users.noreply.github.com>
Date: Tue, 28 Jul 2020 00:02:40 +0900
Subject:  rotation/resize fix, changed ui, added sketchpicker etc.

---
 src/client/util/InteractionUtils.tsx               |   7 +-
 src/client/views/DocumentDecorations.tsx           |  54 +++-
 src/client/views/GestureOverlay.tsx                |  16 +-
 src/client/views/InkingStroke.tsx                  |  15 +-
 .../collectionFreeForm/FormatShapePane.scss        |   4 +-
 .../collectionFreeForm/FormatShapePane.tsx         | 333 ++++++++++++++-------
 .../collectionFreeForm/InkOptionsMenu.tsx          | 128 ++------
 src/client/views/nodes/ColorBox.tsx                |  45 +--
 8 files changed, 347 insertions(+), 255 deletions(-)

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

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 31b2a56e6..69256ce67 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -123,6 +123,12 @@ export namespace InteractionUtils {
         } else {
             pts = points;
         }
+        if (isNaN(scalex)) {
+            scalex = 1;
+        }
+        if (isNaN(scaley)) {
+            scaley = 1;
+        }
         const strpts = pts.reduce((acc: string, pt: { X: number, Y: number }) => acc +
             `${(pt.X - left - width / 2) * scalex + width / 2},
          ${(pt.Y - top - width / 2) * scaley + width / 2} `, "");
@@ -141,7 +147,6 @@ export namespace InteractionUtils {
                     <polygon points={`${2 - arrowDim} ${-Math.max(1, arrowDim / 2)}, ${2 - arrowDim} ${Math.max(1, arrowDim / 2)}, 3 0`} />
                 </marker>}
             </defs>}
-
             <polyline
                 points={strpts}
                 style={{
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 444d2fe50..baf9865fe 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -23,6 +23,8 @@ import { SnappingManager } from '../util/SnappingManager';
 import { HtmlField } from '../../fields/HtmlField';
 import { InkData, InkField, InkTool } from "../../fields/InkField";
 import { Tooltip } from '@material-ui/core';
+import InkOptionsMenu from './collections/collectionFreeForm/InkOptionsMenu';
+import FormatShapePane from './collections/collectionFreeForm/FormatShapePane';
 
 library.add(faCaretUp);
 library.add(faObjectGroup);
@@ -59,6 +61,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     private _prevX = 0;
     private _prevY = 0;
     private _centerPoints: { X: number, Y: number }[] = [];
+    private _inkDocs: { x: number, y: number, width: number, height: number }[] = [];
 
     @observable private _accumulatedTitle = "";
     @observable private _titleControlString: string = "#title";
@@ -309,8 +312,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     const right = Math.max(...xs);
                     const bottom = Math.max(...ys);
 
-                    doc._height = (bottom - top) * element.props.ScreenToLocalTransform().Scale;
-                    doc._width = (right - left) * element.props.ScreenToLocalTransform().Scale;
+                    // doc._height = (bottom - top) * element.props.ScreenToLocalTransform().Scale;
+                    // doc._width = (right - left) * element.props.ScreenToLocalTransform().Scale;
+                    doc._height = (bottom - top);
+                    doc._width = (right - left);
 
                 }
                 index++;
@@ -329,6 +334,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     _dragHeights = new Map<Doc, number>();
     @action
     onPointerDown = (e: React.PointerEvent): void => {
+
+        this._inkDocs = [];
+        SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => {
+            const doc = Document(element.rootDoc);
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height) {
+                this._inkDocs.push({ x: doc.x, y: doc.y, width: doc._width, height: doc._height });
+            }
+
+        }));
+
         setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, (e) => { });
         if (e.button === 0) {
             this._resizeHdlId = e.currentTarget.id;
@@ -501,6 +516,28 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         (e.button === 0) && this._resizeUndo?.end();
         this._resizeUndo = undefined;
         SnappingManager.clearSnapLines();
+
+
+        //need to change points for resize, or else rotation/control points will fail.
+        SelectionManager.SelectedDocuments().forEach(action((element: DocumentView, index) => {
+            const doc = Document(element.rootDoc);
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
+                console.log(doc.x, doc.y, doc._height, doc._width);
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
+                    const newPoints: { X: number, Y: number }[] = [];
+                    for (var i = 0; i < ink.length; i++) {
+                        // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
+                        const newX = (doc.x - this._inkDocs[index].x) + (ink[i].X * doc._width) / this._inkDocs[index].width;
+                        const newY = (doc.y - this._inkDocs[index].y) + (ink[i].Y * doc._height) / this._inkDocs[index].height;
+                        newPoints.push({ X: newX, Y: newY });
+                    }
+                    doc.data = new InkField(newPoints);
+
+                }
+
+            }
+        }));
     }
 
     @computed
@@ -591,6 +628,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         if (bounds.y > bounds.b) {
             bounds.y = bounds.b - (this._resizeBorderWidth + this._linkBoxHeight + this._titleHeight);
         }
+        var offset = 0;
+        //make offset larger for ink to edit points
+        if (seldoc.rootDoc.type === DocumentType.INK) {
+            offset = 20;
+        }
         return (<div className="documentDecorations" style={{ background: darkScheme }} >
             <div className="documentDecorations-background" style={{
                 width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
@@ -603,10 +645,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             </div>
             {bounds.r - bounds.x < 15 && bounds.b - bounds.y < 15 ? (null) : <>
                 <div className="documentDecorations-container" key="container" ref={this.setTextBar} style={{
-                    width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
-                    height: (bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight) + "px",
-                    left: bounds.x - this._resizeBorderWidth / 2,
-                    top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
+                    width: (bounds.r - bounds.x + this._resizeBorderWidth + offset) + "px",
+                    height: (bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight + offset) + "px",
+                    left: bounds.x - this._resizeBorderWidth / 2 - offset / 2,
+                    top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight - offset / 2,
                 }}>
                     {maximizeIcon}
                     {titleArea}
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 2eec8ed6a..9faf5e6a5 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -668,6 +668,10 @@ export default class GestureOverlay extends Touchable {
     }
 
     makePolygon = (shape: string, gesture: boolean) => {
+        //take off gesture recognition for now
+        if (gesture) {
+            return false;
+        }
         const xs = this._points.map(p => p.X);
         const ys = this._points.map(p => p.Y);
         var right = Math.max(...xs);
@@ -796,19 +800,7 @@ export default class GestureOverlay extends Touchable {
                 break;
             case "line":
                 this._points.push({ X: left, Y: top });
-
-                this._points.push({ X: left, Y: top });
-
-                // this._points.push({ X: right, Y: bottom });
-                // this._points.push({ X: right, Y: bottom });
-                // this._points.push({ X: right, Y: bottom });
-                // this._points.push({ X: right, Y: bottom });
-
-
-                this._points.push({ X: right, Y: bottom });
                 this._points.push({ X: right, Y: bottom });
-
-                // this._points.push({ X: right, Y: bottom - 1 });
                 break;
             case "arrow":
                 const x1 = left;
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 22c89b6da..b03d8e79b 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -105,9 +105,9 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
             StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "transparent"),
             "none", "none", "0", scaleX, scaleY, "", this.props.active() ? "visiblepainted" : "none", false, true);
 
-        const controlPoints: { X: number, Y: number, I: number }[] = [];
-        const handlePoints: { X: number, Y: number, I: number, dot1: number, dot2: number }[] = [];
-        const handleLine: { X1: number, Y1: number, X2: number, Y2: number, X3: number, Y3: number, dot1: number, dot2: number }[] = [];
+        var controlPoints: { X: number, Y: number, I: number }[] = [];
+        var handlePoints: { X: number, Y: number, I: number, dot1: number, dot2: number }[] = [];
+        var handleLine: { X1: number, Y1: number, X2: number, Y2: number, X3: number, Y3: number, dot1: number, dot2: number }[] = [];
         if (data.length >= 4) {
             for (var i = 0; i <= data.length - 4; i += 4) {
                 controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
@@ -125,6 +125,15 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
             handleLine.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 });
 
 
+        }
+        if (data.length <= 4) {
+            handlePoints = [];
+            handleLine = [];
+            controlPoints = [];
+            for (var i = 0; i < data.length; i++) {
+                controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
+            }
+
         }
         const dotsize = String(Math.min(width * scaleX, height * scaleY) / 40);
 
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.scss b/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
index 88876471c..010beb836 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
@@ -24,11 +24,13 @@
 
 .formatShapePane-inputBtn {
     width: inherit;
-     position: absolute;
+    position: absolute;
 }
 
 .sketch-picker {
     background: #323232;
+    width: 160px !important;
+    height: 80% !important;
 
     .flexbox-fit {
         background: #323232;
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
index a2dc241c0..a47430453 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
@@ -12,6 +12,8 @@ import { SelectionManager } from "../../../util/SelectionManager";
 import AntimodeMenu from "../../AntimodeMenu";
 import "./FormatShapePane.scss";
 import { undoBatch } from "../../../util/UndoManager";
+import { ColorState, SketchPicker } from 'react-color';
+import { DocumentView } from "../../../views/nodes/DocumentView"
 
 @observer
 export default class FormatShapePane extends AntimodeMenu {
@@ -20,12 +22,11 @@ export default class FormatShapePane extends AntimodeMenu {
     private _lastFill = "#D0021B";
     private _lastLine = "#D0021B";
     private _lastDash = "2";
-    private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF"];
     private _mode = ["fill-drip", "ruler-combined"];
 
-    @observable private _subOpen = [false, false, false, false];
+    @observable private _subOpen = [false, false];
     @observable private _currMode = "fill-drip";
-    @observable private _lock = false;
+    @observable _lock = false;
     @observable private _fillBtn = false;
     @observable private _lineBtn = false;
     @observable _controlBtn = false;
@@ -104,19 +105,58 @@ export default class FormatShapePane extends AntimodeMenu {
     upDownButtons = (dirs: string, field: string) => {
         switch (field) {
             case "rot": this.rotate((dirs === "up" ? .1 : -.1)); break;
+            // case "rot": this.selectedInk?.forEach(i => i.rootDoc.rotation = NumCast(i.rootDoc.rotation) + (dirs === "up" ? 0.1 : -0.1)); break;
             case "Xps": this.selectedInk?.forEach(i => i.rootDoc.x = NumCast(i.rootDoc.x) + (dirs === "up" ? 10 : -10)); break;
             case "Yps": this.selectedInk?.forEach(i => i.rootDoc.y = NumCast(i.rootDoc.y) + (dirs === "up" ? 10 : -10)); break;
             case "stk": this.selectedInk?.forEach(i => i.rootDoc.strokeWidth = NumCast(i.rootDoc.strokeWidth) + (dirs === "up" ? .1 : -.1)); break;
             case "wid": this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
+                //redraw points
                 const oldWidth = NumCast(i.rootDoc._width);
+                const oldHeight = NumCast(i.rootDoc._height);
+                const oldX = NumCast(i.rootDoc.x);
+                const oldY = NumCast(i.rootDoc.y);
                 i.rootDoc._width = oldWidth + (dirs === "up" ? 10 : - 10);
                 this._lock && (i.rootDoc._height = (i.rootDoc._width / oldWidth * NumCast(i.rootDoc._height)));
+                const doc = Document(i.rootDoc);
+                if (doc.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
+                    console.log(doc.x, doc.y, doc._height, doc._width);
+                    const ink = Cast(doc.data, InkField)?.inkData;
+                    console.log(ink);
+                    if (ink) {
+                        const newPoints: { X: number, Y: number }[] = [];
+                        for (var j = 0; j < ink.length; j++) {
+                            // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
+                            const newX = (doc.x - oldX) + (ink[j].X * doc._width) / oldWidth;
+                            const newY = (doc.y - oldY) + (ink[j].Y * doc._height) / oldHeight;
+                            newPoints.push({ X: newX, Y: newY });
+                        }
+                        doc.data = new InkField(newPoints);
+                    }
+                }
             });
                 break;
             case "hgt": this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
+                const oldWidth = NumCast(i.rootDoc._width);
                 const oldHeight = NumCast(i.rootDoc._height);
-                i.rootDoc._height = oldHeight + (dirs === "up" ? 10 : - 10);
+                const oldX = NumCast(i.rootDoc.x);
+                const oldY = NumCast(i.rootDoc.y); i.rootDoc._height = oldHeight + (dirs === "up" ? 10 : - 10);
                 this._lock && (i.rootDoc._width = (i.rootDoc._height / oldHeight * NumCast(i.rootDoc._width)));
+                const doc = Document(i.rootDoc);
+                if (doc.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
+                    console.log(doc.x, doc.y, doc._height, doc._width);
+                    const ink = Cast(doc.data, InkField)?.inkData;
+                    console.log(ink);
+                    if (ink) {
+                        const newPoints: { X: number, Y: number }[] = [];
+                        for (var j = 0; j < ink.length; j++) {
+                            // (new x — oldx) + (oldxpoint * newWidt)/oldWidth 
+                            const newX = (doc.x - oldX) + (ink[j].X * doc._width) / oldWidth;
+                            const newY = (doc.y - oldY) + (ink[j].Y * doc._height) / oldHeight;
+                            newPoints.push({ X: newX, Y: newY });
+                        }
+                        doc.data = new InkField(newPoints);
+                    }
+                }
             });
                 break;
         }
@@ -124,12 +164,11 @@ export default class FormatShapePane extends AntimodeMenu {
 
     @undoBatch
     @action
-    rotate = (degrees: number) => {
-        this.selectedInk?.forEach(action(inkView => {
+    rotate = (angle: number) => {
+        const _centerPoints: { X: number, Y: number }[] = [];
+        SelectionManager.SelectedDocuments().forEach(action(inkView => {
             const doc = Document(inkView.rootDoc);
             if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
-                const angle = Number(degrees) - Number(doc.rotation);
-                doc.rotation = Number(degrees);
                 const ink = Cast(doc.data, InkField)?.inkData;
                 if (ink) {
                     const xs = ink.map(p => p.X);
@@ -138,25 +177,37 @@ export default class FormatShapePane extends AntimodeMenu {
                     const top = Math.min(...ys);
                     const right = Math.max(...xs);
                     const bottom = Math.max(...ys);
-                    const _centerPoints: { X: number, Y: number }[] = [];
                     _centerPoints.push({ X: left, Y: top });
+                }
+            }
+        }));
+
+        var index = 0;
+        SelectionManager.SelectedDocuments().forEach(action(inkView => {
+            const doc = Document(inkView.rootDoc);
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+                doc.rotation = Number(doc.rotation) + Number(angle);
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
 
                     const newPoints: { X: number, Y: number }[] = [];
                     for (var i = 0; i < ink.length; i++) {
-                        const newX = Math.cos(angle) * (ink[i].X - _centerPoints[0].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[0].Y) + _centerPoints[0].X;
-                        const newY = Math.sin(angle) * (ink[i].X - _centerPoints[0].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[0].Y) + _centerPoints[0].Y;
+                        const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X;
+                        const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y;
                         newPoints.push({ X: newX, Y: newY });
                     }
                     doc.data = new InkField(newPoints);
-                    const xs2 = newPoints.map(p => p.X);
-                    const ys2 = newPoints.map(p => p.Y);
-                    const left2 = Math.min(...xs2);
-                    const top2 = Math.min(...ys2);
-                    const right2 = Math.max(...xs2);
-                    const bottom2 = Math.max(...ys2);
-                    doc._height = (bottom2 - top2) * inkView.props.ScreenToLocalTransform().Scale;
-                    doc._width = (right2 - left2) * inkView.props.ScreenToLocalTransform().Scale;
+                    const xs = newPoints.map(p => p.X);
+                    const ys = newPoints.map(p => p.Y);
+                    const left = Math.min(...xs);
+                    const top = Math.min(...ys);
+                    const right = Math.max(...xs);
+                    const bottom = Math.max(...ys);
+
+                    doc._height = (bottom - top);
+                    doc._width = (right - left);
                 }
+                index++;
             }
         }));
     }
@@ -180,8 +231,10 @@ export default class FormatShapePane extends AntimodeMenu {
                                 (order === 0 && controlNum !== 0 && i === controlNum - 1) ||
                                 (order === 3 && i === controlNum - 1) ||
                                 (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 1) ||
-                                (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2)) {
-                                newPoints.push({ X: ink[i].X - (xDiff), Y: ink[i].Y - (yDiff) });
+                                (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2)
+                                || ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1))
+                            ) {
+                                newPoints.push({ X: ink[i].X - (xDiff * inkView.props.ScreenToLocalTransform().Scale), Y: ink[i].Y - (yDiff * inkView.props.ScreenToLocalTransform().Scale) });
                             }
                             else {
                                 newPoints.push({ X: ink[i].X, Y: ink[i].Y });
@@ -189,6 +242,10 @@ export default class FormatShapePane extends AntimodeMenu {
                         }
                         const oldx = doc.x;
                         const oldy = doc.y;
+                        const xs = newPoints.map(p => p.X);
+                        const ys = newPoints.map(p => p.Y);
+                        const left = Math.min(...xs);
+                        const top = Math.min(...ys);
                         doc.data = new InkField(newPoints);
                         const xs2 = newPoints.map(p => p.X);
                         const ys2 = newPoints.map(p => p.Y);
@@ -196,141 +253,202 @@ export default class FormatShapePane extends AntimodeMenu {
                         const top2 = Math.min(...ys2);
                         const right2 = Math.max(...xs2);
                         const bottom2 = Math.max(...ys2);
-                        doc._height = (bottom2 - top2) * inkView.props.ScreenToLocalTransform().Scale;
-                        doc._width = (right2 - left2) * inkView.props.ScreenToLocalTransform().Scale;
-                        doc.x = oldx;
-                        doc.y = oldy;
+                        doc._height = (bottom2 - top2);
+                        doc._width = (right2 - left2);
+
+                        doc.x = oldx - (left - left2);
+                        doc.y = oldy - (top - top2);
                     }
                 }
             }
         }));
     }
 
+    @undoBatch
+    @action
+    switchStk = (color: ColorState) => {
+        const val = String(color.hex);
+        this.colorStk = val;
+        return true;
+    }
 
-    colorPicker(setter: (color: string) => {}) {
-        return <div className="btn-group-palette" key="colorpicker" >
-            {this._palette.map(color =>
-                <button className="antimodeMenu-button" key={color} onPointerDown={undoBatch(action(() => setter(color)))} style={{ zIndex: 1001, position: "relative" }}>
-                    <div className="color-previewII" style={{ backgroundColor: color }} />
-                </button>)}
+    @undoBatch
+    @action
+    switchFil = (color: ColorState) => {
+        const val = String(color.hex);
+        this.colorFil = val;
+        return true;
+    }
+
+
+    colorPicker(setter: (color: string) => {}, type: string) {
+        return <div className="btn-group-palette" key="colorpicker" style={{ width: 160, margin: 10 }}>
+            <SketchPicker onChange={type === "stk" ? this.switchStk : this.switchFil} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
+                color={type === "stk" ? this.colorStk : this.colorFil} />
         </div>;
     }
     inputBox = (key: string, value: any, setter: (val: string) => {}) => {
         return <>
-            <input style={{ color: "black", width: 80, position: "absolute", right: 20 }}
+            <input style={{ color: "black", width: 40, position: "absolute", right: 20 }}
                 type="text" value={value}
-                onChange={e => setter(e.target.value)}
+                onChange={undoBatch(action((e) => setter(e.target.value)))}
                 autoFocus />
-            <button className="antiMenu-Buttonup" key="up" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))}>
+            <button className="antiMenu-Buttonup" key="up1" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))}>
                 ˄
             </button>
             <br />
-            <button className="antiMenu-Buttonup" key="down" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} style={{ marginTop: -8 }}>
+            <button className="antiMenu-Buttonup" key="down1" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} style={{ marginTop: -8 }}>
                 ˅
             </button>
         </>;
     }
 
+    inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => {
+        return <>
+            {title1}
+            <p style={{ marginTop: -20, right: 70, position: "absolute" }}>{title2}</p>
+
+            <input style={{ color: "black", width: 40, position: "absolute", right: 130 }}
+                type="text" value={value}
+                onChange={e => setter(e.target.value)}
+                autoFocus />
+            <button className="antiMenu-Buttonup" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))} style={{ right: 110 }}>
+                ˄
+        </button>
+            <button className="antiMenu-Buttonup" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} style={{ marginTop: 12, right: 110 }}>
+                ˅
+        </button>
+            {title2 === "" ? "" : <>
+                <input style={{ color: "black", width: 40, position: "absolute", right: 20 }}
+                    type="text" value={value2}
+                    onChange={e => setter2(e.target.value)}
+                    autoFocus />
+                <button className="antiMenu-Buttonup" key="up3" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key2)))}>
+                    ˄
+      </button>
+                <br />
+                <button className="antiMenu-Buttonup" key="down3" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key2)))} style={{ marginTop: -8 }}>
+                    ˅
+      </button></>}
+        </>;
+    }
+
+
     colorButton(value: string, setter: () => {}) {
         return <>
-            <button className="antimodeMenu-button" key="fill" onPointerDown={undoBatch(action(e => setter()))} style={{ position: "absolute", right: 80 }}>
-                <FontAwesomeIcon icon="fill-drip" size="lg" />
-                <div className="color-previewI" style={{ backgroundColor: value ?? "121212" }} />
+            <button className="antimodeMenu-button" key="fill" onPointerDown={undoBatch(action(e => setter()))} style={{ position: "relative", marginTop: -5 }}>
+                <div className="color-previewII" style={{ backgroundColor: value ?? "121212" }} />
+                {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -23, position: "fixed" }}>☒</p> : ""}
             </button>
-            <br /> <br />
         </>;
     }
 
     controlPointsButton() {
         return <>
-            <button className="antimodeMenu-button" key="fill" onPointerDown={action(() => this._controlBtn = this._controlBtn ? false : true)} style={{ position: "absolute", right: 80, backgroundColor: this._controlBtn ? "black" : "" }}>
+            <button className="antimodeMenu-button" title="Edit points" key="fill" onPointerDown={action(() => this._controlBtn = this._controlBtn ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._controlBtn ? "black" : "" }}>
                 <FontAwesomeIcon icon="bezier-curve" size="lg" />
             </button>
+            <button className="antimodeMenu-button" title="Lock ratio" key="fill" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._lock ? "black" : "" }}>
+                <FontAwesomeIcon icon="lock" size="lg" />
+
+            </button>
+            <button className="antimodeMenu-button" key="fill" title="Rotate 90˚" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "relative", marginTop: 10, fontSize: 15 }}>
+                ⟲
+            </button>
+            <br /> <br />
+        </>;
+    }
+
+    lockRatioButton() {
+        return <>
+            <button className="antimodeMenu-button" key="fill" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "absolute", right: 80, backgroundColor: this._lock ? "black" : "" }}>
+                {/* <FontAwesomeIcon icon="bezier-curve" size="lg" /> */}
+                <FontAwesomeIcon icon="lock" size="lg" />
+
+            </button>
+            <br /> <br />
+        </>;
+    }
+
+    rotate90Button() {
+        return <>
+            <button className="antimodeMenu-button" key="fill" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "absolute", right: 80, }}>
+                {/* <FontAwesomeIcon icon="bezier-curve" size="lg" /> */}
+                ⟲
+
+            </button>
             <br /> <br />
         </>;
     }
-    @computed get fillButton() { return this.colorButton(this.colorFil, () => this._fillBtn = !this._fillBtn); }
-    @computed get lineButton() { return this.colorButton(this.colorStk, () => this._lineBtn = !this._lineBtn); }
+    @computed get fillButton() { return this.colorButton(this.colorFil, () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
+    @computed get lineButton() { return this.colorButton(this.colorStk, () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
 
-    @computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color); }
-    @computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color); }
+    @computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); }
+    @computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); }
 
     @computed get stkInput() { return this.inputBox("stk", this.widthStk, (val: string) => this.widthStk = val); }
-    @computed get hgtInput() { return this.inputBox("hgt", this.shapeHgt, (val: string) => this.shapeHgt = val); }
+    @computed get dashInput() { return this.inputBox("dsh", this.widthStk, (val: string) => this.widthStk = val); }
+
+    @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => this.shapeHgt = val, "H:", "wid", this.shapeWid, (val: string) => this.shapeWid = val, "W:"); }
     @computed get widInput() { return this.inputBox("wid", this.shapeWid, (val: string) => this.shapeWid = val); }
-    @computed get rotInput() { return this.inputBox("rot", this.shapeRot, (val: string) => this.shapeRot = val); }
-    @computed get XpsInput() { return this.inputBox("Xps", this.shapeXps, (val: string) => this.shapeXps = val); }
+    @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); }
+
+    @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
     @computed get YpsInput() { return this.inputBox("Yps", this.shapeYps, (val: string) => this.shapeYps = val); }
 
     @computed get controlPoints() { return this.controlPointsButton(); }
+    @computed get lockRatio() { return this.lockRatioButton(); }
+    @computed get rotate90() { return this.rotate90Button(); }
 
-    @computed get propertyGroupItems() {
-        const fillCheck = <div key="fill" style={{ display: this._subOpen[0] ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.unFilled} onChange={undoBatch(action(() => this.unFilled = true))} />
-                No Fill
-            <br />
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.solidFil} onChange={undoBatch(action(() => this.solidFil = true))} />
-                Solid Fill
-            <br /> <br />
-            {this.solidFil ? "Color" : ""}
-            {this.solidFil ? this.fillButton : ""}
-            {this._fillBtn && this.solidFil ? this.fillPicker : ""}
-        </div>;
 
-        const markers = <>
-            <input key="markHead" className="formatShapePane-inputBtn" type="checkbox" checked={this.markHead !== ""} onChange={undoBatch(action(() => this.markHead = this.markHead ? "" : "arrow"))} />
-                Arrow Head
-            <br />
-            <input key="markTail" className="formatShapePane-inputBtn" type="checkbox" checked={this.markTail !== ""} onChange={undoBatch(action(() => this.markTail = this.markTail ? "" : "arrow"))} />
-                Arrow End
-            <br />
-        </>;
+    @computed get propertyGroupItems() {
+        const fillCheck = <div key="fill" style={{ display: (this._subOpen[0] && this.selectedInk && this.selectedInk.length >= 1) ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
+            Fill:
+            {this.fillButton}
+            <div style={{ float: "left", width: 100 }} >
+                Stroke:
+            {this.lineButton}
+            </div>
 
-        const lineCheck = <div key="lineCheck" style={{ display: this._subOpen[1] ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.unStrokd} onChange={undoBatch(action(() => this.unStrokd = true))} />
-                No Line
-            <br />
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.solidStk} onChange={undoBatch(action(() => this.solidStk = true))} />
-                Solid Line
-            <br />
-            <input className="formatShapePane-inputBtn" type="radio" checked={this.dashdStk ? true : false} onChange={undoBatch(action(() => this.dashdStk = "2"))} />
-                Dash Line
-            <br />
-            <br />
-            {(this.solidStk || this.dashdStk) ? "Color" : ""}
-            {(this.solidStk || this.dashdStk) ? this.lineButton : ""}
-            {(this.solidStk || this.dashdStk) && this._lineBtn ? this.linePicker : ""}
-            <br />
+            {this._fillBtn ? this.fillPicker : ""}
+            {this._lineBtn ? this.linePicker : ""}
+            {this._fillBtn || this._lineBtn ? "" : <br />}
             {(this.solidStk || this.dashdStk) ? "Width" : ""}
             {(this.solidStk || this.dashdStk) ? this.stkInput : ""}
-            {(this.solidStk || this.dashdStk) ? <input type="range" defaultValue={Number(this.widthStk)} min={1} max={100} onChange={e => this.widthStk = e.target.value} /> : (null)}
-            <br /> <br />
-            {(this.solidStk || this.dashdStk) ? markers : ""}
-        </div>;
 
-        const sizeCheck = <div key="sizeCheck" style={{ display: this._subOpen[2] ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
-            Height {this.hgtInput}
-            <br /> <br />
-                Width {this.widInput}
-            <br /> <br />
-            <input className="formatShapePane-inputBtn" style={{ right: 0 }} type="checkbox" checked={this._lock} onChange={undoBatch(action(() => this._lock = !this._lock))} />
-                Lock Ratio
-            <br />  <br />
-                Rotation {this.rotInput}
-            <br /> <br />
-                Edit Points {this.controlPoints}
-        </div>;
 
-        const positionCheck = <div key="posCheck" style={{ display: this._subOpen[3] ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
-            Horizontal {this.XpsInput}
-            <br /> <br />
-            Vertical {this.YpsInput}
-            <br /> <br />
+            {(this.solidStk || this.dashdStk) ? <input type="range" defaultValue={Number(this.widthStk)} min={1} max={100} onChange={undoBatch(action((e) => this.widthStk = e.target.value))} /> : (null)}
+            <br />
+            {(this.solidStk || this.dashdStk) ? <>
+                <p style={{ position: "absolute", fontSize: 12 }}>Arrow Head</p>
+                <input key="markHead" className="formatShapePane-inputBtn" type="checkbox" checked={this.markHead !== ""} onChange={undoBatch(action(() => this.markHead = this.markHead ? "" : "arrow"))} style={{ position: "absolute", right: 110, width: 20 }} />
+                <p style={{ position: "absolute", fontSize: 12, right: 30 }}>Arrow End</p>
+                <input key="markTail" className="formatShapePane-inputBtn" type="checkbox" checked={this.markTail !== ""} onChange={undoBatch(action(() => this.markTail = this.markTail ? "" : "arrow"))} style={{ position: "absolute", right: 0, width: 20 }} />
+                <br />
+            </> : ""}
+            Dash:                <input key="markHead" className="formatShapePane-inputBtn" type="checkbox" checked={this.dashdStk === "2"} onChange={undoBatch(action(() => this.dashdStk = this.dashdStk === "2" ? "0" : "2"))} style={{ position: "absolute", right: 110, width: 20 }} />
+
+
+
         </div>;
 
-        const subMenus = this._currMode === "fill-drip" ? [`fill`, `line`] : [`size`, `position`];
-        const menuItems = this._currMode === "fill-drip" ? [fillCheck, lineCheck] : [sizeCheck, positionCheck];
-        const indexOffset = this._currMode === "fill-drip" ? 0 : 2;
+
+
+        const sizeCheck =
+
+            <div key="sizeCheck" style={{ display: (this._subOpen[1] && this.selectedInk && this.selectedInk.length >= 1) ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
+                {this.controlPoints}
+                {this.hgtInput}
+                {this.XpsInput}
+                {this.rotInput}
+
+            </div>;
+
+
+        const subMenus = this._currMode === "fill-drip" ? [`Appearance`, 'Transform'] : [];
+        const menuItems = this._currMode === "fill-drip" ? [fillCheck, sizeCheck] : [];
+        const indexOffset = 0;
+
         return <div className="antimodeMenu-sub" key="submenu" style={{ position: "absolute", width: "inherit", top: 60 }}>
             {subMenus.map((subMenu, i) =>
                 <div key={subMenu} style={{ width: "inherit" }}>
@@ -361,6 +479,7 @@ export default class FormatShapePane extends AntimodeMenu {
     }
 
     render() {
-        return this.getElementVert([this.closeBtn, this.propertyGroupBtn, this.propertyGroupItems]);
+        return this.getElementVert([this.closeBtn,
+        this.propertyGroupItems]);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 15707ad9e..80d1264ce 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -16,11 +16,11 @@ import { Document } from "../../../../fields/documentSchemas";
 import { DocumentType } from "../../../documents/DocumentTypes";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faSleigh, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, } from "@fortawesome/free-solid-svg-icons";
+import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faSleigh, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, faArrowRight, faArrowsAltH, faMinus, faCircle, faExclamationTriangle, faSquare, faLongArrowAltRight, faPenFancy, faCaretSquareRight, faAngleDoubleRight, } from "@fortawesome/free-solid-svg-icons";
 import { Cast, StrCast, BoolCast } from "../../../../fields/Types";
 import FormatShapePane from "./FormatShapePane";
 
-library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve);
+library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, faLongArrowAltRight, faArrowsAltH, faMinus, faCircle, faSquare, faSquare, faPenFancy, faAngleDoubleRight,);
 
 
 
@@ -30,18 +30,13 @@ export default class InkOptionsMenu extends AntimodeMenu {
 
     private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
     private _width = ["1", "5", "10", "100"];
-    // private _buttons = ["circle", "triangle", "rectangle", "arrow", "line"];
-    // private _icons = ["O", "∆", "ロ", "➜", "-"];
-    // private _buttons = ["circle", "triangle", "rectangle", "line", "noRec", "",];
-    // private _icons = ["O", "∆", "ロ", "⎯⎯⎯", "✖︎", " "];
-    //arrowStart and arrowEnd must match and defs must exist in Inking Stroke
-    // private _arrowStart = ["arrowStart", "arrowStart", "dot", "dot", "none"];
-    // private _arrowEnd = ["none", "arrowEnd", "none", "dot", "none"];
-    // private _arrowIcons = ["→", "↔︎", "•", "••", " "];
-    private _draw = ["⎯", "→", "↔︎", "∿", "↝", "↭", "ロ", "O", "∆"];
-    private _head = ["", "", "arrow", "", "", "arrow", "", "", ""];
-    private _end = ["", "arrow", "arrow", "", "arrow", "arrow", "", "", ""];
-    private _shape = ["line", "line", "line", "", "", "", "rectangle", "circle", "triangle"];
+    private _dotsize = [10, 20, 30, 40];
+    private _draw = ["∿", "⎯", "→", "↔︎", "ロ", "O"];
+    private _head = ["", "", "", "arrow", "", ""];
+    private _end = ["", "", "arrow", "arrow", "", ""];
+    private _shape = ["", "line", "line", "line", "rectangle", "circle"];
+    private _title = ["pen", "line", "line with arrow", "line with double arrows", "square", "circle",];
+    private _faName = ["pen-fancy", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"];
 
     @observable _shapesNum = this._shape.length;
     @observable _selected = this._shapesNum;
@@ -154,6 +149,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
                 return <button
                     className="antimodeMenu-button"
                     key={icon}
+                    title={this._title[i]}
                     onPointerDown={action(() => {
                         this._double = "";
 
@@ -202,50 +198,19 @@ export default class InkOptionsMenu extends AntimodeMenu {
 
                     })}
                     style={{ backgroundColor: i === this._selected ? "121212" : "", fontSize: "20" }}>
-                    {this._draw[i]}
+                    <FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" />
+
                 </button>;
             })}</div>;
         return drawButtons;
     }
 
-    // @computed get arrowPicker() {
-    //     var currIcon;
-    //     for (var i = 0; i < this._arrowStart.length; i++) {
-    //         if (this._arrowStart[i] === ActiveArrowStart() && this._arrowEnd[i] === ActiveArrowEnd()) {
-    //             currIcon = this._arrowIcons[i];
-    //             if (this._arrowIcons[i] === " ") {
-    //                 currIcon = "➤";
-    //             }
-    //         }
-    //     }
-    //     var arrowPicker = <button
-    //         className="antimodeMenu-button"
-    //         key="arrow"
-    //         onPointerDown={action(e => this._arrowBtn = !this._arrowBtn)}
-    //         style={{ backgroundColor: this._arrowBtn ? "121212" : "" }}>
-    //         {currIcon}
-    //     </button>;
-    //     if (this._arrowBtn) {
-    //         arrowPicker = <div className="btn2-group" key="arrows">
-    //             {arrowPicker}
-    //             {this._arrowStart.map((arrowStart, i) => {
-    //                 return <button
-    //                     className="antimodeMenu-button"
-    //                     key={arrowStart}
-    //                     onPointerDown={action(() => { SetActiveArrowStart(arrowStart); SetActiveArrowEnd(this._arrowEnd[i]); this.editProperties(arrowStart, "arrowStart"), this.editProperties(this._arrowEnd[i], "arrowEnd"); this._arrowBtn = false; })}
-    //                     style={{ backgroundColor: this._arrowBtn ? "121212" : "" }}>
-    //                     {this._arrowIcons[i]}
-    //                 </button>;
-    //             })}
-    //         </div>;
-    //     }
-    //     return arrowPicker;
-    // }
 
     @computed get widthPicker() {
         var widthPicker = <button
             className="antimodeMenu-button"
             key="width"
+            title="change width"
             onPointerDown={action(e => this._widthBtn = !this._widthBtn)}
             style={{ backgroundColor: this._widthBtn ? "121212" : "" }}>
             <FontAwesomeIcon icon="bars" size="lg" />
@@ -253,13 +218,13 @@ export default class InkOptionsMenu extends AntimodeMenu {
         if (this._widthBtn) {
             widthPicker = <div className="btn2-group" key="width">
                 {widthPicker}
-                {this._width.map(wid => {
+                {this._width.map((wid, i) => {
                     return <button
                         className="antimodeMenu-button"
                         key={wid}
                         onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; this.editProperties(wid, "width"); })}
-                        style={{ backgroundColor: this._widthBtn ? "121212" : "", zIndex: 1001 }}>
-                        {wid}
+                        style={{ backgroundColor: this._widthBtn ? "121212" : "", zIndex: 1001, fontSize: this._dotsize[i], padding: 0, textAlign: "center" }}>
+                        •
                     </button>;
                 })}
             </div>;
@@ -273,7 +238,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
         var colorPicker = <button
             className="antimodeMenu-button"
             key="color"
-            title="colorChanger"
+            title="Change Ink Color"
             onPointerDown={action(e => this._colorBtn = !this._colorBtn)}
             style={{ backgroundColor: this._colorBtn ? "121212" : "" }}>
             <FontAwesomeIcon icon="pen-nib" size="lg" />
@@ -302,7 +267,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
             title="toggle foramatting pane"
             onPointerDown={action(e => FormatShapePane.Instance.Pinned = !FormatShapePane.Instance.Pinned)}
             style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
-            <FontAwesomeIcon icon="chevron-right" size="lg" />
+            <FontAwesomeIcon icon="angle-double-right" size="lg" />
         </button>;
     }
 
@@ -310,7 +275,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
         var fillPicker = <button
             className="antimodeMenu-button"
             key="fill"
-            title="fillChanger"
+            title="Change Fill Color"
             onPointerDown={action(e => this._fillBtn = !this._fillBtn)}
             style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
             <FontAwesomeIcon icon="fill-drip" size="lg" />
@@ -334,48 +299,6 @@ export default class InkOptionsMenu extends AntimodeMenu {
         return fillPicker;
     }
 
-    // @computed get shapePicker() {
-    //     var currIcon;
-    //     if (GestureOverlay.Instance.InkShape === "") {
-    //         currIcon = <FontAwesomeIcon icon="shapes" size="lg" />;
-    //     } else {
-    //         for (var i = 0; i < this._icons.length; i++) {
-    //             if (GestureOverlay.Instance.InkShape === this._buttons[i]) {
-    //                 currIcon = this._icons[i];
-    //             }
-    //         }
-    //     }
-    //     var shapePicker = <button
-    //         className="antimodeMenu-button"
-    //         key="shape"
-    //         onPointerDown={action(e => this._shapeBtn = !this._shapeBtn)}
-    //         style={{ backgroundColor: this._shapeBtn ? "121212" : "" }}>
-    //         {currIcon}
-    //     </button>;
-    //     if (this._shapeBtn) {
-    //         shapePicker = <div className="btn2-group" key="shape">
-    //             {shapePicker}
-    //             {this._buttons.map((btn, i) => {
-    //                 var ttl = btn;
-    //                 if (btn === "") {
-    //                     ttl = "no shape";
-    //                 }
-    //                 if (btn === "noRec") {
-    //                     ttl = "disable shape recognition";
-    //                 }
-    //                 return <button
-    //                     className="antimodeMenu-button"
-    //                     title={`Draw ${btn}`}
-    //                     key={ttl}
-    //                     onPointerDown={action((e) => { GestureOverlay.Instance.InkShape = btn; this._shapeBtn = false; })}
-    //                     style={{ backgroundColor: this._shapeBtn ? "121212" : "", fontSize: "20" }}>
-    //                     {this._icons[i]}
-    //                 </button>;
-    //             })}
-    //         </div>;
-    //     }
-    //     return shapePicker;
-    // }
 
     @computed get bezierButton() {
         return <button
@@ -403,18 +326,15 @@ export default class InkOptionsMenu extends AntimodeMenu {
 
     render() {
         const buttons = [
-            // <button className="antimodeMenu-button" title="Drag" key="drag" onPointerDown={e => this.dragStart(e)}>
-            //     <FontAwesomeIcon icon="arrows-alt" size="lg" />
-            // </button>,
-            // this.shapePicker,
-            // this.bezierButton,
+
+            this.drawButtons,
             this.widthPicker,
             this.colorPicker,
             this.fillPicker,
-            this.drawButtons,
+
+
             this.formatPane,
-            // this.arrowPicker,
-            // this.dashButton,
+
             <button className="antimodeMenu-button" key="pin menu" title="Pin menu" onClick={this.toggleMenuPin} style={{ backgroundColor: this.Pinned ? "#121212" : "", display: this.collapsed ? "none" : undefined }}>
                 <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} />
             </button>
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 57028b0ca..b186d9ffc 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -54,27 +54,30 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument
     }
     render() {
         const selDoc = SelectionManager.SelectedDocuments()?.[0]?.rootDoc;
-        return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`}
-            onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}
-            style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
+        // return <div className={`colorBox-container${this.active() ? "-interactive" : ""}`}
+        //     onPointerDown={e => e.button === 0 && !e.ctrlKey && e.stopPropagation()}
+        //     style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
 
-            <SketchPicker onChange={ColorBox.switchColor} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
-                color={StrCast(ActiveInkPen()?.backgroundColor,
-                    StrCast(selDoc?._backgroundColor, StrCast(selDoc?.backgroundColor, "black")))} />
-            <div style={{ display: "grid", gridTemplateColumns: "20% 80%", paddingTop: "10px" }}>
-                <div> {ActiveInkWidth() ?? 2}</div>
-                <input type="range" defaultValue={ActiveInkWidth() ?? 2} min={1} max={100} onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                    SetActiveInkWidth(e.target.value);
-                    SelectionManager.SelectedDocuments().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.strokeWidth = Number(e.target.value));
-                }} />
-                <div> {ActiveInkBezierApprox() ?? 2}</div>
-                <input type="range" defaultValue={ActiveInkBezierApprox() ?? 2} min={0} max={300} onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
-                    SetActiveBezierApprox(e.target.value);
-                    SelectionManager.SelectedDocuments().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.strokeBezier = e.target.value);
-                }} />
-                <br />
-                <br />
-            </div>
-        </div>;
+        //     <SketchPicker onChange={ColorBox.switchColor} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
+        //         color={StrCast(ActiveInkPen()?.backgroundColor,
+        //             StrCast(selDoc?._backgroundColor, StrCast(selDoc?.backgroundColor, "black")))} />
+
+        //     <div style={{ display: "grid", gridTemplateColumns: "20% 80%", paddingTop: "10px" }}>
+        //         <div> {ActiveInkWidth() ?? 2}</div>
+        //         <input type="range" defaultValue={ActiveInkWidth() ?? 2} min={1} max={100} onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+        //             SetActiveInkWidth(e.target.value);
+        //             SelectionManager.SelectedDocuments().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.strokeWidth = Number(e.target.value));
+        //         }} />
+        //         <div> {ActiveInkBezierApprox() ?? 2}</div>
+        //         <input type="range" defaultValue={ActiveInkBezierApprox() ?? 2} min={0} max={300} onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+        //             SetActiveBezierApprox(e.target.value);
+        //             SelectionManager.SelectedDocuments().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.strokeBezier = e.target.value);
+        //         }} />
+        //         <br />
+        //         <br />
+        //     </div>
+        // </div>
+        //     ;
+        return <></>;
     }
 }
-- 
cgit v1.2.3-70-g09d2


From 622ba99eff99f9af2e03c3a5f8a47e9ce95cdf7e Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 27 Jul 2020 23:46:22 -0400
Subject: removed pdf menu pin button.  tried to improve performance by
 computin links in document view.

---
 src/client/views/DocumentButtonBar.tsx         |  4 ++--
 src/client/views/DocumentDecorations.tsx       |  2 +-
 src/client/views/nodes/DocumentLinksButton.tsx | 24 +++++++++++++-----------
 src/client/views/nodes/DocumentView.tsx        | 15 +++++++++------
 src/client/views/pdf/PDFMenu.tsx               |  7 -------
 src/fields/documentSchemas.ts                  |  1 +
 6 files changed, 26 insertions(+), 27 deletions(-)

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

diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index c99034d81..6b85616c2 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -276,10 +276,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
         const considerPush = isText && this.considerGoogleDocsPush;
         return <div className="documentButtonBar">
             <div className="documentButtonBar-button">
-                <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} StartLink={true} />
+                <DocumentLinksButton links={this.view0.allLinks} View={this.view0} AlwaysOn={true} InMenu={true} StartLink={true} />
             </div>
             {DocumentLinksButton.StartLink ? <div className="documentButtonBar-button">
-                <DocumentLinksButton View={this.view0} AlwaysOn={true} InMenu={true} StartLink={false} />
+                <DocumentLinksButton links={this.view0.allLinks} View={this.view0} AlwaysOn={true} InMenu={true} StartLink={false} />
             </div> : null}
             <div className="documentButtonBar-button">
                 {this.templateButton}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9a4df926c..4257ec3c9 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -88,7 +88,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
             var [sptX, sptY] = transform.transformPoint(0, 0);
             let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
-            if (documentView.props.Document.type === DocumentType.LINK) {
+            if (StrCast(Doc.Layout(documentView.props.Document).layout).includes("LinkAnchorBox")) {
                 const docuBox = documentView.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
                 if (docuBox.length) {
                     const rect = docuBox[0].getBoundingClientRect();
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index c9d23ff3a..ddfa77967 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -1,19 +1,19 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from "@material-ui/core";
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../fields/Doc";
-import { emptyFunction, setupMoveUpEvents, returnFalse } from "../../../Utils";
+import { Doc } from "../../../fields/Doc";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
+import { DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
-import { UndoManager, undoBatch } from "../../util/UndoManager";
+import { LinkManager } from "../../util/LinkManager";
+import { undoBatch, UndoManager } from "../../util/UndoManager";
 import './DocumentLinksButton.scss';
 import { DocumentView } from "./DocumentView";
-import React = require("react");
-import { DocUtils } from "../../documents/Documents";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { LinkDocPreview } from "./LinkDocPreview";
-import { TaskCompletionBox } from "./TaskCompletedBox";
 import { LinkDescriptionPopup } from "./LinkDescriptionPopup";
-import { LinkManager } from "../../util/LinkManager";
-import { Tooltip } from "@material-ui/core";
+import { TaskCompletionBox } from "./TaskCompletedBox";
+import React = require("react");
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -24,6 +24,7 @@ interface DocumentLinksButtonProps {
     AlwaysOn?: boolean;
     InMenu?: boolean;
     StartLink?: boolean;
+    links: Doc[];
 }
 @observer
 export class DocumentLinksButton extends React.Component<DocumentLinksButtonProps, {}> {
@@ -158,7 +159,8 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
 
     @computed
     get linkButton() {
-        const links = DocListCast(this.props.View.props.Document.links);
+        TraceMobx();
+        const links = this.props.links;
 
         const menuTitle = this.props.StartLink ? "Drag or tap to start link" : "Tap to complete link";
         const buttonTitle = "Tap to view links";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c6c21a507..3b4dc3741 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -332,8 +332,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 const alias = Doc.MakeAlias(this.props.Document);
                 DocUtils.makeCustomViewClicked(alias, undefined, "onClick");
                 this.props.addDocTab(alias, "onRight");
-            } else if (this.props.Document.links && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
-                DocListCast(this.props.Document.links).length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
+            } else if (this.allLinks && this.Document.isLinkButton && !e.shiftKey && !e.ctrlKey) {
+                this.allLinks.length && this.followLinkClick(e.altKey, e.ctrlKey, e.shiftKey);
             } else {
                 if ((this.layoutDoc.onDragStart || (this.props.Document.rootDocument)) && !(e.ctrlKey || e.button > 0)) {  // onDragStart implies a button doc that we don't want to select when clicking.   RootDocument & isTEmplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
                     stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
@@ -683,7 +683,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @undoBatch
     @action
     makeIntoPortal = async () => {
-        const portalLink = DocListCast(this.Document.links).find(d => d.anchor1 === this.props.Document);
+        const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document);
         if (!portalLink) {
             const portal = Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), title: StrCast(this.props.Document.title) + ".portal" });
             DocUtils.MakeLink({ doc: this.props.Document }, { doc: portal }, "portal to");
@@ -1038,6 +1038,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
     }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
+    @computed.struct get linkOffset() { return [-15, 0]; }
     @computed get contents() {
         TraceMobx();
         return (<div style={{ position: "absolute", width: "100%", height: "100%" }}>
@@ -1081,7 +1082,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors}
             {/* {this.allAnchors} */}
             {this.props.forcedBackgroundColor?.(this.Document) === "transparent" || this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton || this.props.dontRegisterView ? (null) :
-                <DocumentLinksButton View={this} Offset={[-15, 0]} />}
+                <DocumentLinksButton View={this} links={this.allLinks} Offset={this.linkOffset} />}
         </div>
         );
     }
@@ -1104,13 +1105,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     anchorPanelWidth = () => this.props.PanelWidth() || 1;
     anchorPanelHeight = () => this.props.PanelHeight() || 1;
 
-    @computed get allAnchors() {
+    @computed.struct get directLinks() { return LinkManager.Instance.getAllDirectLinks(this.Document); }
+    @computed.struct get allLinks() { return DocListCast(this.Document.links); }
+    @computed.struct get allAnchors() {
         TraceMobx();
         if (this.props.LayoutTemplateString?.includes("LinkAnchorBox")) return null;
         return (this.props.treeViewDoc && this.props.LayoutTemplateString) || // render nothing for: tree view anchor dots
             this.layoutDoc.presBox ||  // presentationbox nodes
             this.props.dontRegisterView ? (null) : // view that are not registered
-            DocUtils.FilterDocs(LinkManager.Instance.getAllDirectLinks(this.Document), this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
+            DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
                 <DocumentView {...this.props} key={i + 1}
                     Document={d}
                     ContainingCollectionView={this.props.ContainingCollectionView}
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 6592c488b..c3e1ae22f 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -84,11 +84,6 @@ export default class PDFMenu extends AntimodeMenu {
         e.preventDefault();
     }
 
-    togglePin = action((e: React.MouseEvent) => {
-        this.Pinned = !this.Pinned;
-        !this.Pinned && (this.Highlighting = false);
-    });
-
     @action
     highlightClicked = (e: React.MouseEvent) => {
         if (!this.Highlight(this.highlightColor) && this.Pinned) {
@@ -161,8 +156,6 @@ export default class PDFMenu extends AntimodeMenu {
                 this.highlighter,
                 <button key="2" className="antimodeMenu-button" title="Drag to Annotate" ref={this._commentCont} onPointerDown={this.pointerDown}>
                     <FontAwesomeIcon icon="comment-alt" size="lg" /></button>,
-                <button key="4" className="antimodeMenu-button" title="Pin Menu" onClick={this.togglePin} style={this.Pinned ? { backgroundColor: "#121212" } : {}}>
-                    <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this.Pinned ? "rotate(45deg)" : "" }} /></button>,
             ] : [
                 <button key="5" className="antimodeMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}>
                     <FontAwesomeIcon icon="trash-alt" size="lg" /></button>,
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index ddffb56c3..8cf8f47b7 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -90,6 +90,7 @@ export const documentSchema = createSchema({
     followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab, ) 
     hideLinkButton: "boolean",  // whether the blue link counter button should be hidden
     hideAllLinks: "boolean",    // whether all individual blue anchor dots should be hidden
+    linkDisplay: "boolean",     // whether a link connection should be shown between link anchor endpoints.
     isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations
     isLinkButton: "boolean",    // whether document functions as a link follow button to follow the first link on the document when clicked   
     isBackground: "boolean",    // whether document is a background element and ignores input events (can only select with marquee)
-- 
cgit v1.2.3-70-g09d2


From ef235dfa63709656af35fa3deaf53529abd3ee4c Mon Sep 17 00:00:00 2001
From: yunahi <60233430+yunahi@users.noreply.github.com>
Date: Wed, 29 Jul 2020 00:48:20 +0900
Subject:  moved inkmenu to collectionMenu

---
 src/client/views/DocumentDecorations.tsx        | 1 -
 src/client/views/collections/CollectionMenu.tsx | 2 ++
 2 files changed, 2 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3d258430e..c5e0a3303 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -526,7 +526,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         SelectionManager.SelectedDocuments().forEach(action((element: DocumentView, index) => {
             const doc = Document(element.rootDoc);
             if (doc.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
-                console.log(doc.x, doc.y, doc._height, doc._width);
                 const ink = Cast(doc.data, InkField)?.inkData;
                 if (ink) {
                     const newPoints: { X: number, Y: number }[] = [];
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 4fa2e51e8..f3b82df83 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -26,6 +26,8 @@ import { DocumentView } from "../nodes/DocumentView";
 import { ColorState } from "react-color";
 import { ObjectField } from "../../../fields/ObjectField";
 import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
+import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faSleigh, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, faArrowRight, faArrowsAltH, faMinus, faCircle, faExclamationTriangle, faSquare, faLongArrowAltRight, faPenFancy, faCaretSquareRight, faAngleDoubleRight, } from "@fortawesome/free-solid-svg-icons";
+library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, faLongArrowAltRight, faArrowsAltH, faMinus, faCircle, faSquare, faSquare, faPenFancy, faAngleDoubleRight,);
 
 @observer
 export default class CollectionMenu extends AntimodeMenu {
-- 
cgit v1.2.3-70-g09d2


From ac3bc783a331d61037c5547cc7aee03ee40bf8f4 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 29 Jul 2020 09:57:40 -0400
Subject: removed InkOptionsMenu

---
 src/client/util/InteractionUtils.tsx               |  11 -
 src/client/views/DocumentDecorations.tsx           |   4 +-
 src/client/views/GestureOverlay.tsx                |   1 -
 .../collectionFreeForm/InkOptionsMenu.tsx          | 355 ---------------------
 4 files changed, 1 insertion(+), 370 deletions(-)
 delete mode 100644 src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx

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

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 3a7fd7626..04a750f93 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -171,17 +171,6 @@ export namespace InteractionUtils {
         </svg>);
     }
 
-    // export function makeArrow() {
-    //     return (
-    //         InkOptionsMenu.Instance.getColors().map(color => {
-    //             const id1 = "arrowStartTest" + color;
-    //             <marker id={id1} orient="auto" overflow="visible" refX="0" refY="1" markerWidth="10" markerHeight="7">
-    //                 <polygon points="0 0, 3 1, 0 2" fill={"#" + color} />
-    //             </marker>;
-    //         })
-    //     );
-    // }
-
     export function makePolygon(shape: string, points: { X: number, Y: number }[]) {
         if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y + 1 === points[0].Y) {
             //pointer is up (first and last points are the same)
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c5e0a3303..c0a35a32a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -21,10 +21,8 @@ import e = require('express');
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { SnappingManager } from '../util/SnappingManager';
 import { HtmlField } from '../../fields/HtmlField';
-import { InkData, InkField, InkTool } from "../../fields/InkField";
+import { InkField } from "../../fields/InkField";
 import { Tooltip } from '@material-ui/core';
-import InkOptionsMenu from './collections/collectionFreeForm/InkOptionsMenu';
-import FormatShapePane from './collections/collectionFreeForm/FormatShapePane';
 
 library.add(faCaretUp);
 library.add(faObjectGroup);
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 53bc01b3d..5bc1b902e 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -22,7 +22,6 @@ import { RadialMenu } from "./nodes/RadialMenu";
 import HorizontalPalette from "./Palette";
 import { Touchable } from "./Touchable";
 import TouchScrollableMenu, { TouchScrollableMenuItem } from "./TouchScrollableMenu";
-import InkOptionsMenu from "./collections/collectionFreeForm/InkOptionsMenu";
 import * as fitCurve from 'fit-curve';
 import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu";
 
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
deleted file mode 100644
index 80d1264ce..000000000
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ /dev/null
@@ -1,355 +0,0 @@
-import React = require("react");
-import AntimodeMenu from "../../AntimodeMenu";
-import { observer } from "mobx-react";
-import { observable, action, computed } from "mobx";
-import "./InkOptionsMenu.scss";
-import { ActiveInkColor, ActiveInkBezierApprox, ActiveFillColor, ActiveArrowStart, ActiveArrowEnd, SetActiveInkWidth, SetActiveInkColor, SetActiveBezierApprox, SetActiveFillColor, SetActiveArrowStart, SetActiveArrowEnd, ActiveDash, SetActiveDash } from "../../InkingStroke";
-import { Scripting } from "../../../util/Scripting";
-import { InkTool } from "../../../../fields/InkField";
-import { ColorState } from "react-color";
-import { Utils } from "../../../../Utils";
-import GestureOverlay from "../../GestureOverlay";
-import { Doc } from "../../../../fields/Doc";
-import { SelectionManager } from "../../../util/SelectionManager";
-import { DocumentView } from "../../../views/nodes/DocumentView";
-import { Document } from "../../../../fields/documentSchemas";
-import { DocumentType } from "../../../documents/DocumentTypes";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faSleigh, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, faArrowRight, faArrowsAltH, faMinus, faCircle, faExclamationTriangle, faSquare, faLongArrowAltRight, faPenFancy, faCaretSquareRight, faAngleDoubleRight, } from "@fortawesome/free-solid-svg-icons";
-import { Cast, StrCast, BoolCast } from "../../../../fields/Types";
-import FormatShapePane from "./FormatShapePane";
-
-library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, faLongArrowAltRight, faArrowsAltH, faMinus, faCircle, faSquare, faSquare, faPenFancy, faAngleDoubleRight,);
-
-
-
-@observer
-export default class InkOptionsMenu extends AntimodeMenu {
-    static Instance: InkOptionsMenu;
-
-    private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
-    private _width = ["1", "5", "10", "100"];
-    private _dotsize = [10, 20, 30, 40];
-    private _draw = ["∿", "⎯", "→", "↔︎", "ロ", "O"];
-    private _head = ["", "", "", "arrow", "", ""];
-    private _end = ["", "", "arrow", "arrow", "", ""];
-    private _shape = ["", "line", "line", "line", "rectangle", "circle"];
-    private _title = ["pen", "line", "line with arrow", "line with double arrows", "square", "circle",];
-    private _faName = ["pen-fancy", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"];
-
-    @observable _shapesNum = this._shape.length;
-    @observable _selected = this._shapesNum;
-
-    @observable private collapsed: boolean = false;
-    @observable _double = "";
-
-    @observable _colorBtn = false;
-    @observable _widthBtn = false;
-    @observable _fillBtn = false;
-    // @observable _arrowBtn = false;
-    // @observable _dashBtn = false;
-    // @observable _shapeBtn = false;
-
-
-
-    constructor(props: Readonly<{}>) {
-        super(props);
-        InkOptionsMenu.Instance = this;
-        this._canFade = false; // don't let the inking menu fade away
-        this.Pinned = BoolCast(Doc.UserDoc()["menuInkOptions-pinned"]);
-
-    }
-
-    @action
-    toggleMenuPin = (e: React.MouseEvent) => {
-        Doc.UserDoc()["menuInkOptions-pinned"] = this.Pinned = !this.Pinned;
-        if (!this.Pinned) {
-            // this.fadeOut(true);
-        }
-    }
-
-    @action
-    protected toggleCollapse = (e: React.MouseEvent) => {
-        this.collapsed = !this.collapsed;
-        setTimeout(() => {
-            const x = Math.min(this._left, window.innerWidth - InkOptionsMenu.Instance.width);
-            InkOptionsMenu.Instance.jumpTo(x, this._top, true);
-        }, 0);
-    }
-
-
-
-
-    getColors = () => {
-        return this._palette;
-    }
-
-    // @action
-    // changeArrow = (arrowStart: string, arrowEnd: string) => {
-    //     SetActiveArrowStart(arrowStart);
-    //     SetActiveArrowEnd(arrowEnd);
-    // }
-
-    @action
-    changeColor = (color: string, type: string) => {
-        const col: ColorState = {
-            hex: color, hsl: { a: 0, h: 0, s: 0, l: 0, source: "" }, hsv: { a: 0, h: 0, s: 0, v: 0, source: "" },
-            rgb: { a: 0, r: 0, b: 0, g: 0, source: "" }, oldHue: 0, source: "",
-        };
-        if (type === "color") {
-            SetActiveInkColor(Utils.colorString(col));
-        } else if (type === "fill") {
-            SetActiveFillColor(Utils.colorString(col));
-        }
-    }
-
-    @action
-    editProperties = (value: any, field: string) => {
-        SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => {
-            const doc = Document(element.rootDoc);
-            if (doc.type === DocumentType.INK) {
-                switch (field) {
-                    case "width":
-                        doc.strokeWidth = Number(value);
-                        break;
-                    case "color":
-                        doc.color = String(value);
-                        break;
-                    case "fill":
-                        doc.fillColor = String(value);
-                        break;
-                    case "bezier":
-                        // doc.strokeBezier === 300 ? doc.strokeBezier = 0 : doc.strokeBezier = 300;
-                        break;
-                    case "dash":
-                        doc.strokeDash = Number(value);
-                    default:
-                        break;
-                }
-            }
-        }));
-    }
-
-
-    @action
-    changeBezier = (e: React.PointerEvent): void => {
-        SetActiveBezierApprox(!ActiveInkBezierApprox() ? "300" : "");
-        this.editProperties(0, "bezier");
-    }
-    @action
-    changeDash = (e: React.PointerEvent): void => {
-        SetActiveDash(ActiveDash() === "0" ? "2" : "0");
-        this.editProperties(ActiveDash(), "strokeDash");
-    }
-
-    @computed get drawButtons() {
-        const drawButtons = <div className="btn-draw" key="draw">
-            {this._draw.map((icon, i) => {
-                return <button
-                    className="antimodeMenu-button"
-                    key={icon}
-                    title={this._title[i]}
-                    onPointerDown={action(() => {
-                        this._double = "";
-
-                        if (this._selected !== i) {
-                            this._selected = i;
-                            Doc.SetSelectedTool(InkTool.Pen);
-                            SetActiveArrowStart(this._head[i]);
-                            SetActiveArrowEnd(this._end[i]);
-                            SetActiveBezierApprox("300");
-
-                            GestureOverlay.Instance.InkShape = this._shape[i];
-                        } else {
-                            this._selected = this._shapesNum;
-                            Doc.SetSelectedTool(InkTool.None);
-                            SetActiveArrowStart("");
-                            SetActiveArrowEnd("");
-                            GestureOverlay.Instance.InkShape = "";
-                            SetActiveBezierApprox("0");
-
-                        }
-                        console.log(this._selected);
-
-                    })}
-                    onDoubleClick={action(() => {
-                        console.log("double");
-                        this._double = this._draw[i];
-                        if (this._selected !== i) {
-                            this._selected = i;
-                            Doc.SetSelectedTool(InkTool.Pen);
-                            SetActiveArrowStart(this._head[i]);
-                            SetActiveArrowEnd(this._end[i]);
-                            SetActiveBezierApprox("300");
-
-                            GestureOverlay.Instance.InkShape = this._shape[i];
-                        } else {
-                            this._selected = this._shapesNum;
-                            Doc.SetSelectedTool(InkTool.None);
-                            SetActiveArrowStart("");
-                            SetActiveArrowEnd("");
-                            GestureOverlay.Instance.InkShape = "";
-                            SetActiveBezierApprox("0");
-
-                        }
-
-
-
-                    })}
-                    style={{ backgroundColor: i === this._selected ? "121212" : "", fontSize: "20" }}>
-                    <FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" />
-
-                </button>;
-            })}</div>;
-        return drawButtons;
-    }
-
-
-    @computed get widthPicker() {
-        var widthPicker = <button
-            className="antimodeMenu-button"
-            key="width"
-            title="change width"
-            onPointerDown={action(e => this._widthBtn = !this._widthBtn)}
-            style={{ backgroundColor: this._widthBtn ? "121212" : "" }}>
-            <FontAwesomeIcon icon="bars" size="lg" />
-        </button>;
-        if (this._widthBtn) {
-            widthPicker = <div className="btn2-group" key="width">
-                {widthPicker}
-                {this._width.map((wid, i) => {
-                    return <button
-                        className="antimodeMenu-button"
-                        key={wid}
-                        onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; this.editProperties(wid, "width"); })}
-                        style={{ backgroundColor: this._widthBtn ? "121212" : "", zIndex: 1001, fontSize: this._dotsize[i], padding: 0, textAlign: "center" }}>
-                        •
-                    </button>;
-                })}
-            </div>;
-        }
-        return widthPicker;
-    }
-
-
-
-    @computed get colorPicker() {
-        var colorPicker = <button
-            className="antimodeMenu-button"
-            key="color"
-            title="Change Ink Color"
-            onPointerDown={action(e => this._colorBtn = !this._colorBtn)}
-            style={{ backgroundColor: this._colorBtn ? "121212" : "" }}>
-            <FontAwesomeIcon icon="pen-nib" size="lg" />
-            <div className="color-previewI" style={{ backgroundColor: ActiveInkColor() ?? "121212" }}></div>
-
-        </button>;
-        if (this._colorBtn) {
-            colorPicker = <div className="btn-group" key="color">
-                {colorPicker}
-                {this._palette.map(color => {
-                    return <button
-                        className="antimodeMenu-button"
-                        key={color}
-                        onPointerDown={action(() => { this.changeColor(color, "color"); this._colorBtn = false; this.editProperties(color, "color"); })}
-                        style={{ backgroundColor: this._colorBtn ? "121212" : "", zIndex: 1001 }}>
-                        {/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */}
-                        <div className="color-previewII" style={{ backgroundColor: color }}></div>
-                    </button>;
-                })}
-            </div>;
-        }
-        return colorPicker;
-    }
-    @computed get formatPane() {
-        return <button className="antimodeMenu-button" key="format"
-            title="toggle foramatting pane"
-            onPointerDown={action(e => FormatShapePane.Instance.Pinned = !FormatShapePane.Instance.Pinned)}
-            style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
-            <FontAwesomeIcon icon="angle-double-right" size="lg" />
-        </button>;
-    }
-
-    @computed get fillPicker() {
-        var fillPicker = <button
-            className="antimodeMenu-button"
-            key="fill"
-            title="Change Fill Color"
-            onPointerDown={action(e => this._fillBtn = !this._fillBtn)}
-            style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
-            <FontAwesomeIcon icon="fill-drip" size="lg" />
-            <div className="color-previewI" style={{ backgroundColor: ActiveFillColor() ?? "121212" }}></div>
-        </button>;
-        if (this._fillBtn) {
-            fillPicker = <div className="btn-group" key="fill" >
-                {fillPicker}
-                {this._palette.map(color => {
-                    return <button
-                        className="antimodeMenu-button"
-                        key={color}
-                        onPointerDown={action(() => { this.changeColor(color, "fill"); this._fillBtn = false; this.editProperties(color, "fill"); })}
-                        style={{ backgroundColor: this._fillBtn ? "121212" : "", zIndex: 1001 }}>
-                        <div className="color-previewII" style={{ backgroundColor: color }}></div>
-                    </button>;
-                })}
-
-            </div>;
-        }
-        return fillPicker;
-    }
-
-
-    @computed get bezierButton() {
-        return <button
-            className="antimodeMenu-button"
-            title="Bezier changer"
-            key="bezier"
-            onPointerDown={e => this.changeBezier(e)}
-            style={{ backgroundColor: ActiveInkBezierApprox() ? "121212" : "" }}>
-            <FontAwesomeIcon icon="bezier-curve" size="lg" />
-
-        </button>;
-    }
-
-    @computed get dashButton() {
-        return <button
-            className="antimodeMenu-button"
-            title="dash changer"
-            key="dash"
-            onPointerDown={e => this.changeDash(e)}
-            style={{ backgroundColor: ActiveDash() !== "0" ? "121212" : "" }}>
-            <FontAwesomeIcon icon="ellipsis-h" size="lg" />
-
-        </button>;
-    }
-
-    render() {
-        const buttons = [
-
-            this.drawButtons,
-            this.widthPicker,
-            this.colorPicker,
-            this.fillPicker,
-
-
-            this.formatPane,
-
-            <button className="antimodeMenu-button" key="pin menu" title="Pin menu" onClick={this.toggleMenuPin} style={{ backgroundColor: this.Pinned ? "#121212" : "", display: this.collapsed ? "none" : undefined }}>
-                <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.Pinned ? 45 : 0}deg)` }} />
-            </button>
-        ];
-
-        // return this.getElement(buttons);
-        return this.getElement(buttons);
-    }
-}
-Scripting.addGlobal(function activatePen(penBtn: any) {
-    if (penBtn) {
-        InkOptionsMenu.Instance.jumpTo(300, 300);
-        InkOptionsMenu.Instance.Pinned = true;
-    } else {
-        InkOptionsMenu.Instance.Pinned = false;
-        InkOptionsMenu.Instance.fadeOut(true);
-    }
-});
-- 
cgit v1.2.3-70-g09d2


From f3f51bb4933cada9ae83594912db10d88082be24 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 30 Jul 2020 10:53:21 -0400
Subject: made 'floatin' document API cleaner.  fixed interactions with draggin
 blue dots off and link lines to link documents.  removed Recommndations UI
 stuff.  changed treeView to avoid "No, no, no" error warnin when tryin to
 render promises

---
 src/client/documents/DocumentTypes.ts              |   1 -
 src/client/documents/Documents.ts                  |   9 -
 src/client/views/DocumentDecorations.tsx           |   2 +-
 src/client/views/GlobalKeyHandler.ts               |   1 -
 src/client/views/RecommendationsBox.scss           |  69 -------
 src/client/views/RecommendationsBox.tsx            | 201 ---------------------
 src/client/views/TemplateMenu.tsx                  |   6 +-
 src/client/views/collections/CollectionMenu.tsx    |   2 +-
 src/client/views/collections/CollectionSubView.tsx |   2 +-
 .../views/collections/CollectionTreeView.tsx       |   4 +-
 src/client/views/nodes/DocumentContentsView.tsx    |   3 +-
 src/client/views/nodes/DocumentView.tsx            |  33 ++--
 src/client/views/nodes/LinkAnchorBox.tsx           |   4 +-
 13 files changed, 30 insertions(+), 307 deletions(-)
 delete mode 100644 src/client/views/RecommendationsBox.scss
 delete mode 100644 src/client/views/RecommendationsBox.tsx

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

diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 7578b7df0..985fcce11 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -36,6 +36,5 @@ export enum DocumentType {
 
     LINKDB = "linkdb",          // database of links  ??? why do we have this
     SCRIPTDB = "scriptdb",          // database of scripts
-    RECOMMENDATION = "recommendation", // view of a recommendation
     GROUPDB = "groupdb"         // database of groups
 }
\ No newline at end of file
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7e094089f..984d43e32 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -45,7 +45,6 @@ import { SliderBox } from "../views/nodes/SliderBox";
 import { VideoBox } from "../views/nodes/VideoBox";
 import { WebBox } from "../views/nodes/WebBox";
 import { PresElementBox } from "../views/presentationview/PresElementBox";
-import { RecommendationsBox } from "../views/RecommendationsBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
 import { DocumentType } from "./DocumentTypes";
 import { Networking } from "../Network";
@@ -301,10 +300,6 @@ export namespace Docs {
                 layout: { view: FontIconBox, dataField: defaultDataKey },
                 options: { _width: 40, _height: 40, borderRounding: "100%" },
             }],
-            [DocumentType.RECOMMENDATION, {
-                layout: { view: RecommendationsBox, dataField: defaultDataKey },
-                options: { _width: 200, _height: 200 },
-            }],
             [DocumentType.WEBCAM, {
                 layout: { view: DashWebRTCVideo, dataField: defaultDataKey }
             }],
@@ -805,10 +800,6 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.IMPORT), new List<Doc>(), options);
         }
 
-        export function RecommendationsDocument(data: Doc[], options: DocumentOptions = {}) {
-            return InstanceFromProto(Prototypes.get(DocumentType.RECOMMENDATION), new List<Doc>(data), options);
-        }
-
         export type DocConfig = {
             doc: Doc,
             initialWidth?: number,
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 190dbc8c3..51325ae1b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -89,7 +89,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
             var [sptX, sptY] = transform.transformPoint(0, 0);
             let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
-            if (StrCast(Doc.Layout(documentView.props.Document).layout).includes("LinkAnchorBox")) {
+            if (documentView.props.LayoutTemplateString?.includes("LinkAnchorBox")) {
                 const docuBox = documentView.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
                 if (docuBox.length) {
                     const rect = docuBox[0].getBoundingClientRect();
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 086085db5..c9f95a538 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -105,7 +105,6 @@ export default class KeyManager {
                 }
                 doDeselect && SelectionManager.DeselectAll();
                 DictationManager.Controls.stop();
-                // RecommendationsBox.Instance.closeMenu();
                 GoogleAuthenticationManager.Instance.cancel();
                 HypothesisAuthenticationManager.Instance.cancel();
                 SharingManager.Instance.close();
diff --git a/src/client/views/RecommendationsBox.scss b/src/client/views/RecommendationsBox.scss
deleted file mode 100644
index 7d89042a4..000000000
--- a/src/client/views/RecommendationsBox.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-@import "globalCssVariables";
-
-.rec-content *{
-    display: inline-block;
-    margin: auto;
-    width: 50;
-    height: 150px;
-    border: 1px dashed grey;
-    padding: 10px 10px;
-}
-
-.rec-content {
-    float: left;
-    width: inherit;
-    align-content: center;
-}
-
-.rec-scroll {
-    overflow-y: scroll;
-    overflow-x: hidden;
-    position: absolute;
-    pointer-events: all;
-    // display: flex;
-    z-index: 10000;
-    box-shadow: gray 0.2vw 0.2vw 0.4vw;
-    // flex-direction: column;
-    background: whitesmoke;
-    padding-bottom: 10px;
-    padding-top: 20px;
-    // border-radius: 15px;
-    border: solid #BBBBBBBB 1px;
-    width: 100%;
-    text-align: center;
-    // max-height: 250px;
-    height: 100%;
-    text-transform: uppercase;
-    color: grey;
-    letter-spacing: 2px;
-}
-
-.content {
-    padding: 10px;
-    display: flex;
-    flex-direction: row;
-    align-items: center;
-    justify-content: center;
-}
-
-.image-background {
-    pointer-events: none;
-    background-color: transparent;
-    width: 50%;
-    text-align: center;
-    margin-left: 5px;
-}
-
-// bcz: UGH!!  Can't have global settings like this!!!
-// img{
-//     width: 100%;
-//     height: 100%;
-// }
-
-.score {
-    // margin-left: 15px;
-    width: 50%;
-    height: 100%;
-    text-align: center;
-    margin-left: 10px;
-}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
deleted file mode 100644
index 196151e32..000000000
--- a/src/client/views/RecommendationsBox.tsx
+++ /dev/null
@@ -1,201 +0,0 @@
-import { observer } from "mobx-react";
-import React = require("react");
-import { observable, action, computed, runInAction } from "mobx";
-import Measure from "react-measure";
-import "./RecommendationsBox.scss";
-import { Doc, DocListCast, WidthSym, HeightSym } from "../../fields/Doc";
-import { DocumentIcon } from "./nodes/DocumentIcon";
-import { StrCast, NumCast } from "../../fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath, returnZero, returnEmptyFilter } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { ObjectField } from "../../fields/ObjectField";
-import { DocumentView } from "./nodes/DocumentView";
-import { DocumentType } from '../documents/DocumentTypes';
-import { ClientRecommender } from "../ClientRecommender";
-import { DocServer } from "../DocServer";
-import { Id } from "../../fields/FieldSymbols";
-import { FieldView, FieldViewProps } from "./nodes/FieldView";
-import { DocumentManager } from "../util/DocumentManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
-import { DocUtils } from "../documents/Documents";
-
-export interface RecProps {
-    documents: { preview: Doc, similarity: number }[];
-    node: Doc;
-}
-
-library.add(faBullseye, faLink);
-
-@observer
-export class RecommendationsBox extends React.Component<FieldViewProps> {
-
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
-
-    // @observable private _display: boolean = false;
-    @observable private _pageX: number = 0;
-    @observable private _pageY: number = 0;
-    @observable private _width: number = 0;
-    @observable private _height: number = 0;
-    @observable.shallow private _docViews: JSX.Element[] = [];
-    // @observable private _documents: { preview: Doc, score: number }[] = [];
-    private previewDocs: Doc[] = [];
-
-    constructor(props: FieldViewProps) {
-        super(props);
-    }
-
-    @action
-    private DocumentIcon(doc: Doc) {
-        const layoutresult = StrCast(doc.type);
-        let renderDoc = doc;
-        //let box: number[] = [];
-        if (layoutresult.indexOf(DocumentType.COL) !== -1) {
-            renderDoc = Doc.MakeDelegate(renderDoc);
-        }
-        const returnXDimension = () => 150;
-        const returnYDimension = () => 150;
-        const scale = () => returnXDimension() / NumCast(renderDoc._nativeWidth, returnXDimension());
-        //let scale = () => 1;
-        const newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
-        newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
-        newRenderDoc.autoHeight = false;
-        const docview = <div>
-            <DocumentView
-                fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
-                Document={newRenderDoc}
-                addDocument={returnFalse}
-                LibraryPath={emptyPath}
-                removeDocument={returnFalse}
-                rootSelected={returnFalse}
-                ScreenToLocalTransform={Transform.Identity}
-                addDocTab={returnFalse}
-                pinToPres={returnFalse}
-                renderDepth={1}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
-                PanelWidth={returnXDimension}
-                PanelHeight={returnYDimension}
-                focus={emptyFunction}
-                backgroundColor={returnEmptyString}
-                parentActive={returnFalse}
-                whenActiveChanged={returnFalse}
-                bringToFront={emptyFunction}
-                docFilters={returnEmptyFilter}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
-                ContentScaling={scale}
-            />
-        </div>;
-        return docview;
-
-    }
-
-    // @action
-    // closeMenu = () => {
-    //     this._display = false;
-    //     this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
-    //     this.previewDocs = [];
-    // }
-
-    // @action
-    // resetDocuments = () => {
-    //     this._documents = [];
-    // }
-
-    // @action
-    // displayRecommendations(x: number, y: number) {
-    //     this._pageX = x;
-    //     this._pageY = y;
-    //     this._display = true;
-    // }
-
-    static readonly buffer = 20;
-
-    // get pageX() {
-    //     const x = this._pageX;
-    //     if (x < 0) {
-    //         return 0;
-    //     }
-    //     const width = this._width;
-    //     if (x + width > window.innerWidth - RecommendationsBox.buffer) {
-    //         return window.innerWidth - RecommendationsBox.buffer - width;
-    //     }
-    //     return x;
-    // }
-
-    // get pageY() {
-    //     const y = this._pageY;
-    //     if (y < 0) {
-    //         return 0;
-    //     }
-    //     const height = this._height;
-    //     if (y + height > window.innerHeight - RecommendationsBox.buffer) {
-    //         return window.innerHeight - RecommendationsBox.buffer - height;
-    //     }
-    //     return y;
-    // }
-
-    // get createDocViews() {
-    //     return DocListCast(this.props.Document.data).map(doc => {
-    //         return (
-    //             <div className="content">
-    //                 <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-    //                     {this.DocumentIcon(doc)}
-    //                 </span>
-    //                 <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-    //                 <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-    //                 </div>
-    //                 <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
-    //                     <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-    //                 </div>
-    //             </div>
-    //         );
-    //     });
-    // }
-
-    componentDidMount() { //TODO: invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set
-        runInAction(() => {
-            if (this._docViews.length === 0) {
-                this._docViews = DocListCast(this.props.Document.data).map(doc => {
-                    return (
-                        <div className="content">
-                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-                                {this.DocumentIcon(doc)}
-                            </span>
-                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-                            </div>
-                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "Recommender", "", undefined)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-                            </div>
-                        </div>
-                    );
-                });
-            }
-        });
-    }
-
-    render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered. 
-        // if (!this._display) {
-        //     return null;
-        // }
-        // let style = { left: this.pageX, top: this.pageY };
-        //const transform = "translate(" + (NumCast(this.props.node.x) + 350) + "px, " + NumCast(this.props.node.y) + "px"
-        let title = StrCast((this.props.Document.sourceDoc as Doc).title);
-        if (title.length > 15) {
-            title = title.substring(0, 15) + "...";
-        }
-        return (
-            <div className="rec-scroll">
-                <p>Recommendations for "{title}"</p>
-                {this._docViews}
-            </div>
-        );
-    }
-    // 
-    // 
-}
\ No newline at end of file
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 9fb8a227e..ebaf2cfcb 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -64,11 +64,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
     }
 
     toggleFloat = (e: React.ChangeEvent<HTMLInputElement>): void => {
-        SelectionManager.DeselectAll();
-        const topDocView = this.props.docViews[0];
-        const ex = e.target.getBoundingClientRect().left;
-        const ey = e.target.getBoundingClientRect().top;
-        DocumentView.FloatDoc(topDocView, ex, ey);
+        DocumentView.FloatDoc(this.props.docViews[0]);
     }
 
     toggleAudio = (e: React.ChangeEvent<HTMLInputElement>): void => {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index d6cb79e9c..8813861d2 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -313,7 +313,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                 <div className="collectionMenu">
                     <div className="collectionViewBaseChrome">
                         {this.props.type === CollectionViewType.Invalid || this.props.type === CollectionViewType.Docking ? (null) : this.viewModes}
-                        {this.props.type === CollectionViewType.Invalid || this.props.type === CollectionViewType.Docking ? (null) : this.templateChrome}
+                        {this.props.type === CollectionViewType.Docking ? (null) : this.templateChrome}
                         <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
                             <button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} >
                                 <FontAwesomeIcon icon="filter" size="lg" />
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a89fcc703..9f78c15eb 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -127,7 +127,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
 
             const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc);
             const docFilters = this.docFilters();
-            const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
+            const viewSpecScript = ScriptCast(this.props.Document.viewSpecScript);
             const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
 
             return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, docFilters, docRangeFilters, viewSpecScript);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 651357e5d..705871a6f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -100,8 +100,8 @@ class TreeView extends React.Component<TreeViewProps> {
     childDocList(field: string) {
         const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
         return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
-            (layout ? Cast(layout[field], listSpec(Doc)) : undefined) || // else if there's a layout doc, display it's fields
-            Cast(this.doc[field], listSpec(Doc))) as Doc[]; // otherwise use the document's data field
+            (layout ? DocListCast(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
+            DocListCast(this.doc[field])) as Doc[]; // otherwise use the document's data field
     }
     @computed get childDocs() { return this.childDocList(this.fieldKey); }
     @computed get childLinks() { return this.childDocList("links"); }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 47dc0a773..e8173d103 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -35,7 +35,6 @@ import { VideoBox } from "./VideoBox";
 import { WebBox } from "./WebBox";
 import { InkingStroke } from "../InkingStroke";
 import React = require("react");
-import { RecommendationsBox } from "../RecommendationsBox";
 import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
 import { ScriptField } from "../../../fields/ScriptField";
 import XRegExp = require("xregexp");
@@ -194,7 +193,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
                     PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
                     ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
-                    RecommendationsBox, ScreenshotBox, HTMLtag, ComparisonBox
+                    ScreenshotBox, HTMLtag, ComparisonBox
                 }}
                 bindings={bindings}
                 jsx={layoutFrame}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c47edefd6..15cf9556b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -238,20 +238,28 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
-    public static FloatDoc(topDocView: DocumentView, x: number, y: number) {
+    @undoBatch @action
+    public static FloatDoc(topDocView: DocumentView, x?: number, y?: number) {
         const topDoc = topDocView.props.Document;
-        const de = new DragManager.DocumentDragData([topDoc]);
-        de.dragDivName = topDocView.props.dragDivName;
-        de.moveDocument = topDocView.props.moveDocument;
-        setTimeout(() => {
-            const newDocView = DocumentManager.Instance.getDocumentView(topDoc);
-            if (newDocView) {
-                const contentDiv = newDocView.ContentDiv!;
-                const xf = contentDiv.getBoundingClientRect();
-                DragManager.StartDocumentDrag([contentDiv], de, x, y, { offsetX: x - xf.left, offsetY: y - xf.top, hideSource: true });
+        const container = topDocView.props.ContainingCollectionView;
+        if (container) {
+            SelectionManager.DeselectAll();
+            if (topDoc.z && (x === undefined && y === undefined)) {
+                const spt = container.screenToLocalTransform().inverse().transformPoint(NumCast(topDoc.x), NumCast(topDoc.y));
+                topDoc.z = 0;
+                topDoc.x = spt[0];
+                topDoc.y = spt[1];
+                topDocView.props.removeDocument?.(topDoc);
+                topDocView.props.addDocTab(topDoc, "inParent");
+            } else {
+                const spt = topDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+                const fpt = container.screenToLocalTransform().transformPoint(x !== undefined ? x : spt[0], y !== undefined ? y : spt[1]);
+                topDoc.z = 1;
+                topDoc.x = fpt[0];
+                topDoc.y = fpt[1];
             }
-        }, 0);
-        UndoManager.RunInBatch(action(() => topDoc.z = topDoc.z ? 0 : 1), "float");
+            setTimeout(() => SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(topDoc, container)!, false), 0);
+        }
     }
 
     onKeyDown = (e: React.KeyboardEvent) => {
@@ -849,6 +857,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (this.props.LayoutTemplateString?.includes("LinkAnchorBox")) return null;
         return (this.props.treeViewDoc && this.props.LayoutTemplateString) || // render nothing for: tree view anchor dots
             this.layoutDoc.presBox ||  // presentationbox nodes
+            this.rootDoc.type === DocumentType.LINK ||
             this.props.dontRegisterView ? (null) : // view that are not registered
             DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
                 <DocumentView {...this.props} key={i + 1}
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index d4ab70200..e02ea61f7 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -54,9 +54,9 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
                 const dragData = new DragManager.DocumentDragData([this.rootDoc]);
                 dragData.dropAction = "alias";
                 dragData.removeDropProperties = ["anchor1_x", "anchor1_y", "anchor2_x", "anchor2_y", "isLinkButton"];
-                DragManager.StartDocumentDrag([this._ref.current!], dragData, down[0], down[1]);
+                DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]);
                 return true;
-            } else if (dragdist > separation) {
+            } else {
                 this.rootDoc[this.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
                 this.rootDoc[this.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
             }
-- 
cgit v1.2.3-70-g09d2

