From 53d456afb43b70cc240bc6a37094fa37cfe37436 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 12 Oct 2023 11:24:19 -0400
Subject: performance fixes to reduce re-rendering : moved link brushing out of
 Doc's highlighting and into Annotation.tsx, stopped freeformview from
 rerendering whenever its invalidated by not always setting layoutElements to
 a new list.

---
 src/client/views/nodes/DocumentView.tsx | 43 +++++----------------------------
 1 file changed, 6 insertions(+), 37 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e4fc6c4a2..e8c33a10e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -156,7 +156,6 @@ export interface DocumentViewSharedProps {
     contentBounds?: () => undefined | { x: number; y: number; r: number; b: number };
     fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
     suppressSetHeight?: boolean;
-    thumbShown?: () => boolean;
     setContentView?: (view: DocComponentView) => any;
     CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
     PanelWidth: () => number;
@@ -299,10 +298,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
     }
     @computed get widgetDecorations() {
-        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Decorations + (this.props.isSelected() ? ':selected' : ''));
+        TraceMobx();
+        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Decorations);
     }
     @computed get backgroundBoxColor() {
-        return this.thumbShown() ? undefined : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor + ':box');
+        return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor + ':box');
     }
     @computed get docContents() {
         return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.DocContents);
@@ -317,7 +317,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         return this.props?.styleProvider?.(this.layoutDoc, this.props, StyleProp.TitleHeight) || 0;
     }
     @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined {
-        return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.props.isSelected() ? ':selected' : ''));
+        return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents);
     }
     @computed get finalLayoutKey() {
         return StrCast(this.Document.layout_fieldKey, 'layout');
@@ -884,23 +884,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             : undefined;
     }
     isContentActive = (): boolean | undefined => this._isContentActive;
-    @observable _retryThumb = 1;
-    @computed get _thumbShown() {
-        const childHighlighted = () => false;
-        // Array.from(Doc.highlightedDocs.keys())
-        //     .concat(Array.from(Doc.brushManager.BrushedDoc.keys()))
-        //     .some(doc => Doc.AreProtosEqual(DocCast(doc.annotationOn), this.rootDoc));
-        const childOverlayed = () => Array.from(DocumentManager._overlayViews).some(view => Doc.AreProtosEqual(view.rootDoc, this.rootDoc));
-        return !this.props.LayoutTemplateString &&
-            !this.isContentActive() &&
-            LightboxView.LightboxDoc !== this.rootDoc &&
-            this.thumb &&
-            !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
-            ((!childHighlighted() && !childOverlayed() && !Doc.isBrushedHighlightedDegree(this.rootDoc)) || this.rootDoc._type_collection === CollectionViewType.Docking)
-            ? true
-            : false;
-    }
-    thumbShown = () => this._thumbShown;
     childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
 
     /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive
@@ -918,25 +901,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     pointerEvents: (isInk ? 'none' : this.contentPointerEvents()) ?? 'all',
                     height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
                 }}>
-                {!this._retryThumb || !this.thumbShown() ? null : (
-                    <img
-                        style={{ background: 'white', top: 0, position: 'relative' }}
-                        src={this.thumb} // + '?d=' + (new Date()).getTime()}
-                        width={this.props.PanelWidth()}
-                        height={this.props.PanelHeight()}
-                        onError={(e: any) => {
-                            setTimeout(action(() => (this._retryThumb = 0)));
-                            // prettier-ignore
-                            setTimeout(action(() => (this._retryThumb = 1)), 150 );
-                        }}
-                    />
-                )}
                 <DocumentContentsView
                     key={1}
                     {...this.props}
                     pointerEvents={this.contentPointerEvents}
                     docViewPath={this.props.viewPath}
-                    thumbShown={this.thumbShown}
                     setContentView={this.setContentView}
                     childFilters={this.childFilters}
                     NativeDimScaling={this.props.NativeDimScaling}
