From 21cd63dc9536deea17814231605ff22ea59e26b4 Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Mon, 18 May 2020 14:24:28 -0700
Subject: fixed some bugs with webbox and hacked some problems with cognitive
 services

---
 .../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 c6bae66a4..c3a77841e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -438,9 +438,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                 console.log("end");
                 if (this._inkToTextStartX && this._inkToTextStartY) {
                     const end = this.getTransform().transformPoint(Math.max(...ge.points.map(p => p.X)), Math.max(...ge.points.map(p => p.Y)));
-                    const setDocs = this.getActiveDocuments().filter(s => s.proto?.type === "text" && s.color);
+                    const setDocs = this.getActiveDocuments().filter(s => s.proto?.type === "rtf" && s.color);
                     const sets = setDocs.map((sd) => {
-                        return Cast(sd.data, RichTextField)?.Text as string;
+                        return Cast(sd.text, RichTextField)?.Text as string;
                     });
                     if (sets.length && sets[0]) {
                         this._wordPalette.clear();
@@ -476,6 +476,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                         }
                     });
 
+                    console.log(this._wordPalette)
                     CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then((results) => {
                         console.log(results);
                         const wordResults = results.filter((r: any) => r.category === "inkWord");
-- 
cgit v1.2.3-70-g09d2


From 8fd0f6f8b3ce585e58f388d856360373480ecdde Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 28 May 2020 16:53:49 -0400
Subject: fixed pdf text selection

---
 package-lock.json                                  | 84 +++++++++-------------
 package.json                                       |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  8 +--
 src/client/views/pdf/PDFViewer.scss                |  4 ++
 src/client/views/pdf/PDFViewer.tsx                 |  4 +-
 6 files changed, 45 insertions(+), 59 deletions(-)

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

diff --git a/package-lock.json b/package-lock.json
index 8b10d91f3..21e4c4e27 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2800,8 +2800,7 @@
                         },
                         "ansi-regex": {
                             "version": "2.1.1",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "aproba": {
                             "version": "1.2.0",
@@ -2819,13 +2818,11 @@
                         },
                         "balanced-match": {
                             "version": "1.0.0",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "brace-expansion": {
                             "version": "1.1.11",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "balanced-match": "^1.0.0",
                                 "concat-map": "0.0.1"
@@ -2838,18 +2835,15 @@
                         },
                         "code-point-at": {
                             "version": "1.1.0",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "concat-map": {
                             "version": "0.0.1",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "console-control-strings": {
                             "version": "1.1.0",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "core-util-is": {
                             "version": "1.0.2",
@@ -2952,8 +2946,7 @@
                         },
                         "inherits": {
                             "version": "2.0.4",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "ini": {
                             "version": "1.3.5",
@@ -2963,7 +2956,6 @@
                         "is-fullwidth-code-point": {
                             "version": "1.0.0",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "number-is-nan": "^1.0.0"
                             }
@@ -2976,20 +2968,17 @@
                         "minimatch": {
                             "version": "3.0.4",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "brace-expansion": "^1.1.7"
                             }
                         },
                         "minimist": {
                             "version": "1.2.5",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "minipass": {
                             "version": "2.9.0",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -3006,7 +2995,6 @@
                         "mkdirp": {
                             "version": "0.5.3",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "minimist": "^1.2.5"
                             }
@@ -3062,8 +3050,7 @@
                         },
                         "npm-normalize-package-bin": {
                             "version": "1.0.1",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "npm-packlist": {
                             "version": "1.4.8",
@@ -3088,8 +3075,7 @@
                         },
                         "number-is-nan": {
                             "version": "1.0.1",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "object-assign": {
                             "version": "4.1.1",
@@ -3099,7 +3085,6 @@
                         "once": {
                             "version": "1.4.0",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "wrappy": "1"
                             }
@@ -3168,8 +3153,7 @@
                         },
                         "safe-buffer": {
                             "version": "5.1.2",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "safer-buffer": {
                             "version": "2.1.2",
@@ -3199,7 +3183,6 @@
                         "string-width": {
                             "version": "1.0.2",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "code-point-at": "^1.0.0",
                                 "is-fullwidth-code-point": "^1.0.0",
@@ -3217,7 +3200,6 @@
                         "strip-ansi": {
                             "version": "3.0.1",
                             "bundled": true,
-                            "optional": true,
                             "requires": {
                                 "ansi-regex": "^2.0.0"
                             }
@@ -3256,13 +3238,11 @@
                         },
                         "wrappy": {
                             "version": "1.0.2",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         },
                         "yallist": {
                             "version": "3.1.1",
-                            "bundled": true,
-                            "optional": true
+                            "bundled": true
                         }
                     }
                 }
@@ -9456,7 +9436,7 @@
                 },
                 "chownr": {
                     "version": "1.1.4",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
                     "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
                 },
                 "ci-info": {
@@ -9762,7 +9742,7 @@
                 },
                 "deep-extend": {
                     "version": "0.6.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
                     "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
                 },
                 "defaults": {
@@ -10261,7 +10241,7 @@
                 },
                 "glob": {
                     "version": "7.1.6",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
                     "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
                     "requires": {
                         "fs.realpath": "^1.0.0",
@@ -10349,7 +10329,7 @@
                 },
                 "hosted-git-info": {
                     "version": "2.8.8",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
                     "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg=="
                 },
                 "http-cache-semantics": {
@@ -10485,7 +10465,7 @@
                 },
                 "is-ci": {
                     "version": "1.2.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
                     "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
                     "requires": {
                         "ci-info": "^1.5.0"
@@ -10561,7 +10541,7 @@
                 },
                 "is-retry-allowed": {
                     "version": "1.2.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
                     "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg=="
                 },
                 "is-stream": {
@@ -11070,7 +11050,7 @@
                 },
                 "mkdirp": {
                     "version": "0.5.4",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
                     "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
                     "requires": {
                         "minimist": "^1.2.5"
@@ -11078,7 +11058,7 @@
                     "dependencies": {
                         "minimist": {
                             "version": "1.2.5",
-                            "resolved": false,
+                            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
                             "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
                         }
                     }
@@ -11130,7 +11110,7 @@
                 },
                 "node-gyp": {
                     "version": "5.1.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz",
                     "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==",
                     "requires": {
                         "env-paths": "^2.2.0",
@@ -11244,7 +11224,7 @@
                 },
                 "npm-packlist": {
                     "version": "1.4.8",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
                     "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
                     "requires": {
                         "ignore-walk": "^3.0.1",
@@ -11264,7 +11244,7 @@
                 },
                 "npm-profile": {
                     "version": "4.0.4",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz",
                     "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==",
                     "requires": {
                         "aproba": "^1.1.2 || 2",
@@ -11274,7 +11254,7 @@
                 },
                 "npm-registry-fetch": {
                     "version": "4.0.3",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz",
                     "integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==",
                     "requires": {
                         "JSONStream": "^1.3.4",
@@ -11709,7 +11689,7 @@
                 },
                 "rc": {
                     "version": "1.2.8",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
                     "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
                     "requires": {
                         "deep-extend": "^0.6.0",
@@ -11720,7 +11700,7 @@
                     "dependencies": {
                         "minimist": {
                             "version": "1.2.5",
-                            "resolved": false,
+                            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
                             "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
                         }
                     }
@@ -11779,7 +11759,7 @@
                 },
                 "readable-stream": {
                     "version": "3.6.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
                     "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
                     "requires": {
                         "inherits": "^2.0.3",
@@ -11800,7 +11780,7 @@
                 },
                 "registry-auth-token": {
                     "version": "3.4.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
                     "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
                     "requires": {
                         "rc": "^1.1.6",
@@ -11864,7 +11844,7 @@
                 },
                 "rimraf": {
                     "version": "2.7.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
                     "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
                     "requires": {
                         "glob": "^7.1.3"
@@ -12163,7 +12143,7 @@
                 },
                 "string_decoder": {
                     "version": "1.3.0",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
                     "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
                     "requires": {
                         "safe-buffer": "~5.2.0"
@@ -12171,7 +12151,7 @@
                     "dependencies": {
                         "safe-buffer": {
                             "version": "5.2.0",
-                            "resolved": false,
+                            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
                             "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
                         }
                     }
@@ -12483,7 +12463,7 @@
                 },
                 "widest-line": {
                     "version": "2.0.1",
-                    "resolved": false,
+                    "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
                     "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
                     "requires": {
                         "string-width": "^2.1.1"
diff --git a/package.json b/package.json
index 8bf1e6b74..ca82d523d 100644
--- a/package.json
+++ b/package.json
@@ -228,4 +228,4 @@
         "xoauth2": "^1.2.0",
         "xregexp": "^4.3.0"
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 3e99af724..87fe79e19 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -748,7 +748,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 Document.childLayoutTemplate = heroView;
                 Document.childClickedOpenTemplateView = new PrefetchProxy(detailView);
                 Document._viewType = CollectionViewType.Time;
-                Document._forceActive = true;
+                Document.forceActive = true;
                 Document._pivotField = "company";
                 Document.childDropAction = "alias";
             }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0639d74a8..9d10ff158 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -76,6 +76,7 @@ const PanZoomDocument = makeInterface(panZoomSchema, collectionSchema, documentS
 export type collectionFreeformViewProps = {
     forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox)
     viewDefDivClick?: ScriptField;
+    childPointerEvents?: boolean;
 };
 
 @observer
@@ -1124,10 +1125,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                     replica={entry[1].replica}
                     dataProvider={this.childDataProvider}
                     sizeProvider={this.childSizeProvider}
-                    pointerEvents={
-                        this.backgroundActive ?
-                            true :
-                            (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? false : undefined}
+                    pointerEvents={this.backgroundActive || this.props.childPointerEvents ?
+                        true :
+                        (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? false : undefined}
                     jitterRotation={NumCast(this.props.Document._jitterRotation) || ((Doc.UserDoc().renderStyle === "comic" ? 10 : 0))}
                     //fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
                     fitToBox={BoolCast(this.props.freezeChildDimensions)} // bcz: check this
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 8541a3149..affffc44e 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -29,6 +29,7 @@
 
     .page {
         position: relative;
+        border: unset;
     }
     .pdfViewer-text-selected {
         .textLayer{
@@ -57,6 +58,9 @@
         display: inline-block;
         width:100%;
     }
+    .pdfViewer-overlay {
+        pointer-events: none;
+    }
     
     .pdfViewer-annotationLayer {
         position: absolute;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 810ce5aea..217032c1f 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -31,6 +31,7 @@ import Annotation from "./Annotation";
 import PDFMenu from "./PDFMenu";
 import "./PDFViewer.scss";
 import React = require("react");
+import { SnappingManager } from "../../util/SnappingManager";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
 
@@ -641,7 +642,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     panelWidth = () => (this.Document.scrollHeight || this.Document._nativeHeight || 0);
     panelHeight = () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : (this.Document._nativeWidth || 0);
     @computed get overlayLayer() {
-        return <div className={`pdfViewer-overlay${InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : ""}`} id="overlay"
+        return <div className={`pdfViewer-overlay${InkingControl.Instance.selectedTool !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`} id="overlay"
             style={{ transform: `scale(${this._zoomed})` }}>
             <CollectionFreeFormView {...this.props}
                 LibraryPath={this.props.ContainingCollectionView?.props.LibraryPath ?? emptyPath}
@@ -661,6 +662,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 ContentScaling={this.contentZoom}
                 bringToFront={emptyFunction}
                 whenActiveChanged={this.whenActiveChanged}
+                childPointerEvents={true}
                 removeDocument={this.removeDocument}
                 moveDocument={this.moveDocument}
                 addDocument={this.addDocument}
-- 
cgit v1.2.3-70-g09d2


From 57c4cde2fab898976deec3fd037a3c9052ee2d30 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 28 May 2020 18:43:14 -0400
Subject: added aimated transitions to presentations of frame animations

---
 .../collectionFreeForm/CollectionFreeFormView.tsx          | 14 +++++++++++---
 src/client/views/nodes/CollectionFreeFormDocumentView.tsx  |  5 +++--
 src/client/views/nodes/PresBox.tsx                         |  5 +++++
 3 files changed, 19 insertions(+), 5 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 9d10ff158..cb1228fed 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1350,8 +1350,14 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             getContainerTransform={this.getContainerTransform}
             getTransform={this.getTransform}
             isAnnotationOverlay={this.isAnnotationOverlay}>
-            <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} shifted={!this.nativeHeight && !this.isAnnotationOverlay}
-                easing={this.easing} viewDefDivClick={this.props.viewDefDivClick} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
+            <CollectionFreeFormViewPannableContents
+                centeringShiftX={this.centeringShiftX}
+                centeringShiftY={this.centeringShiftY}
+                shifted={!this.nativeHeight && !this.isAnnotationOverlay}
+                easing={this.easing}
+                transition={Cast(this.layoutDoc.transition, "string", null)}
+                viewDefDivClick={this.props.viewDefDivClick}
+                zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
                 {this.children}
             </CollectionFreeFormViewPannableContents>
             {this._timelineVisible ? <Timeline ref={this._timelineRef} {...this.props} /> : (null)}
@@ -1445,6 +1451,7 @@ interface CollectionFreeFormViewPannableContentsProps {
     viewDefDivClick?: ScriptField;
     children: () => JSX.Element[];
     shifted: boolean;
+    transition?: string;
 }
 
 @observer
@@ -1459,7 +1466,8 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
         return <div className={freeformclass}
             style={{
                 width: this.props.shifted ? 0 : undefined, height: this.props.shifted ? 0 : undefined,
-                transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`
+                transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`,
+                transition: this.props.transition
             }}>
             {this.props.children()}
         </div>;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 682aed8f5..697111ac8 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -96,12 +96,12 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             opacityindexed?.length <= timecode + 1 && opacityindexed.push(undefined as any as number);
             doc.transition = "all 1s";
         });
-        setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010);
+        setTimeout(() => docs.forEach(doc => doc.transition = "inherit"), 1010);
     }
 
     public static gotoKeyframe(docs: Doc[]) {
         docs.forEach(doc => doc.transition = "all 1s");
-        setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010);
+        setTimeout(() => docs.forEach(doc => doc.transition = "inherit"), 1010);
     }
 
     public static setupKeyframes(docs: Doc[], timecode: number, progressivize: boolean = false) {
@@ -119,6 +119,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             doc.x = ComputedField.MakeInterpolated("x", "activeFrame");
             doc.y = ComputedField.MakeInterpolated("y", "activeFrame");
             doc.opacity = ComputedField.MakeInterpolated("opacity", "activeFrame");
+            doc.transition = "inherit";
         });
     }
 
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 05306c29f..56a543f46 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -62,6 +62,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const lastFrame = Cast(presTargetDoc.lastFrame, "number", null);
         const curFrame = NumCast(presTargetDoc.currentFrame);
         if (lastFrame !== undefined && curFrame < lastFrame) {
+            //const docs = DocListCast(presTargetDoc[Doc.LayoutFieldKey(presTargetDoc)]);
+            presTargetDoc.transition = "all 1s";
+            setTimeout(() => presTargetDoc.transition = undefined, 1010);
+            // docs.forEach(doc => doc.transition = "all 1s");
+            // setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010);
             presTargetDoc.currentFrame = curFrame + 1;
         }
         else if (this.childDocs[this.itemIndex + 1] !== undefined) {
-- 
cgit v1.2.3-70-g09d2


From 895e84fe6999a39eb9553db68b378aee5c1864a3 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 29 May 2020 01:29:02 -0400
Subject: moved frame animation into freeform chrome.   fixed marquees of docs
 at non-zero frame.  fixed pile view to use its own _pileLayoutEngine key to
 avoid leaving colleciton in an animated state.  added toggle for snap linew
 views.  cached transforms in CollectionFreeformView for performance.

---
 src/client/views/MainView.tsx                      |   6 +-
 .../views/collections/CollectionPileView.tsx       |   8 +-
 .../views/collections/CollectionViewChromes.scss   |  60 +++++-
 .../views/collections/CollectionViewChromes.tsx    | 201 +++++++++++++--------
 .../collectionFreeForm/CollectionFreeFormView.scss |  26 ---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  68 +++----
 .../collections/collectionFreeForm/MarqueeView.tsx |  12 +-
 src/client/views/nodes/DocumentView.tsx            |   9 +-
 src/client/views/nodes/PresBox.tsx                 |   3 -
 9 files changed, 223 insertions(+), 170 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 958ba0ce3..a0a6adab7 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -534,10 +534,10 @@ export class MainView extends React.Component {
     }
 
     @computed get snapLines() {
-        return <div className="mainView-snapLines">
+        return !Doc.UserDoc().showSnapLines ? (null) : <div className="mainView-snapLines">
             <svg style={{ width: "100%", height: "100%" }}>
-                {/* {SnappingManager.horizSnapLines().map(l => <line x1="0" y1={l} x2="2000" y2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={"1 1"} />)}
-                {SnappingManager.vertSnapLines().map(l => <line y1="0" x1={l} y2="2000" x2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={"1 1"} />)} */}
+                {SnappingManager.horizSnapLines().map(l => <line x1="0" y1={l} x2="2000" y2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={"1 1"} />)}
+                {SnappingManager.vertSnapLines().map(l => <line y1="0" x1={l} y2="2000" x2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={"1 1"} />)}
             </svg>
         </div>;
     }
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 020a87b2e..fc48e0327 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -23,7 +23,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
     @observable _childClickedScript: Opt<ScriptField>;
     componentDidMount() {
         if (this.layoutEngine() !== "pass" && this.layoutEngine() !== "starburst") {
-            this.Document._layoutEngine = "pass";
+            this.Document._pileLayoutEngine = "pass";
         }
         this._originalChrome = StrCast(this.layoutDoc._chromeStatus);
         this.layoutDoc._chromeStatus = "disabled";
@@ -34,7 +34,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
         this.layoutDoc._chromeStatus = this._originalChrome;
     }
 
-    layoutEngine = () => StrCast(this.Document._layoutEngine);
+    layoutEngine = () => StrCast(this.Document._pileLayoutEngine);
 
     @computed get contents() {
         return <div className="collectionPileView-innards" style={{ pointerEvents: this.layoutEngine() === "starburst" ? undefined : "none" }} >
@@ -53,7 +53,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
             Doc.pileup(this.childDocs);
             this.layoutDoc._panX = 0;
             this.layoutDoc._panY = -10;
-            this.props.Document._layoutEngine = 'pass';
+            this.props.Document._pileLayoutEngine = 'pass';
         } else {
             const defaultSize = 25;
             this.layoutDoc._overflow = 'visible';
@@ -67,7 +67,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
             }
             this.layoutDoc._panX = this.layoutDoc._panY = 0;
             this.layoutDoc._width = this.layoutDoc._height = defaultSize;
-            this.props.Document._layoutEngine = 'starburst';
+            this.props.Document._pileLayoutEngine = 'starburst';
         }
     });
 
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index e4581eb46..03bd9a01a 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -8,10 +8,12 @@
     z-index: 9001;
     transition: top .5s;
     background: lightgrey;
+    transform-origin: top left;
 
     .collectionViewChrome {
         display: flex;
-        padding-bottom: 10px;
+        padding-bottom: 1px;
+        height:32px;
         border-bottom: .5px solid rgb(180, 180, 180);
         overflow: hidden;
 
@@ -21,12 +23,12 @@
             .collectionViewBaseChrome-viewPicker {
                 font-size: 75%;
                 //text-transform: uppercase;
-                letter-spacing: 2px;
+                //letter-spacing: 2px;
                 background: rgb(238, 238, 238);
                 color: grey;
                 outline-color: black;
                 border: none;
-                padding: 12px 10px 11px 10px;
+                //padding: 12px 10px 11px 10px;
             }
 
             .collectionViewBaseChrome-viewPicker:active {
@@ -47,6 +49,7 @@
             .collectionViewBaseChrome-cmdPicker {
                 margin-left: 3px;
                 margin-right: 0px;
+                font-size: 75%;
                 background: rgb(238, 238, 238);
                 border: none;
                 color: grey;
@@ -56,6 +59,7 @@
                 background-color: gray;
                 display: flex;
                 flex-direction: row;
+                height:30px;
                 .commandEntry-drop {
                     color:white;
                     width:25px;
@@ -95,8 +99,8 @@
                     margin: auto;
                     background: gray;
                     color: white;
-                    width: 40px;
-                    height: 40px;
+                    width: 30px;
+                    height: 30px;
                     align-items: center;
                     justify-content: center;
                 }
@@ -195,8 +199,7 @@
             .collectionTreeViewChrome-pivotField-label {
                 vertical-align: center;
                 padding-left: 10px;
-                padding-top: 10px;
-                padding-bottom: 10px;
+                margin:auto;
             }
 
             .collectionStackingViewChrome-pivotField,
@@ -204,14 +207,15 @@
                 color: white;
                 width:100%;
                 min-width: 100px;
-                text-align: center;
+                display: flex;
+                align-items: center;
                 background: rgb(238, 238, 238);
 
                 .editable-view-input,
                 input,
                 .editableView-container-editing-oneLine,
                 .editableView-container-editing {
-                    padding: 12px 10px 11px 10px;
+                    margin:auto;
                     border: 0px;
                     color: grey;
                     text-align: center;
@@ -235,6 +239,44 @@
     }
 }
 
+.collectionFreeFormViewChrome-cont {
+    width: 60px;
+    display: flex;
+    position: relative;
+    align-items: center;
+    .fwdKeyframe, .numKeyframe, .backKeyframe {
+        cursor: pointer;
+        position: absolute;
+        width: 20;
+        height: 30;
+        bottom: 0;
+        background: gray;
+        display: flex;
+        align-items: center;
+        color:white;
+    }
+    .backKeyframe {
+        left:0;
+        svg {
+            display:block;
+            margin:auto;
+        }
+    }
+    .numKeyframe {
+        left:20;
+        display: flex;
+        flex-direction: column;
+        padding: 5px;
+    }
+    .fwdKeyframe {
+        left:40;
+        svg {
+            display:block;
+            margin:auto;
+        }
+    }
+}
+
 .collectionSchemaViewChrome-cont {
     display: flex;
     font-size: 10.5px;
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 8c4d53d63..29a3e559a 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -15,6 +15,7 @@ import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss";
 import { CollectionViewType } from "./CollectionView";
 import { CollectionView } from "./CollectionView";
 import "./CollectionViewChromes.scss";
+import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 const datepicker = require('js-datepicker');
 
 interface CollectionViewChromeProps {
@@ -44,7 +45,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         initialize: emptyFunction,
     };
     _narrativeCommand = {
-        params: ["target", "source"], title: "=> click clicked open view",
+        params: ["target", "source"], title: "=> child click view",
         script: "this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])",
         immediate: (source: Doc[]) => this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]),
         initialize: emptyFunction,
@@ -83,22 +84,16 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     private _viewRef = React.createRef<HTMLInputElement>();
     @observable private _currentKey: string = "";
 
-    componentDidMount = () => {
-        runInAction(() => {
-            // chrome status is one of disabled, collapsed, or visible. this determines initial state from document
-            const chromeStatus = this.props.CollectionView.props.Document._chromeStatus;
-            if (chromeStatus) {
-                if (chromeStatus === "disabled") {
-                    throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!");
-                }
-                else if (chromeStatus === "collapsed") {
-                    if (this.props.collapse) {
-                        this.props.collapse(true);
-                    }
-                }
-            }
-        });
-    }
+    componentDidMount = action(() => {
+        // chrome status is one of disabled, collapsed, or visible. this determines initial state from document
+        switch (this.props.CollectionView.props.Document._chromeStatus) {
+            case "disabled":
+                throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!");
+            case "collapsed":
+                this.props.collapse?.(true);
+                break;
+        }
+    })
 
     @undoBatch
     viewChanged = (e: React.ChangeEvent) => {
@@ -197,10 +192,11 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         }
     }
 
-    subChrome = () => {
+    @computed get subChrome() {
         const collapsed = this.document._chromeStatus !== "enabled";
         if (collapsed) return null;
         switch (this.props.type) {
+            case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
             case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
             case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
             case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
@@ -236,7 +232,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
             const vtype = this.props.CollectionView.collectionViewType;
             const c = {
                 params: ["target"], title: vtype,
-                script: `this.target._viewType = ${StrCast(this.props.CollectionView.props.Document._viewType)}`,
+                script: `this.target._viewType = '${StrCast(this.props.CollectionView.props.Document._viewType)}'`,
                 immediate: (source: Doc[]) => this.props.CollectionView.props.Document._viewType = Doc.getDocTemplate(source?.[0]),
                 initialize: emptyFunction,
             };
@@ -254,14 +250,61 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         }, emptyFunction, emptyFunction);
     }
 
+    @computed get templateChrome() {
+        const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled";
+        return <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} style={{ display: collapsed ? "none" : undefined }}>
+            <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
+                <div className="commandEntry-drop">
+                    <FontAwesomeIcon icon="bullseye" size="2x" />
+                </div>
+                <select
+                    className="collectionViewBaseChrome-cmdPicker"
+                    onPointerDown={stopPropagation}
+                    onChange={this.commandChanged}
+                    value={this._currentKey}>
+                    <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={"empty"} value={""} />
+                    {this._buttonizableCommands.map(cmd =>
+                        <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>{cmd.title}</option>
+                    )}
+                </select>
+            </div>
+        </div>;
+    }
+
+    @computed get viewModes() {
+        const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled";
+        return <div className="collectionViewBaseChrome-viewModes" style={{ display: collapsed ? "none" : undefined }}>
+            <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._viewRef} onPointerDown={this.dragViewDown}>
+                <div className="commandEntry-drop">
+                    <FontAwesomeIcon icon="bullseye" size="2x" />
+                </div>
+                <select
+                    className="collectionViewBaseChrome-viewPicker"
+                    onPointerDown={stopPropagation}
+                    onChange={this.viewChanged}
+                    value={StrCast(this.props.CollectionView.props.Document._viewType)}>
+                    {Object.values(CollectionViewType).map(type => ["invalid", "docking"].includes(type) ? (null) : (
+                        <option
+                            key={Utils.GenerateGuid()}
+                            className="collectionViewBaseChrome-viewOption"
+                            onPointerDown={stopPropagation}
+                            value={type}>
+                            {type[0].toUpperCase() + type.substring(1)}
+                        </option>
+                    ))}
+                </select>
+            </div>
+        </div>;
+    }
+
     render() {
         const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled";
+        const scale = Math.min(1, this.props.CollectionView.props.ScreenToLocalTransform().Scale);
         return (
             <div className="collectionViewChrome-cont" style={{
                 top: collapsed ? -70 : 0, height: collapsed ? 0 : undefined,
-                transform: collapsed ? "" : `scale(${Math.min(1, this.props.CollectionView.props.ScreenToLocalTransform().Scale)})`,
-                transformOrigin: "top left",
-                width: `${this.props.PanelWidth() / Math.min(1, this.props.CollectionView.props.ScreenToLocalTransform().Scale)}px`
+                transform: collapsed ? "" : `scale(${scale})`,
+                width: `${this.props.PanelWidth() / scale}px`
             }}>
                 <div className="collectionViewChrome" style={{ border: "unset", pointerEvents: collapsed ? "none" : undefined }}>
                     <div className="collectionViewBaseChrome">
@@ -276,58 +319,71 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                             title="Collapse collection chrome" onClick={this.toggleCollapse}>
                             <FontAwesomeIcon icon="caret-up" size="2x" />
                         </button>
-                        <div className="collectionViewBaseChrome-viewModes" style={{ display: collapsed ? "none" : undefined }}>
-                            <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._viewRef} onPointerDown={this.dragViewDown}>
-                                <div className="commandEntry-drop">
-                                    <FontAwesomeIcon icon="bullseye" size="2x"></FontAwesomeIcon>
-                                </div>
-                                <select
-                                    className="collectionViewBaseChrome-viewPicker"
-                                    onPointerDown={stopPropagation}
-                                    onChange={this.viewChanged}
-                                    value={StrCast(this.props.CollectionView.props.Document._viewType)}>
-                                    {Object.values(CollectionViewType).map(type => ["invalid", "docking"].includes(type) ? (null) : (
-                                        <option
-                                            key={Utils.GenerateGuid()}
-                                            className="collectionViewBaseChrome-viewOption"
-                                            onPointerDown={stopPropagation}
-                                            value={type}>
-                                            {type[0].toUpperCase() + type.substring(1)}
-                                        </option>
-                                    ))}
-                                </select>
-                            </div>
-                        </div>
+                        {this.viewModes}
                         <div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: collapsed ? "none" : "grid" }}>
                             <div className="collectionViewBaseChrome-filterIcon" onPointerDown={this.toggleViewSpecs} >
                                 <FontAwesomeIcon icon="filter" size="2x" />
                             </div>
                         </div>
-                        <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} style={{ display: collapsed ? "none" : undefined }}>
-                            <div className="commandEntry-outerDiv" title="drop document to apply or drag to create button" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
-                                <div className="commandEntry-drop">
-                                    <FontAwesomeIcon icon="bullseye" size="2x" />
-                                </div>
-                                <select
-                                    className="collectionViewBaseChrome-cmdPicker"
-                                    onPointerDown={stopPropagation}
-                                    onChange={this.commandChanged}
-                                    value={this._currentKey}>
-                                    <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={"empty"} value={""}>{""}</option>
-                                    {this._buttonizableCommands.map(cmd =>
-                                        <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>{cmd.title}</option>
-                                    )}
-                                </select>
-                            </div>
-                        </div>
+                        {this.templateChrome}
                     </div>
-                    {this.subChrome()}
+                    {this.subChrome}
                 </div>
             </div>
         );
     }
 }
 
+@observer
+export class CollectionFreeFormViewChrome extends React.Component<CollectionViewChromeProps> {
+
+    get Document() { return this.props.CollectionView.props.Document; }
+    @computed get dataField() {
+        return this.props.CollectionView.props.Document[Doc.LayoutFieldKey(this.props.CollectionView.props.Document)];
+    }
+    @computed get childDocs() {
+        return DocListCast(this.dataField);
+    }
+    @undoBatch
+    @action
+    nextKeyframe = (): void => {
+        const currentFrame = NumCast(this.Document.currentFrame);
+        if (currentFrame === undefined) {
+            this.Document.currentFrame = 0;
+            CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
+        }
+        CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0);
+        this.Document.currentFrame = Math.max(0, (currentFrame || 0) + 1);
+        this.Document.lastFrame = Math.max(NumCast(this.Document.currentFrame), NumCast(this.Document.lastFrame));
+    }
+    @undoBatch
+    @action
+    prevKeyframe = (): void => {
+        const currentFrame = NumCast(this.Document.currentFrame);
+        if (currentFrame === undefined) {
+            this.Document.currentFrame = 0;
+            CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
+        }
+        CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice());
+        this.Document.currentFrame = Math.max(0, (currentFrame || 0) - 1);
+    }
+    render() {
+        return this.Document.isAnnotationOverlay ? (null) :
+            <div className="collectionFreeFormViewChrome-cont">
+                <div key="back" title="back frame" className="backKeyframe" onClick={this.prevKeyframe}>
+                    <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
+                </div>
+                <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: this.Document.editing ? "#759c75" : "#c56565" }}
+                    onClick={action(() => this.Document.editing = !this.Document.editing)} >
+                    {NumCast(this.Document.currentFrame)}
+                </div>
+                <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={this.nextKeyframe}>
+                    <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
+                </div>
+            </div>;
+    }
+}
+
 @observer
 export class CollectionStackingViewChrome extends React.Component<CollectionViewChromeProps> {
     @observable private _currentKey: string = "";
@@ -474,19 +530,20 @@ export class CollectionSchemaViewChrome extends React.Component<CollectionViewCh
 @observer
 export class CollectionTreeViewChrome extends React.Component<CollectionViewChromeProps> {
 
-    get dataExtension() {
-        return this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "_ext"] as Doc;
+    get sortAscending() {
+        return this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"];
     }
-    @computed private get descending() {
-        return this.dataExtension && Cast(this.dataExtension.sortAscending, "boolean", null);
+    set sortAscending(value) {
+        this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"] = value;
+    }
+    @computed private get ascending() {
+        return Cast(this.sortAscending, "boolean", null);
     }
 
     @action toggleSort = () => {
-        if (this.dataExtension) {
-            if (this.dataExtension.sortAscending) this.dataExtension.sortAscending = undefined;
-            else if (this.dataExtension.sortAscending === undefined) this.dataExtension.sortAscending = false;
-            else this.dataExtension.sortAscending = true;
-        }
+        if (this.sortAscending) this.sortAscending = undefined;
+        else if (this.sortAscending === undefined) this.sortAscending = false;
+        else this.sortAscending = true;
     }
 
     render() {
@@ -496,7 +553,7 @@ export class CollectionTreeViewChrome extends React.Component<CollectionViewChro
                     <div className="collectionTreeViewChrome-sortLabel">
                         Sort
                         </div>
-                    <div className="collectionTreeViewChrome-sortIcon" style={{ transform: `rotate(${this.descending === undefined ? "90" : this.descending ? "180" : "0"}deg)` }}>
+                    <div className="collectionTreeViewChrome-sortIcon" style={{ transform: `rotate(${this.ascending === undefined ? "90" : this.ascending ? "180" : "0"}deg)` }}>
                         <FontAwesomeIcon icon="caret-up" size="2x" color="white" />
                     </div>
                 </button>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 5478a1c4a..d9011c9d3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -41,32 +41,6 @@
     // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions.
     touch-action: none;
 
-    .fwdKeyframe, .numKeyframe, .backKeyframe{
-        cursor: pointer;
-        position: absolute;
-        width: 20;
-        height:20;
-        bottom:0;
-        background:gray;
-    }
-    .backKeyframe {
-        right:45;
-        svg {
-            display:block;
-            margin:auto;
-        }
-    }
-    .numKeyframe {
-        right:25;
-        text-align:center;
-    }
-    .fwdKeyframe {
-        right:5;
-        svg {
-            display:block;
-            margin:auto;
-        }
-    }
 
     .collectionfreeformview-placeholder {
         background: gray;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index cb1228fed..c753a703d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
 import { library } from "@fortawesome/fontawesome-svg-core";
 import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons";
 import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed, trace } from "mobx";
 import { observer } from "mobx-react";
 import { computedFn } from "mobx-utils";
 import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../fields/Doc";
@@ -118,12 +118,28 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
         this.Document.scale || 1)
 
-    private centeringShiftX = () => !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0;  // shift so pan position is at center of window for non-overlay collections
-    private centeringShiftY = () => !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections
-    private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
-    private getTransformOverlay = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1);
-    private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
-    private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
+    @computed get cachedCenteringShiftX(): number {
+        return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0;  // shift so pan position is at center of window for non-overlay collections
+    }
+    @computed get cachedCenteringShiftY(): number {
+        return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections
+    }
+    @computed get cachedGetLocalTransform(): Transform {
+        return Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
+    }
+    @computed get cachedGetContainerTransform(): Transform {
+        return this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
+    }
+    @computed get cachedGetTransform(): Transform {
+        return this.getTransformOverlay().translate(- this.cachedCenteringShiftX, - this.cachedCenteringShiftY).transform(this.cachedGetLocalTransform);
+    }
+
+    private centeringShiftX = () => this.cachedCenteringShiftX;
+    private centeringShiftY = () => this.cachedCenteringShiftY;
+    private getTransform = () => this.cachedGetTransform.copy();
+    private getLocalTransform = () => this.cachedGetLocalTransform.copy();
+    private getContainerTransform = () => this.cachedGetContainerTransform.copy();
+    private getTransformOverlay = () => this.getContainerTransform().translate(1, 1);
     private addLiveTextBox = (newBox: Doc) => {
         FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
         this.addDocument(newBox);
@@ -162,30 +178,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         return retVal;
     })
 
-    @undoBatch
-    @action
-    nextKeyframe = (): void => {
-        const currentFrame = this.Document.currentFrame;
-        if (currentFrame === undefined) {
-            this.Document.currentFrame = 0;
-            CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
-        }
-        CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0);
-        this.Document.currentFrame = Math.max(0, (currentFrame || 0) + 1);
-        this.Document.lastFrame = Math.max(NumCast(this.Document.currentFrame), NumCast(this.Document.lastFrame));
-    }
-    @undoBatch
-    @action
-    prevKeyframe = (): void => {
-        const currentFrame = this.Document.currentFrame;
-        if (currentFrame === undefined) {
-            this.Document.currentFrame = 0;
-            CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
-        }
-        CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice());
-        this.Document.currentFrame = Math.max(0, (currentFrame || 0) - 1);
-    }
-
     private selectDocuments = (docs: Doc[]) => {
         SelectionManager.DeselectAll();
         docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).map(dv => dv && SelectionManager.SelectDoc(dv, true));
@@ -1219,6 +1211,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
 
         optionItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
+        optionItems.push({ description: "toggle snap line display", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" });
         optionItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
         optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
         optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
@@ -1397,18 +1390,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ?
                 this.placeholder : this.marqueeView}
             <CollectionFreeFormOverlayView elements={this.elementFunc} />
-            {this.isAnnotationOverlay || !this.props.isSelected() || this.props.Document._viewType === CollectionViewType.Pile ? (null) :
-                <>
-                    <div key="back" className="backKeyframe" onClick={this.prevKeyframe}>
-                        <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
-                    </div>
-                    <div key="num" className="numKeyframe" style={{ backgroundColor: this.Document.editing ? "#759c75" : "#c56565" }} onClick={action(() => this.Document.editing = !this.Document.editing)} >
-                        {NumCast(this.Document.currentFrame)}
-                    </div>
-                    <div key="fwd" className="fwdKeyframe" onClick={this.nextKeyframe}>
-                        <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
-                    </div>
-                </>}
+
             <div className={"pullpane-indicator"}
                 style={{
                     display: this._pullDirection ? "block" : "none",
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ed70ac9e8..cdfeeaa6b 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -357,10 +357,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         const selected = this.marqueeSelect(false);
         if (e instanceof KeyboardEvent ? e.key === "c" : true) {
             selected.map(action(d => {
-                //this.props.removeDocument(d);
-                d.x = NumCast(d.x) - bounds.left - bounds.width / 2;
-                d.y = NumCast(d.y) - bounds.top - bounds.height / 2;
-                d.displayTimecode = undefined;  // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+                const dx = NumCast(d.x);
+                const dy = NumCast(d.y);
+                delete d.x;
+                delete d.y;
+                delete d.activeFrame;
+                delete d.displayTimecode;  // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+                d.x = dx - bounds.left - bounds.width / 2;
+                d.y = dy - bounds.top - bounds.height / 2;
                 return d;
             }));
             this.props.removeDocument(selected);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 00d19752f..2de7b3460 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -965,9 +965,6 @@ 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());
-    panelWidth = () => this.props.PanelWidth();
-    panelHeight = () => this.props.PanelHeight();
-    screenToLocalTransform = () => this.props.ScreenToLocalTransform();
     @computed get contents() {
         TraceMobx();
         return (<>
@@ -988,10 +985,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 addDocument={this.props.addDocument}
                 removeDocument={this.props.removeDocument}
                 moveDocument={this.props.moveDocument}
-                ScreenToLocalTransform={this.screenToLocalTransform}
+                ScreenToLocalTransform={this.props.ScreenToLocalTransform}
                 renderDepth={this.props.renderDepth}
-                PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight}
+                PanelWidth={this.props.PanelWidth}
+                PanelHeight={this.props.PanelHeight}
                 ignoreAutoHeight={this.props.ignoreAutoHeight}
                 focus={this.props.focus}
                 parentActive={this.props.parentActive}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 56a543f46..9f1e99c77 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -62,11 +62,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const lastFrame = Cast(presTargetDoc.lastFrame, "number", null);
         const curFrame = NumCast(presTargetDoc.currentFrame);
         if (lastFrame !== undefined && curFrame < lastFrame) {
-            //const docs = DocListCast(presTargetDoc[Doc.LayoutFieldKey(presTargetDoc)]);
             presTargetDoc.transition = "all 1s";
             setTimeout(() => presTargetDoc.transition = undefined, 1010);
-            // docs.forEach(doc => doc.transition = "all 1s");
-            // setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010);
             presTargetDoc.currentFrame = curFrame + 1;
         }
         else if (this.childDocs[this.itemIndex + 1] !== undefined) {
-- 
cgit v1.2.3-70-g09d2

