From 691d5500c0722d0af9ef3b3ab9036042970e75e9 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Tue, 21 Jan 2020 13:35:06 -0500
Subject: cffview nested panning

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx  | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 01b978c81..132bf9c8e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -347,6 +347,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                         this._lastX = pt.pageX;
                         this._lastY = pt.pageY;
                         e.preventDefault();
+                        e.stopPropagation();
                     }
                     else {
                         e.preventDefault();
@@ -362,7 +363,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             case GestureUtils.Gestures.Stroke:
                 const points = ge.points;
                 const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
-                const inkDoc = Docs.Create.InkDocument(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, parseInt(InkingControl.Instance.selectedWidth), points, { x: B.x, y: B.y, width: B.width, height: B.height });
+                const inkDoc = Docs.Create.InkDocument(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, parseInt(InkingControl.Instance.selectedWidth), points, { title: "ink stroke", x: B.x, y: B.y, width: B.width, height: B.height });
                 this.addDocument(inkDoc);
                 e.stopPropagation();
                 break;
@@ -384,7 +385,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     }
                     return pass;
                 });
-                this.addDocument(Docs.Create.FreeformDocument(sel, { x: bounds.x, y: bounds.y, width: bWidth, height: bHeight, panX: 0, panY: 0 }));
+                this.addDocument(Docs.Create.FreeformDocument(sel, { title: "nested collection", x: bounds.x, y: bounds.y, width: bWidth, height: bHeight, panX: 0, panY: 0 }));
                 sel.forEach(d => this.props.removeDocument(d));
                 break;
 
-- 
cgit v1.2.3-70-g09d2


From b04bb12a5942d97eef369936e30b36db62b51f30 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Mon, 27 Jan 2020 19:08:05 -0500
Subject: pen updates

