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}
);
}
}