From ba3b3f6f261074bd3f35012bde8730f5d4a36905 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 29 Nov 2023 10:02:34 -0500
Subject: numerous changes to fix bugs and to fix/remove old or hacky code. 
 fixed doc dec resizing.  moving this.rootDoc => this.Document .  fixing
 template artifacts.

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 199 +++++++++++----------
 1 file changed, 101 insertions(+), 98 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 7f8bde9b4..6babe3c8f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -134,7 +134,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         return (this.props.fitContentsToBox?.() || this.Document._freeform_fitContentsToBox) && !this.isAnnotationOverlay;
     }
     @computed get contentBounds() {
-        const cb = Cast(this.rootDoc.contentBounds, listSpec('number'));
+        const cb = Cast(this.dataDoc.contentBounds, listSpec('number'));
         return cb
             ? { x: cb[0], y: cb[1], r: cb[2], b: cb[3] }
             : aggregateBounds(
@@ -155,9 +155,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
     @computed get cachedCenteringShiftY(): number {
         const dv = this.props.DocumentView?.();
+        const fitWidth = this.props.layout_fitWidth?.(this.Document) ?? dv?.layoutDoc.layout_fitWidth;
         const scaling = this.fitContentsToBox || !this.nativeDimScaling ? 1 : this.nativeDimScaling;
         // if freeform has a native aspect, then the panel height needs to be adjusted to match it
-        const aspect = dv?.nativeWidth && dv?.nativeHeight && !dv.layoutDoc.layout_fitWidth ? dv.nativeHeight / dv.nativeWidth : this.props.PanelHeight() / this.props.PanelWidth();
+        const aspect = dv?.nativeWidth && dv?.nativeHeight && !fitWidth ? dv.nativeHeight / dv.nativeWidth : this.props.PanelHeight() / this.props.PanelWidth();
         return this.props.isAnnotationOverlay || this.props.originTopLeft ? 0 : (aspect * this.props.PanelWidth()) / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
     }
     @computed get panZoomXf() {
@@ -181,15 +182,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const timecode = Math.round(time);
         docs.forEach(doc => {
             CollectionFreeFormDocumentView.animFields.forEach(val => {
-                const findexed = Cast(doc[`${val.key}-indexed`], listSpec('number'), null);
+                const findexed = Cast(doc[`${val.key}_indexed`], listSpec('number'), null);
                 findexed?.length <= timecode + 1 && findexed.push(undefined as any as number);
             });
             CollectionFreeFormDocumentView.animStringFields.forEach(val => {
-                const findexed = Cast(doc[`${val}-indexed`], listSpec('string'), null);
+                const findexed = Cast(doc[`${val}_indexed`], listSpec('string'), null);
                 findexed?.length <= timecode + 1 && findexed.push(undefined as any as string);
             });
             CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => {
-                const findexed = Cast(doc[`${val}-indexed`], listSpec(InkField), null);
+                const findexed = Cast(doc[`${val}_indexed`], listSpec(InkField), null);
                 findexed?.length <= timecode + 1 && findexed.push(undefined as any);
             });
         });
@@ -262,7 +263,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             for (const newBox of newBoxes) {
                 if (newBox.activeFrame !== undefined) {
                     const vals = CollectionFreeFormDocumentView.animFields.map(field => newBox[field.key]);
-                    CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field.key}-indexed`]);
+                    CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field.key}_indexed`]);
                     CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[field.key]);
                     delete newBox.activeFrame;
                     CollectionFreeFormDocumentView.animFields.forEach((field, i) => field.key !== 'opacity' && (newBox[field.key] = vals[i]));
