import { action, computed, IReactionDisposer, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { returnFalse, setupMoveUpEvents } from '../../../ClientUtils'; import { Doc, DocListCast, FieldResult } from '../../../fields/Doc'; import { ScriptField } from '../../../fields/ScriptField'; import { NumCast, StrCast, toList } from '../../../fields/Types'; import { emptyFunction } from '../../../Utils'; import { DocUtils } from '../../documents/DocUtils'; import { dropActionType } from '../../util/DropActionTypes'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { OpenWhere } from '../nodes/OpenWhere'; import { computePassLayout, computeStarburstLayout } from './collectionFreeForm'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import './CollectionPileView.scss'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { DocumentView } from '../nodes/DocumentView'; @observer export class CollectionPileView extends CollectionSubView() { _originalChrome: FieldResult = ''; _disposers: { [name: string]: IReactionDisposer } = {}; constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } componentDidMount() { if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) { this.Document._freeform_pileEngine = computePassLayout.name; } this._originalChrome = this.layoutDoc._chromeHidden; this.layoutDoc._chromeHidden = true; } componentWillUnmount() { this.layoutDoc._chromeHidden = this._originalChrome; Object.values(this._disposers).forEach(disposer => disposer?.()); } layoutEngine = () => StrCast(this.Document._freeform_pileEngine); @undoBatch addPileDoc = (docs: Doc | Doc[]) => { toList(docs).map(doc => DocUtils.iconify(doc)); return this._props.addDocument?.(docs) || false; }; @undoBatch removePileDoc = (docs: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { toList(docs).forEach(doc => Doc.deiconifyView(doc)); const ret = this._props.moveDocument?.(docs, targetCollection, addDoc) || false; if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.DocumentView?.()._props.removeDocument?.(this.Document); return ret; }; @computed get toggleIcon() { return ScriptField.MakeScript('documentView.iconify()', { documentView: 'any' }); } @computed get contentEvents() { const isStarburst = this.layoutEngine() === computeStarburstLayout.name; return this._props.isContentActive() && isStarburst ? undefined : 'none'; } // returns the contents of the pileup in a CollectionFreeFormView @computed get contents() { return (
); } // toggles the pileup between starburst to compact toggleStarburst = action(() => { this.layoutDoc._freeform_scale = undefined; if (this.layoutEngine() === computeStarburstLayout.name) { if (NumCast(this.layoutDoc._width) !== NumCast(this.Document._starburstDiameter, 500)) { this.Document._starburstDiameter = NumCast(this.layoutDoc._width); } const defaultSize = 110; this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - NumCast(this.layoutDoc._freeform_pileWidth, defaultSize) / 2; this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - NumCast(this.layoutDoc._freeform_pileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._freeform_pileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._freeform_pileHeight, defaultSize); DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); this.layoutDoc._freeform_panX = 0; this.layoutDoc._freeform_panY = -10; this.Document._freeform_pileEngine = computePassLayout.name; } else { const defaultSize = NumCast(this.Document._starburstDiameter, 400); this.Document.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width) / 2 - defaultSize / 2; this.Document.y = NumCast(this.Document.y) + NumCast(this.layoutDoc._height) / 2 - defaultSize / 2; this.layoutDoc._freeform_pileWidth = NumCast(this.layoutDoc._width); this.layoutDoc._freeform_pileHeight = NumCast(this.layoutDoc._height); this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0; this.layoutDoc._width = this.layoutDoc._height = defaultSize; this.layoutDoc.background; this.Document._freeform_pileEngine = computeStarburstLayout.name; } }); // for dragging documents out of the pileup view _undoBatch: UndoManager.Batch | undefined; pointerDown = (e: React.PointerEvent) => { let dist = 0; setupMoveUpEvents( this, e, (moveEv: PointerEvent, down: number[], delta: number[]) => { if (this.layoutEngine() === 'pass' && this.childDocs.length && moveEv.shiftKey) { dist += Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]); if (dist > 100) { if (!this._undoBatch) { this._undoBatch = UndoManager.StartBatch('layout pile'); } const doc = this.childDocs[0]; doc.x = moveEv.clientX; doc.y = moveEv.clientY; this._props.addDocTab(doc, OpenWhere.inParentFromScreen) && (this._props.removeDocument?.(doc) || false); dist = 0; } } return false; }, () => { this._undoBatch?.end(); this._undoBatch = undefined; }, emptyFunction, e.shiftKey && this.layoutEngine() === computePassLayout.name, this.layoutEngine() === computePassLayout.name && e.shiftKey ); // this sets _doubleTap }; // onClick for toggling the pileup view @undoBatch onClick = (e: React.MouseEvent) => { if (e.button === 0) { DocumentView.DeselectAll(); this.toggleStarburst(); e.stopPropagation(); } }; render() { return (
{this.contents}
); } }