diff options
| author | monoguitari <113245090+monoguitari@users.noreply.github.com> | 2023-08-22 14:15:04 -0400 |
|---|---|---|
| committer | monoguitari <113245090+monoguitari@users.noreply.github.com> | 2023-08-22 14:15:04 -0400 |
| commit | 9293fd8c4128b41b31f9b2214d6799fdff0f2aaa (patch) | |
| tree | 45809c42545b10515f6f88065318b454549dacd1 /src/client/views/collections/TabDocView.tsx | |
| parent | 347e8e2bd32854b36828b7bcc645c9c361204251 (diff) | |
| parent | 1c52bd054385d2584bbeae41eecdf9ba6999c25f (diff) | |
Merge branch 'master' into advanced-trails
Diffstat (limited to 'src/client/views/collections/TabDocView.tsx')
| -rw-r--r-- | src/client/views/collections/TabDocView.tsx | 198 |
1 files changed, 104 insertions, 94 deletions
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 75e4e8abf..ea473d5cf 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { clamp } from 'lodash'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, observable, ObservableSet, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as ReactDOM from 'react-dom/client'; import { Doc, Opt } from '../../../fields/Doc'; @@ -34,6 +34,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import React = require('react'); +import { Popup, Toggle, Type } from 'browndash-components'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -43,12 +44,21 @@ interface TabDocViewProps { } @observer export class TabDocView extends React.Component<TabDocViewProps> { + static _allTabs = new ObservableSet<TabDocView>(); _mainCont: HTMLDivElement | null = null; _tabReaction: IReactionDisposer | undefined; @observable _activated: boolean = false; @observable _panelWidth = 0; @observable _panelHeight = 0; + @observable _hovering = false; @observable _isActive: boolean = false; + @observable _isAnyChildContentActive = false; + @computed get _isUserActivated() { + return SelectionManager.Views().some(view => view.rootDoc === this._document) || this._isAnyChildContentActive; + } + @computed get _isContentActive() { + return this._isUserActivated || this._hovering; + } @observable _document: Doc | undefined; @observable _view: DocumentView | undefined; @@ -61,9 +71,7 @@ export class TabDocView extends React.Component<TabDocViewProps> { return 'transparent'; } @computed get tabColor() { - let tabColor = StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); - if (tabColor === 'transparent') return 'black'; - return tabColor; + return this._isUserActivated ? Colors.WHITE : this._hovering ? Colors.LIGHT_GRAY : Colors.MEDIUM_GRAY; } @computed get tabTextColor() { return this._document?.type === DocumentType.PRES ? 'black' : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color))); @@ -191,7 +199,7 @@ export class TabDocView extends React.Component<TabDocViewProps> { } }); tab._disposers.selectionDisposer = reaction( - () => SelectionManager.Views().some(v => v.topMost && v.props.Document === doc), + () => SelectionManager.Views().some(view => view.rootDoc === this._document), action(selected => { if (selected) this._activated = true; const toggle = tab.element[0].children[2].children[0] as HTMLInputElement; @@ -248,46 +256,47 @@ export class TabDocView extends React.Component<TabDocViewProps> { return; } const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps); - const pinDoc = Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); - pinDoc.presentationTargetDoc = anchorDoc ?? doc; + const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); + pinDoc.presentation_targetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; pinDoc.data = new List<Doc>(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data - pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; - pinDoc.presDuration = pinDoc.presDuration ?? 1000; - pinDoc.groupWithUp = false; - pinDoc.embedContainer = curPres; + pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; + pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000; + pinDoc.presentation_groupWithUp = false; + Doc.SetContainer(pinDoc, curPres); // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time - pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area - pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. - pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. - pinDoc.treeViewFieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field - pinDoc.treeViewExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view - pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header + pinDoc.treeView = ''; // not really needed, but makes key value pane look better + pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area + pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. + pinDoc.treeView_ChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. + pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field + pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view + pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); if (pinProps.pinViewport) PresBox.pinDocView(pinDoc, pinProps, anchorDoc ?? doc); if (!pinProps?.audioRange && duration !== undefined) { pinDoc.mediaStart = 'manual'; pinDoc.mediaStop = 'manual'; - pinDoc.presStartTime = NumCast(doc.clipStart); - pinDoc.presEndTime = NumCast(doc.clipEnd, duration); + pinDoc.config_clipStart = NumCast(doc.clipStart); + pinDoc.config_clipEnd = NumCast(doc.clipEnd, duration); } if (pinProps?.activeFrame !== undefined) { - pinDoc.presActiveFrame = pinProps?.activeFrame; + pinDoc.config_activeFrame = pinProps?.activeFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinProps?.currentFrame !== undefined) { - pinDoc.presCurrentFrame = pinProps?.currentFrame; + pinDoc.config_currentFrame = pinProps?.currentFrame; pinDoc.title = doc.title + ' (move)'; - pinDoc.presMovement = PresMovement.Pan; + pinDoc.presentation_movement = PresMovement.Pan; } if (pinDoc.stroke_isInkMask) { - pinDoc.presHideAfter = true; - pinDoc.presHideBefore = true; - pinDoc.presMovement = PresMovement.None; + pinDoc.presentation_hideAfter = true; + pinDoc.presentation_hideBefore = true; + pinDoc.presentation_movement = PresMovement.None; } - if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; + if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true; Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement()); PresBox.Instance?.clearSelectedArray(); pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array @@ -305,6 +314,7 @@ export class TabDocView extends React.Component<TabDocViewProps> { setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs } + @action componentDidMount() { new _global.ResizeObserver( action((entries: any) => { @@ -319,14 +329,17 @@ export class TabDocView extends React.Component<TabDocViewProps> { // this._tabReaction = reaction(() => ({ selected: this.active(), title: this.tab?.titleElement[0] }), // ({ selected, title }) => title && (title.style.backgroundColor = selected ? "white" : ""), // { fireImmediately: true }); + TabDocView._allTabs.add(this); } componentDidUpdate() { this._view && DocumentManager.Instance.AddView(this._view); } + @action componentWillUnmount() { this._tabReaction?.(); this._view && DocumentManager.Instance.RemoveView(this._view); + TabDocView._allTabs.delete(this); this.props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged); } @@ -335,6 +348,7 @@ export class TabDocView extends React.Component<TabDocViewProps> { private onActiveContentItemChanged(contentItem: any) { if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) { this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab; + if (!this._view) setTimeout(() => SelectionManager.SelectView(this._view, false)); !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one. } } @@ -348,10 +362,10 @@ export class TabDocView extends React.Component<TabDocViewProps> { // lightbox - will add the document to any collection along the path from the document to the docking view that has a field isLightbox. if none is found, it adds to the full screen lightbox addDocTab = (doc: Doc, location: OpenWhere) => { SelectionManager.DeselectAll(); - const whereFields = doc._type_collection === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':'); + const whereFields = location.split(':'); const keyValue = whereFields[1]?.includes('KeyValue'); const whereMods: OpenWhereMod = whereFields.length > 1 ? (whereFields[1].replace('KeyValue', '') as OpenWhereMod) : OpenWhereMod.none; - if (doc.dockingConfig) return DashboardView.openDashboard(doc); + if (doc.dockingConfig && !keyValue) return DashboardView.openDashboard(doc); // prettier-ignore switch (whereFields[0]) { case undefined: @@ -364,8 +378,6 @@ export class TabDocView extends React.Component<TabDocViewProps> { } } return LightboxView.AddDocTab(doc, location); - case OpenWhere.dashboard: return DashboardView.openDashboard(doc); - case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods); case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, whereMods, this.stack, undefined, keyValue); case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods, this.stack, undefined, keyValue); @@ -382,10 +394,10 @@ export class TabDocView extends React.Component<TabDocViewProps> { }; getCurrentFrame = () => { - return NumCast(Cast(PresBox.Instance.activeItem.presentationTargetDoc, Doc, null)._currentFrame); + return NumCast(Cast(PresBox.Instance.activeItem.presentation_targetDoc, Doc, null)._currentFrame); }; static Activate = (tabDoc: Doc) => { - const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc); + const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(tab => tab.DashDoc === tabDoc && !tab.contentItem.config.props.keyValue); tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost) return tab !== undefined; }; @@ -405,11 +417,11 @@ export class TabDocView extends React.Component<TabDocViewProps> { }; PanelWidth = () => this._panelWidth; PanelHeight = () => this._panelHeight; - miniMapColor = () => this.tabColor; + miniMapColor = () => Colors.MEDIUM_GRAY; tabView = () => this._view; disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._type_collection !== CollectionViewType.Freeform; - hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.layout_hideMinimap); - + whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive); + isContentActive = () => this._isContentActive; @computed get docView() { return !this._activated || !this._document ? null : ( <> @@ -427,7 +439,7 @@ export class TabDocView extends React.Component<TabDocViewProps> { DataDoc={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined} onBrowseClick={MainView.Instance.exploreMode} waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick} - isContentActive={returnTrue} + isContentActive={this.isContentActive} isDocumentActive={returnFalse} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} @@ -441,30 +453,15 @@ export class TabDocView extends React.Component<TabDocViewProps> { ScreenToLocalTransform={this.ScreenToLocalTransform} dontCenter={'y'} rootSelected={returnTrue} - whenChildContentsActiveChanged={emptyFunction} + whenChildContentsActiveChanged={this.whenChildContentActiveChanges} focus={this.focusFunc} docViewPath={returnEmptyDoclist} bringToFront={emptyFunction} pinToPres={TabDocView.PinDoc} /> - <TabMinimapView key="minimap" hideMinimap={this.hideMinimap} addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} /> - <Tooltip key="ttip" title={<div className="dash-tooltip">{this._document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}> - <div - className="miniMap-hidden" - style={{ - display: this.disableMinimap() || this._document._type_collection !== 'freeform' ? 'none' : undefined, - color: this._document.layout_hideMinimap ? Colors.BLACK : Colors.WHITE, - backgroundColor: this._document.layout_hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE, - boxShadow: this._document.layout_hideMinimap ? Shadows.STANDARD_SHADOW : undefined, - }} - onPointerDown={e => e.stopPropagation()} - onClick={action(e => { - e.stopPropagation(); - this._document!.layout_hideMinimap = !this._document!.layout_hideMinimap; - })}> - <FontAwesomeIcon icon={'globe-asia'} size="lg" /> - </div> - </Tooltip> + {this.disableMinimap() || this._document._type_collection !== CollectionViewType.Freeform ? null : ( + <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} /> + )} </> ); } @@ -476,6 +473,10 @@ export class TabDocView extends React.Component<TabDocViewProps> { style={{ fontFamily: Doc.UserDoc().renderStyle === 'comic' ? 'Comic Sans MS' : undefined, }} + onPointerEnter={action(() => (this._hovering = true))} + onPointerLeave={action(() => (this._hovering = false))} + onDragOver={action(() => (this._hovering = true))} + onDragLeave={action(() => (this._hovering = false))} ref={ref => { if ((this._mainCont = ref)) { if (this._lastTab) { @@ -495,7 +496,6 @@ export class TabDocView extends React.Component<TabDocViewProps> { interface TabMinimapViewProps { document: Doc; - hideMinimap: () => boolean; tabView: () => DocumentView | undefined; addDocTab: (doc: Doc, where: OpenWhere) => boolean; PanelWidth: () => number; @@ -570,46 +570,56 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> { if (!this.renderBounds) return null; const miniWidth = (this.props.PanelWidth() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100; const miniHeight = (this.props.PanelHeight() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100; - const miniLeft = 50 + ((NumCast(this.props.document._freeform_) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2; + const miniLeft = 50 + ((NumCast(this.props.document._freeform_panX) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2; const miniTop = 50 + ((NumCast(this.props.document._freeform_panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2; const miniSize = this.returnMiniSize(); - return this.props.hideMinimap() ? null : ( - <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}> - <CollectionFreeFormView - Document={this.props.document} - docViewPath={returnEmptyDoclist} - childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this. - noOverlay={true} // don't render overlay Docs since they won't scale - setHeight={returnFalse} - isContentActive={emptyFunction} - isAnyChildContentActive={returnFalse} - select={emptyFunction} - dropAction={undefined} - isSelected={returnFalse} - dontRegisterView={true} - fieldKey={Doc.LayoutFieldKey(this.props.document)} - bringToFront={emptyFunction} - rootSelected={returnTrue} - addDocument={returnFalse} - moveDocument={returnFalse} - removeDocument={returnFalse} - PanelWidth={this.returnMiniSize} - PanelHeight={this.returnMiniSize} - ScreenToLocalTransform={Transform.Identity} - renderDepth={0} - whenChildContentsActiveChanged={emptyFunction} - focus={emptyFunction} - styleProvider={TabMinimapView.miniStyleProvider} - addDocTab={this.props.addDocTab} - pinToPres={TabDocView.PinDoc} - childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist} - childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist} - searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist} - fitContentsToBox={returnTrue} + return ( + <div className="miniMap-hidden"> + <Popup + icon={<FontAwesomeIcon icon="globe-asia" size="lg" />} + color={StrCast(Doc.UserDoc().userVariantColor, Colors.MEDIUM_BLUE)} + type={Type.TERT} + onPointerDown={e => e.stopPropagation()} + placement={'top-end'} + popup={ + <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}> + <CollectionFreeFormView + Document={this.props.document} + docViewPath={returnEmptyDoclist} + childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this. + noOverlay={true} // don't render overlay Docs since they won't scale + setHeight={returnFalse} + isContentActive={emptyFunction} + isAnyChildContentActive={returnFalse} + select={emptyFunction} + isSelected={returnFalse} + dontRegisterView={true} + fieldKey={Doc.LayoutFieldKey(this.props.document)} + bringToFront={emptyFunction} + rootSelected={returnTrue} + addDocument={returnFalse} + moveDocument={returnFalse} + removeDocument={returnFalse} + PanelWidth={this.returnMiniSize} + PanelHeight={this.returnMiniSize} + ScreenToLocalTransform={Transform.Identity} + renderDepth={0} + whenChildContentsActiveChanged={emptyFunction} + focus={emptyFunction} + styleProvider={TabMinimapView.miniStyleProvider} + addDocTab={this.props.addDocTab} + pinToPres={TabDocView.PinDoc} + childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist} + childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist} + searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist} + fitContentsToBox={returnTrue} + /> + <div className="miniOverlay" onPointerDown={this.miniDown}> + <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} /> + </div> + </div> + } /> - <div className="miniOverlay" onPointerDown={this.miniDown}> - <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} /> - </div> </div> ); } |
