aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx27
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.scss1
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx5
-rw-r--r--src/client/views/collections/CollectionSubView.tsx12
-rw-r--r--src/client/views/collections/CollectionTreeView.scss11
-rw-r--r--src/client/views/collections/TabDocView.tsx42
-rw-r--r--src/client/views/collections/TreeView.scss17
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss28
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx190
14 files changed, 163 insertions, 186 deletions
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 39e2cc17d..6d70cc0d2 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -175,7 +175,7 @@ export class CollectionDockingView extends CollectionSubView() {
@undoBatch
@action
public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
- if (document._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document);
+ if (document?._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document);
if (!CollectionDockingView.Instance) return false;
const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
if (tab) {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index cfbcec2d6..eb55650e4 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -769,6 +769,21 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false;
}
+ public static gotoKeyFrame(doc: Doc, newFrame: number) {
+ if (!doc) {
+ return;
+ }
+ const dataField = doc[Doc.LayoutFieldKey(doc)];
+ const childDocs = DocListCast(dataField);
+ const currentFrame = Cast(doc._currentFrame, 'number', null);
+ if (currentFrame === undefined) {
+ doc._currentFrame = 0;
+ CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
+ }
+ CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
+ doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
+ }
+
@undoBatch
@action
nextKeyframe = (): void => {
@@ -1010,7 +1025,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
<FontAwesomeIcon icon={'caret-left'} size={'lg'} />
</div>
</Tooltip>
- <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
+ <Tooltip key="num" title={<div className="dash-tooltip">Frame number</div>} placement="bottom">
<div
className="numKeyframe"
style={{ color: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? 'white' : 'black', backgroundColor: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? '#5B9FDD' : '#AEDDF8' }}
@@ -1569,13 +1584,5 @@ export class CollectionGridViewChrome extends React.Component<CollectionViewMenu
}
}
ScriptingGlobals.add(function gotoFrame(doc: any, newFrame: any) {
- const dataField = doc[Doc.LayoutFieldKey(doc)];
- const childDocs = DocListCast(dataField);
- const currentFrame = Cast(doc._currentFrame, 'number', null);
- if (currentFrame === undefined) {
- doc._currentFrame = 0;
- CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
- }
- CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
- doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
+ CollectionFreeFormViewChrome.gotoKeyFrame(doc, newFrame);
});
diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index 6611477e5..c296e1172 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -2,6 +2,7 @@
.collectionStackedTimeline-timelineContainer {
height: 100%;
+ position: absolute;
overflow-x: auto;
overflow-y: hidden;
border: none;
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 48e3abbc7..2543624d3 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -668,7 +668,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
)}
</div>
</div>
- <div className="timeline-hoverUI" style={{ left: `calc(${((this._hoverTime - this.clipStart) / this.clipDuration) * 100}%` }}>
+ <div className="timeline-hoverUI" style={{ left: ((this._hoverTime - this.clipStart) / this.clipDuration) * this.timelineContentWidth - this._scroll }}>
<div className="hoverTime">{formatTime(this._hoverTime - this.clipStart)}</div>
{this._thumbnail && <img className="videoBox-thumbnail" src={this._thumbnail} />}
</div>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 6683eddf3..cf781b54a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -300,9 +300,10 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return this.addDocument?.(newDoc);
}
};
- isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+ isContentActive = () => (this.props.isSelected() || this.props.isContentActive() ? true : this.props.isSelected() === false || this.props.isContentActive() === false ? false : undefined);
- isChildContentActive = () => this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive));
+ isChildContentActive = () =>
+ this.props.isDocumentActive?.() && (this.props.childDocumentsActive?.() || BoolCast(this.rootDoc.childDocumentsActive)) ? true : this.props.childDocumentsActive?.() === false || this.rootDoc.childDocumentsActive === false ? false : undefined;
// this is what renders the document that you see on the screen
// called in Children: this actually adds a document to our children list
getDisplayDoc(doc: Doc, width: () => number) {
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5479929bd..e33bb77de 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -88,11 +88,11 @@ export function CollectionSubView<X>(moreProps?: X) {
}
collectionFilters = () => this._focusFilters ?? StrListCast(this.props.Document._docFilters);
collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.props.Document._docRangeFilters, listSpec('string'), []);
+ // child filters apply to the descendants of the documents in this collection
childDocFilters = () => [...(this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()];
+ // unrecursive filters apply to the documents in the collection, but no their children. See Utils.noRecursionHack
unrecursiveDocFilters = () => [...(this.props.docFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])];
childDocRangeFilters = () => [...(this.props.docRangeFilters?.() || []), ...this.collectionRangeDocFilters()];
- IsFiltered = () =>
- this.collectionFilters().length || this.collectionRangeDocFilters().length ? 'hasFilter' : this.props.docFilters?.().filter(f => Utils.IsRecursiveFilter(f)).length || this.props.docRangeFilters().length ? 'inheritsFilter' : undefined;
searchFilterDocs = () => this.props.searchFilterDocs?.() ?? DocListCast(this.props.Document._searchFilterDocs);
@computed.struct get childDocs() {
TraceMobx();
@@ -122,13 +122,11 @@ export function CollectionSubView<X>(moreProps?: X) {
return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one
}
- // console.log(Doc.ActiveDashboard._docFilters);
- // if (!this.props.Document._docFilters && this.props.Document.currentFilter) {
- // (this.props.Document.currentFilter as Doc).filterBoolean = (this.props.ContainingCollectionDoc?.currentFilter as Doc)?.filterBoolean;
- // }
const docsforFilter: Doc[] = [];
childDocs.forEach(d => {
- // if (DocUtils.Excluded(d, docFilters)) return;
+ // dragging facets
+ const dragged = this.props.docFilters?.().some(f => f.includes(Utils.noDragsDocFilter));
+ if (dragged && DragManager.docsBeingDragged.includes(d)) return false;
let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), docRangeFilters, viewSpecScript, this.props.Document).length > 0;
if (notFiltered) {
notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, viewSpecScript, this.props.Document).length > 0;
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 93523a6cf..c0561e42c 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -1,6 +1,5 @@
-@import "../global/globalCssVariables";
+@import '../global/globalCssVariables';
-
.collectionTreeView-container {
transform-origin: top left;
height: 100%;
@@ -28,7 +27,7 @@
list-style: none;
padding-left: $TREE_BULLET_WIDTH;
margin-bottom: 1px; // otherwise vertical scrollbars may pop up for no apparent reason....
- > .contentFittingDocumentView {
+ > .contentFittingDocumentView {
width: unset;
height: unset;
}
@@ -39,7 +38,7 @@
.no-indent {
padding-left: 0;
- width: max-content;
+ //width: max-content;
}
.no-indent-outline {
@@ -85,7 +84,7 @@
width: 100%;
height: max-content;
.contentFittingDocumentView {
- display: block; // makes titleBar take up full width of the treeView (flex doesn't for some reason)
+ display: block; // makes titleBar take up full width of the treeView (flex doesn't for some reason)
}
}
@@ -114,4 +113,4 @@
padding-left: 3px;
padding-right: 3px;
padding-bottom: 2px;
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 2d08b1c09..e147f34d2 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -212,11 +212,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
@action
public static PinDoc(docs: Doc | Doc[], pinProps?: PinProps) {
const docList = docs instanceof Doc ? [docs] : docs;
- const batch = UndoManager.StartBatch('pinning doc');
// all docs will be added to the ActivePresentation as stored on CurrentUserUtils
const curPres = Doc.ActivePresentation;
- curPres &&
+ if (curPres) {
+ const batch = UndoManager.StartBatch('pinning doc');
docList.forEach(doc => {
// Edge Case 1: Cannot pin document to itself
if (doc === curPres) {
@@ -288,31 +288,33 @@ export class TabDocView extends React.Component<TabDocViewProps> {
pinDoc.presEndTime = NumCast(doc.clipEnd, duration);
}
//save position
- if (pinProps?.setPosition || pinDoc.isInkMask) {
- pinDoc.setPosition = true;
- pinDoc.y = doc.y;
- pinDoc.x = doc.x;
+ if (pinProps?.activeFrame !== undefined) {
+ pinDoc.presActiveFrame = pinProps?.activeFrame;
+ pinDoc.title = doc.title + ' (move)';
+ pinDoc.presMovement = PresMovement.Pan;
+ }
+ if (pinDoc.isInkMask) {
pinDoc.presHideAfter = true;
pinDoc.presHideBefore = true;
- pinDoc.title = doc.title + ' (move)';
pinDoc.presMovement = PresMovement.None;
}
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
- PresBox.Instance?._selectedArray.clear();
- pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
+ PresBox.Instance?.clearSelectedArray();
+ pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); //Update selected array
});
- if (
- CollectionDockingView.Instance &&
- !Array.from(CollectionDockingView.Instance.tabMap)
- .map(d => d.DashDoc)
- .includes(curPres)
- ) {
- const docs = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), []);
- if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1);
- CollectionDockingView.AddSplit(curPres, 'right');
- setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things
+ if (
+ CollectionDockingView.Instance &&
+ !Array.from(CollectionDockingView.Instance.tabMap)
+ .map(d => d.DashDoc)
+ .includes(curPres)
+ ) {
+ const docs = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), []);
+ if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1);
+ CollectionDockingView.AddSplit(curPres, 'right');
+ setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things
+ }
+ setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
}
- setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
}
componentDidMount() {
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index f587dbbf6..ce87e6f89 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -1,4 +1,4 @@
-@import "../global/globalCssVariables";
+@import '../global/globalCssVariables';
.treeView-label {
max-height: 1.5em;
@@ -21,7 +21,7 @@
}
.treeView-bulletIcons {
- // width: $TREE_BULLET_WIDTH;
+ // width: $TREE_BULLET_WIDTH;
width: 100%;
height: 100%;
@@ -101,6 +101,9 @@
.treeView-border {
display: flex;
overflow: hidden;
+ > ul {
+ width: 100%;
+ }
}
.treeView-border {
@@ -118,7 +121,6 @@
}
.formattedTextBox-cont {
-
.formattedTextbox-sidebar,
.formattedTextbox-sidebar-inking {
overflow: visible !important;
@@ -144,12 +146,12 @@
pointer-events: all;
cursor: pointer;
- >svg {
+ > svg {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
- >svg {
+ > svg {
//display: none;
opacity: 0;
pointer-events: none;
@@ -176,8 +178,7 @@
}
.treeView-rightButtons {
-
- >svg,
+ > svg,
.styleProvider-treeView-icon {
display: inherit;
opacity: unset;
@@ -196,4 +197,4 @@
.treeView-header-inside {
border: black 1px solid;
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 3d85d32a0..89cc22d07 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -34,6 +34,7 @@ export interface PoolData {
zIndex?: number;
width?: number;
height?: number;
+ backgroundColor?: string;
color?: string;
opacity?: number;
transition?: string;
@@ -45,6 +46,7 @@ export interface PoolData {
export interface ViewDefResult {
ele: JSX.Element;
bounds?: ViewDefBounds;
+ inkMask?: number; //sort elements into either the mask layer (which has a mixedBlendMode appropriate for transparent masks), or the regular documents layer; -1 = no mask, 0 = mask layer but stroke is transprent (hidden), >0 = mask layer and not hidden
}
function toLabel(target: FieldResult<Field>) {
if (typeof target === 'number' || Number(target)) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index d979ef961..bf9de6760 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -195,7 +195,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const bDocBounds = (B.props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 };
const aleft = this.visibleX(adiv);
const bleft = this.visibleX(bdiv);
- const clipped = aleft !== a.left || atop !== a.top || bleft !== b.left || btop !== b.top;
+ const aclipped = aleft !== a.left || atop !== a.top;
+ const bclipped = bleft !== b.left || btop !== b.top;
+ if (aclipped && bclipped) return undefined;
+ const clipped = aclipped || bclipped;
const pt1 = [aleft + a.width / 2, atop + a.height / 2];
const pt2 = [bleft + b.width / 2, btop + b.width / 2];
const pt1vec = [(bDocBounds.left + bDocBounds.right) / 2 - pt1[0], (bDocBounds.top + bDocBounds.bottom) / 2 - pt1[1]];
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 8720c9097..b8344dc0c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -5,11 +5,14 @@ import { DocumentManager } from '../../../util/DocumentManager';
import './CollectionFreeFormLinksView.scss';
import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView';
import React = require('react');
+import { LightboxView } from '../../LightboxView';
@observer
export class CollectionFreeFormLinksView extends React.Component<React.PropsWithChildren<{}>> {
@computed get uniqueConnections() {
- return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)).map(c => <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />);
+ return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews))
+ .filter(c => !LightboxView.LightboxDoc || (LightboxView.IsLightboxDocView(c.a.docViewPath) && LightboxView.IsLightboxDocView(c.b.docViewPath)))
+ .map(c => <CollectionFreeFormLinkView key={c.l[Id]} A={c.a} B={c.b} LinkDocs={[c.l]} />);
}
render() {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 79e063f7f..d80fcdfc3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -1,4 +1,4 @@
-@import "../../global/globalCssVariables";
+@import '../../global/globalCssVariables';
.collectionfreeformview-none {
position: inherit;
@@ -20,8 +20,24 @@
pointer-events: none;
}
+.collectionfreeformview-mask-empty,
+.collectionfreeformview-mask {
+ z-index: 5000;
+ width: $INK_MASK_SIZE;
+ height: $INK_MASK_SIZE;
+ transform: translate($INK_MASK_SIZE_HALF, $INK_MASK_SIZE_HALF);
+ pointer-events: none;
+ position: absolute;
+ background-color: transparent;
+ transition: background-color 1s ease 0s;
+}
+.collectionfreeformview-mask {
+ mix-blend-mode: multiply;
+ background-color: rgba(0, 0, 0, 0.7);
+}
+
.collectionfreeformview-viewdef {
- >.collectionFreeFormDocumentView-container {
+ > .collectionFreeFormDocumentView-container {
pointer-events: none;
.contentFittingDocumentDocumentView-previewDoc {
@@ -210,13 +226,13 @@
}
}
- .collectionfreeformview>.jsx-parser {
+ .collectionfreeformview > .jsx-parser {
position: inherit;
height: 100%;
width: 100%;
}
- >.jsx-parser {
+ > .jsx-parser {
z-index: 0;
}
@@ -268,6 +284,6 @@
.pullpane-indicator {
z-index: 99999;
- background-color: rgba($color: #000000, $alpha: .4);
+ background-color: rgba($color: #000000, $alpha: 0.4);
position: absolute;
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 82b377dfa..03beaf65e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -34,7 +34,7 @@ import { COLLECTION_BORDER_WIDTH } from '../../../views/global/globalCssVariable
import { Timeline } from '../../animationtimeline/Timeline';
import { ContextMenu } from '../../ContextMenu';
import { GestureOverlay } from '../../GestureOverlay';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
import { LightboxView } from '../../LightboxView';
import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView';
import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView';
@@ -109,19 +109,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _hLines: number[] | undefined;
@observable _vLines: number[] | undefined;
@observable _firstRender = true; // this turns off rendering of the collection's content so that there's instant feedback when a tab is switched of what content will be shown.
- @observable _pullCoords: number[] = [0, 0];
- @observable _pullDirection: string = '';
@observable _showAnimTimeline = false;
@observable _clusterSets: Doc[][] = [];
@observable _deleteList: DocumentView[] = [];
@observable _timelineRef = React.createRef<Timeline>();
@observable _marqueeRef = React.createRef<HTMLDivElement>();
@observable _marqueeViewRef = React.createRef<MarqueeView>();
- @observable _keyframeEditing = false;
@observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged.
@computed get views() {
- return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele);
+ const viewsMask = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask !== -1).map(ele => ele.ele);
+ const renderableEles = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask === -1).map(ele => ele.ele);
+ if (viewsMask.length) renderableEles.push(<div className={`collectionfreeformview-mask${this._layoutElements.some(ele => (ele.inkMask ?? 0) > 0) ? '' : '-empty'}`}>{viewsMask}</div>);
+ return renderableEles;
}
@computed get fitToContentVals() {
return {
@@ -184,8 +184,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.Document.lastFrame = Math.max(NumCast(this.Document._currentFrame), NumCast(this.Document.lastFrame));
}
};
- @action setKeyFrameEditing = (set: boolean) => (this._keyframeEditing = set);
- getKeyFrameEditing = () => this._keyframeEditing;
onBrowseClickHandler = () => this.props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick);
onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
@@ -271,15 +269,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
.sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
zsorted.forEach((doc, index) => (doc.zIndex = doc.isInkMask ? 5000 : index + 1));
const dvals = CollectionFreeFormDocumentView.getValues(refDoc, NumCast(refDoc.activeFrame, 1000));
- const dropPos = this.Document._currentFrame !== undefined ? [dvals.x || 0, dvals.y || 0] : [NumCast(refDoc.x), NumCast(refDoc.y)];
+ const dropPos = this.Document._currentFrame !== undefined ? [NumCast(dvals.x), NumCast(dvals.y)] : [NumCast(refDoc.x), NumCast(refDoc.y)];
for (let i = 0; i < docDragData.droppedDocuments.length; i++) {
const d = docDragData.droppedDocuments[i];
const layoutDoc = Doc.Layout(d);
if (this.Document._currentFrame !== undefined) {
CollectionFreeFormDocumentView.setupKeyframes([d], NumCast(this.Document._currentFrame), false);
const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
- vals.x = x + (vals.x || 0) - dropPos[0];
- vals.y = y + (vals.y || 0) - dropPos[1];
+ vals.x = x + NumCast(vals.x) - dropPos[0];
+ vals.y = y + NumCast(vals.y) - dropPos[1];
vals._scrollTop = this.Document.editScrollProgressivize ? vals._scrollTop : undefined;
CollectionFreeFormDocumentView.setValues(NumCast(this.Document._currentFrame), d, vals);
} else {
@@ -462,20 +460,23 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
getClusterColor = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => {
let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1
- if (property !== StyleProp.BackgroundColor) return styleProp;
- const cluster = NumCast(doc?.cluster);
- if (this.Document._useClusters) {
- if (this._clusterSets.length <= cluster) {
- setTimeout(() => doc && this.updateCluster(doc));
- } else {
- // choose a cluster color from a palette
- const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)'];
- styleProp = colors[cluster % colors.length];
- const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
- // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document
- set?.map(s => (styleProp = StrCast(s.backgroundColor)));
- }
- } //else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray";
+ switch (property) {
+ case StyleProp.BackgroundColor:
+ const cluster = NumCast(doc?.cluster);
+ if (this.Document._useClusters) {
+ if (this._clusterSets.length <= cluster) {
+ setTimeout(() => doc && this.updateCluster(doc));
+ } else {
+ // choose a cluster color from a palette
+ const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)'];
+ styleProp = colors[cluster % colors.length];
+ const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
+ // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document
+ set?.map(s => (styleProp = StrCast(s.backgroundColor)));
+ }
+ }
+ break;
+ }
return styleProp;
};
@@ -520,17 +521,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
case InkTool.Pen:
break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
case InkTool.Eraser:
- document.addEventListener('pointermove', this.onEraserMove);
- document.addEventListener('pointerup', this.onEraserUp);
this._batch = UndoManager.StartBatch('collectionErase');
- e.stopPropagation();
- e.preventDefault();
+ setupMoveUpEvents(this, e, this.onEraserMove, this.onEraserUp, emptyFunction);
break;
case InkTool.None:
if (!(this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) {
this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY));
- document.addEventListener('pointermove', this.onPointerMove);
- document.addEventListener('pointerup', this.onPointerUp);
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, false);
}
break;
}
@@ -579,6 +576,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
ActiveArrowEnd(),
ActiveDash(),
points,
+ ActiveIsInkMask(),
{
title: 'ink stroke',
x: B.x - ActiveInkWidth() / 2,
@@ -694,23 +692,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
@action
onEraserUp = (e: PointerEvent): void => {
- if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
- document.removeEventListener('pointermove', this.onEraserMove);
- document.removeEventListener('pointerup', this.onEraserUp);
- this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc));
- this._deleteList = [];
- this._batch?.end();
- }
- };
-
- @action
- onPointerUp = (e: PointerEvent): void => {
- if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
- document.removeEventListener('pointermove', this.onPointerMove);
- document.removeEventListener('pointerup', this.onPointerUp);
- this.removeMoveListeners();
- this.removeEndListeners();
- }
+ this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc));
+ this._deleteList = [];
+ this._batch?.end();
};
onClick = (e: React.MouseEvent) => {
@@ -748,46 +732,42 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
* However, if Shift is held, then no segmentation is done -- instead any intersected stroke is deleted in its entirety.
*/
@action
- onEraserMove = (e: PointerEvent) => {
+ onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => {
const currPoint = { X: e.clientX, Y: e.clientY };
- this.getEraserIntersections({ X: this._lastX, Y: this._lastY }, currPoint).forEach(intersect => {
+ this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => {
if (!this._deleteList.includes(intersect.inkView)) {
this._deleteList.push(intersect.inkView);
SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.strokeWidth?.toString()) || '1');
SetActiveInkColor(StrCast(intersect.inkView.rootDoc.color?.toString()) || 'black');
// create a new curve by appending all curves of the current segment together in order to render a single new stroke.
- !e.shiftKey &&
+ if (!e.shiftKey) {
this.segmentInkStroke(intersect.inkView, intersect.t).forEach(segment =>
GestureOverlay.Instance.dispatchGesture(
GestureUtils.Gestures.Stroke,
segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[])
)
);
+ }
// Lower ink opacity to give the user a visual indicator of deletion.
intersect.inkView.layoutDoc.opacity = 0.5;
+ intersect.inkView.layoutDoc.dontIntersect = true;
}
});
- this._lastX = currPoint.X;
- this._lastY = currPoint.Y;
-
- e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
- e.preventDefault();
+ return false;
};
@action
- onPointerMove = (e: PointerEvent): void => {
- if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return;
+ onPointerMove = (e: PointerEvent): boolean => {
+ if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return false;
if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
Doc.ActiveTool = InkTool.None;
if (this.props.isContentActive(true)) e.stopPropagation();
} else if (!e.cancelBubble) {
if (this.tryDragCluster(e, this._hitCluster)) {
- document.removeEventListener('pointermove', this.onPointerMove);
- document.removeEventListener('pointerup', this.onPointerUp);
+ return true;
} else this.pan(e);
- e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
- e.preventDefault();
}
+ return false;
};
/**
@@ -797,6 +777,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
getEraserIntersections = (lastPoint: { X: number; Y: number }, currPoint: { X: number; Y: number }) => {
const eraserMin = { X: Math.min(lastPoint.X, currPoint.X), Y: Math.min(lastPoint.Y, currPoint.Y) };
const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) };
+
return this.childDocs
.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView))
.filter(inkView => inkView?.ComponentView instanceof InkingStroke)
@@ -884,7 +865,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const tVals: number[] = [];
// Iterating through all ink strokes in the current freeform collection.
this.childDocs
- .filter(doc => doc.type === DocumentType.INK)
+ .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect)
.forEach(doc => {
const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)?.ComponentView as InkingStroke;
const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
@@ -915,7 +896,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
e.preventDefault();
document.removeEventListener('pointermove', this.onPointerMove);
- document.removeEventListener('pointerup', this.onPointerUp);
return;
}
// TODO: nda - this allows us to pan collections with finger -> only want to do this when collection is selected'
@@ -963,13 +943,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2;
// const transformed = this.getTransform().inverse().transformPoint(centerX, centerY);
- if (!this._pullDirection) {
- // if we are not bezel movement
- this.pan({ clientX: centerX, clientY: centerY });
- } else {
- this._pullCoords = [centerX, centerY];
- }
-
this._lastX = centerX;
this._lastY = centerY;
}
@@ -994,24 +967,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const centerY = Math.min(pt1.clientY, pt2.clientY) + Math.abs(pt2.clientY - pt1.clientY) / 2;
this._lastX = centerX;
this._lastY = centerY;
- const screenBox = this._mainCont?.getBoundingClientRect();
-
- // determine if we are using a bezel movement
- if (screenBox) {
- if (screenBox.right - centerX < 100) {
- this._pullCoords = [centerX, centerY];
- this._pullDirection = 'right';
- } else if (centerX - screenBox.left < 100) {
- this._pullCoords = [centerX, centerY];
- this._pullDirection = 'left';
- } else if (screenBox.bottom - centerY < 100) {
- this._pullCoords = [centerX, centerY];
- this._pullDirection = 'bottom';
- } else if (centerY - screenBox.top < 100) {
- this._pullCoords = [centerX, centerY];
- this._pullDirection = 'top';
- }
- }
this.removeMoveListeners();
this.addMoveListeners();
@@ -1023,19 +978,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
};
cleanUpInteractions = () => {
- switch (this._pullDirection) {
- case 'left':
- case 'right':
- case 'top':
- case 'bottom':
- CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: 'New Collection' }), this._pullDirection);
- }
-
- this._pullDirection = '';
- this._pullCoords = [0, 0];
-
- document.removeEventListener('pointermove', this.onPointerMove);
- document.removeEventListener('pointerup', this.onPointerUp);
this.removeMoveListeners();
this.removeEndListeners();
};
@@ -1372,22 +1314,23 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
});
getCalculatedPositions(params: { pair: { layout: Doc; data?: Doc }; index: number; collection: Doc }): PoolData {
- const layoutDoc = Doc.Layout(params.pair.layout);
- const { z, color, zIndex } = params.pair.layout;
- const { x, y, opacity } =
- this.Document._currentFrame === undefined
- ? { x: params.pair.layout.x, y: params.pair.layout.y, opacity: this.props.styleProvider?.(params.pair.layout, this.props, StyleProp.Opacity) }
- : CollectionFreeFormDocumentView.getValues(params.pair.layout, NumCast(this.Document._currentFrame));
+ const curFrame = Cast(this.Document._currentFrame, 'number');
+ const childDoc = params.pair.layout;
+ const childDocLayout = Doc.Layout(childDoc);
+ const { z, zIndex } = childDoc;
+ const { backgroundColor, color } = curFrame === undefined ? { backgroundColor: undefined, color: undefined } : CollectionFreeFormDocumentView.getStringValues(childDoc, curFrame);
+ const { x, y, opacity } = curFrame === undefined ? { x: childDoc.x, y: childDoc.y, opacity: this.props.childOpacity?.() } : CollectionFreeFormDocumentView.getValues(childDoc, curFrame);
return {
x: NumCast(x),
y: NumCast(y),
z: Cast(z, 'number'),
- color: StrCast(color),
+ color: Cast(color, 'string') ? StrCast(color) : this.props.styleProvider?.(childDoc, this.props, StyleProp.Color),
+ backgroundColor: Cast(backgroundColor, 'string') ? StrCast(backgroundColor) : this.props.styleProvider?.(childDoc, this.props, StyleProp.BackgroundColor),
+ opacity: Cast(opacity, 'number') ?? this.props.styleProvider?.(childDoc, this.props, StyleProp.Opacity),
zIndex: Cast(zIndex, 'number'),
- transition: StrCast(layoutDoc.dataTransition),
- opacity: this._keyframeEditing ? 1 : Cast(opacity, 'number', null),
- width: Cast(layoutDoc._width, 'number'),
- height: Cast(layoutDoc._height, 'number'),
+ width: Cast(childDocLayout._width, 'number'),
+ height: Cast(childDocLayout._height, 'number'),
+ transition: StrCast(childDocLayout.dataTransition),
pair: params.pair,
replica: '',
};
@@ -1502,7 +1445,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
for (const entry of array) {
const lastPos = this._cachedPool.get(entry[0]); // last computed pos
const newPos = entry[1];
- if (!lastPos || newPos.opacity !== lastPos.opacity || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) {
+ if (
+ !lastPos ||
+ newPos.color !== lastPos.color ||
+ newPos.backgroundColor !== lastPos.backgroundColor ||
+ newPos.opacity !== lastPos.opacity ||
+ newPos.x !== lastPos.x ||
+ newPos.y !== lastPos.y ||
+ newPos.z !== lastPos.z ||
+ newPos.zIndex !== lastPos.zIndex
+ ) {
this._layoutPoolData.set(entry[0], newPos);
}
if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) {
@@ -1519,6 +1471,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
elements.push({
ele: this.getChildDocView(entry[1]),
bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica),
+ inkMask: BoolCast(entry[1].pair.layout.isInkMask) ? NumCast(entry[1].pair.layout.opacity) : -1,
})
);
@@ -1910,7 +1863,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
getContainerTransform={this.getContainerTransform}
getTransform={this.getTransform}
isAnnotationOverlay={this.isAnnotationOverlay}>
- <div className="marqueeView-div" ref={this._marqueeRef} style={{ opacity: this.props.dontRenderDocuments ? 0 : undefined }}>
+ <div className="marqueeView-div" ref={this._marqueeRef} style={{ opacity: this.props.dontRenderDocuments ? 0.7 : undefined }}>
{this.layoutDoc._backgroundGridShow ? (
<div>
<CollectionFreeFormBackgroundGrid // bcz : UGHH don't know why, but if we don't wrap in a div, then PDF's don't render whenn taking snapshot of a dashboard and the background grid is on!!?
@@ -1991,15 +1944,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
{this._firstRender ? this.placeholder : this.marqueeView}
{this.props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
- <div
- className={'pullpane-indicator'}
- style={{
- display: this._pullDirection ? 'block' : 'none',
- top: clientRect ? (this._pullDirection === 'bottom' ? this._pullCoords[1] - clientRect.y : 0) : 'auto',
- left: clientRect ? (this._pullDirection === 'right' ? this._pullCoords[0] - clientRect.x : 0) : 'auto',
- width: clientRect ? (this._pullDirection === 'left' ? this._pullCoords[0] - clientRect.left : this._pullDirection === 'right' ? clientRect.right - this._pullCoords[0] : clientRect.width) : 0,
- height: clientRect ? (this._pullDirection === 'top' ? this._pullCoords[1] - clientRect.top : this._pullDirection === 'bottom' ? clientRect.bottom - this._pullCoords[1] : clientRect.height) : 0,
- }}></div>
{
// uncomment to show snap lines
<div className="snapLines" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', pointerEvents: 'none' }}>