---
 src/client/util/InteractionUtils.tsx               |  5 ++-
 src/client/views/GestureOverlay.tsx                | 52 +++++++++++++++++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 28 ++++++------
 src/pen-gestures/ndollar.ts                        |  7 ++-
 5 files changed, 72 insertions(+), 22 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 1fe95474c..ad1d1b5de 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -63,7 +63,7 @@ export namespace InteractionUtils {
     export function GetMyTargetTouches(mte: InteractionUtils.MultiTouchEvent<React.TouchEvent | TouchEvent>, prevPoints: Map<number, React.Touch>, ignorePen: boolean): React.Touch[] {
         const myTouches = new Array<React.Touch>();
         for (const pt of mte.touches) {
-            if (!ignorePen || (pt.radiusX > 1 && pt.radiusY > 1)) {
+            if (!ignorePen || ((pt as any).radiusX > 1 && (pt as any).radiusY > 1)) {
                 for (const tPt of mte.targetTouches) {
                     if (tPt?.screenX === pt?.screenX && tPt?.screenY === pt?.screenY) {
                         if (pt && prevPoints.has(pt.identifier)) {
@@ -73,6 +73,9 @@ export namespace InteractionUtils {
                 }
             }
         }
+        if (mte.touches.length !== myTouches.length) {
+            throw Error("opo")
+        }
         return myTouches;
     }
 
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index e8d685139..9dd87554f 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -20,6 +20,12 @@ import { DocumentView } from "./nodes/DocumentView";
 import { Transform } from "../util/Transform";
 import { DocumentContentsView } from "./nodes/DocumentContentsView";
 
+/**
+ * This class handles all of the gesture and touch events first. Native touch and pen
+ * events should be ignored by all classes and handled up here, and this class will interpret
+ * these events before dispatching our custom Dash gesture and touch events. Classes that want
+ * to use touch and pen events should handle custom Dash events, as opposed to native events.
+ */
 @observer
 export default class GestureOverlay extends Touchable {
     static Instance: GestureOverlay;
@@ -54,6 +60,15 @@ export default class GestureOverlay extends Touchable {
         GestureOverlay.Instance = this;
     }
 
+    /**
+     * @description 
+     * Given a touch event, returns three arrays that represent the event's targetTouches,
+     * changedTouches, and touches after filtering out the touch events that are being handled
+     * as hands. This helps us separate hand events and touch events, as they are different
+     * events in the mental model that we are pursuing.
+     * @param e - Touch event to filter
+     * @returns \{ newTargetTouches, newChangedTouches, newTouches }
+     */
     getNewTouches(e: React.TouchEvent | TouchEvent) {
         const ntt: (React.Touch | Touch)[] = Array.from(e.targetTouches);
         const nct: (React.Touch | Touch)[] = Array.from(e.changedTouches);
@@ -61,6 +76,7 @@ export default class GestureOverlay extends Touchable {
         this._hands.forEach((hand) => {
             for (let i = 0; i < e.targetTouches.length; i++) {
                 const pt = e.targetTouches.item(i);
+                // if there is a finger in this hand that matches the current point, ignore the current point
                 if (pt && hand.some((finger) => finger.screenX === pt.screenX && finger.screenY === pt.screenY)) {
                     ntt.splice(ntt.indexOf(pt), 1);
                 }
@@ -83,7 +99,11 @@ export default class GestureOverlay extends Touchable {
         return { ntt, nct, nt };
     }
 
+    /**
+     * @description Handler for the native React touchStart event.
+     */
     onReactTouchStart = (te: React.TouchEvent) => {
+        // clean up any ghost points that are remaining but don't actually exist
         const actualPts: React.Touch[] = [];
         for (let i = 0; i < te.touches.length; i++) {
             const pt: any = te.touches.item(i);
@@ -91,9 +111,6 @@ export default class GestureOverlay extends Touchable {
             // pen is also a touch, but with a radius of 0.5 (at least with the surface pens)
             // and this seems to be the only way of differentiating pen and touch on touch events
             if (pt.radiusX > 1 && pt.radiusY > 1) {
-                // if (typeof pt.identifier !== "string") {
-                //     pt.identifier = Utils.GenerateGuid();
-                // }
                 this.prevPoints.set(pt.identifier, pt);
             }
         }
@@ -106,10 +123,11 @@ export default class GestureOverlay extends Touchable {
         });
 
         ptsToDelete.forEach(pt => this.prevPoints.delete(pt));
-        const nts = this.getNewTouches(te);
-        console.log(nts.nt.length);
 
+        // decide whether we should be handling this as a hand event or a touch event
+        const nts = this.getNewTouches(te);
         if (nts.nt.length < 5) {
+            // dispatch a touch event
             const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
             target?.dispatchEvent(
                 new CustomEvent<InteractionUtils.MultiTouchEvent<React.TouchEvent>>("dashOnTouchStart",
@@ -131,12 +149,17 @@ export default class GestureOverlay extends Touchable {
             document.addEventListener("touchend", this.onReactTouchEnd);
         }
         else {
+            // handle this event as a hand event
             this.handleHandDown(te);
             document.removeEventListener("touchmove", this.onReactTouchMove);
             document.removeEventListener("touchend", this.onReactTouchEnd);
         }
     }
 
+    /**
+     * @description Handler for the native React touchMove event. Filters and dispatches
+     * the custom Dash touchMove event.
+     */
     onReactTouchMove = (e: TouchEvent) => {
         const nts: any = this.getNewTouches(e);
         document.dispatchEvent(
@@ -154,7 +177,11 @@ export default class GestureOverlay extends Touchable {
         );
     }
 
+    /**
+     * @description Handler for the native React touchEnd event.
+     */
     onReactTouchEnd = (e: TouchEvent) => {
+        // filter and dispatch custom touchEnd event
         const nts: any = this.getNewTouches(e);
         document.dispatchEvent(
             new CustomEvent<InteractionUtils.MultiTouchEvent<TouchEvent>>("dashOnTouchEnd",
@@ -169,6 +196,8 @@ export default class GestureOverlay extends Touchable {
                     }
                 })
         );
+
+        // clean up any points that have ended
         for (let i = 0; i < e.changedTouches.length; i++) {
             const pt = e.changedTouches.item(i);
             if (pt) {
@@ -178,6 +207,7 @@ export default class GestureOverlay extends Touchable {
             }
         }
 
+        // clean up events
         if (this.prevPoints.size === 0) {
             document.removeEventListener("touchmove", this.onReactTouchMove);
             document.removeEventListener("touchend", this.onReactTouchEnd);
@@ -185,8 +215,12 @@ export default class GestureOverlay extends Touchable {
         e.stopPropagation();
     }
 
+    /**
+     * @description Handler for "handDown" events
+     */
     handleHandDown = async (e: React.TouchEvent) => {
         const fingers = new Array<React.Touch>();
+        // log all the fingers on the hand
         for (let i = 0; i < e.touches.length; i++) {
             const pt: any = e.touches.item(i);
             if (pt.radiusX > 1 && pt.radiusY > 1) {
@@ -200,6 +234,8 @@ export default class GestureOverlay extends Touchable {
                 }
             }
         }
+
+        // figure out left/right hand and thumb/pointer finger
         const thumb = fingers.reduce((a, v) => a.clientY > v.clientY ? a : v, fingers[0]);
         const rightMost = Math.max(...fingers.map(f => f.clientX));
         const leftMost = Math.min(...fingers.map(f => f.clientX));
@@ -229,6 +265,7 @@ export default class GestureOverlay extends Touchable {
         const minX = Math.min(...others.map(f => f.clientX));
         const minY = Math.min(...others.map(f => f.clientY));
 
+        // pull up the palette
         const thumbDoc = await Cast(CurrentUserUtils.setupThumbDoc(CurrentUserUtils.UserDocument), Doc);
         if (thumbDoc) {
             runInAction(() => {
@@ -246,6 +283,9 @@ export default class GestureOverlay extends Touchable {
         document.addEventListener("touchend", this.handleHandUp);
     }
 
+    /**
+     * @description Handler for "handMove" event
+     */
     @action
     handleHandMove = (e: TouchEvent) => {
         const fingers = new Array<React.Touch>();
@@ -370,7 +410,7 @@ export default class GestureOverlay extends Touchable {
             else {
                 const result = GestureUtils.GestureRecognizer.Recognize(new Array(points));
                 let actionPerformed = false;
-                if (result && result.Score > 0.7) {
+                if (result && result.Score > 0.8) {
                     switch (result.Name) {
                         case GestureUtils.Gestures.Box:
                             const target = document.elementFromPoint(this._points[0].X, this._points[0].Y);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 132bf9c8e..a0c75c1b7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -347,7 +347,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                         this._lastX = pt.pageX;
                         this._lastY = pt.pageY;
                         e.preventDefault();
-                        e.stopPropagation();
+                        // e.stopPropagation();
                     }
                     else {
                         e.preventDefault();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e0913b154..82ee1bd63 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -316,21 +316,23 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
         if (this.Document.onPointerDown) return;
         const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
-        this._downX = touch.clientX;
-        this._downY = touch.clientY;
-        if (!e.nativeEvent.cancelBubble) {
-            this._hitTemplateDrag = false;
-            for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) {
-                if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") {
-                    this._hitTemplateDrag = true;
+        if (touch) {
+            this._downX = touch.clientX;
+            this._downY = touch.clientY;
+            if (!e.nativeEvent.cancelBubble) {
+                this._hitTemplateDrag = false;
+                for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) {
+                    if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") {
+                        this._hitTemplateDrag = true;
+                    }
                 }
+                if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation();
+                this.removeMoveListeners();
+                this.addMoveListeners();
+                this.removeEndListeners();
+                this.addEndListeners();
+                e.stopPropagation();
             }
-            if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation();
-            this.removeMoveListeners();
-            this.addMoveListeners();
-            this.removeEndListeners();
-            this.addEndListeners();
-            e.stopPropagation();
         }
     }
 
diff --git a/src/pen-gestures/ndollar.ts b/src/pen-gestures/ndollar.ts
index ef5ca38c6..9e15ada2d 100644
--- a/src/pen-gestures/ndollar.ts
+++ b/src/pen-gestures/ndollar.ts
@@ -168,7 +168,12 @@ export class NDollarRecognizer {
         //
         this.Multistrokes = new Array(NumMultistrokes);
         this.Multistrokes[0] = new Multistroke(GestureUtils.Gestures.Box, useBoundedRotationInvariance, new Array(
-            new Array(new Point(30, 146), new Point(30, 222), new Point(106, 225), new Point(106, 146), new Point(30, 146))
+            new Array(
+                new Point(30, 146), //new Point(29, 160), new Point(30, 180), new Point(31, 200),
+                new Point(30, 222), //new Point(50, 219), new Point(70, 225), new Point(90, 230),
+                new Point(106, 225), //new Point(100, 200), new Point(106, 180), new Point(110, 160),
+                new Point(106, 146), //new Point(80, 150), new Point(50, 146),
+                new Point(30, 143))
         ));
         this.Multistrokes[1] = new Multistroke(GestureUtils.Gestures.Line, useBoundedRotationInvariance, new Array(
             new Array(new Point(12, 347), new Point(119, 347))
-- 
cgit v1.2.3-70-g09d2


From 17dcf7e4d8c2f038dc3a6168b1ff6b8d3cb15536 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Thu, 30 Jan 2020 18:39:20 -0500
Subject: i think some bugs are fixed

---
 src/client/util/InteractionUtils.tsx                                | 6 +++---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +-
 src/client/views/nodes/DocumentView.tsx                             | 1 +
 3 files changed, 5 insertions(+), 4 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index ad1d1b5de..7194feb2e 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -73,9 +73,9 @@ export namespace InteractionUtils {
                 }
             }
         }
-        if (mte.touches.length !== myTouches.length) {
-            throw Error("opo")
-        }
+        // if (mte.touches.length !== myTouches.length) {
+        //     throw Error("opo")
+        // }
         return myTouches;
     }
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a0c75c1b7..132bf9c8e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -347,7 +347,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                         this._lastX = pt.pageX;
                         this._lastY = pt.pageY;
                         e.preventDefault();
-                        // e.stopPropagation();
+                        e.stopPropagation();
                     }
                     else {
                         e.preventDefault();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 82ee1bd63..ad28c9b1c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -316,6 +316,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>) => {
         if (this.Document.onPointerDown) return;
         const touch = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true)[0];
+        console.log("down");
         if (touch) {
             this._downX = touch.clientX;
             this._downY = touch.clientY;
-- 
cgit v1.2.3-70-g09d2


From 1cb72c720d2e287032bfe586f25ebd941ab3f393 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 30 Jan 2020 23:16:19 -0500
Subject: small fixes to textbox sidebar.  requires testing for annotationskey
 in COllectionSubView's childLayoutPairs

---
 src/client/views/collections/CollectionSubView.tsx         |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx          | 14 +++++++-------
 src/client/views/nodes/FormattedTextBox.tsx                |  9 +++++----
 3 files changed, 13 insertions(+), 12 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 8679c8bd1..9482435a0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -98,7 +98,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
 
         get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
             const { Document, DataDoc } = this.props;
-            const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout);
+            const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout);
             return validPairs.map(({ data, layout }) => ({ data: data!, layout: layout! })); // this mapping is a bit of a hack to coerce types
         }
         get childDocList() {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 41ef8c2a6..0022a4dbd 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -834,23 +834,23 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     layoutDocsInGrid = () => {
         UndoManager.RunInBatch(() => {
-            const docs = DocListCast(this.Document[this.props.fieldKey]);
+            const docs = this.childLayoutPairs;
             const startX = this.Document._panX || 0;
             let x = startX;
             let y = this.Document._panY || 0;
             let i = 0;
-            const width = Math.max(...docs.map(doc => NumCast(doc._width)));
-            const height = Math.max(...docs.map(doc => NumCast(doc._height)));
-            for (const doc of docs) {
-                doc.x = x;
-                doc.y = y;
+            const width = Math.max(...docs.map(doc => NumCast(doc.layout._width)));
+            const height = Math.max(...docs.map(doc => NumCast(doc.layout._height)));
+            docs.forEach(pair => {
+                pair.layout.x = x;
+                pair.layout.y = y;
                 x += width + 20;
                 if (++i === 6) {
                     i = 0;
                     x = startX;
                     y += height + 20;
                 }
-            }
+            });
         }, "arrange contents");
     }
 
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 675f72011..939df2540 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1062,7 +1062,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
     }
 
     @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "0%"); }
-    @computed get sidebarWidth() { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); }
+    sidebarWidth = () => { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); }
+    sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()), 0);
     @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
     render() {
         TraceMobx();
@@ -1107,7 +1108,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                         style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
                         <CollectionFreeFormView {...this.props}
                             PanelHeight={this.props.PanelHeight}
-                            PanelWidth={() => this.sidebarWidth}
+                            PanelWidth={this.sidebarWidth}
                             annotationsKey={this.annotationKey}
                             isAnnotationOverlay={false}
                             focus={this.props.focus}
@@ -1118,9 +1119,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                             whenActiveChanged={this.whenActiveChanged}
                             removeDocument={this.removeDocument}
                             moveDocument={this.moveDocument}
-                            addDocument={(doc: Doc) => { doc._showSidebar = false; return this.addDocument(doc); }}
+                            addDocument={this.addDocument}
                             CollectionView={undefined}
-                            ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)}
+                            ScreenToLocalTransform={this.sidebarScreenToLocal}
                             renderDepth={this.props.renderDepth + 1}
                             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                             chromeCollapsed={true}>
-- 
cgit v1.2.3-70-g09d2


From b0544ea44ef78a93deb9290815f95d6d9308447d Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 31 Jan 2020 10:12:32 -0500
Subject: fixed text labeling in pivot view

---
 .../CollectionFreeFormLayoutEngines.tsx            | 38 +++++++++++++++++-----
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  3 +-
 3 files changed, 32 insertions(+), 11 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index be1317b25..18ca71c2a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -4,7 +4,7 @@ import { ScriptBox } from "../../ScriptBox";
 import { CompileScript } from "../../../util/Scripting";
 import { ScriptField } from "../../../../new_fields/ScriptField";
 import { OverlayView, OverlayElementOptions } from "../../OverlayView";
-import { emptyFunction } from "../../../../Utils";
+import { emptyFunction, aggregateBounds } from "../../../../Utils";
 import React = require("react");
 import { ObservableMap, runInAction } from "mobx";
 import { Id, ToString } from "../../../../new_fields/FieldSymbols";
@@ -42,7 +42,13 @@ function toLabel(target: FieldResult<Field>) {
     return String(target);
 }
 
-export function computePivotLayout(poolData: ObservableMap<string, any>, pivotDoc: Doc, childDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: any) => ViewDefResult[]) {
+export function computePivotLayout(
+    poolData: ObservableMap<string, any>,
+    pivotDoc: Doc,
+    pwidth: number, pheight: number,
+    childDocs: Doc[],
+    childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: any) => ViewDefResult[]
+) {
     const pivotAxisWidth = NumCast(pivotDoc.pivotWidth, 200);
     const pivotColumnGroups = new Map<FieldResult<Field>, Doc[]>();
 
@@ -99,21 +105,37 @@ export function computePivotLayout(poolData: ObservableMap<string, any>, pivotDo
         x += pivotAxisWidth * (numCols * expander + gap);
     });
 
+    const grpEles = groupNames.map(gn => { return { x: gn.x, y: gn.y, width: gn.width, height: gn.height }; });
+    const docEles = childPairs.map(pair => {
+        const newPos = docMap.get(pair.layout) || { x: NumCast(pair.layout.x), y: NumCast(pair.layout.y) }; // new pos is computed pos, or pos written to the document's fields
+        return {
+            x: newPos.x,
+            y: newPos.y,
+            width: NumCast(pair.layout._width),
+            height: NumCast(pair.layout._height)
+        };
+    }
+    );
+    const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0);
+
+    const scale = Math.min(pheight / (aggBounds.b - aggBounds.y), pwidth / (aggBounds.r - aggBounds.x));
+
     childPairs.map(pair => {
-        const defaultPosition = {
+        const fallbackPos = {
             x: NumCast(pair.layout.x),
             y: NumCast(pair.layout.y),
             z: NumCast(pair.layout.z),
             width: NumCast(pair.layout._width),
             height: NumCast(pair.layout._height)
         };
-        const pos = docMap.get(pair.layout) || defaultPosition;
-        const data = poolData.get(pair.layout[Id]);
-        if (!data || pos.x !== data.x || pos.y !== data.y || pos.z !== data.z || pos.width !== data.width || pos.height !== data.height) {
-            runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...pos }));
+        const newPosRaw = docMap.get(pair.layout) || fallbackPos; // new pos is computed pos, or pos written to the document's fields
+        const newPos = { x: newPosRaw.x * scale, y: newPosRaw.y * scale, z: newPosRaw.z, width: newPosRaw.width * scale, height: newPosRaw.height * scale };
+        const lastPos = poolData.get(pair.layout[Id]); // last computed pos
+        if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.width !== lastPos.width || newPos.height !== lastPos.height) {
+            runInAction(() => poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos }));
         }
     });
-    return { elements: viewDefsToJSX(groupNames) };
+    return { elements: viewDefsToJSX(groupNames.map(gname => { return { type: gname.type, text: gname.text, x: gname.x * scale, y: gname.y * scale, width: gname.width * scale, height: gname.height, fontSize: gname.fontSize } })) };
 }
 
 export function AddCustomFreeFormLayout(doc: Doc, dataKey: string): () => void {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0022a4dbd..90bed2899 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -776,7 +776,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }.bind(this));
 
     doPivotLayout(poolData: ObservableMap<string, any>) {
-        return computePivotLayout(poolData, this.props.Document, this.childDocs,
+        return computePivotLayout(poolData, this.props.Document, this.props.PanelWidth(), this.props.PanelHeight(), this.childDocs,
             this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)), [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
     }
 
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 939df2540..fe9b8e0ff 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1070,8 +1070,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground;
         if (this.props.isSelected()) {
-            // TODO: ftong --> update from dash in richtextmenu
-            RichTextMenu.Instance.updateFromDash(this._editorView!, undefined, this.props);
+            this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props);
         } else if (FormattedTextBoxComment.textBox === this) {
             FormattedTextBoxComment.Hide();
         }
-- 
cgit v1.2.3-70-g09d2