@@ -1232,10 +1201,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         }
     }
     @computed get highlighting() {
-        return this.props.styleProvider?.(this.props.Document, this.props, StyleProp.Highlighting);
+        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting);
     }
     @computed get borderPath() {
-        return this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath);
+        return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BorderPath);
     }
     render() {
         TraceMobx();
-- 
cgit v1.2.3-70-g09d2


From 37cc69bcc8be3a6b160c45e5c16f969bd593fa88 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 16 Oct 2023 10:58:24 -0400
Subject: added auto reset view option for collections.

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 36 +++++++++++++++-------
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 2 files changed, 26 insertions(+), 12 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 407f18d62..3f23ee15a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -109,6 +109,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     private get panYFieldKey() {
         return (this.props.viewField ?? '') + '_freeform_panY';
     }
+    private get autoResetFieldKey() {
+        return (this.props.viewField ?? '') + '_freeform_autoReset';
+    }
     private get borderWidth() {
         return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH;
     }
@@ -1619,6 +1622,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     { fireImmediately: true, name: 'doLayout' }
                 );
 
+                this._disposers.active = reaction(
+                    () => this.isContentActive(),
+                    active => this.rootDoc[this.autoResetFieldKey] && !active && this.resetView()
+                );
+
                 this._disposers.fitContent = reaction(
                     () => this.rootDoc.fitContentOnce,
                     fitContentOnce => {
@@ -1774,9 +1782,21 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     ///
     @undoBatch
     resetView = () => {
-        if (!this.props.Document._isGroup) {
-            this.props.Document[this.panXFieldKey] = this.props.Document[this.panYFieldKey] = 0;
-            this.props.Document[this.scaleFieldKey] = 1;
+        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);
+    };
+    ///
+    /// resetView restores a freeform collection to unit scale and centered at (0,0)  UNLESS
+    ///  the view is a group, in which case this does nothing (since Groups calculate their own scale and center)
+    ///
+    @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];
         }
     };
 