@@ -283,15 +284,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     groupFocus = (anchor: Doc, options: DocFocusOptions) => {
-        options.docTransform = new Transform(-NumCast(this.rootDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.rootDoc[this.panYFieldKey]) + NumCast(anchor.y), 1);
-        const res = this.props.focus(this.rootDoc, options);
+        options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1);
+        const res = this.props.focus(this.Document, options);
         options.docTransform = undefined;
         return res;
     };
 
     focus = (anchor: Doc, options: DocFocusOptions) => {
         if (this._lightboxDoc) return;
-        if (anchor === this.rootDoc) {
+        if (anchor === this.Document) {
             if (options.willZoomCentered && options.zoomScale) {
                 this.fitContentOnce();
                 options.didMove = true;
@@ -300,7 +301,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (anchor.type !== DocumentType.CONFIG && !DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor)) return;
         const xfToCollection = options?.docTransform ?? Transform.Identity();
         const savedState = { panX: NumCast(this.Document[this.panXFieldKey]), panY: NumCast(this.Document[this.panYFieldKey]), scale: options?.willZoomCentered ? this.Document[this.scaleFieldKey] : undefined };
-        const cantTransform = this.fitContentsToBox || ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc);
+        const cantTransform = this.fitContentsToBox || ((this.Document.isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc);
         const { panX, panY, scale } = cantTransform || (!options.willPan && !options.willZoomCentered) ? savedState : this.calculatePanIntoView(anchor, xfToCollection, options?.willZoomCentered ? options?.zoomScale ?? 0.75 : undefined);
 
         // focus on the document in the collection
@@ -407,7 +408,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             let added = false;
             //  do nothing if link is dropped into any freeform view parent of dragged document
             const source =
-                !linkDragData.dragDocument.embedContainer || linkDragData.dragDocument.embedContainer !== this.rootDoc
+                !linkDragData.dragDocument.embedContainer || linkDragData.dragDocument.embedContainer !== this.Document
                     ? Docs.Create.TextDocument('', { _width: 200, _height: 75, x: xp, y: yp, title: 'dropped annotation' })
                     : Docs.Create.FontIconDocument({
                           title: 'anchor',
@@ -582,27 +583,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     clusterStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => {
         let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props'  used to be renderDepth + 1
-        switch (property) {
-            case StyleProp.BackgroundColor:
-                const cluster = NumCast(doc?.layout_cluster);
-                if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) {
-                    if (this._clusterSets.length <= cluster) {
-                        setTimeout(() => doc && this.updateCluster(doc));
-                    } else {
-                        // choose a cluster color from a palette
-                        const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)'];
-                        styleProp = colors[cluster % colors.length];
-                        const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
-                        // override the cluster color with an explicitly set color on a non-background document.  then override that with an explicitly set color on a background document
-                        set?.map(s => (styleProp = StrCast(s.backgroundColor)));
+        if (doc && this.childDocList?.includes(doc))
+            switch (property) {
+                case StyleProp.BackgroundColor:
+                    const cluster = NumCast(doc?.layout_cluster);
+                    if (this.Document._freeform_useClusters && doc?.type !== DocumentType.IMG) {
+                        if (this._clusterSets.length <= cluster) {
+                            setTimeout(() => doc && this.updateCluster(doc));
+                        } else {
+                            // choose a cluster color from a palette
+                            const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)'];
+                            styleProp = colors[cluster % colors.length];
+                            const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
+                            // override the cluster color with an explicitly set color on a non-background document.  then override that with an explicitly set color on a background document
+                            set?.map(s => (styleProp = StrCast(s.backgroundColor)));
+                        }
                     }
-                }
-                break;
-            case StyleProp.FillColor:
-                if (doc && this.Document._currentFrame !== undefined) {
-                    return CollectionFreeFormDocumentView.getStringValues(doc, NumCast(this.Document._currentFrame))?.fillColor;
-                }
-        }
+                    break;
+                case StyleProp.FillColor:
+                    if (doc && this.Document._currentFrame !== undefined) {
+                        return CollectionFreeFormDocumentView.getStringValues(doc, NumCast(this.Document._currentFrame))?.fillColor;
+                    }
+            }
         return styleProp;
     };
 
@@ -623,7 +625,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this._downTime = Date.now();
         const scrollMode = e.altKey ? (Doc.UserDoc().freeformScrollMode === freeformScrollMode.Pan ? freeformScrollMode.Zoom : freeformScrollMode.Pan) : Doc.UserDoc().freeformScrollMode;
         if (e.button === 0 && (!(e.ctrlKey && !e.metaKey) || scrollMode !== freeformScrollMode.Pan) && this.props.isContentActive(true)) {
-            if (!this.props.Document._isGroup) {
+            if (!this.Document.isGroup) {
                 // group freeforms don't pan when dragged -- instead let the event go through to allow the group itself to drag
                 // prettier-ignore
                 switch (Doc.ActiveTool) {
@@ -697,7 +699,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     @action
     onEraserUp = (e: PointerEvent): void => {
-        this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc));
+        this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.Document));
         this._deleteList = [];
         this._batch?.end();
     };
@@ -752,8 +754,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => {
             if (!this._deleteList.includes(intersect.inkView)) {
                 this._deleteList.push(intersect.inkView);
-                SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.stroke_width?.toString()) || '1');
-                SetActiveInkColor(StrCast(intersect.inkView.rootDoc.color?.toString()) || 'black');
+                SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1');
+                SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black');
                 // create a new curve by appending all curves of the current segment together in order to render a single new stroke.
                 if (!e.shiftKey) {
                     this._eraserLock++;
@@ -785,7 +787,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             return true;
         }
         // pan the view if this is a regular collection, or it's an overlay and the overlay is zoomed (otherwise, there's nothing to pan)
-        if (!this.props.isAnnotationOverlay || 1 - NumCast(this.rootDoc._freeform_scale_min, 1) / this.zoomScaling()) {
+        if (!this.props.isAnnotationOverlay || 1 - NumCast(this.layoutDoc._freeform_scale_min, 1) / this.zoomScaling()) {
             this.pan(e);
             e.stopPropagation(); // if we are actually panning, stop propagation -- this will preven things like the overlayView from dragging the document while we're panning
         }
@@ -927,7 +929,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     zoom = (pointX: number, pointY: number, deltaY: number): void => {
-        if (this.Document._isGroup || this.Document[(this.props.viewField ?? '_') + 'freeform_noZoom']) return;
+        if (this.Document.isGroup || this.Document[(this.props.viewField ?? '_') + 'freeform_noZoom']) return;
         let deltaScale = deltaY > 0 ? 1 / 1.05 : 1.05;
         if (deltaScale < 0) deltaScale = -deltaScale;
         const [x, y] = this.screenToLocalXf.transformPoint(pointX, pointY);
@@ -935,15 +937,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         if (deltaScale * invTransform.Scale > 20) {
             deltaScale = 20 / invTransform.Scale;
         }
-        if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc[this.scaleFieldKey + '_min'])) {
+        if (deltaScale < 1 && invTransform.Scale <= NumCast(this.Document[this.scaleFieldKey + '_min'])) {
             this.setPan(0, 0);
             return;
         }
-        if (deltaScale * invTransform.Scale > NumCast(this.rootDoc[this.scaleFieldKey + '_max'], Number.MAX_VALUE)) {
-            deltaScale = NumCast(this.rootDoc[this.scaleFieldKey + '_max'], 1) / invTransform.Scale;
+        if (deltaScale * invTransform.Scale > NumCast(this.Document[this.scaleFieldKey + '_max'], Number.MAX_VALUE)) {
+            deltaScale = NumCast(this.Document[this.scaleFieldKey + '_max'], 1) / invTransform.Scale;
         }
-        if (deltaScale * invTransform.Scale < NumCast(this.rootDoc[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0)) {
-            deltaScale = NumCast(this.rootDoc[this.scaleFieldKey + '_min'], 1) / invTransform.Scale;
+        if (deltaScale * invTransform.Scale < NumCast(this.Document[this.scaleFieldKey + '_min'], this.isAnnotationOverlay ? 1 : 0)) {
+            deltaScale = NumCast(this.Document[this.scaleFieldKey + '_min'], 1) / invTransform.Scale;
         }
 
         const localTransform = invTransform.scaleAbout(deltaScale, x, y);
@@ -956,11 +958,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        if (this.Document._isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
+        if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom
         PresBox.Instance?.pauseAutoPres();
         if (this.layoutDoc._Transform || this.props.Document.treeView_OutlineMode === TreeViewType.outline) return;
         e.stopPropagation();
-        const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight);
+        const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight);
         const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4;
         switch (
             !e.ctrlKey && !e.shiftKey && !e.metaKey && !e.altKey ?//
@@ -1024,28 +1026,28 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         }
         if (!this.layoutDoc._lockedTransform || LightboxView.LightboxDoc) {
             this.setPanZoomTransition(panTime);
-            const minScale = NumCast(this.rootDoc._freeform_scale_min, 1);
+            const minScale = NumCast(this.dataDoc._freeform_scale_min, 1);
             const scale = 1 - minScale / this.zoomScaling();
-            const minPanX = NumCast(this.rootDoc._freeform_panX_min, 0);
-            const minPanY = NumCast(this.rootDoc._freeform_panY_min, 0);
-            const maxPanX = NumCast(this.rootDoc._freeform_panX_max, this.nativeWidth);
+            const minPanX = NumCast(this.dataDoc._freeform_panX_min, 0);
+            const minPanY = NumCast(this.dataDoc._freeform_panY_min, 0);
+            const maxPanX = NumCast(this.dataDoc._freeform_panX_max, this.nativeWidth);
             const newPanX = Math.min(minPanX + scale * maxPanX, Math.max(minPanX, panX));
             const fitYscroll = (((this.nativeHeight / this.nativeWidth) * this.props.PanelWidth() - this.props.PanelHeight()) * this.props.ScreenToLocalTransform().Scale) / minScale;
             const nativeHeight = (this.props.PanelHeight() / this.props.PanelWidth() / (this.nativeHeight / this.nativeWidth)) * this.nativeHeight;
             const maxScrollTop = this.nativeHeight / this.props.ScreenToLocalTransform().Scale - this.props.PanelHeight();
             const maxPanY =
                 minPanY + // minPanY + scrolling introduced by view scaling + scrolling introduced by layout_fitWidth
-                scale * NumCast(this.rootDoc._panY_max, nativeHeight) +
+                scale * NumCast(this.dataDoc._panY_max, nativeHeight) +
                 (!this.props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning
             let newPanY = Math.max(minPanY, Math.min(maxPanY, panY));
-            if (false && NumCast(this.rootDoc.layout_scrollTop) && NumCast(this.rootDoc._freeform_scale, minScale) !== minScale) {
-                const relTop = NumCast(this.rootDoc.layout_scrollTop) / maxScrollTop;
-                this.rootDoc.layout_scrollTop = undefined;
+            if (false && NumCast(this.layoutDoc.layout_scrollTop) && NumCast(this.layoutDoc._freeform_scale, minScale) !== minScale) {
+                const relTop = NumCast(this.layoutDoc.layout_scrollTop) / maxScrollTop;
+                this.layoutDoc.layout_scrollTop = undefined;
                 newPanY = minPanY + relTop * (maxPanY - minPanY);
-            } else if (fitYscroll > 2 && this.rootDoc.layout_scrollTop === undefined && NumCast(this.rootDoc._freeform_scale, minScale) === minScale) {
+            } else if (fitYscroll > 2 && this.layoutDoc.layout_scrollTop === undefined && NumCast(this.layoutDoc._freeform_scale, minScale) === minScale) {
                 const maxPanY = minPanY + fitYscroll;
                 const relTop = (panY - minPanY) / (maxPanY - minPanY);
-                setTimeout(() => (this.rootDoc.layout_scrollTop = relTop * maxScrollTop), 10);
+                setTimeout(() => (this.layoutDoc.layout_scrollTop = relTop * maxScrollTop), 10);
                 newPanY = minPanY;
             }
             !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX);
@@ -1055,8 +1057,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     nudge = (x: number, y: number, nudgeTime: number = 500) => {
-        const collectionDoc = this.props.docViewPath().lastElement().rootDoc;
-        if (collectionDoc?._type_collection !== CollectionViewType.Freeform || collectionDoc._freeform_ !== undefined) {
+        const collectionDoc = this.props.docViewPath().lastElement().Document;
+        if (collectionDoc?._type_collection !== CollectionViewType.Freeform) {
             this.setPan(
                 NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
                 NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(),
@@ -1104,7 +1106,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     zoomSmoothlyAboutPt(docpt: number[], scale: number, transitionTime = 500) {
-        if (this.Document._isGroup) return;
+        if (this.Document.isGroup) return;
         this.setPanZoomTransition(transitionTime);
         const screenXY = this.screenToLocalXf.inverse().transformPoint(docpt[0], docpt[1]);
         this.layoutDoc[this.scaleFieldKey] = scale;
@@ -1162,17 +1164,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @action
     onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
         const docView = fieldProps.DocumentView?.();
-        if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
+        if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
             e.stopPropagation?.();
             const below = !e.altKey && e.key !== 'Tab';
             const layout_fieldKey = StrCast(docView.LayoutFieldKey);
-            const newDoc = Doc.MakeCopy(docView.rootDoc, true);
-            const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)];
+            const newDoc = Doc.MakeCopy(docView.Document, true);
+            const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)];
             newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
-            if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10;
-            else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10;
-            if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) {
-                newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey];
+            if (below) newDoc.y = NumCast(docView.Document.y) + NumCast(docView.Document._height) + 10;
+            else newDoc.x = NumCast(docView.Document.x) + NumCast(docView.Document._width) + 10;
+            if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) {
+                newDoc[layout_fieldKey] = docView.Document[layout_fieldKey];
             }
             Doc.GetProto(newDoc).text = undefined;
             FormattedTextBox.SelectOnLoad = newDoc[Id];
@@ -1228,7 +1230,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 searchFilterDocs={this.searchFilterDocs}
                 isDocumentActive={childLayout.pointerEvents === 'none' ? returnFalse : this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
                 isContentActive={this.childContentsActive}
-                focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
+                focus={this.Document.isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
                 addDocTab={this.addDocTab}
                 addDocument={this.props.addDocument}
                 removeDocument={this.props.removeDocument}
@@ -1237,7 +1239,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
                 docViewPath={this.props.docViewPath}
                 styleProvider={this.clusterStyleProvider}
-                dragAction={(this.rootDoc.childDragAction ?? this.props.childDragAction) as dropActionType}
+                dragAction={(this.Document.childDragAction ?? this.props.childDragAction) as dropActionType}
                 bringToFront={this.bringToFront}
                 layout_showTitle={this.props.childlayout_showTitle}
                 dontRegisterView={this.props.dontRegisterView}
@@ -1288,9 +1290,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const contentFrameNumber = Cast(childDocLayout._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
         const { z, zIndex } = childDoc;
         const { backgroundColor, color } = contentFrameNumber === undefined ? { backgroundColor: undefined, color: undefined } : CollectionFreeFormDocumentView.getStringValues(childDoc, contentFrameNumber);
-        const { x, y, _width, _height, opacity, _rotation } =
+        const { x, y, autoDim, _width, _height, opacity, _rotation } =
             layoutFrameNumber === undefined // -1 for width/height means width/height should be PanelWidth/PanelHeight (prevents collectionfreeformdocumentview width/height from getting out of synch with panelWIdth/Height which causes detailView to re-render and lose focus because HTMLtag scaling gets set to a bad intermediate value)
-                ? { _width: -1, _height: -1, _rotation: Cast(childDocLayout._rotation, 'number'), x: childDoc.x, y: childDoc.y, opacity: this.props.childOpacity?.() }
+                ? { autoDim: 1, _width: Cast(childDoc._width, 'number'), _height: Cast(childDoc._height, 'number'), _rotation: Cast(childDocLayout._rotation, 'number'), x: childDoc.x, y: childDoc.y, opacity: this.props.childOpacity?.() }
                 : CollectionFreeFormDocumentView.getValues(childDoc, layoutFrameNumber);
         // prettier-ignore
         const rotation = Cast(_rotation,'number',
@@ -1300,6 +1302,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             x: Number.isNaN(NumCast(x)) ? 0 : NumCast(x),
             y: Number.isNaN(NumCast(y)) ? 0 : NumCast(y),
             z: Cast(z, 'number'),
+            autoDim,
             rotation,
             color: Cast(color, 'string') ? StrCast(color) : this.props.styleProvider?.(childDoc, this.props, StyleProp.Color),
             backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.clusterStyleProvider(childDoc, this.props, StyleProp.BackgroundColor),
@@ -1413,8 +1416,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
         // create an anchor that saves information about the current state of the freeform view (pan, zoom, view type)
-        const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.rootDoc });
-        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document._isGroup, type_collection: true, filters: true } }, this.rootDoc);
+        const anchor = Docs.Create.ConfigDocument({ title: 'ViewSpec - ' + StrCast(this.layoutDoc._type_collection), layout_unrendered: true, presentation_transition: 500, annotationOn: this.Document });
+        PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), pannable: !this.Document.isGroup, type_collection: true, filters: true } }, this.Document);
 
         if (addAsAnnotation) {
             if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) {
@@ -1434,7 +1437,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 this._firstRender = false;
                 this._disposers.groupBounds = reaction(
                     () => {
-                        if (this.Document._isGroup && this.childDocs.length === this.childDocList?.length) {
+                        if (this.Document.isGroup && this.childDocs.length === this.childDocList?.length) {
                             const clist = this.childDocs.map(cd => ({ x: NumCast(cd.x), y: NumCast(cd.y), width: NumCast(cd._width), height: NumCast(cd._height) }));
                             return aggregateBounds(clist, NumCast(this.layoutDoc._xPadding), NumCast(this.layoutDoc._yPadding));
                         }
@@ -1481,7 +1484,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
                 this._disposers.active = reaction(
                     () => this.isContentActive(), // if autoreset is on, then whenever the view is selected, it will be restored to it default pan/zoom positions
-                    active => !SnappingManager.GetIsDragging() && this.rootDoc[this.autoResetFieldKey] && active && this.resetView()
+                    active => !SnappingManager.GetIsDragging() && this.dataDoc[this.autoResetFieldKey] && active && this.resetView()
                 );
             })
         );
@@ -1575,7 +1578,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     componentWillUnmount() {
-        this.rootDoc[this.autoResetFieldKey] && this.resetView();
+        this.dataDoc[this.autoResetFieldKey] && this.resetView();
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
@@ -1616,9 +1619,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     ///
     @undoBatch
     resetView = () => {
-        this.rootDoc[this.panXFieldKey] = NumCast(this.rootDoc[this.panXFieldKey + '_reset']);
-        this.props.Document[this.panYFieldKey] = NumCast(this.rootDoc[this.panYFieldKey + '_reset']);
-        this.rootDoc[this.scaleFieldKey] = NumCast(this.rootDoc[this.scaleFieldKey + '_reset'], 1);
+        this.layoutDoc[this.panXFieldKey] = NumCast(this.dataDoc[this.panXFieldKey + '_reset']);
+        this.layoutDoc[this.panYFieldKey] = NumCast(this.dataDoc[this.panYFieldKey + '_reset']);
+        this.layoutDoc[this.scaleFieldKey] = NumCast(this.dataDoc[this.scaleFieldKey + '_reset'], 1);
     };
     ///
     /// resetView restores a freeform collection to unit scale and centered at (0,0)  UNLESS
@@ -1626,11 +1629,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     ///
     @undoBatch
     toggleResetView = () => {
-        this.rootDoc[this.autoResetFieldKey] = !this.rootDoc[this.autoResetFieldKey];
-        if (this.rootDoc[this.autoResetFieldKey]) {
-            this.rootDoc[this.panXFieldKey + '_reset'] = this.rootDoc[this.panXFieldKey];
-            this.rootDoc[this.panYFieldKey + '_reset'] = this.rootDoc[this.panYFieldKey];
-            this.rootDoc[this.scaleFieldKey + '_reset'] = this.rootDoc[this.scaleFieldKey];
+        this.dataDoc[this.autoResetFieldKey] = !this.dataDoc[this.autoResetFieldKey];
+        if (this.dataDoc[this.autoResetFieldKey]) {
+            this.dataDoc[this.panXFieldKey + '_reset'] = this.dataDoc[this.panXFieldKey];
+            this.dataDoc[this.panYFieldKey + '_reset'] = this.dataDoc[this.panYFieldKey];
+            this.dataDoc[this.scaleFieldKey + '_reset'] = this.dataDoc[this.scaleFieldKey];
         }
     };
 
@@ -1639,8 +1642,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         const appearance = ContextMenu.Instance.findByDescription('Appearance...');
         const appearanceItems = appearance && 'subitems' in appearance ? appearance.subitems : [];
-        !this.props.Document._isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' });
-        !this.props.Document._isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' });
+        !this.props.Document.isGroup && appearanceItems.push({ description: 'Reset View', event: this.resetView, icon: 'compress-arrows-alt' });
+        !this.props.Document.isGroup && appearanceItems.push({ description: 'Toggle Auto Reset View', event: this.toggleResetView, icon: 'compress-arrows-alt' });
         !Doc.noviceMode &&
             appearanceItems.push({
                 description: 'Toggle auto arrange',
@@ -1652,11 +1655,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             return;
         }
         !Doc.noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: 'Reset default note style', event: () => (Doc.UserDoc().defaultTextLayout = undefined), icon: 'eye' });
-        appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' });
+        appearanceItems.push({ description: `Pin View`, event: () => this.props.pinToPres(this.Document, { pinViewport: MarqueeView.CurViewBounds(this.dataDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' });
         !Doc.noviceMode && appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: 'compress-arrows-alt' });
         this.props.renderDepth && appearanceItems.push({ description: 'Ungroup collection', event: this.promoteCollection, icon: 'table' });
 
-        this.props.Document._isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' });
+        this.props.Document.isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: this.transcribeStrokes, icon: 'font' });
 
         !Doc.noviceMode ? appearanceItems.push({ description: 'Arrange contents in grid', event: this.layoutDocsInGrid, icon: 'table' }) : null;
         !Doc.noviceMode ? appearanceItems.push({ description: (this.Document._freeform_useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null;
@@ -1681,7 +1684,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @undoBatch
     @action
     transcribeStrokes = () => {
-        if (this.props.Document._isGroup && this.props.Document.transcription) {
+        if (this.props.Document.isGroup && this.props.Document.transcription) {
             const text = StrCast(this.props.Document.transcription);
             const lines = text.split('\n');
             const height = 30 + 15 * lines.length;
@@ -1697,9 +1700,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     @action
     dragStarting = (snapToDraggedDoc: boolean = false, showGroupDragTarget: boolean = true, visited = new Set<Doc>()) => {
-        if (visited.has(this.rootDoc)) return;
-        visited.add(this.rootDoc);
-        showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document._isGroup));
+        if (visited.has(this.Document)) return;
+        visited.add(this.Document);
+        showGroupDragTarget && (this.GroupChildDrag = BoolCast(this.Document.isGroup));
         const activeDocs = this.getActiveDocuments();
         const size = this.screenToLocalXf.transformDirection(this.props.PanelWidth(), this.props.PanelHeight());
         const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] };
@@ -1708,14 +1711,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         const snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to
         activeDocs
-            .filter(doc => doc._isGroup && SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc))
+            .filter(doc => doc.isGroup && SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc))
             .forEach(doc => DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.dragStarting?.(snapToDraggedDoc, false, visited));
 
         const horizLines: number[] = [];
         const vertLines: number[] = [];
         const invXf = this.screenToLocalXf.inverse();
         snappableDocs
-            .filter(doc => !doc._isGroup && (snapToDraggedDoc || (SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc))))
+            .filter(doc => !doc.isGroup && (snapToDraggedDoc || (SnappingManager.GetIsResizing() !== doc && !DragManager.docsBeingDragged.includes(doc))))
             .forEach(doc => {
                 const { left, top, width, height } = docDims(doc);
                 const topLeftInScreen = invXf.transformPoint(left, top);
@@ -1783,7 +1786,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this.incrementalRender();
         return (
             <CollectionFreeFormPannableContents
-                rootDoc={this.rootDoc}
+                Document={this.Document}
                 brushedView={this.brushedView}
                 isAnnotationOverlay={this.isAnnotationOverlay}
                 transform={this.PanZoomCenterXf}
@@ -1801,7 +1804,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             <MarqueeView
                 {...this.props}
                 ref={this._marqueeViewRef}
-                ungroup={this.rootDoc._isGroup ? this.promoteCollection : undefined}
+                ungroup={this.Document.isGroup ? this.promoteCollection : undefined}
                 nudge={this.isAnnotationOverlay || this.props.renderDepth > 0 ? undefined : this.nudge}
                 addDocTab={this.addDocTab}
                 slowLoadDocuments={this.slowLoadDocuments}
@@ -1828,7 +1831,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const nh = this.nativeHeight;
         const hscale = nh ? this.props.PanelHeight() / nh : 1;
         const wscale = nw ? this.props.PanelWidth() / nw : 1;
-        return wscale < hscale || this.layoutDoc.layout_fitWidth ? wscale : hscale;
+        return wscale < hscale || (this.props.layout_fitWidth?.(this.Document) ?? this.layoutDoc.layout_fitWidth) ? wscale : hscale;
     }
     nativeDim = () => this.nativeDimScaling;
 
@@ -1849,7 +1852,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     lightboxPanelHeight = () => Math.max(0, this.props.PanelHeight() - 30);
     lightboxScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-15, -15);
     onPassiveWheel = (e: WheelEvent) => {
-        const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight);
+        const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight);
         const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling;
         this.props.isSelected() && !scrollable && e.preventDefault();
     };
@@ -1930,14 +1933,14 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY
     dv &&
         DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
             if (!focused) {
-                const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
+                const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
                 let containers = dv.props.docViewPath();
                 let parFfview = dv.CollectionFreeFormView;
                 for (var cont of containers) {
                     parFfview = parFfview ?? cont.CollectionFreeFormView;
                 }
-                while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView;
-                const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it.  Otherwise, zoom out on the parent ffview
+                while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView;
+                const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it.  Otherwise, zoom out on the parent ffview
                 ffview?.zoomSmoothlyAboutPt(ffview.screenToLocalXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime);
                 Doc.linkFollowHighlight(dv?.props.Document, false);
             }
-- 
cgit v1.2.3-70-g09d2

