diff options
| author | Sophie Zhang <sophie_zhang@brown.edu> | 2023-10-19 00:58:50 -0400 |
|---|---|---|
| committer | Sophie Zhang <sophie_zhang@brown.edu> | 2023-10-19 00:58:50 -0400 |
| commit | 1efba5a6a80cba09633426fc8cb42be4bf9b2e74 (patch) | |
| tree | abd78b4818115b300fb934e343f41417ac13e19f /src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | |
| parent | 612f3d05927113c7b010861c17765fcead4752e5 (diff) | |
| parent | abf40af6dd617de6486a97e8b5f276db232119ed (diff) | |
Merge branch 'master' into sophie-ai-images
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 676e96714..bfc61f601 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import { DateField } from '../../../../fields/DateField'; @@ -59,7 +59,7 @@ export type collectionFreeformViewProps = { originTopLeft?: boolean; annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox) viewDefDivClick?: ScriptField; - childPointerEvents?: string; + childPointerEvents?: () => string | undefined; viewField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; @@ -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; } @@ -1082,7 +1085,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection case freeformScrollMode.Pan: // if ctrl is selected then zoom if (!e.ctrlKey && this.props.isContentActive(true)) { - this.scrollPan({ deltaX: -e.deltaX, deltaY: e.shiftKey ? 0 : -Math.max(-1, Math.min(1, e.deltaY)) }); + this.scrollPan({ deltaX: -e.deltaX * this.getTransform().Scale, deltaY: e.shiftKey ? 0 : -e.deltaY * this.getTransform().Scale }); break; } default: @@ -1292,7 +1295,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); const pointerEvents = DocumentView.Interacting ? 'none' - : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.()); + : this.props.childPointerEvents?.() ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) || this.isContentActive() === false ? 'none' : this.props.pointerEvents?.()); return pointerEvents; } pointerEvents = () => this._pointerEvents; @@ -1508,9 +1511,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } @observable _numLoaded = 1; + _lastPoolSize = 0; get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; const array = Array.from(newPool.entries()); + let somethingChanged = array.length !== this._lastPoolSize; + this._lastPoolSize = array.length; runInAction(() => { for (const entry of array) { const lastPos = this._cachedPool.get(entry[0]); // last computed pos @@ -1528,12 +1534,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection newPos.transition !== lastPos.transition ) { this._layoutPoolData.set(entry[0], newPos); + somethingChanged = true; } if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) { this._layoutSizeData.set(entry[0], { width: newPos.width, height: newPos.height }); + somethingChanged = true; } } }); + if (!somethingChanged) return undefined; this._cachedPool.clear(); Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1])); const elements = computedElementData.slice(); @@ -1609,10 +1618,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection this._disposers.layoutComputation = reaction( () => this.doLayoutComputation, - elements => (this._layoutElements = elements || []), + elements => { + if (elements !== undefined) this._layoutElements = elements || []; + }, { 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 => { @@ -1768,9 +1784,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]; } }; @@ -1780,6 +1808,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', @@ -1816,14 +1845,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' }); } @@ -1917,7 +1939,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection <MarqueeView {...this.props} ref={this._marqueeViewRef} - ungroup={this.props.Document._isGroup ? this.promoteCollection : undefined} + ungroup={this.rootDoc._isGroup ? this.promoteCollection : undefined} nudge={this.isAnnotationOverlay || this.props.renderDepth > 0 ? undefined : this.nudge} addDocTab={this.addDocTab} slowLoadDocuments={this.slowLoadDocuments} |