@@ -1786,6 +1806,7 @@ 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' });
         !Doc.noviceMode &&
             appearanceItems.push({
                 description: 'Toggle auto arrange',
@@ -1822,14 +1843,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             !Doc.noviceMode &&
             optionItems.push({ description: (this._showAnimTimeline ? 'Close' : 'Open') + ' Animation Timeline', event: action(() => (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' });
         this.props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' });
-        this.props.renderDepth &&
-            optionItems.push({
-                description: 'Fit Content Once',
-                event: () => {
-                    this.fitContentOnce();
-                },
-                icon: 'object-group',
-            });
+        this.props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' });
         if (!Doc.noviceMode) {
             optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' });
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e8c33a10e..96d3adff5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -114,7 +114,7 @@ export interface DocComponentView {
     getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
     restoreView?: (viewSpec: Doc) => boolean;
     scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt<number>; // returns the duration of the focus
-    brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void;
+    brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number) => void; // highlight a region of a view (used by freeforms)
     getView?: (doc: Doc) => Promise<Opt<DocumentView>>; // returns a nested DocumentView for the specified doc or undefined
     addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox
     addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections)
-- 
cgit v1.2.3-70-g09d2


From f6337ba3244f2d7270dccb6b319c047e608c6a72 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 16 Oct 2023 13:57:01 -0400
Subject: cleaned up css and cursor pointer for tableboxes. prevent links being
 drawn to keyvaluebox.

---
 .../CollectionFreeFormLayoutEngines.tsx            |  1 -
 .../views/nodes/DataVizBox/components/Chart.scss   | 40 ++++++++++++++--------
 .../views/nodes/DataVizBox/components/TableBox.tsx | 12 +++----
 src/client/views/nodes/DocumentView.tsx            |  3 +-
 src/client/views/nodes/LinkAnchorBox.tsx           |  4 +++
 5 files changed, 37 insertions(+), 23 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 15b6e1d37..c1c01eacb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -6,7 +6,6 @@ import { RefField } from '../../../../fields/RefField';
 import { listSpec } from '../../../../fields/Schema';
 import { Cast, NumCast, StrCast } from '../../../../fields/Types';
 import { aggregateBounds } from '../../../../Utils';
-import { ColorScheme } from '../../../util/SettingsManager';
 import React = require('react');
 
 export interface ViewDefBounds {
diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index a6ce0b88c..c788a64c2 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -92,21 +92,33 @@
 .tableBox {
     display: flex;
     flex-direction: column;
+    cursor: default;
     height: calc(100% - 40px); // bcz: hack 40px is the size of the button rows
-    .table {
-        height: 100%;
-    }
-}
-.table-container {
-    overflow: scroll;
-    margin: 5px;
-    margin-left: 25px;
-    margin-right: 10px;
-    margin-bottom: 0;
-    tr td {
-        height: $DATA_VIZ_TABLE_ROW_HEIGHT !important; // bcz: hack.  you can't set a <tr> height directly, but you can set the height of all of it's <td>s.  So this is the height of a tableBox row.
-        padding: 0 !important;
-        vertical-align: middle !important;
+    .tableBox-container {
+        overflow: scroll;
+        margin: 5px;
+        margin-left: 25px;
+        margin-right: 10px;
+        margin-bottom: 0;
+        .tableBox-table {
+            height: 100%;
+            width: 100%;
+            .tableBox-row {
+                cursor: pointer;
+                .tableBox-cell {
+                    text-overflow: ellipsis;
+                    width: 100%;
+                    white-space: pre;
+                    max-width: 150;
+                    overflow: hidden;
+                }
+            }
+        }
+        tr td {
+            height: $DATA_VIZ_TABLE_ROW_HEIGHT !important; // bcz: hack.  you can't set a <tr> height directly, but you can set the height of all of it's <td>s.  So this is the height of a tableBox row.
+            padding: 0 !important;
+            vertical-align: middle !important;
+        }
     }
 }
 .selectAll-buttons {
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 1ece3f238..b88389de6 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -175,7 +175,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                         <Button onClick={action(() => (this.props.layoutDoc.dataViz_selectedRows = new List<number>()))} text="Deselect All" type={Type.SEC} color={'black'} />
                     </div>
                     <div
-                        className={`table-container ${this.columns[0]}`}
+                        className={`tableBox-container ${this.columns[0]}`}
                         style={{ height: '100%', overflow: 'auto' }}
                         onScroll={this.handleScroll}
                         ref={action((r: HTMLDivElement | null) => {
@@ -193,7 +193,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                             }
                         })}>
                         <table
-                            className="table"
+                            className="tableBox-table"
                             ref={action((r: HTMLTableElement | null) => {
                                 if (!this.props.docView?.()?.ContentDiv?.hidden && r) {
                                     this._tableHeight = r?.getBoundingClientRect().height ?? 0;
@@ -220,21 +220,19 @@ export class TableBox extends React.Component<TableBoxProps> {
                             <tbody>
                                 {this._tableDataIds
                                     .filter(rowId => this.startID <= rowId && rowId <= this.endID)
-                                    ?.map(rowId => ({ record: this.props.records[rowId], rowId }))
-                                    .map(({ record, rowId }) => (
+                                    ?.map(rowId => (
                                         <tr
                                             key={rowId}
-                                            className={`table-row ${this.columns[0]}`}
+                                            className={`tableBox-row ${this.columns[0]}`}
                                             onClick={e => this.tableRowClick(e, rowId)}
                                             style={{
                                                 background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '',
-                                                width: '110%',
                                             }}>
                                             {this.columns.map(col => {
                                                 const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false;
                                                 return (
                                                     <td key={this.columns.indexOf(col)} style={{ border: colSelected ? '3px solid black' : '1px solid black', fontWeight: colSelected ? 'bolder' : 'normal' }}>
-                                                        <div style={{ textOverflow: 'ellipsis', width: '100%', whiteSpace: 'pre', maxWidth: 150, overflow: 'hidden' }}>{record[col]}</div>
+                                                        <div className="tableBox-cell">{this.props.records[rowId][col]}</div>
                                                     </td>
                                                 );
                                             })}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 96d3adff5..da665a502 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -52,6 +52,7 @@ import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
+import { KeyValueBox } from './KeyValueBox';
 const { Howl } = require('howler');
 
 interface Window {
@@ -963,7 +964,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get allLinkEndpoints() {
         // the small blue dots that mark the endpoints of links
         TraceMobx();
-        if (this.props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.layout_unrendered) return null;
+        if (this._componentView instanceof KeyValueBox || this.props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.layout_unrendered) return null;
         const filtered = DocUtils.FilterDocs(this.directLinks, this.props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines);
         return filtered.map(link => (
             <div className="documentView-anchorCont" key={link[Id]}>
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 9bcd04cf5..fd7d13655 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -28,6 +28,10 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @observable _x = 0;
     @observable _y = 0;
 
+    componentDidMount() {
+        this.props.setContentView?.(this);
+    }
+
     @computed get linkSource() {
         return this.props.docViewPath()[this.props.docViewPath().length - 2].rootDoc; // this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource);
     }
-- 
cgit v1.2.3-70-g09d2

