import React = require('react');
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { ColorState, SketchPicker } from 'react-color';
import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
import { Doc, DocListCast, DocListCastAsync, FieldResult } from '../../../../fields/Doc';
import { Copy } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
import { ObjectField } from '../../../../fields/ObjectField';
import { listSpec } from '../../../../fields/Schema';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents, StopEvent } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { SelectionManager } from '../../../util/SelectionManager';
import { SettingsManager } from '../../../util/SettingsManager';
import { undoBatch, UndoManager } from '../../../util/UndoManager';
import { CollectionDockingView } from '../../collections/CollectionDockingView';
import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm';
import { CollectionView } from '../../collections/CollectionView';
import { TabDocView } from '../../collections/TabDocView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import './PresBox.scss';
import { PresEffect, PresMovement, PresStatus } from './PresEnums';

export interface PinProps {
    audioRange?: boolean;
    activeFrame?: number;
    hidePresBox?: boolean;
    pinWithView?: PinViewProps;
    pinDocView?: boolean; // whether the current view specs of the document should be saved the pinned document
    panelWidth?: number; // panel width and height of the document (used to compute the bounds of the pinned view area)
    panelHeight?: number;
}

export interface PinViewProps {
    bounds: MarqueeViewBounds;
    scale: number;
}

