import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { StylesProvider, Tooltip } from '@material-ui/core'; import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, HeightSym, Opt, WidthSym } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnTrue, StopEvent, Utils } from '../../../../Utils'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { Colors, Shadows } from '../../global/globalEnums'; import { DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { DocumentView } from '../../nodes/DocumentView'; import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup'; import { StyleProp } from '../../StyleProvider'; import { CollectionStackedTimeline } from '../CollectionStackedTimeline'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionLinearView.scss'; /** * CollectionLinearView is the class for rendering the horizontal collection * of documents, it useful for horizontal menus. It can either be expandable * or not using the linearViewExpandable field. * It is used in the following locations: * - It is used in the popup menu on the bottom left (see docButtons() in MainView.tsx) * - It is used for the context sensitive toolbar at the top (see contMenuButtons() in CollectionMenu.tsx) */ @observer export class CollectionLinearView extends CollectionSubView() { @observable public addMenuToggle = React.createRef(); @observable private _selectedIndex = -1; private _dropDisposer?: DragManager.DragDropDisposer; private _widthDisposer?: IReactionDisposer; private _selectedDisposer?: IReactionDisposer; componentWillUnmount() { this._dropDisposer?.(); this._widthDisposer?.(); this._selectedDisposer?.(); this.childLayoutPairs.map((pair, ind) => ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log)); } componentDidMount() { this._widthDisposer = reaction( () => 5 + (this.layoutDoc.linearViewIsExpanded ? this.childDocs.length * this.rootDoc[HeightSym]() : 10), width => this.childDocs.length && (this.layoutDoc._width = width), { fireImmediately: true } ); this._selectedDisposer = reaction( () => NumCast(this.layoutDoc.selectedIndex), i => runInAction(() => { this._selectedIndex = i; let selected: any = undefined; this.childLayoutPairs.map(async (pair, ind) => { const isSelected = this._selectedIndex === ind; if (isSelected) { selected = pair; } else { ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log); } }); if (selected && selected.layout) { ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log); } }), { fireImmediately: true } ); } protected createDashEventsTarget = (ele: HTMLDivElement | null) => { //used for stacking and masonry view this._dropDisposer && this._dropDisposer(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); } }; dimension = () => NumCast(this.rootDoc._height); // 2 * the padding getTransform = (ele: Opt) => { if (!ele) return Transform.Identity(); const { scale, translateX, translateY } = Utils.GetScreenTransform(ele); return new Transform(-translateX, -translateY, 1); }; @action exitLongLinks = () => { if (DocumentLinksButton.StartLink) { if (DocumentLinksButton.StartLink.Document) { action((e: React.PointerEvent) => { Doc.UnBrushDoc(DocumentLinksButton.StartLink?.Document as Doc); }); } } DocumentLinksButton.StartLink = undefined; DocumentLinksButton.StartLinkView = undefined; }; @action changeDescriptionSetting = () => { if (LinkDescriptionPopup.showDescriptions) { if (LinkDescriptionPopup.showDescriptions === 'ON') { LinkDescriptionPopup.showDescriptions = 'OFF'; LinkDescriptionPopup.descriptionPopup = false; } else { LinkDescriptionPopup.showDescriptions = 'ON'; } } else { LinkDescriptionPopup.showDescriptions = 'OFF'; LinkDescriptionPopup.descriptionPopup = false; } }; myContextMenu = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); }; getLinkUI = () => { return !DocumentLinksButton.StartLink ? null : ( e.stopPropagation()}> Creating link from:{' '} {(DocumentLinksButton.AnnotationId ? 'Annotation in ' : ' ') + (StrCast(DocumentLinksButton.StartLink.title).length < 51 ? DocumentLinksButton.StartLink.title : StrCast(DocumentLinksButton.StartLink.title).slice(0, 50) + '...')} {'Toggle description pop-up'} } placement="top"> Labels: {LinkDescriptionPopup.showDescriptions ? LinkDescriptionPopup.showDescriptions : 'ON'} Exit linking mode} placement="top"> Stop ); }; getCurrentlyPlayingUI = () => { return !CollectionStackedTimeline.CurrentlyPlaying?.length ? null : ( Currently playing: {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) => ( DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}> {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? '' : ',')} ))} ); }; getDisplayDoc = (doc: Doc, preview: boolean = false) => { if (doc.icon === 'linkui') return this.getLinkUI(); if (doc.icon === 'currentlyplayingui') return this.getCurrentlyPlayingUI(); const nested = doc._viewType === CollectionViewType.Linear; const hidden = doc.hidden === true; let dref: Opt; const docXf = () => this.getTransform(dref); // const scalable = pair.layout.onClick || pair.layout.onDragStart; return hidden ? null : (
(dref = r || undefined)} style={{ pointerEvents: 'all', width: nested ? undefined : NumCast(doc._width), height: nested ? undefined : NumCast(doc._height), marginLeft: !nested ? 2.5 : 0, marginRight: !nested ? 2.5 : 0, // width: NumCast(pair.layout._width), // height: NumCast(pair.layout._height), }}>
); }; render() { const flexDir = StrCast(this.Document.flexDirection); // Specify direction of linear view content const flexGap = NumCast(this.Document.flexGap); // Specify the gap between linear view content const isExpanded = BoolCast(this.layoutDoc.linearViewIsExpanded); const menuOpener = ( ); return (
{!this.props.Document.linearViewExpandable ? null : ( {isExpanded ? 'Close' : 'Open'}
} placement="top"> {menuOpener} )} { ScriptCast(this.Document.onClick)?.script.run({ this: this.layoutDoc, self: this.rootDoc, _readOnly_: false, scriptContext: this.props.scriptContext, thisContainer: this.props.ContainingCollectionDoc, documentView: this.props.docViewPath().lastElement(), }); this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked; })} />
{this.childLayoutPairs.map(pair => this.getDisplayDoc(pair.layout))}
); } }