@observer
export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
    public static LayoutString(fieldKey: string) {
        return FieldView.LayoutString(PresBox, fieldKey);
    }

    /**
     * transitions & effects for documents
     * @param renderDoc
     * @param layoutDoc
     */
    static renderEffectsDoc(renderDoc: any, layoutDoc: Doc, presDoc: Doc) {
        const effectProps = {
            left: presDoc.presEffectDirection === PresEffect.Left,
            right: presDoc.presEffectDirection === PresEffect.Right,
            top: presDoc.presEffectDirection === PresEffect.Top,
            bottom: presDoc.presEffectDirection === PresEffect.Bottom,
            opposite: true,
            delay: presDoc.presTransition,
            // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
        };
        //prettier-ignore
        switch (presDoc.presEffect) {
            default: 
            case PresEffect.None:       return renderDoc;
            case PresEffect.Zoom:       return <Zoom {...effectProps}>{renderDoc}</Zoom>;
            case PresEffect.Fade:       return <Fade {...effectProps}>{renderDoc}</Fade>;
            case PresEffect.Flip:       return <Flip {...effectProps}>{renderDoc}</Flip>;
            case PresEffect.Rotate:     return <Rotate {...effectProps}>{renderDoc}</Rotate>;
            case PresEffect.Bounce:     return <Bounce {...effectProps}>{renderDoc}</Bounce>;
            case PresEffect.Roll:       return <Roll {...effectProps}>{renderDoc}</Roll>;
            case PresEffect.Lightspeed: return <LightSpeed {...effectProps}>{renderDoc}</LightSpeed>;
        }
    }
    public static EffectsProvider(layoutDoc: Doc, renderDoc: any) {
        return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) : renderDoc;
    }

    private _disposers: { [name: string]: IReactionDisposer } = {};
    public selectedArray = new ObservableSet<Doc>();

    @observable public static Instance: PresBox;
    @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView

    @observable _isChildActive = false;
    @observable _moveOnFromAudio: boolean = true;
    @observable _presTimer!: NodeJS.Timeout;

    @observable _eleArray: HTMLElement[] = [];
    @observable _dragArray: HTMLElement[] = [];
    @observable _pathBoolean: boolean = false;
    @observable _expandBoolean: boolean = false;
    @observable _transitionTools: boolean = false;
    @observable _newDocumentTools: boolean = false;
    @observable _progressivizeTools: boolean = false;
    @observable _openMovementDropdown: boolean = false;
    @observable _openEffectDropdown: boolean = false;
    @observable _presentTools: boolean = false;
    @observable _treeViewMap: Map<Doc, number> = new Map();
    @observable _presKeyEvents: boolean = false;
    @observable _forceKeyEvents: boolean = false;
    @computed get isTreeOrStack() {
        return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._viewType) as any);
    }
    @computed get isTree() {
        return this.layoutDoc._viewType === CollectionViewType.Tree;
    }
    @computed get presFieldKey() {
        return StrCast(this.layoutDoc.presFieldKey, 'data');
    }
    @computed get childDocs() {
        return DocListCast(this.rootDoc[this.presFieldKey]);
    }
    @computed get tagDocs() {
        return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null));
    }
    @computed get itemIndex() {
        return NumCast(this.rootDoc._itemIndex);
    }
    @computed get activeItem() {
        return Cast(this.childDocs[NumCast(this.rootDoc._itemIndex)], Doc, null);
    }
    @computed get targetDoc() {
        return Cast(this.activeItem?.presentationTargetDoc, Doc, null);
    }
    @computed get scrollable() {
        if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
        return false;
    }
    @computed get panable() {
        if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
        return false;
    }
    @computed get selectedDocumentView() {
        if (SelectionManager.Views().length) return SelectionManager.Views()[0];
        if (this.selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc);
    }
    @computed get isPres() {
        return this.selectedDoc === this.rootDoc;
    }
    @computed get selectedDoc() {
        return this.selectedDocumentView?.rootDoc;
    }
    clearSelectedArray = () => this.selectedArray.clear();
    addToSelectedArray = (doc: Doc) => this.selectedArray.add(doc);
    removeFromSelectedArray = (doc: Doc) => this.selectedArray.delete(doc);

    _unmounting = false;
    @action
    componentWillUnmount() {
        this._unmounting = true;
        document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
        this.resetPresentation();
        // Turn of progressivize editors
        this.turnOffEdit(true);
        Object.values(this._disposers).forEach(disposer => disposer?.());
    }

    @action
    componentDidMount() {
        this._disposers.keyboard = reaction(
            () => this.selectedDoc,
            selected => {
                document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
                (this._presKeyEvents = selected === this.rootDoc) && document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
            },
            { fireImmediately: true }
        );
        this._disposers.forcekeyboard = reaction(
            () => this._forceKeyEvents,
            force => {
                if (force) {
                    document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
                    document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
                    this._presKeyEvents = true;
                }
                this._forceKeyEvents = false;
            },
            { fireImmediately: true }
        );
        this.props.setContentView?.(this);
        this._unmounting = false;
        this.rootDoc._forceRenderEngine = 'timeline';
        this.layoutDoc.presStatus = PresStatus.Edit;
        this.layoutDoc._gridGap = 0;
        this.layoutDoc._yMargin = 0;
        this.turnOffEdit(true);
        this._disposers.selection = reaction(
            () => SelectionManager.Views(),
            views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation()
        );
    }

    @action
    updateCurrentPresentation = (pres?: Doc) => {
        Doc.ActivePresentation = pres ?? this.rootDoc;
        PresBox.Instance = this;
    };

    // There are still other internal frames and should go through all frames before going to next slide
    nextInternalFrame = (targetDoc: Doc, activeItem: Doc) => {
        const currentFrame = Cast(targetDoc?._currentFrame, 'number', null);
        const childDocs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
        targetDoc._viewTransition = 'all 1s';
        setTimeout(() => (targetDoc._viewTransition = undefined), 1010);
        this.nextKeyframe(targetDoc, activeItem);
        if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc);
        else targetDoc.keyFrameEditing = true;
    };

    _mediaTimer!: [NodeJS.Timeout, Doc];
    // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
    startTempMedia = (targetDoc: Doc, activeItem: Doc) => {
        const duration: number = NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime);
        if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) {
            const targMedia = DocumentManager.Instance.getDocumentView(targetDoc);
            targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.presStartTime), NumCast(activeItem.presStartTime) + duration);
        }
    };

    stopTempMedia = (targetDocField: FieldResult) => {
        const targetDoc = Cast(targetDocField, Doc, null);
        if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) {
            const targMedia = DocumentManager.Instance.getDocumentView(targetDoc);
            targMedia?.ComponentView?.Pause?.();
        }
    };

    //TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time
    // TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions
    // No more frames in current doc and next slide is defined, therefore move to next slide
    nextSlide = (activeNext: Doc) => {
        const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
        console.info('nextSlide', activeNext.title, targetNext?.title);
        let nextSelected = this.itemIndex + 1;
        this.gotoDocument(nextSelected, this.activeItem);
        for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
            if (!this.childDocs[nextSelected].groupWithUp) {
                break;
            } else {
                console.log('Title: ' + this.childDocs[nextSelected].title);
                this.gotoDocument(nextSelected, this.activeItem, true);
            }
        }
    };

    // Called when the user activates 'next' - to move to the next part of the pres. trail
    @action
    next = () => {
        const activeNext = Cast(this.childDocs[this.itemIndex + 1], Doc, null);
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        const lastFrame = Cast(targetDoc?.lastFrame, 'number', null);
        const curFrame = NumCast(targetDoc?._currentFrame);
        let internalFrames: boolean = false;
        if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true;
        if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) {
            // Case 1: There are still other frames and should go through all frames before going to next slide
            this.nextInternalFrame(targetDoc, activeItem);
        } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
            // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide
            this.nextSlide(activeNext);
        } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
            // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
            this.gotoDocument(0, this.activeItem);
        }
    };

    // Called when the user activates 'back' - to move to the previous part of the pres. trail
    @action
    back = () => {
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        const prevItem = Cast(this.childDocs[Math.max(0, this.itemIndex - 1)], Doc, null);
        const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null);
        const lastFrame = Cast(targetDoc.lastFrame, 'number', null);
        const curFrame = NumCast(targetDoc._currentFrame);
        let prevSelected = this.itemIndex;
        // Functionality for group with up
        let didZoom = activeItem.presMovement;
        for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
            didZoom = this.childDocs[prevSelected].presMovement;
        }
        if (lastFrame !== undefined && curFrame >= 1) {
            // Case 1: There are still other frames and should go through all frames before going to previous slide
            this.prevKeyframe(targetDoc, activeItem);
        } else if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
            // Case 2: There are no other frames so it should go to the previous slide
            prevSelected = Math.max(0, prevSelected - 1);
            this.gotoDocument(prevSelected, activeItem);
            if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc._currentFrame = NumCast(prevTargetDoc.lastFrame);
        } else if (this.childDocs[this.itemIndex - 1] === undefined && this.layoutDoc.presLoop) {
            // Case 3: Pres loop is on so it should go to the last slide
            this.gotoDocument(this.childDocs.length - 1, activeItem);
        }
    };

    //The function that is called when a document is clicked or reached through next or back.
    //it'll also execute the necessary actions if presentation is playing.
    @undoBatch
    public gotoDocument = action((index: number, from?: Doc, group?: boolean) => {
        Doc.UnBrushAllDocs();

        if (index >= 0 && index < this.childDocs.length) {
            this.rootDoc._itemIndex = index;
            const activeItem: Doc = this.activeItem;
            const targetDoc: Doc = this.targetDoc;
            if (activeItem.presActiveFrame !== undefined) {
                const transTime = NumCast(activeItem.presTransition, 500);
                const context = DocCast(DocCast(activeItem.presentationTargetDoc).context);
                if (context) {
                    const contextView = DocumentManager.Instance.getFirstDocumentView(context);
                    if (contextView?.ComponentView) {
                        CollectionFreeFormDocumentView.gotoKeyframe((contextView.ComponentView as CollectionFreeFormView).childDocs.slice(), transTime);
                        context._currentFrame = NumCast(activeItem.presActiveFrame);
                    }
                }
            }
            if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
                DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia);
            }
            if (from?.mediaStop === 'auto' && this.layoutDoc.presStatus !== PresStatus.Edit) {
                this.stopTempMedia(from.presentationTargetDoc);
            }
            // If next slide is audio / video 'Play automatically' then the next slide should be played
            if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && activeItem.mediaStart === 'auto') {
                this.startTempMedia(targetDoc, activeItem);
            }
            if (targetDoc) {
                Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc);
                targetDoc && runInAction(() => (targetDoc.focusSpeed = activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500)));
                setTimeout(() => (targetDoc.focusSpeed = undefined), NumCast(targetDoc.focusSpeed) + 10);
            }
            if (targetDoc?.lastFrame !== undefined) {
                targetDoc._currentFrame = 0;
            }
            if (!group) this.clearSelectedArray();
            this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array
            this.turnOffEdit();
            this.navigateToActiveItem(); //Handles movement to element only when presTrail is list
            this.onHideDocument(); //Handles hide after/before
        }
    });
    static pinDataTypes(target: Doc) {
        const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(target.type as any) || target._viewType === CollectionViewType.Stacking;
        const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform);
        const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any);
        const clippable = [DocumentType.COMPARISON].includes(target.type as any);
        const dataview = [DocumentType.INK].includes(target.type as any) && target.activeFrame === undefined;
        const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined;
        return { scrollable, pannable, temporal, clippable, dataview, textview };
    }

    @action
    static restoreTargetDocView(bestTarget: Doc, activeItem: Doc) {
        const transTime = NumCast(activeItem.presTransition, 500);
        const presTransitionTime = `all ${transTime}ms`;
        const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(bestTarget);
        bestTarget._viewTransition = presTransitionTime;
        if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth;
        if (temporal) bestTarget._currentTimecode = activeItem.presStartTime;
        if (scrollable) bestTarget._scrollTop = activeItem.presPinViewScroll;
        if (dataview) Doc.GetProto(bestTarget).data = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
        if (textview) Doc.GetProto(bestTarget).text = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
        if (pannable) {
            bestTarget._panX = activeItem.presPinViewX;
            bestTarget._panY = activeItem.presPinViewY;
            bestTarget._viewScale = activeItem.presPinViewScale;
            const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
            if (contentBounds) {
                const dv = DocumentManager.Instance.getDocumentView(bestTarget);
                dv && (bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0])));
            }
        }
        return setTimeout(() => (bestTarget._viewTransition = undefined), transTime + 10);
    }

    /// copies values from the targetDoc (which is the prototype of the pinDoc) to
    /// reserved fields on the pinDoc so that those values can be restored to the
    /// target doc when navigating to it.
    @action
    static pinDocView(pinDoc: Doc, pinProps: PinProps | undefined, targetDoc: Doc) {
        if (pinProps?.pinWithView) {
            // If pinWithView option set then update scale and x / y props of slide
            const bounds = pinProps.pinWithView.bounds;
            pinDoc.presPinView = true;
            pinDoc.presPinViewX = bounds.left + bounds.width / 2;
            pinDoc.presPinViewY = bounds.top + bounds.height / 2;
            pinDoc.presPinViewScale = pinProps.pinWithView.scale;
            pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
        }
        if (pinProps?.pinDocView) {
            const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc);
            pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable || dataview || textview || pinProps.activeFrame !== undefined;
            pinDoc.presX = NumCast(targetDoc.x);
            pinDoc.presY = NumCast(targetDoc.y);
            pinDoc.presRot = NumCast(targetDoc.jitterRotation);
            pinDoc.presWidth = NumCast(targetDoc.width);
            pinDoc.presHeight = NumCast(targetDoc.height);

            if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop;
            if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth;
            if (temporal) pinDoc.presEndTime = NumCast((pinDoc.presStartTime = pinDoc._currentTimecode)) + 0.1;
            if (textview) pinDoc.presData = targetDoc.text instanceof ObjectField ? targetDoc.text[Copy]() : targetDoc.text;
            if (dataview) pinDoc.presData = targetDoc.data instanceof ObjectField ? targetDoc.data[Copy]() : targetDoc.data;
            if (pannable) {
                const panX = NumCast(pinDoc._panX);
                const panY = NumCast(pinDoc._panY);
                const pw = NumCast(pinProps.panelWidth);
                const ph = NumCast(pinProps.panelHeight);
                const ps = NumCast(pinDoc._viewScale, 1);
                if (pw && ph && ps) {
                    pinDoc.presPinViewBounds = new List<number>([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]);
                }
                pinDoc.presPinViewX = panX;
                pinDoc.presPinViewY = panY;
                pinDoc.presPinViewScale = ps;
            }
        }
    }

    static _navTimer: NodeJS.Timeout;
    /**
     * This method makes sure that cursor navigates to the element that
     * has the option open and last in the group.
     * Design choice: If the next document is not in presCollection or
     * presCollection itself then if there is a presCollection it will add
     * a new tab. If presCollection is undefined it will open the document
     * on the right.
     */
    navigateToActiveItem = () => {
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null);
        const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
        const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
        const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc);
        const tab = CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === srcContext);
        // Handles the setting of presCollection
        if (includesDoc) {
            //Case 1: Pres collection should not change as it is already the same
        } else if (tab !== undefined) {
            // Case 2: Pres collection should update
            this.layoutDoc.presCollection = srcContext;
        }
        const presStatus = this.rootDoc.presStatus;
        const selViewCache = Array.from(this.selectedArray);
        const dragViewCache = Array.from(this._dragArray);
        const eleViewCache = Array.from(this._eleArray);
        const self = this;
        const resetSelection = action(() => {
            const presDocView = DocumentManager.Instance.getDocumentView(self.rootDoc);
            if (presDocView) SelectionManager.SelectView(presDocView, false);
            self.rootDoc.presStatus = presStatus;
            self.clearSelectedArray();
            selViewCache.forEach(doc => self.addToSelectedArray(doc));
            self._dragArray.splice(0, self._dragArray.length, ...dragViewCache);
            self._eleArray.splice(0, self._eleArray.length, ...eleViewCache);
        });
        const openInTab = (doc: Doc, finished?: () => void) => {
            (collectionDocView ?? this).props.addDocTab(doc, '');
            this.layoutDoc.presCollection = targetDoc;
            // this still needs some fixing
            setTimeout(resetSelection, 500);
            if (doc !== targetDoc) {
                setTimeout(finished ?? emptyFunction, 100); /// give it some time to create the targetDoc if we're opening up its context
            } else {
                finished?.();
            }
        };
        PresBox.NavigateToTarget(targetDoc, activeItem, openInTab, srcContext, includesDoc || tab ? undefined : resetSelection);
    };

    static NavigateToTarget(targetDoc: Doc, activeItem: Doc, openInTab: any, srcContext: Doc, finished?: () => void) {
        if (activeItem.presPinView && DocCast(targetDoc.context)?._currentFrame === undefined) {
            const transTime = NumCast(activeItem.presTransition, 500);
            const presTransitionTime = `all ${transTime}ms`;
            targetDoc._dataTransition = presTransitionTime;
            targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x));
            targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y));
            targetDoc.jitterRotation = NumCast(activeItem.presRot, NumCast(targetDoc.jitterRotation));
            targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width));
            targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height));
            setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10);
        }
        // If openDocument is selected then it should open the document for the user
        if (activeItem.openDocument) {
            LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc);
        } else if (targetDoc && activeItem.presMovement !== PresMovement.None) {
            LightboxView.SetLightboxDoc(undefined);
            const zooming = activeItem.presMovement !== PresMovement.Pan;
            DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom));
        }
        // After navigating to the document, if it is added as a presPinView then it will
        // adjust the pan and scale to that of the pinView when it was added.
        if (activeItem.presPinView) {
            clearTimeout(PresBox._navTimer);
            // targetDoc may or may not be displayed.  this gets the first available document (or alias) view that matches targetDoc
            const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
            if (bestTarget) PresBox._navTimer = PresBox.restoreTargetDocView(bestTarget, activeItem);
        }
    }

    /**
     * Uses the viewfinder to progressivize through the different views of a single collection.
     * @param activeItem: document for which internal zoom is used
     */
    zoomProgressivizeNext = (activeItem: Doc) => {
        const targetDoc: Doc = this.targetDoc;
        const srcContext = Cast(targetDoc?.context, Doc, null);
        const docView = DocumentManager.Instance.getDocumentView(targetDoc);
        const vfLeft = this.checkList(targetDoc, activeItem['viewfinder-left-indexed']);
        const vfWidth = this.checkList(targetDoc, activeItem['viewfinder-width-indexed']);
        const vfTop = this.checkList(targetDoc, activeItem['viewfinder-top-indexed']);
        const vfHeight = this.checkList(targetDoc, activeItem['viewfinder-height-indexed']);
        // Case 1: document that is not a Golden Layout tab
        if (srcContext) {
            const srcDocView = DocumentManager.Instance.getDocumentView(srcContext);
            if (srcDocView) {
                const layoutdoc = Doc.Layout(targetDoc);
                const panelWidth: number = srcDocView.props.PanelWidth();
                const panelHeight: number = srcDocView.props.PanelHeight();
                const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2;
                const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2;
                const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
                srcContext._panX = newPanX + (vfLeft + vfWidth / 2);
                srcContext._panY = newPanY + (vfTop + vfHeight / 2);
                srcContext._viewScale = newScale;
            }
        }
        // Case 2: document is the containing collection
        if (docView && !srcContext) {
            const panelWidth: number = docView.props.PanelWidth();
            const panelHeight: number = docView.props.PanelHeight();
            const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
            targetDoc._panX = vfLeft + vfWidth / 2;
            targetDoc._panY = vfTop + vfWidth / 2;
            targetDoc._viewScale = newScale;
        }
        const resize = document.getElementById('resizable');
        if (resize) {
            resize.style.width = vfWidth + 'px';
            resize.style.height = vfHeight + 'px';
            resize.style.top = vfTop + 'px';
            resize.style.left = vfLeft + 'px';
        }
    };

    /**
     * For 'Hide Before' and 'Hide After' buttons making sure that
     * they are hidden each time the presentation is updated.
     */
    @action
    onHideDocument = () => {
        this.childDocs.forEach((doc, index) => {
            const curDoc = Cast(doc, Doc, null);
            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
            //if (tagDoc) tagDoc.opacity = 1;
            const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc);
            const curInd: number = itemIndexes.indexOf(index);
            if (tagDoc === this.layoutDoc.presCollection) {
                tagDoc.opacity = 1;
            } else {
                if (curDoc.presHideBefore) {
                    if (itemIndexes.length > 1 && curInd !== 0) {
                        tagDoc.opacity = 1;
                    } else {
                        if (index > this.itemIndex) {
                            tagDoc.opacity = 0;
                        } else if (index === this.itemIndex || !curDoc.presHideAfter) {
                            tagDoc.opacity = 1;
                        }
                    }
                }
                if (curDoc.presHideAfter) {
                    if (itemIndexes.length > 1 && curInd !== itemIndexes.length - 1) {
                        tagDoc.opacity = 1;
                    } else {
                        if (index < this.itemIndex) {
                            tagDoc.opacity = 0;
                        } else if (index === this.itemIndex || !curDoc.presHideBefore) {
                            tagDoc.opacity = 1;
                        }
                    }
                }
            }
        });
    };

    //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc
    @action
    startAutoPres = (startSlide: number) => {
        this.updateCurrentPresentation();
        let activeItem: Doc = this.activeItem;
        let targetDoc: Doc = this.targetDoc;
        let duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
        const timer = (ms: number) => new Promise(res => (this._presTimer = setTimeout(res, ms)));
        const load = async () => {
            // Wrap the loop into an async function for this to work
            for (var i = startSlide; i < this.childDocs.length; i++) {
                activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
                targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
                duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
                if (duration < 100) {
                    duration = 2500;
                }
                if (NumCast(targetDoc.lastFrame) > 0) {
                    for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) {
                        await timer(duration / NumCast(targetDoc.lastFrame));
                        this.next();
                    }
                }

                await timer(duration);
                this.next(); // then the created Promise can be awaited
                if (i === this.childDocs.length - 1) {
                    setTimeout(() => {
                        clearTimeout(this._presTimer);
                        if (this.layoutDoc.presStatus === 'auto' && !this.layoutDoc.presLoop) this.layoutDoc.presStatus = PresStatus.Manual;
                        else if (this.layoutDoc.presLoop) this.startAutoPres(0);
                    }, duration);
                }
            }
        };
        this.layoutDoc.presStatus = PresStatus.Autoplay;
        this.startPresentation(startSlide);
        this.gotoDocument(startSlide, activeItem);
        load();
    };

    // The function pauses the auto presentation
    @action
    pauseAutoPres = () => {
        if (this.layoutDoc.presStatus === PresStatus.Autoplay) {
            if (this._presTimer) clearTimeout(this._presTimer);
            this.layoutDoc.presStatus = PresStatus.Manual;
            this.layoutDoc.presLoop = false;
            this.childDocs.forEach(this.stopTempMedia);
        }
    };

    //The function that resets the presentation by removing every action done by it. It also
    //stops the presentaton.
    resetPresentation = () => {
        this.rootDoc._itemIndex = 0;
        this.childDocs
            .map(doc => Cast(doc.presentationTargetDoc, Doc, null))
            .filter(doc => doc instanceof Doc)
            .forEach(doc => {
                try {
                    doc.opacity = 1;
                } catch (e) {
                    console.log('Reset presentation error: ', e);
                }
            });
    };

    // The function allows for viewing the pres path on toggle
    @action togglePath = (srcContext: Doc, off?: boolean) => {
        if (off) {
            this._pathBoolean = false;
            srcContext.presPathView = false;
        } else {
            runInAction(() => (this._pathBoolean = !this._pathBoolean));
            srcContext.presPathView = this._pathBoolean;
        }
    };

    // The function allows for expanding the view of pres on toggle
    @action toggleExpandMode = () => {
        runInAction(() => (this._expandBoolean = !this._expandBoolean));
        this.rootDoc.expandBoolean = this._expandBoolean;
        this.childDocs.forEach(doc => {
            doc.presExpandInlineButton = this._expandBoolean;
        });
    };

    /**
     * The function that starts the presentation at the given index, also checking if actions should be applied
     * directly at start.
     * @param startIndex: index that the presentation will start at
     */
    startPresentation = (startIndex: number) => {
        this.updateCurrentPresentation();
        this.childDocs.map(doc => {
            const tagDoc = doc.presentationTargetDoc as Doc;
            if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) {
                tagDoc.opacity = 0;
            }
            if (doc.presHideAfter && this.childDocs.indexOf(doc) < startIndex) {
                tagDoc.opacity = 0;
            }
        });
    };

    /**
     * The method called to open the presentation as a minimized view
     */
    @action
    updateMinimize = async () => {
        if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
            this.layoutDoc.presStatus = PresStatus.Edit;
            Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc);
            CollectionDockingView.AddSplit(this.rootDoc, 'right');
        } else {
            this.layoutDoc.presStatus = PresStatus.Edit;
            clearTimeout(this._presTimer);
            const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
            this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
            this.rootDoc.y = pt[1] + 10;
            this.rootDoc._height = 30;
            this.rootDoc._width = 248;
            Doc.AddDocToList(Doc.MyOverlayDocs, undefined, this.rootDoc);
            this.props.removeDocument?.(this.layoutDoc);
        }
    };

    /**
     * Called when the user changes the view type
     * Either 'List' (stacking) or 'Slides' (carousel)
     */
    @undoBatch
    viewChanged = action((e: React.ChangeEvent) => {
        //@ts-ignore
        const viewType = e.target.selectedOptions[0].value as CollectionViewType;
        this.layoutDoc.presFieldKey = this.fieldKey + (viewType === CollectionViewType.Tree ? '-linearized' : '');
        // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
        [CollectionViewType.Tree || CollectionViewType.Stacking].includes(viewType) && (this.rootDoc._pivotField = undefined);
        this.rootDoc._viewType = viewType;
        if (this.isTreeOrStack) {
            this.layoutDoc._gridGap = 0;
        }
    });

    /**
     * Called when the user changes the view type
     * Either 'List' (stacking) or 'Slides' (carousel)
     */
    // @undoBatch
    mediaStopChanged = action((e: React.ChangeEvent) => {
        const activeItem: Doc = this.activeItem;
        //@ts-ignore
        const stopDoc = e.target.selectedOptions[0].value as string;
        const stopDocIndex: number = Number(stopDoc[0]);
        activeItem.mediaStopDoc = stopDocIndex;
        if (this.childDocs[stopDocIndex - 1].mediaStopTriggerList) {
            const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
            list.push(activeItem);
            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
            console.log(list);
        } else {
            this.childDocs[stopDocIndex - 1].mediaStopTriggerList = new List<Doc>();
            const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
            list.push(activeItem);
            // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
            console.log(list);
        }
    });

    movementName = action((activeItem: Doc) => {
        if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) {
            activeItem.presMovement = 'zoom';
        }
        return StrCast(activeItem.presMovement);
    });

    whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive)));
    // For dragging documents into the presentation trail
    addDocumentFilter = (docs: Doc[]) => {
        docs.forEach((doc, i) => {
            if (doc.presentationTargetDoc) return true;
            if (doc.type === DocumentType.LABEL) {
                const audio = Cast(doc.annotationOn, Doc, null);
                if (audio) {
                    audio.mediaStart = 'manual';
                    audio.mediaStop = 'manual';
                    audio.presStartTime = NumCast(doc._timecodeToShow /* audioStart */, NumCast(doc._timecodeToShow /* videoStart */));
                    audio.presEndTime = NumCast(doc._timecodeToHide /* audioEnd */, NumCast(doc._timecodeToHide /* videoEnd */));
                    audio.presDuration = audio.presStartTime - audio.presEndTime;
                    TabDocView.PinDoc(audio, { audioRange: true });
                    setTimeout(() => this.removeDocument(doc), 0);
                    return false;
                }
            } else {
                if (!doc.aliasOf) {
                    const original = Doc.MakeAlias(doc);
                    TabDocView.PinDoc(original);
                    setTimeout(() => this.removeDocument(doc), 0);
                    return false;
                } else {
                    if (!doc.presentationTargetDoc) doc.title = doc.title + ' - Slide';
                    doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
                    doc.presMovement = PresMovement.Zoom;
                    if (this._expandBoolean) doc.presExpandInlineButton = true;
                }
            }
        });
        return true;
    };
    childLayoutTemplate = () => (!this.isTreeOrStack ? undefined : DocCast(Doc.UserDoc().presElement));
    removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc);
    getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight
    panelHeight = () => this.props.PanelHeight() - 40;
    isContentActive = (outsideReaction?: boolean) =>
        Doc.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false;

    /**
     * For sorting the array so that the order is maintained when it is dropped.
     */
    sortArray = () => this.childDocs.filter(doc => this.selectedArray.has(doc));

    /**
     * Method to get the list of selected items in the order in which they have been selected
     */
    @computed get listOfSelected() {
        return Array.from(this.selectedArray).map((doc: Doc, index: any) => {
            const curDoc = Cast(doc, Doc, null);
            const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
            if (curDoc && curDoc === this.activeItem)
                return (
                    <div key={index} className="selectedList-items">
                        <b>
                            {index + 1}. {curDoc.title}
                        </b>
                    </div>
                );
            else if (tagDoc)
                return (
                    <div key={index} className="selectedList-items">
                        {index + 1}. {curDoc.title}
                    </div>
                );
            else if (curDoc)
                return (
                    <div key={index} className="selectedList-items">
                        {index + 1}. {curDoc.title}
                    </div>
                );
        });
    }

    @action
    selectPres = () => {
        const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
        presDocView && SelectionManager.SelectView(presDocView, false);
    };

    //Regular click
    @action
    selectElement = async (doc: Doc) => {
        this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
        if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(DocCast(doc.context)), 0);
        else this.updateCurrentPresentation(DocCast(doc.context));
    };

    //Command click
    @action
    multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
        if (!this.selectedArray.has(doc)) {
            this.addToSelectedArray(doc);
            this._eleArray.push(ref);
            this._dragArray.push(drag);
        } else {
            this.removeFromSelectedArray(doc);
            this._eleArray.splice(this._eleArray.indexOf(ref));
            this._dragArray.splice(this._dragArray.indexOf(drag));
        }
        this.selectPres();
    };

    //Shift click
    @action
    shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
        this.clearSelectedArray();
        // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
        if (this.activeItem) {
            for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) {
                this.addToSelectedArray(this.childDocs[i]);
                this._eleArray.push(ref);
                this._dragArray.push(drag);
            }
        }
        this.selectPres();
    };

    //regular click
    @action
    regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, selectPres = true) => {
        this.clearSelectedArray();
        this.addToSelectedArray(doc);
        this._eleArray.splice(0, this._eleArray.length, ref);
        this._dragArray.splice(0, this._dragArray.length, drag);
        focus && this.selectElement(doc);
        selectPres && this.selectPres();
    };

    modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean) => {
        if (cmdClick) this.multiSelect(doc, ref, drag);
        else if (shiftClick) this.shiftSelect(doc, ref, drag);
        else this.regularSelect(doc, ref, drag, focus);
    };

    static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance.keyEvents(e);

    // Key for when the presentaiton is active
    @action
    keyEvents = (e: KeyboardEvent) => {
        if (e.target instanceof HTMLInputElement) return;
        let handled = false;
        const anchorNode = document.activeElement as HTMLDivElement;
        if (anchorNode && anchorNode.className?.includes('lm_title')) return;
        switch (e.key) {
            case 'Backspace':
                if (this.layoutDoc.presStatus === 'edit') {
                    undoBatch(
                        action(() => {
                            for (const doc of this.selectedArray) {
                                this.removeDocument(doc);
                            }
                            this.clearSelectedArray();
                            this._eleArray.length = 0;
                            this._dragArray.length = 0;
                        })
                    )();
                    handled = true;
                }
                break;
            case 'Escape':
                if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
                    this.updateMinimize();
                } else if (this.layoutDoc.presStatus === 'edit') {
                    this.clearSelectedArray();
                    this._eleArray.length = this._dragArray.length = 0;
                } else this.layoutDoc.presStatus = 'edit';
                if (this._presTimer) clearTimeout(this._presTimer);
                handled = true;
                break;
            case 'Down':
            case 'ArrowDown':
            case 'Right':
            case 'ArrowRight':
                if (e.shiftKey && this.itemIndex < this.childDocs.length - 1) {
                    // TODO: update to work properly
                    this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) + 1;
                    this.addToSelectedArray(this.childDocs[this.rootDoc._itemIndex]);
                } else {
                    this.next();
                    if (this._presTimer) {
                        clearTimeout(this._presTimer);
                        this.layoutDoc.presStatus = PresStatus.Manual;
                    }
                }
                handled = true;
                break;
            case 'Up':
            case 'ArrowUp':
            case 'Left':
            case 'ArrowLeft':
                if (e.shiftKey && this.itemIndex !== 0) {
                    // TODO: update to work properly
                    this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) - 1;
                    this.addToSelectedArray(this.childDocs[this.rootDoc._itemIndex]);
                } else {
                    this.back();
                    if (this._presTimer) {
                        clearTimeout(this._presTimer);
                        this.layoutDoc.presStatus = PresStatus.Manual;
                    }
                }
                handled = true;
                break;
            case 'Spacebar':
            case ' ':
                if (this.layoutDoc.presStatus === PresStatus.Manual) this.startAutoPres(this.itemIndex);
                else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer);
                handled = true;
                break;
            case 'a':
                if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === 'edit') {
                    this.clearSelectedArray();
                    this.childDocs.forEach(doc => this.addToSelectedArray(doc));
                    handled = true;
                }
            default:
                break;
        }
        if (handled) {
            e.stopPropagation();
            e.preventDefault();
        }
    };

    /**
     *
     */
    @action
    viewPaths = () => {
        const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
        if (srcContext) {
            this.togglePath(srcContext);
        }
    };

    getAllIndexes = (arr: Doc[], val: Doc) => arr.map((doc, i) => (doc === val ? i : -1)).filter(i => i !== -1);

    // Adds the index in the pres path graphically
    @computed get order() {
        const order: JSX.Element[] = [];
        const docs: Doc[] = [];
        const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
        const dv = DocumentManager.Instance.getDocumentView(presCollection);
        this.childDocs
            .filter(doc => Cast(doc.presentationTargetDoc, Doc, null))
            .forEach((doc, index) => {
                const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
                const srcContext = Cast(tagDoc.context, Doc, null);
                const width = NumCast(tagDoc._width) / 10;
                const height = Math.max(NumCast(tagDoc._height) / 10, 15);
                const edge = Math.max(width, height);
                const fontSize = edge * 0.8;
                const gap = 2;
                if (presCollection === srcContext) {
                    // Case A: Document is contained within the collection
                    if (docs.includes(tagDoc)) {
                        const prevOccurances: number = this.getAllIndexes(docs, tagDoc).length;
                        docs.push(tagDoc);
                        order.push(
                            <div
                                className="pathOrder"
                                key={tagDoc.id + 'pres' + index}
                                style={{ top: NumCast(tagDoc.y) + (prevOccurances * (edge + gap) - edge / 2), left: NumCast(tagDoc.x) - edge / 2, width: edge, height: edge, fontSize: fontSize }}
                                onClick={() => this.selectElement(doc)}>
                                <div className="pathOrder-frame">{index + 1}</div>
                            </div>
                        );
                    } else {
                        docs.push(tagDoc);
                        order.push(
                            <div
                                className="pathOrder"
                                key={tagDoc.id + 'pres' + index}
                                style={{ top: NumCast(tagDoc.y) - edge / 2, left: NumCast(tagDoc.x) - edge / 2, width: edge, height: edge, fontSize: fontSize }}
                                onClick={() => this.selectElement(doc)}>
                                <div className="pathOrder-frame">{index + 1}</div>
                            </div>
                        );
                    }
                } else if (doc.presPinView && presCollection === tagDoc && dv) {
                    // Case B: Document is presPinView and is presCollection
                    const scale: number = 1 / NumCast(doc.presPinViewScale);
                    const height: number = dv.props.PanelHeight() * scale;
                    const width: number = dv.props.PanelWidth() * scale;
                    const indWidth = width / 10;
                    const indHeight = Math.max(height / 10, 15);
                    const indEdge = Math.max(indWidth, indHeight);
                    const indFontSize = indEdge * 0.8;
                    const xLoc: number = NumCast(doc.presPinViewX) - width / 2;
                    const yLoc: number = NumCast(doc.presPinViewY) - height / 2;
                    docs.push(tagDoc);
                    order.push(
                        <>
                            <div className="pathOrder" key={tagDoc.id + 'pres' + index} style={{ top: yLoc - indEdge / 2, left: xLoc - indEdge / 2, width: indEdge, height: indEdge, fontSize: indFontSize }} onClick={() => this.selectElement(doc)}>
                                <div className="pathOrder-frame">{index + 1}</div>
                            </div>
                            <div className="pathOrder-presPinView" style={{ top: yLoc, left: xLoc, width: width, height: height, borderWidth: indEdge / 10 }}></div>
                        </>
                    );
                }
            });
        return order;
    }

    /**
     * Method called for viewing paths which adds a single line with
     * points at the center of each document added.
     * Design choice: When this is called it sets _fitContentsToBox as true so the
     * user can have an overview of all of the documents in the collection.
     * (Design needed for when documents in presentation trail are in another
     * collection)
     */
    @computed get paths() {
        let pathPoints = '';
        const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
        this.childDocs.forEach((doc, index) => {
            const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
            const srcContext = Cast(tagDoc?.context, Doc, null);
            if (tagDoc && presCollection === srcContext) {
                const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2;
                const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2;
                if ((index = 0)) pathPoints = n1x + ',' + n1y;
                else pathPoints = pathPoints + ' ' + n1x + ',' + n1y;
            } else if (doc.presPinView && presCollection === tagDoc) {
                const n1x = NumCast(doc.presPinViewX);
                const n1y = NumCast(doc.presPinViewY);
                if ((index = 0)) pathPoints = n1x + ',' + n1y;
                else pathPoints = pathPoints + ' ' + n1x + ',' + n1y;
            }
        });
        return (
            <polyline
                points={pathPoints}
                style={{
                    opacity: 1,
                    stroke: '#69a6db',
                    strokeWidth: 5,
                    strokeDasharray: '10 5',
                    boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
                }}
                fill="none"
                markerStart="url(#markerArrow)"
                markerMid="url(#markerSquare)"
                markerEnd="url(#markerSquareFilled)"
            />
        );
    }

    // Converts seconds to ms and updates presTransition
    setTransitionTime = (number: String, change?: number) => {
        let timeInMS = Number(number) * 1000;
        if (change) timeInMS += change;
        if (timeInMS < 100) timeInMS = 100;
        if (timeInMS > 10000) timeInMS = 10000;
        this.selectedArray.forEach(doc => (doc.presTransition = timeInMS));
    };

    // Converts seconds to ms and updates presTransition
    setZoom = (number: String, change?: number) => {
        let scale = Number(number) / 100;
        if (change) scale += change;
        if (scale < 0.01) scale = 0.01;
        if (scale > 1.5) scale = 1.5;
        this.selectedArray.forEach(doc => (doc.presZoom = scale));
    };

    // Converts seconds to ms and updates presDuration
    setDurationTime = (number: String, change?: number) => {
        let timeInMS = Number(number) * 1000;
        if (change) timeInMS += change;
        if (timeInMS < 100) timeInMS = 100;
        if (timeInMS > 20000) timeInMS = 20000;
        this.selectedArray.forEach(doc => (doc.presDuration = timeInMS));
    };

    /**
     * When the movement dropdown is changes
     */
    @undoBatch
    updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presMovement = movement)));

    @undoBatch
    @action
    updateHideBefore = (activeItem: Doc) => {
        activeItem.presHideBefore = !activeItem.presHideBefore;
        this.selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore));
    };

    @undoBatch
    @action
    updateHideAfter = (activeItem: Doc) => {
        activeItem.presHideAfter = !activeItem.presHideAfter;
        this.selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter));
    };

    @undoBatch
    @action
    updateOpenDoc = (activeItem: Doc) => {
        activeItem.openDocument = !activeItem.openDocument;
        this.selectedArray.forEach(doc => (doc.openDocument = activeItem.openDocument));
    };

    @undoBatch
    @action
    updateEffectDirection = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect));

    @undoBatch
    @action
    updateEffect = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffect = effect));

    _batch: UndoManager.Batch | undefined = undefined;

    @computed get transitionDropdown() {
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection;
        const isPinWithView: boolean = BoolCast(activeItem.presPinView);
        const presEffect = (effect: PresEffect) => (
            <div className={`presBox-dropdownOption ${this.activeItem.presEffect === effect || (effect === PresEffect.None && !this.activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect)}>
                {effect}
            </div>
        );
        const presMovement = (movement: PresMovement) => (
            <div className={`presBox-dropdownOption ${activeItem.presMovement === movement ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateMovement(movement)}>
                {movement}
            </div>
        );
        const presDirection = (diretion: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => {
            const color = this.activeItem.presEffectDirection === diretion || (diretion === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black';
            return (
                <Tooltip title={<div className="dash-tooltip">{diretion}</div>}>
                    <div
                        style={{ ...opts, border: diretion === PresEffect.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }}
                        onClick={() => this.updateEffectDirection(diretion)}>
                        {icon ? <FontAwesomeIcon icon={icon as any} /> : null}
                    </div>
                </Tooltip>
            );
        };
        const inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => {
            return (
                <input
                    type="range"
                    step={step}
                    min={min}
                    max={max}
                    value={value}
                    className={`toolbar-slider ${active ? '' : 'none'}`}
                    onPointerDown={() => (this._batch = UndoManager.StartBatch('pres slider'))}
                    onPointerUp={() => this._batch?.end()}
                    onChange={e => {
                        e.stopPropagation();
                        change(e.target.value);
                    }}
                />
            );
        };
        if (activeItem && targetDoc) {
            const type = targetDoc.type;
            const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
            const zoom = activeItem.presZoom ? NumCast(activeItem.presZoom) * 100 : 75;
            let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2;
            if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
            const effect = this.activeItem.presEffect ? this.activeItem.presEffect : 'None';
            activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
            return (
                <div
                    className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? 'active' : ''}`}
                    onPointerDown={StopEvent}
                    onPointerUp={StopEvent}
                    onClick={action(e => {
                        e.stopPropagation();
                        this._openMovementDropdown = false;
                        this._openEffectDropdown = false;
                    })}>
                    <div className="ribbon-box">
                        Movement
                        {isPresCollection || (isPresCollection && isPinWithView) ? (
                            <div className="ribbon-property" style={{ marginLeft: 0, height: 25, textAlign: 'left', paddingLeft: 5, paddingRight: 5, fontSize: 10 }}>
                                {this.scrollable ? 'Scroll to pinned view' : !isPinWithView ? 'No movement' : 'Pan & Zoom to pinned view'}
                            </div>
                        ) : (
                            <div
                                className="presBox-dropdown"
                                onClick={action(e => {
                                    e.stopPropagation();
                                    this._openMovementDropdown = !this._openMovementDropdown;
                                })}
                                style={{ borderBottomLeftRadius: this._openMovementDropdown ? 0 : 5, border: this._openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
                                {this.movementName(activeItem)}
                                <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
                                <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={StopEvent} style={{ display: this._openMovementDropdown ? 'grid' : 'none' }}>
                                    {presMovement(PresMovement.None)}
                                    {presMovement(PresMovement.Zoom)}
                                    {presMovement(PresMovement.Pan)}
                                    {presMovement(PresMovement.Jump)}
                                </div>
                            </div>
                        )}
                        <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
                            <div className="presBox-subheading">Zoom (% screen filled)</div>
                            <div className="ribbon-property">
                                <input className="presBox-input" type="number" value={zoom} onChange={action(e => this.setZoom(e.target.value))} />%
                            </div>
                            <div className="ribbon-propertyUpDown">
                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
                                    <FontAwesomeIcon icon={'caret-up'} />
                                </div>
                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
                                    <FontAwesomeIcon icon={'caret-down'} />
                                </div>
                            </div>
                        </div>
                        {inputter('0', '1', '150', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)}
                        <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
                            <div className="presBox-subheading">Movement Speed</div>
                            <div className="ribbon-property">
                                <input className="presBox-input" type="number" value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.setTransitionTime(e.target.value))} /> s
                            </div>
                            <div className="ribbon-propertyUpDown">
                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), 1000))}>
                                    <FontAwesomeIcon icon={'caret-up'} />
                                </div>
                                <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), -1000))}>
                                    <FontAwesomeIcon icon={'caret-down'} />
                                </div>
                            </div>
                        </div>
                        {inputter('0.1', '0.1', '10', transitionSpeed, [PresMovement.Pan, PresMovement.Zoom].includes(activeItem.presMovement as any), this.setTransitionTime)}
                        <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}>
                            <div className="slider-text">Fast</div>
                            <div className="slider-text">Medium</div>
                            <div className="slider-text">Slow</div>
                        </div>
                    </div>
                    <div className="ribbon-box">
                        Visibility {'&'} Duration
                        <div className="ribbon-doubleButton">
                            {isPresCollection ? null : (
                                <Tooltip title={<div className="dash-tooltip">{'Hide before presented'}</div>}>
                                    <div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}>
                                        Hide before
                                    </div>
                                </Tooltip>
                            )}
                            {isPresCollection ? null : (
                                <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
                                    <div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}>
                                        Hide after
                                    </div>
                                </Tooltip>
                            )}
                            <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}>
                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}>
                                    Lightbox
                                </div>
                            </Tooltip>
                        </div>
                        {type === DocumentType.AUDIO || type === DocumentType.VID ? null : (
                            <>
                                <div className="ribbon-doubleButton">
                                    <div className="presBox-subheading">Slide Duration</div>
                                    <div className="ribbon-property">
                                        <input className="presBox-input" type="number" value={duration} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.setDurationTime(e.target.value))} /> s
                                    </div>
                                    <div className="ribbon-propertyUpDown">
                                        <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), 1000))}>
                                            <FontAwesomeIcon icon={'caret-up'} />
                                        </div>
                                        <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), -1000))}>
                                            <FontAwesomeIcon icon={'caret-down'} />
                                        </div>
                                    </div>
                                </div>
                                {inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)}
                                <div className={'slider-headers'} style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'grid' }}>
                                    <div className="slider-text">Short</div>
                                    <div className="slider-text">Medium</div>
                                    <div className="slider-text">Long</div>
                                </div>
                            </>
                        )}
                    </div>
                    {isPresCollection ? null : (
                        <div className="ribbon-box">
                            Effects
                            <div
                                className="presBox-dropdown"
                                onClick={action(e => {
                                    e.stopPropagation();
                                    this._openEffectDropdown = !this._openEffectDropdown;
                                })}
                                style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
                                {effect.toString()}
                                <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
                                <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this._openEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
                                    {presEffect(PresEffect.None)}
                                    {presEffect(PresEffect.Fade)}
                                    {presEffect(PresEffect.Flip)}
                                    {presEffect(PresEffect.Rotate)}
                                    {presEffect(PresEffect.Bounce)}
                                    {presEffect(PresEffect.Roll)}
                                </div>
                            </div>
                            <div className="ribbon-doubleButton" style={{ display: effect === 'None' ? 'none' : 'inline-flex' }}>
                                <div className="presBox-subheading">Effect direction</div>
                                <div className="ribbon-property">{StrCast(this.activeItem.presEffectDirection)}</div>
                            </div>
                            <div className="effectDirection" style={{ display: effect === 'None' ? 'none' : 'grid', width: 40 }}>
                                {presDirection(PresEffect.Left, 'angle-right', 1, 2, {})}
                                {presDirection(PresEffect.Right, 'angle-left', 3, 2, {})}
                                {presDirection(PresEffect.Top, 'angle-down', 2, 1, {})}
                                {presDirection(PresEffect.Bottom, 'angle-up', 2, 3, {})}
                                {presDirection(PresEffect.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
                            </div>
                        </div>
                    )}
                    <div className="ribbon-final-box">
                        <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
                            Apply to all
                        </div>
                    </div>
                </div>
            );
        }
    }

    @undoBatch
    @action
    applyTo = (array: Doc[]) => {
        this.updateMovement(this.activeItem.presMovement as PresMovement, true);
        this.updateEffect(this.activeItem.presEffect as PresEffect, true);
        this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffect, true);
        const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem;
        array.forEach(curDoc => {
            curDoc.presTransition = presTransition;
            curDoc.presDuration = presDuration;
            curDoc.presHideBefore = presHideBefore;
            curDoc.presHideAfter = presHideAfter;
        });
    };

    @computed get mediaOptionsDropdown() {
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        const clipStart: number = NumCast(activeItem.clipStart);
        const clipEnd: number = NumCast(activeItem.clipEnd);
        const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc);
        if (activeItem && targetDoc) {
            return (
                <div>
                    <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                        <div>
                            <div className="ribbon-box">
                                Start {'&'} End Time
                                <div className={'slider-headers'}>
                                    <div className="slider-block">
                                        <div className="slider-text" style={{ fontWeight: 500 }}>
                                            Start time (s)
                                        </div>
                                        <div id={'startTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
                                            <input
                                                className="presBox-input"
                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
                                                type="number"
                                                value={NumCast(activeItem.presStartTime)}
                                                onKeyDown={e => e.stopPropagation()}
                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
                                                    activeItem.presStartTime = Number(e.target.value);
                                                })}
                                            />
                                        </div>
                                    </div>
                                    <div className="slider-block">
                                        <div className="slider-text" style={{ fontWeight: 500 }}>
                                            Duration (s)
                                        </div>
                                        <div className="slider-number" style={{ backgroundColor: Colors.LIGHT_BLUE }}>
                                            {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10}
                                        </div>
                                    </div>
                                    <div className="slider-block">
                                        <div className="slider-text" style={{ fontWeight: 500 }}>
                                            End time (s)
                                        </div>
                                        <div id={'endTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
                                            <input
                                                className="presBox-input"
                                                onKeyDown={e => e.stopPropagation()}
                                                style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
                                                type="number"
                                                value={NumCast(activeItem.presEndTime)}
                                                onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
                                                    activeItem.presEndTime = Number(e.target.value);
                                                })}
                                            />
                                        </div>
                                    </div>
                                </div>
                                <div className="multiThumb-slider">
                                    <input
                                        type="range"
                                        step="0.1"
                                        min={clipStart}
                                        max={clipEnd}
                                        value={NumCast(activeItem.presEndTime)}
                                        style={{ gridColumn: 1, gridRow: 1 }}
                                        className={`toolbar-slider ${'end'}`}
                                        id="toolbar-slider"
                                        onPointerDown={() => {
                                            this._batch = UndoManager.StartBatch('presEndTime');
                                            const endBlock = document.getElementById('endTime');
                                            if (endBlock) {
                                                endBlock.style.color = Colors.LIGHT_GRAY;
                                                endBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
                                            }
                                        }}
                                        onPointerUp={() => {
                                            this._batch?.end();
                                            const endBlock = document.getElementById('endTime');
                                            if (endBlock) {
                                                endBlock.style.color = Colors.BLACK;
                                                endBlock.style.backgroundColor = Colors.LIGHT_GRAY;
                                            }
                                        }}
                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                                            e.stopPropagation();
                                            activeItem.presEndTime = Number(e.target.value);
                                        }}
                                    />
                                    <input
                                        type="range"
                                        step="0.1"
                                        min={clipStart}
                                        max={clipEnd}
                                        value={NumCast(activeItem.presStartTime)}
                                        style={{ gridColumn: 1, gridRow: 1 }}
                                        className={`toolbar-slider ${'start'}`}
                                        id="toolbar-slider"
                                        onPointerDown={() => {
                                            this._batch = UndoManager.StartBatch('presStartTime');
                                            const startBlock = document.getElementById('startTime');
                                            if (startBlock) {
                                                startBlock.style.color = Colors.LIGHT_GRAY;
                                                startBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
                                            }
                                        }}
                                        onPointerUp={() => {
                                            this._batch?.end();
                                            const startBlock = document.getElementById('startTime');
                                            if (startBlock) {
                                                startBlock.style.color = Colors.BLACK;
                                                startBlock.style.backgroundColor = Colors.LIGHT_GRAY;
                                            }
                                        }}
                                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                                            e.stopPropagation();
                                            activeItem.presStartTime = Number(e.target.value);
                                        }}
                                    />
                                </div>
                                <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}>
                                    <div className="slider-text">{clipStart} s</div>
                                    <div className="slider-text"></div>
                                    <div className="slider-text">{clipEnd} s</div>
                                </div>
                            </div>
                            <div className="ribbon-final-box">
                                Playback
                                <div className="presBox-subheading">Start playing:</div>
                                <div className="presBox-radioButtons">
                                    <div className="checkbox-container">
                                        <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'manual')} checked={activeItem.mediaStart === 'manual'} />
                                        <div>On click</div>
                                    </div>
                                    <div className="checkbox-container">
                                        <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'auto')} checked={activeItem.mediaStart === 'auto'} />
                                        <div>Automatically</div>
                                    </div>
                                </div>
                                <div className="presBox-subheading">Stop playing:</div>
                                <div className="presBox-radioButtons">
                                    <div className="checkbox-container">
                                        <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'manual')} checked={activeItem.mediaStop === 'manual'} />
                                        <div>At audio end time</div>
                                    </div>
                                    <div className="checkbox-container">
                                        <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'auto')} checked={activeItem.mediaStop === 'auto'} />
                                        <div>On slide change</div>
                                    </div>
                                    {/* <div className="checkbox-container">
                                    <input className="presBox-checkbox"
                                        type="checkbox"
                                        onChange={() => activeItem.mediaStop = "afterSlide"}
                                        checked={activeItem.mediaStop === "afterSlide"}
                                    />
                                    <div className="checkbox-dropdown">
                                        After chosen slide
                                        <select className="presBox-viewPicker"
                                            style={{ opacity: activeItem.mediaStop === "afterSlide" && this.itemIndex !== this.childDocs.length - 1 ? 1 : 0.3 }}
                                            onPointerDown={e => e.stopPropagation()}
                                            onChange={this.mediaStopChanged}
                                            value={mediaStopDocStr}>
                                            {this.mediaStopSlides}
                                        </select>
                                    </div>
                                </div> */}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            );
        }
    }

    @computed get newDocumentToolbarDropdown() {
        return (
            <div
                className={'presBox-toolbar-dropdown'}
                style={{ display: this._newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
                onClick={e => e.stopPropagation()}
                onPointerUp={e => e.stopPropagation()}
                onPointerDown={e => e.stopPropagation()}>
                <div className="layout-container" style={{ height: 'max-content' }}>
                    <div
                        className="layout"
                        style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
                        onClick={action(() => {
                            this.layout = 'blank';
                            this.createNewSlide(this.layout);
                        })}
                    />
                    <div
                        className="layout"
                        style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
                        onClick={action(() => {
                            this.layout = 'title';
                            this.createNewSlide(this.layout);
                        })}>
                        <div className="title">Title</div>
                        <div className="subtitle">Subtitle</div>
                    </div>
                    <div
                        className="layout"
                        style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
                        onClick={action(() => {
                            this.layout = 'header';
                            this.createNewSlide(this.layout);
                        })}>
                        <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
                            Section header
                        </div>
                    </div>
                    <div
                        className="layout"
                        style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
                        onClick={action(() => {
                            this.layout = 'content';
                            this.createNewSlide(this.layout);
                        })}>
                        <div className="title" style={{ alignSelf: 'center' }}>
                            Title
                        </div>
                        <div className="content">Text goes here</div>
                    </div>
                </div>
            </div>
        );
    }

    @observable openLayouts: boolean = false;
    @observable addFreeform: boolean = true;
    @observable layout: string = '';
    @observable title: string = '';

    @computed get newDocumentDropdown() {
        return (
            <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                <div className="ribbon-box">
                    Slide Title: <br></br>
                    <input
                        className="ribbon-textInput"
                        placeholder="..."
                        type="text"
                        name="fname"
                        onChange={e => {
                            e.stopPropagation();
                            e.preventDefault();
                            runInAction(() => (this.title = e.target.value));
                        }}></input>
                </div>
                <div className="ribbon-box">
                    Choose type:
                    <div className="ribbon-doubleButton">
                        <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
                            Text
                        </div>
                        <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
                            Freeform
                        </div>
                    </div>
                </div>
                <div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
                    Preset layouts:
                    <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
                        <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
                        <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
                            <div className="title">Title</div>
                            <div className="subtitle">Subtitle</div>
                        </div>
                        <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
                            <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
                                Section header
                            </div>
                        </div>
                        <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
                            <div className="title" style={{ alignSelf: 'center' }}>
                                Title
                            </div>
                            <div className="content">Text goes here</div>
                        </div>
                        <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
                            <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
                                Title
                            </div>
                            <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>
                                Column one text
                            </div>
                            <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>
                                Column two text
                            </div>
                        </div>
                    </div>
                    <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
                        <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
                    </div>
                </div>
                <div className="ribbon-final-box">
                    <div
                        className={this.title !== '' && ((this.addFreeform && this.layout !== '') || !this.addFreeform) ? 'ribbon-final-button-hidden' : 'ribbon-final-button'}
                        onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
                        Create New Slide
                    </div>
                </div>
            </div>
        );
    }

    createNewSlide = (layout?: string, title?: string, freeform?: boolean) => {
        let doc = undefined;
        if (layout) doc = this.createTemplate(layout);
        if (freeform && layout) doc = this.createTemplate(layout, title);
        if (!freeform && !layout) doc = Docs.Create.TextDocument('', { _nativeWidth: 400, _width: 225, title: title });
        if (doc) {
            const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
            const data = Cast(presCollection?.data, listSpec(Doc));
            const presData = Cast(this.rootDoc.data, listSpec(Doc));
            if (data && presData) {
                data.push(doc);
                TabDocView.PinDoc(doc);
                this.gotoDocument(this.childDocs.length, this.activeItem);
            } else {
                this.props.addDocTab(doc, 'add:right');
            }
        }
    };

    createTemplate = (layout: string, input?: string) => {
        const x = this.activeItem && this.targetDoc ? NumCast(this.targetDoc.x) : 0;
        const y = this.activeItem && this.targetDoc ? NumCast(this.targetDoc.y) + NumCast(this.targetDoc._height) + 20 : 0;
        const title = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 58, _fontSize: '24pt' });
        const subtitle = () => Docs.Create.TextDocument('Click to change subtitle', { title: 'Slide subtitle', _width: 380, _height: 50, x: 10, y: 118, _fontSize: '16pt' });
        const header = () => Docs.Create.TextDocument('Click to change header', { title: 'Slide header', _width: 380, _height: 65, x: 10, y: 80, _fontSize: '20pt' });
        const contentTitle = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 10, _fontSize: '24pt' });
        const content = () => Docs.Create.TextDocument('Click to change text', { title: 'Slide text', _width: 380, _height: 145, x: 10, y: 70, _fontSize: '14pt' });
        const content1 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 1', _width: 185, _height: 140, x: 10, y: 80, _fontSize: '14pt' });
        const content2 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 2', _width: 185, _height: 140, x: 205, y: 80, _fontSize: '14pt' });
        // prettier-ignore
        switch (layout) {
            case 'blank': return Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x, y });
            case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
            case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
            case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
            case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _fitContentsToBox: true, x, y })
        }
    };

    // Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view)
    @computed get presentDropdown() {
        return (
            <div className={`dropdown-play ${this._presentTools ? 'active' : ''}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                <div
                    className="dropdown-play-button"
                    onClick={undoBatch(
                        action(() => {
                            this.updateMinimize();
                            this.turnOffEdit(true);
                            this.gotoDocument(this.itemIndex, this.activeItem);
                        })
                    )}>
                    Mini-player
                </div>
                <div
                    className="dropdown-play-button"
                    onClick={undoBatch(
                        action(() => {
                            this.layoutDoc.presStatus = 'manual';
                            this.turnOffEdit(true);
                            this.gotoDocument(this.itemIndex, this.activeItem);
                        })
                    )}>
                    Sidebar player
                </div>
            </div>
        );
    }

    // Case in which the document has keyframes to navigate to next key frame
    @action
    nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => {
        const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
        const currentFrame = Cast(tagDoc._currentFrame, 'number', null);
        if (currentFrame === undefined) {
            tagDoc._currentFrame = 0;
            // CollectionFreeFormDocumentView.setupScroll(tagDoc, 0);
            // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
        }
        // if (tagDoc.editScrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame);
        CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc);
        tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1);
        tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame));
    };

    @action
    prevKeyframe = (tagDoc: Doc, actItem: Doc): void => {
        const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
        const currentFrame = Cast(tagDoc._currentFrame, 'number', null);
        if (currentFrame === undefined) {
            tagDoc._currentFrame = 0;
            // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
        }
        CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice());
        tagDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1);
    };

    /**
     * Returns the collection type as a string for headers
     */
    @computed get stringType() {
        if (this.activeItem) {
            // prettier-ignore
            switch (this.targetDoc.type) {
                case DocumentType.PDF: return 'PDF';
                case DocumentType.RTF: return 'Text node';
                case DocumentType.COL: return 'Collection';
                case DocumentType.AUDIO: return 'Audio';
                case DocumentType.VID: return 'Video';
                case DocumentType.IMG: return 'Image';
                case DocumentType.WEB: return 'Web page';
                case DocumentType.MAP: return 'Map';
                default: return 'Other node';
            }
        }
        return '';
    }

    @observable private openActiveColorPicker: boolean = false;
    @observable private openViewedColorPicker: boolean = false;

    @computed get progressivizeDropdown() {
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        if (activeItem && targetDoc) {
            const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black';
            const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black';
            return (
                <div className={`presBox-ribbon ${this._progressivizeTools && this.layoutDoc.presStatus === 'edit' ? 'active' : ''}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                    <div className="ribbon-box">
                        {this.stringType} selected
                        <div
                            className="ribbon-doubleButton"
                            style={{
                                borderTop: 'solid 1px darkgrey',
                                display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
                            }}>
                            <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeChild}>
                                Contents
                            </div>
                            <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editProgressivize}>
                                Edit
                            </div>
                        </div>
                        <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
                            <div className="presBox-subheading">Active text color</div>
                            <div
                                className="ribbon-colorBox"
                                style={{ backgroundColor: activeFontColor, height: 15, width: 15 }}
                                onClick={action(() => {
                                    this.openActiveColorPicker = !this.openActiveColorPicker;
                                })}></div>
                        </div>
                        {this.activeColorPicker}
                        <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
                            <div className="presBox-subheading">Viewed font color</div>
                            <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => (this.openViewedColorPicker = !this.openViewedColorPicker))}></div>
                        </div>
                        {this.viewedColorPicker}
                        <div
                            className="ribbon-doubleButton"
                            style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? 'inline-flex' : 'none' }}>
                            <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeZoom}>
                                Zoom
                            </div>
                            <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editZoomProgressivize}>
                                Edit
                            </div>
                        </div>
                        <div
                            className="ribbon-doubleButton"
                            style={{
                                borderTop: 'solid 1px darkgrey',
                                display: targetDoc._viewType === 'stacking' || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
                            }}>
                            <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeScroll}>
                                Scroll
                            </div>
                            <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editScrollProgressivize}>
                                Edit
                            </div>
                        </div>
                    </div>
                    <div className="ribbon-final-box">
                        Frames
                        <div className="ribbon-doubleButton">
                            <div className="ribbon-frameSelector">
                                <div
                                    key="back"
                                    title="back frame"
                                    className="backKeyframe"
                                    onClick={e => {
                                        e.stopPropagation();
                                        this.prevKeyframe(targetDoc, activeItem);
                                    }}>
                                    <FontAwesomeIcon icon={'caret-left'} size={'lg'} />
                                </div>
                                <div
                                    key="num"
                                    title="toggle view all"
                                    className="numKeyframe"
                                    style={{ color: targetDoc.keyFrameEditing ? 'white' : 'black', backgroundColor: targetDoc.keyFrameEditing ? Colors.MEDIUM_BLUE : Colors.LIGHT_BLUE }}
                                    onClick={action(() => (targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}>
                                    {NumCast(targetDoc._currentFrame)}
                                </div>
                                <div
                                    key="fwd"
                                    title="forward frame"
                                    className="fwdKeyframe"
                                    onClick={e => {
                                        e.stopPropagation();
                                        this.nextKeyframe(targetDoc, activeItem);
                                    }}>
                                    <FontAwesomeIcon icon={'caret-right'} size={'lg'} />
                                </div>
                            </div>
                            <Tooltip
                                title={
                                    <>
                                        <div className="dash-tooltip">{'Last frame'}</div>
                                    </>
                                }>
                                <div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div>
                            </Tooltip>
                        </div>
                        <div className="ribbon-frameList">
                            {this.frameListHeader}
                            {this.frameList}
                        </div>
                        <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(' TODO: play frames')}>
                            Play
                        </div>
                    </div>
                </div>
            );
        }
    }

    @undoBatch
    @action
    switchActive = (color: ColorState) => {
        this.targetDoc['pres-text-color'] = String(color.hex);
        return true;
    };
    @undoBatch
    @action
    switchPresented = (color: ColorState) => {
        this.targetDoc['pres-text-viewed-color'] = String(color.hex);
        return true;
    };

    @computed get activeColorPicker() {
        return !this.openActiveColorPicker ? null : (
            <SketchPicker
                onChange={this.switchActive}
                presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
                color={StrCast(this.targetDoc['pres-text-color'])}
            />
        );
    }

    @computed get viewedColorPicker() {
        return !this.openViewedColorPicker ? null : (
            <SketchPicker
                onChange={this.switchPresented}
                presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
                color={StrCast(this.targetDoc['pres-text-viewed-color'])}
            />
        );
    }

    @action
    turnOffEdit = (paths?: boolean) => {
        // Turn off paths
        if (paths) {
            const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
            if (srcContext) this.togglePath(srcContext, true);
        }
        // Turn off the progressivize editors for each document
        this.childDocs.forEach(doc => {
            doc.editSnapZoomProgressivize = false;
            doc.editZoomProgressivize = false;
            const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
            if (targetDoc) {
                targetDoc.editZoomProgressivize = false;
                // targetDoc.editScrollProgressivize = false;
            }
        });
    };

    //Toggle whether the user edits or not
    @action
    editZoomProgressivize = (e: React.MouseEvent) => {
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        if (!targetDoc.editZoomProgressivize) {
            if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true;
            targetDoc.zoomProgressivize = true;
            targetDoc.editZoomProgressivize = true;
            activeItem.editZoomProgressivize = true;
        } else {
            targetDoc.editZoomProgressivize = false;
            activeItem.editZoomProgressivize = false;
        }
    };

    //Toggle whether the user edits or not
    @action
    editScrollProgressivize = (e: React.MouseEvent) => {
        const targetDoc: Doc = this.targetDoc;
        if (!targetDoc.editScrollProgressivize) {
            if (!targetDoc.scrollProgressivize) {
                targetDoc.scrollProgressivize = true;
                this.activeItem.scrollProgressivize = true;
            }
            targetDoc.editScrollProgressivize = true;
        } else {
            targetDoc.editScrollProgressivize = false;
        }
    };

    //Progressivize Zoom
    @action
    progressivizeScroll = (e: React.MouseEvent) => {
        e.stopPropagation();
        this.activeItem.scrollProgressivize = !this.activeItem.scrollProgressivize;
        const targetDoc: Doc = this.targetDoc;
        targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize;
        // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame));
        if (targetDoc.editScrollProgressivize) {
            targetDoc.editScrollProgressivize = false;
            targetDoc._currentFrame = 0;
            targetDoc.lastFrame = 0;
        }
    };

    //Progressivize Zoom
    @action
    progressivizeZoom = (e: React.MouseEvent) => {
        e.stopPropagation();
        const activeItem: Doc = this.activeItem;
        activeItem.zoomProgressivize = !activeItem.zoomProgressivize;
        const targetDoc: Doc = this.targetDoc;
        targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize;
        CollectionFreeFormDocumentView.setupZoom(activeItem, targetDoc);
        if (activeItem.editZoomProgressivize) {
            activeItem.editZoomProgressivize = false;
            targetDoc._currentFrame = 0;
            targetDoc.lastFrame = 0;
        }
    };

    //Progressivize Child Docs
    @action
    editProgressivize = (e: React.MouseEvent) => {
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        targetDoc._currentFrame = targetDoc.lastFrame;
        if (!targetDoc.editProgressivize) {
            if (!activeItem.presProgressivize) {
                activeItem.presProgressivize = true;
                targetDoc.presProgressivize = true;
            }
            targetDoc.editProgressivize = true;
        } else {
            targetDoc.editProgressivize = false;
        }
    };

    @action
    progressivizeChild = (e: React.MouseEvent) => {
        e.stopPropagation();
        const activeItem: Doc = this.activeItem;
        const targetDoc: Doc = this.targetDoc;
        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
        if (!activeItem.presProgressivize) {
            targetDoc.keyFrameEditing = false;
            activeItem.presProgressivize = true;
            targetDoc.presProgressivize = true;
            targetDoc._currentFrame = 0;
            docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true));
            targetDoc.lastFrame = targetDoc.lastFrame ? NumCast(targetDoc.lastFrame) : docs.length - 1;
        } else {
            // targetDoc.editProgressivize = false;
            activeItem.presProgressivize = false;
            targetDoc.presProgressivize = false;
            targetDoc._currentFrame = 0;
            targetDoc.keyFrameEditing = true;
        }
    };

    @action
    checkMovementLists = (doc: Doc, xlist: any, ylist: any) => {
        const x: List<number> = xlist;
        const y: List<number> = ylist;
        const tags: JSX.Element[] = [];
        let pathPoints = ''; //List of all of the pathpoints that need to be added
        for (let i = 0; i < x.length - 1; i++) {
            if (y[i] || x[i]) {
                if (i === 0) pathPoints = x[i] - 11 + ',' + (y[i] + 33);
                else pathPoints = pathPoints + ' ' + (x[i] - 11) + ',' + (y[i] + 33);
                tags.push(
                    <div className="progressivizeMove-frame" style={{ position: 'absolute', top: y[i], left: x[i] }}>
                        {i}
                    </div>
                );
            }
        }
        tags.push(
            <svg style={{ overflow: 'visible', position: 'absolute' }}>
                <polyline
                    points={pathPoints}
                    style={{
                        position: 'absolute',
                        opacity: 1,
                        stroke: '#000000',
                        strokeWidth: 2,
                        strokeDasharray: '10 5',
                    }}
                    fill="none"
                />
            </svg>
        );
        return tags;
    };

    @observable
    toggleDisplayMovement = (doc: Doc) => (doc.displayMovement = !doc.displayMovement);

    @action
    checkList = (doc: Doc, list: any): number => {
        const x: List<number> = list;
        if (x?.length >= NumCast(doc._currentFrame) + 1) {
            return x[NumCast(doc._currentFrame)];
        } else if (x) {
            x.length = NumCast(doc._currentFrame) + 1;
            x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1];
            return x[NumCast(doc._currentFrame)];
        }
        return 100;
    };

    @computed get progressivizeChildDocs() {
        const targetDoc: Doc = this.targetDoc;
        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
        const tags: JSX.Element[] = [];
        docs.forEach((doc, index) => {
            if (doc['x-indexed'] && doc['y-indexed']) {
                tags.push(<div style={{ position: 'absolute', display: doc.displayMovement ? 'block' : 'none' }}>{this.checkMovementLists(doc, doc['x-indexed'], doc['y-indexed'])}</div>);
            }
            tags.push(
                <div
                    className="progressivizeButton"
                    key={index}
                    onPointerLeave={() => {
                        if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0;
                    }}
                    onPointerOver={() => {
                        if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5;
                    }}
                    onClick={e => {
                        this.toggleDisplayMovement(doc);
                        e.stopPropagation();
                    }}
                    style={{ backgroundColor: doc.displayMovement ? Colors.LIGHT_BLUE : '#c8c8c8', top: NumCast(doc.y), left: NumCast(doc.x) }}>
                    <div className="progressivizeButton-prev">
                        <FontAwesomeIcon
                            icon={'caret-left'}
                            size={'lg'}
                            onClick={e => {
                                e.stopPropagation();
                                this.prevAppearFrame(doc, index);
                            }}
                        />
                    </div>
                    <div className="progressivizeButton-frame">{NumCast(doc.appearFrame)}</div>
                    <div className="progressivizeButton-next">
                        <FontAwesomeIcon
                            icon={'caret-right'}
                            size={'lg'}
                            onClick={e => {
                                e.stopPropagation();
                                this.nextAppearFrame(doc, index);
                            }}
                        />
                    </div>
                </div>
            );
        });
        return tags;
    }

    @action
    nextAppearFrame = (doc: Doc, i: number) => {
        doc.appearFrame = (Cast(doc.appearFrame, 'number', null) ?? 0) + 1;
        this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame));
    };

    @action
    prevAppearFrame = (doc: Doc, i: number) => {
        doc.appearFrame = Math.max(0, (Cast(doc.appearFrame, 'number', null) ?? 0) - 1);
        this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame));
    };

    @action
    updateOpacityList = (list: any, frame: number) => {
        const x: List<number> = list;
        if (x && x.length >= frame) {
            for (let i = 0; i < x.length; i++) {
                if (i < frame) {
                    x[i] = 0;
                } else if (i >= frame) {
                    x[i] = 1;
                }
            }
            list = x;
        } else {
            x.length = frame + 1;
            for (let i = 0; i < x.length; i++) {
                if (i < frame) {
                    x[i] = 0;
                } else if (i >= frame) {
                    x[i] = 1;
                }
            }
            list = x;
        }
    };

    @computed
    get toolbarWidth(): number {
        return this.props.PanelWidth();
    }

    @action
    toggleProperties = () => (SettingsManager.propertiesWidth = SettingsManager.propertiesWidth > 0 ? 0 : 250);

    @computed get toolbar() {
        const propIcon = SettingsManager.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
        const propTitle = SettingsManager.propertiesWidth > 0 ? 'Close Presentation Panel' : 'Open Presentation Panel';
        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
        const isMini: boolean = this.toolbarWidth <= 100;
        const activeColor = Colors.LIGHT_BLUE;
        const inactiveColor = Colors.WHITE;
        return mode === CollectionViewType.Carousel3D ? null : (
            <div id="toolbarContainer" className={'presBox-toolbar'}>
                {/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
                    <FontAwesomeIcon icon={"plus"} />
                    <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
                </div></Tooltip> */}
                <Tooltip title={<div className="dash-tooltip">{'View paths'}</div>}>
                    <div
                        style={{ opacity: this.childDocs.length > 1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }}
                        className={'toolbar-button'}
                        onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}>
                        <FontAwesomeIcon icon={'exchange-alt'} />
                    </div>
                </Tooltip>
                {isMini ? null : (
                    <>
                        <div className="toolbar-divider" />
                        {/* <Tooltip title={<><div className="dash-tooltip">{this._expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
                            <div className={"toolbar-button"}
                                style={{ color: this._expandBoolean ? Colors.MEDIUM_BLUE : 'white' }}
                                onClick={this.toggleExpandMode}>
                                <FontAwesomeIcon icon={"eye"} />
                            </div>
                        </Tooltip>
                        <div className="toolbar-divider" /> */}
                        <Tooltip title={<div className="dash-tooltip">{this._presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}</div>}>
                            <div className="toolbar-button" style={{ cursor: this._presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
                                <FontAwesomeIcon className={'toolbar-thumbtack'} icon={'keyboard'} style={{ color: this._presKeyEvents ? activeColor : inactiveColor }} />
                            </div>
                        </Tooltip>
                        <Tooltip title={<div className="dash-tooltip">{propTitle}</div>}>
                            <div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
                                <FontAwesomeIcon className={'toolbar-thumbtack'} icon={propIcon} style={{ color: SettingsManager.propertiesWidth > 0 ? activeColor : inactiveColor }} />
                            </div>
                        </Tooltip>
                    </>
                )}
            </div>
        );
    }

    /**
     * Top panel containes:
     * viewPicker: The option to choose between List and Slides view for the presentaiton trail
     * presentPanel: The button to start the presentation / open minimized view of the presentation
     */
    @computed get topPanel() {
        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
        const isMini: boolean = this.toolbarWidth <= 100;
        return (
            <div className="presBox-buttons" style={{ background: Doc.ActivePresentation === this.rootDoc ? 'green' : undefined, display: !this.rootDoc._chromeHidden ? 'none' : undefined }}>
                {isMini ? null : (
                    <select className="presBox-viewPicker" style={{ display: this.layoutDoc.presStatus === 'edit' ? 'block' : 'none' }} onPointerDown={e => e.stopPropagation()} onChange={this.viewChanged} value={mode}>
                        <option onPointerDown={StopEvent} value={CollectionViewType.Stacking}>
                            List
                        </option>
                        <option onPointerDown={StopEvent} value={CollectionViewType.Tree}>
                            Tree
                        </option>
                        {Doc.noviceMode ? null : (
                            <option onPointerDown={StopEvent} value={CollectionViewType.Carousel3D}>
                                3D Carousel
                            </option>
                        )}
                    </select>
                )}
                <div className="presBox-presentPanel" style={{ opacity: this.childDocs.length ? 1 : 0.3 }}>
                    <span className={`presBox-button ${this.layoutDoc.presStatus === 'edit' ? 'present' : ''}`}>
                        <div
                            className="presBox-button-left"
                            onClick={undoBatch(() => {
                                if (this.childDocs.length) {
                                    this.layoutDoc.presStatus = 'manual';
                                    this.gotoDocument(this.itemIndex, this.activeItem);
                                }
                            })}>
                            <FontAwesomeIcon icon={'play-circle'} />
                            <div style={{ display: this.props.PanelWidth() > 200 ? 'inline-flex' : 'none' }}>&nbsp; Present</div>
                        </div>
                        {mode === CollectionViewType.Carousel3D || isMini ? null : (
                            <div
                                className={`presBox-button-right ${this._presentTools ? 'active' : ''}`}
                                onClick={action(() => {
                                    if (this.childDocs.length) this._presentTools = !this._presentTools;
                                })}>
                                <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this._presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'angle-down'} />
                                {this.presentDropdown}
                            </div>
                        )}
                    </span>
                    {this.playButtons}
                </div>
            </div>
        );
    }

    @action
    getList = (list: any): List<number> => list;

    @action
    updateList = (list: any): List<number> => {
        const targetDoc: Doc = this.targetDoc;
        const x: List<number> = list;
        x[x.length - 1] = NumCast(targetDoc._scrollY);
        return x;
    };

    @action
    newFrame = () => {
        const activeItem: Doc = this.activeItem;
        const type: string = StrCast(this.targetDoc.type);
        if (!activeItem.frameList) activeItem.frameList = new List<number>();
        switch (type) {
            case DocumentType.PDF || DocumentType.RTF || DocumentType.WEB:
                this.updateList(activeItem.frameList);
                break;
        }
    };

    @computed get frameListHeader() {
        return (
            <div className="frameList-header">
                &nbsp; Frames {this.panable ? <i>Panable</i> : this.scrollable ? <i>Scrollable</i> : null}
                <div className={'frameList-headerButtons'}>
                    <Tooltip title={<div className="dash-tooltip">{'Add frame by example'}</div>}>
                        <div
                            className={'headerButton'}
                            onClick={e => {
                                e.stopPropagation();
                                this.newFrame();
                            }}>
                            <FontAwesomeIcon icon={'plus'} onPointerDown={e => e.stopPropagation()} />
                        </div>
                    </Tooltip>
                    <Tooltip title={<div className="dash-tooltip">{'Edit in collection'}</div>}>
                        <div
                            className={'headerButton'}
                            onClick={e => {
                                e.stopPropagation();
                                console.log('New frame');
                            }}>
                            <FontAwesomeIcon icon={'edit'} onPointerDown={e => e.stopPropagation()} />
                        </div>
                    </Tooltip>
                </div>
            </div>
        );
    }

    @computed get frameList() {
        const frameList: List<number> = this.getList(this.activeItem.frameList);
        return !frameList ? null : (
            <div className="frameList-container">
                {frameList.map(value => (
                    <div className="framList-item" />
                ))}
            </div>
        );
    }

    @computed get playButtonFrames() {
        const targetDoc = this.targetDoc;
        return !this.targetDoc ? null : (
            <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? 'inline-flex' : 'none' }}>
                <div>{NumCast(targetDoc._currentFrame)}</div>
                <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
                <div>{NumCast(targetDoc.lastFrame)}</div>
            </div>
        );
    }

    @computed get playButtons() {
        const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1;
        const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0;
        // Case 1: There are still other frames and should go through all frames before going to next slide
        return (
            <div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== 'edit' ? 'inline-flex' : 'none' }}>
                <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
                    <div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : 'white' }} onClick={() => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop)}>
                        <FontAwesomeIcon icon={'redo-alt'} />
                    </div>
                </Tooltip>
                <div className="presPanel-divider" />
                <div
                    className="presPanel-button"
                    style={{ opacity: presStart ? 0.4 : 1 }}
                    onClick={() => {
                        this.back();
                        if (this._presTimer) {
                            clearTimeout(this._presTimer);
                            this.layoutDoc.presStatus = PresStatus.Manual;
                        }
                    }}>
                    <FontAwesomeIcon icon={'arrow-left'} />
                </div>
                <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
                    <div className="presPanel-button" onClick={this.startOrPause}>
                        <FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} />
                    </div>
                </Tooltip>
                <div
                    className="presPanel-button"
                    style={{ opacity: presEnd ? 0.4 : 1 }}
                    onClick={() => {
                        this.next();
                        if (this._presTimer) {
                            clearTimeout(this._presTimer);
                            this.layoutDoc.presStatus = PresStatus.Manual;
                        }
                    }}>
                    <FontAwesomeIcon icon={'arrow-right'} />
                </div>
                <div className="presPanel-divider"></div>
                <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
                    <div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}>
                        <b>1</b>
                    </div>
                </Tooltip>
                <div className="presPanel-button-text" onClick={() => this.gotoDocument(0, this.activeItem)} style={{ display: this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}>
                    Slide {this.itemIndex + 1} / {this.childDocs.length}
                    {this.playButtonFrames}
                </div>
                <div className="presPanel-divider"></div>
                {this.props.PanelWidth() > 250 ? (
                    <div
                        className="presPanel-button-text"
                        onClick={undoBatch(
                            action(() => {
                                this.layoutDoc.presStatus = 'edit';
                                clearTimeout(this._presTimer);
                            })
                        )}>
                        EXIT
                    </div>
                ) : (
                    <div className="presPanel-button" onClick={undoBatch(action(() => (this.layoutDoc.presStatus = 'edit')))}>
                        <FontAwesomeIcon icon={'times'} />
                    </div>
                )}
            </div>
        );
    }

    @action
    startOrPause = () => {
        if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex);
        else this.pauseAutoPres();
    };

    @action
    prevClicked = (e: PointerEvent) => {
        this.back();
        if (this._presTimer) {
            clearTimeout(this._presTimer);
            this.layoutDoc.presStatus = PresStatus.Manual;
        }
    };

    @action
    nextClicked = (e: PointerEvent) => {
        this.next();
        if (this._presTimer) {
            clearTimeout(this._presTimer);
            this.layoutDoc.presStatus = PresStatus.Manual;
        }
    };
    @undoBatch
    @action
    exitClicked = (e: PointerEvent) => {
        this.updateMinimize();
        this.layoutDoc.presStatus = PresStatus.Edit;
        clearTimeout(this._presTimer);
    };

    @action
    startMarqueeCreateSlide = () => (PresBox.startMarquee = true);

    AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
        var indexNum = 0;
        for (let i = 0; i < index.length; i++) {
            indexNum += index[i] * 10 ** -i;
        }
        if (this._treeViewMap.get(treeViewDoc) !== indexNum) {
            this._treeViewMap.set(treeViewDoc, indexNum);
            const sorted = this.sort(this._treeViewMap);
            const curList = DocListCast(this.dataDoc[this.presFieldKey]);
            if (sorted.length !== curList.length || sorted.some((doc, ind) => doc !== curList[ind])) {
                this.dataDoc[this.presFieldKey] = new List<Doc>(sorted); // this is a flat array of Docs
            }
        }
        return this.childDocs;
    };

    RemFromMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
        if (!this._unmounting && this.isTree) {
            this._treeViewMap.delete(treeViewDoc);
            this.dataDoc[this.presFieldKey] = new List<Doc>(this.sort(this._treeViewMap));
        }
        return this.childDocs;
    };

    // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1])
    sort = (treeViewMap: Map<Doc, number>) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]);

    render() {
        // needed to ensure that the childDocs are loaded for looking up fields
        this.childDocs.slice();
        const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
        const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1;
        const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0;
        return DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc) ? (
            <div className="miniPres" onClick={e => e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}>
                <div
                    className="presPanelOverlay"
                    style={{ display: 'inline-flex', height: 30, background: Doc.ActivePresentation === this.rootDoc ? 'green' : '#323232', top: 0, zIndex: 3000000, boxShadow: this._presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
                    <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
                        <div
                            className="presPanel-button"
                            style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }}
                            onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop), false, false)}>
                            <FontAwesomeIcon icon={'redo-alt'} />
                        </div>
                    </Tooltip>
                    <div className="presPanel-divider"></div>
                    <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
                        <FontAwesomeIcon icon={'arrow-left'} />
                    </div>
                    <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
                        <div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}>
                            <FontAwesomeIcon icon={this.layoutDoc.presStatus === 'auto' ? 'pause' : 'play'} />
                        </div>
                    </Tooltip>
                    <div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.nextClicked, false, false)}>
                        <FontAwesomeIcon icon={'arrow-right'} />
                    </div>
                    <div className="presPanel-divider"></div>
                    <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
                        <div className="presPanel-button" style={{ border: 'solid 1px white' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}>
                            <b>1</b>
                        </div>
                    </Tooltip>
                    <div className="presPanel-button-text">
                        Slide {this.itemIndex + 1} / {this.childDocs.length}
                        {this.playButtonFrames}
                    </div>
                    <div className="presPanel-divider" />
                    <div className="presPanel-button-text" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}>
                        EXIT
                    </div>
                </div>
            </div>
        ) : (
            <div className="presBox-cont" style={{ minWidth: DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc) ? 240 : undefined }}>
                {this.topPanel}
                {this.toolbar}
                {this.newDocumentToolbarDropdown}
                <div className="presBox-listCont">
                    <div className="Slide" style={{ height: `calc(100% - 30px)` }}>
                        {mode !== CollectionViewType.Invalid ? (
                            <CollectionView
                                {...this.props}
                                ContainingCollectionDoc={this.props.Document}
                                PanelWidth={this.props.PanelWidth}
                                PanelHeight={this.panelHeight}
                                childIgnoreNativeSize={true}
                                moveDocument={returnFalse}
                                childFitWidth={returnTrue}
                                childOpacity={returnOne}
                                childLayoutTemplate={this.childLayoutTemplate}
                                filterAddDocument={this.addDocumentFilter}
                                removeDocument={returnFalse}
                                dontRegisterView={true}
                                focus={this.selectElement}
                                scriptContext={this}
                                ScreenToLocalTransform={this.getTransform}
                                AddToMap={this.AddToMap}
                                RemFromMap={this.RemFromMap}
                                hierarchyIndex={[]}
                            />
                        ) : null}
                    </div>

                    {
                        // if the document type is a presentation, then the collection stacking view has a "+ new slide" button at the bottom of the stack
                        <Tooltip title={<div className="dash-tooltip">{'Click on document to pin to presentaiton or make a marquee selection to pin your desired view'}</div>}>
                            <button className="add-slide-button" onPointerDown={this.startMarqueeCreateSlide}>
                                + NEW SLIDE
                            </button>
                        </Tooltip>
                    }
                </div>
            </div>
        );
    }
    static NavigateToDoc(bestTarget: Doc, activeItem: Doc) {
        const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null);
        const openInTab = (doc: Doc, finished?: () => void) => {
            CollectionDockingView.AddSplit(doc, 'right');
            finished?.();
        };
        PresBox.NavigateToTarget(bestTarget, activeItem, openInTab, srcContext);
    }
}

ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) {
    PresBox.NavigateToDoc(bestTarget, activeItem);
});
