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.scss2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx28
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx1
-rw-r--r--src/client/views/collections/CollectionMasonryViewFieldRow.tsx8
-rw-r--r--src/client/views/collections/CollectionMenu.tsx45
-rw-r--r--src/client/views/collections/CollectionPileView.tsx14
-rw-r--r--src/client/views/collections/CollectionSchemaCells.tsx6
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx67
-rw-r--r--src/client/views/collections/CollectionSubView.tsx19
-rw-r--r--src/client/views/collections/TabDocView.scss1
-rw-r--r--src/client/views/collections/TabDocView.tsx100
-rw-r--r--src/client/views/collections/TreeView.tsx20
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx8
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss16
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx125
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx13
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx5
18 files changed, 320 insertions, 160 deletions
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 8b1594b21..f4736eb29 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -4,7 +4,7 @@
.lm_title {
margin-top: 3px;
border-radius: 5px;
- border: solid 1px dimgray;
+ border: solid 0px dimgray;
border-width: 2px 2px 0px;
height: 20px;
transform: translate(0px, -3px);
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 2eaa284cc..abe8477e4 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -22,6 +22,8 @@ import { CollectionViewType } from './CollectionView';
import { TabDocView } from './TabDocView';
import React = require("react");
import { stat } from 'fs';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { listSpec } from '../../../fields/Schema';
const _global = (window /* browser */ || global /* node */) as any;
@observer
@@ -108,6 +110,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
}
@undoBatch
+ @action
public static ReplaceTab(document: Doc, panelName: string, stack: any, addToSplit?: boolean): boolean {
const instance = CollectionDockingView.Instance;
if (!instance) return false;
@@ -140,8 +143,21 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
// Creates a split on any side of the docking view based on the passed input pullSide and then adds the Document to the requested side
//
@undoBatch
+ @action
public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
+ if (document.type === DocumentType.PRES) {
+ const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []);
+ if (docs.includes(document)) {
+ docs.splice(docs.indexOf(document), 1);
+ }
+ }
if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), document);
+
+ const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
+ if (tab) {
+ tab.header.parent.setActiveContentItem(tab.contentItem);
+ return true;
+ }
const instance = CollectionDockingView.Instance;
if (!instance) return false;
const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
@@ -308,9 +324,15 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
@action
onPointerDown = (e: React.PointerEvent): void => {
- window.addEventListener("mouseup", this.onPointerUp);
- if (!(e.target as HTMLElement).closest("*.lm_content") && ((e.target as HTMLElement).closest("*.lm_tab") || (e.target as HTMLElement).closest("*.lm_stack"))) {
- this._flush = UndoManager.StartBatch("golden layout edit");
+ let hitFlyout = false;
+ for (let par = e.target as any; !hitFlyout && par; par = par.parentElement) {
+ hitFlyout = (par.className === "dockingViewButtonSelector");
+ }
+ if (!hitFlyout) {
+ window.addEventListener("mouseup", this.onPointerUp);
+ if (!(e.target as HTMLElement).closest("*.lm_content") && ((e.target as HTMLElement).closest("*.lm_tab") || (e.target as HTMLElement).closest("*.lm_stack"))) {
+ this._flush = UndoManager.StartBatch("golden layout edit");
+ }
}
if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) &&
Doc.GetSelectedTool() !== InkTool.Highlighter && Doc.GetSelectedTool() !== InkTool.Pen) {
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 0eac5136a..b6ab3f0e0 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -129,7 +129,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
{this.childLayoutPairs.map((pair, ind) => {
const nested = pair.layout._viewType === CollectionViewType.Linear;
const dref = React.createRef<HTMLDivElement>();
- const nativeWidth = NumCast(pair.layout._nativeWidth, this.dimension());
const scalable = pair.layout.onClick || pair.layout.onDragStart;
return <div className={`collectionLinearView-docBtn` + (scalable ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
style={{
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 7014966c7..b35644c6b 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -138,7 +138,8 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
}
@action
- addDocument = (value: string, shiftDown?: boolean) => {
+ addDocument = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
+ if (!value && !forceEmptyNote) return false;
this._createAliasSelected = false;
const key = StrCast(this.props.parent.props.Document._pivotField);
const newDoc = Docs.Create.TextDocument(value, { _autoHeight: true, _width: 200, title: value });
@@ -239,6 +240,10 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
</div>
</div>);
}
+ @action
+ textCallback = (char: string) => {
+ return this.addDocument("", false);
+ }
@computed get contentLayout() {
const rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
@@ -247,6 +252,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
const newEditableViewProps = {
GetValue: () => "",
SetValue: this.addDocument,
+ textCallback: this.textCallback,
contents: "+ NEW",
HeadingObject: this.props.headingObject,
toggle: this.toggleVisibility,
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index b2b1b7d25..b2b23115f 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -344,7 +344,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed get viewModes() {
const excludedViewTypes = Doc.UserDoc().noviceMode ? [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.Map, CollectionViewType.Linear, CollectionViewType.Time] :
[CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.Linear];
- return <div className="collectionViewBaseChrome-viewModes" >
+ const isPres: boolean = (this.document && this.document.type === DocumentType.PRES);
+ return isPres ? (null) : (<div className="collectionViewBaseChrome-viewModes" >
<Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
<div className="commandEntry-outerDiv" ref={this._viewRef} onPointerDown={this.dragViewDown}>
<button className={"antimodeMenu-button"}>
@@ -367,7 +368,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
</select>
</div>
</Tooltip>
- </div>;
+ </div>);
}
@computed get selectedDocumentView() {
@@ -399,12 +400,15 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
pinWithView = (targetDoc: Opt<Doc>) => {
if (targetDoc) {
TabDocView.PinDoc(targetDoc, false);
- const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB) {
+ const presArray: Doc[] = PresBox.Instance?.sortArray();
+ const size: number = PresBox.Instance?._selectedArray.size;
+ const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+ const activeDoc = presSelected ? PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.indexOf(presSelected) + 1] : PresBox.Instance?.childDocs[PresBox.Instance?.childDocs.length - 1];
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
const scroll = targetDoc._scrollTop;
activeDoc.presPinView = true;
activeDoc.presPinViewScroll = scroll;
- } else {
+ } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
const x = targetDoc._panX;
const y = targetDoc._panY;
const scale = targetDoc._viewScale;
@@ -412,6 +416,13 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
activeDoc.presPinViewX = x;
activeDoc.presPinViewY = y;
activeDoc.presPinViewScale = scale;
+ } else if (targetDoc.type === DocumentType.VID) {
+ activeDoc.presPinTimecode = targetDoc._currentTimecode;
+ activeDoc.presPinView = true;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const width = targetDoc._clipWidth;
+ activeDoc.presPinClipWidth = width;
+ activeDoc.presPinView = true;
}
}
}
@@ -421,7 +432,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
const targetDoc = this.selectedDoc;
{/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
- return (targetDoc && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+ return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin with current view"}</div></>} placement="top">
<button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
onClick={() => this.pinWithView(targetDoc)}>
{presPinWithViewIcon}
@@ -468,7 +479,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed
get aliasButton() {
const targetDoc = this.selectedDoc;
- return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
+ return !targetDoc || targetDoc.type === DocumentType.PRES ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
<button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: "drag" }}>
<FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="lg" />
</button>
@@ -478,13 +489,19 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed get lightboxButton() {
const targetDoc = this.selectedDoc;
return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Show Lightbox of Images"}</div>} placement="top">
- <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc._isLightboxOpen = true)} onClick={this.onAlias}>
+ <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc._isLightboxOpen = true)}>
<FontAwesomeIcon className="documentdecorations-icon" icon="desktop" size="lg" />
</button>
</Tooltip>;
}
-
-
+ @computed get gridbackgroundButton() {
+ const targetDoc = this.selectedDoc;
+ return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Toggle background grid"}</div>} placement="top">
+ <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc["_backgroundGrid-show"] = !targetDoc["_backgroundGrid-show"])}>
+ <FontAwesomeIcon className="documentdecorations-icon" icon={targetDoc["_backgroundGrid-show"] ? "border-all" : ["far", "square"]} size="lg" />
+ </button>
+ </Tooltip>;
+ }
render() {
return (
@@ -502,6 +519,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
</button>
</Tooltip>}
{this.notACollection ? (null) : this.lightboxButton}
+ {this.notACollection ? (null) : this.gridbackgroundButton}
{this.aliasButton}
{/* {this.pinButton} */}
{this.pinWithViewButton}
@@ -529,7 +547,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
}
get document() { return this.props.docView.props.Document; }
@computed get dataField() {
- return this.document[this.props.docView.LayoutFieldKey];
+ return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? "-annotations" : "")];
}
@computed get childDocs() {
return DocListCast(this.dataField);
@@ -540,7 +558,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
}
@computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
@computed get isText() {
- return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any)?.focused ? true : false;
+ return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false;
}
@undoBatch
@@ -757,6 +775,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
} else {
history.push(this._url);
}
+ this.props.docView.props.Document._scrollTop = 0;
future && (future.length = 0);
}
this._url = url;
@@ -1312,5 +1331,5 @@ Scripting.addGlobal(function gotoFrame(doc: any, newFrame: any) {
CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
}
CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
- doc._currentFrame = Math.max(0, newFrame);
+ doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
});
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 5b4730848..2636b98e5 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -6,7 +6,7 @@ import { emptyFunction, setupMoveUpEvents } from "../../../Utils";
import { DocUtils } from "../../documents/Documents";
import { SelectionManager } from "../../util/SelectionManager";
import { SnappingManager } from "../../util/SnappingManager";
-import { UndoManager } from "../../util/UndoManager";
+import { UndoManager, undoBatch } from "../../util/UndoManager";
import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
import "./CollectionPileView.scss";
import { CollectionSubView } from "./CollectionSubView";
@@ -34,14 +34,14 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
const draggingSelf = this.props.isSelected();
return <div className="collectionPileView-innards" style={{ pointerEvents: this.layoutEngine() === "starburst" || (SnappingManager.GetIsDragging() && !draggingSelf) ? undefined : "none", zIndex: this.layoutEngine() === "starburst" && !SnappingManager.GetIsDragging() ? -10 : "auto" }} >
<CollectionFreeFormView {...this.props} layoutEngine={this.layoutEngine}
- addDocument={(doc: Doc | Doc[]) => {
+ addDocument={undoBatch((doc: Doc | Doc[]) => {
(doc instanceof Doc ? [doc] : doc).map((d) => DocUtils.iconify(d));
return this.props.addDocument(doc);
- }}
- moveDocument={(doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
- (doc instanceof Doc ? [doc] : doc).map((d) => Doc.deiconifyView(d));
+ })}
+ moveDocument={undoBatch((doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => {
+ (doc instanceof Doc ? [doc] : doc).map(undoBatch((d) => Doc.deiconifyView(d)));
return this.props.moveDocument(doc, targetCollection, addDoc);
- }} />
+ })} />
</div>;
}
@@ -107,6 +107,8 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
}
// onClick for toggling the pileup view
+ @undoBatch
+ @action
onClick = (e: React.MouseEvent) => {
if (e.button === 0) {
SelectionManager.DeselectAll();
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 2896a8243..0b3dfe1e4 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -398,10 +398,10 @@ export class CollectionSchemaImageCell extends CollectionSchemaCell {
const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths;
const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
- const heightToWidth = NumCast(this._rowDoc._nativeHeight) / NumCast(this._rowDoc._nativeWidth);
+ const aspect = Doc.NativeAspect(this._rowDoc);
let width = Math.min(75, this.props.rowProps.width);
- const height = Math.min(75, width * heightToWidth);
- width = height / heightToWidth;
+ const height = Math.min(75, width / aspect);
+ width = height * aspect;
const reference = React.createRef<HTMLDivElement>();
return <div className="collectionSchemaView-cellWrapper" ref={this._focusRef} tabIndex={-1} onPointerDown={this.onPointerDown}>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index fc4ca3100..97eacaeab 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -28,6 +28,7 @@ import { CollectionViewType } from "./CollectionView";
import { SnappingManager } from "../../util/SnappingManager";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
import { DocUtils } from "../../documents/Documents";
+import { DocAfterFocusFunc } from "../nodes/DocumentView";
const _global = (window /* browser */ || global /* node */) as any;
type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>;
@@ -59,7 +60,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
@computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
@computed get showAddAGroup() { return (this.pivotField && (this.chromeStatus !== 'view-mode' && this.chromeStatus !== 'disabled')); }
@computed get columnWidth() {
- return Math.min(this.props.PanelWidth() / this.props.ContentScaling() - 2 * this.xMargin,
+ return Math.min(this.props.PanelWidth() / this.props.ContentScaling() /* / NumCast(this.layoutDoc._viewScale, 1)*/ - 2 * this.xMargin,
this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this.props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
}
@computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
@@ -170,9 +171,9 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
}
- focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => {
+ focusDocument = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, didFocus?: boolean) => {
Doc.BrushDoc(doc);
- this.props.focus(doc);
+ this.props.focus(this.props.Document, true); // bcz: want our containing collection to zoom
Doc.linkFollowHighlight(doc);
const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName("documentView-node")).find((node: any) => node.id === doc[Id]);
@@ -233,27 +234,27 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
getDocWidth(d?: Doc) {
if (!d) return 0;
const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.());
- const nw = NumCast(layoutDoc._nativeWidth);
+ const nw = Doc.NativeWidth(layoutDoc);
return Math.min(nw && !this.layoutDoc._columnsFill ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns);
}
getDocHeight(d?: Doc) {
if (!d) return 0;
- const dataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc;
- const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.());
- const layoutField = Doc.LayoutFieldKey(layoutDoc);
- const nw = NumCast(layoutDoc._nativeWidth) || NumCast(dataDoc?.[`${layoutField}-nativeWidth`]);
- const nh = NumCast(layoutDoc._nativeHeight) || NumCast(dataDoc?.[`${layoutField}-nativeHeight`]);
+ const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc;
+ const childLayoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.());
+ const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc);
+ const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc);
let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
+ if (!this.layoutDoc._columnsFill) wid = Math.min(wid, childLayoutDoc[WidthSym]());
const hllimit = NumCast(this.layoutDoc.childLimitHeight, -1);
- if (!layoutDoc._fitWidth && nw && nh) {
+ if (!childLayoutDoc._fitWidth && nw && nh) {
const aspect = nw && nh ? nh / nw : 1;
if (!(this.layoutDoc._columnsFill)) wid = Math.min(this.getDocWidth(d), wid);
return Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, wid * aspect);
}
- return layoutDoc._fitWidth ?
+ return childLayoutDoc._fitWidth ?
(!nh ? this.props.PanelHeight() - 2 * this.yMargin :
Math.min(wid * nh / (nw || 1), this.layoutDoc._autoHeight ? 100000 : this.props.PanelHeight() - 2 * this.yMargin)) :
- Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, Math.max(20, layoutDoc[HeightSym]()));
+ Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, Math.max(20, childLayoutDoc[HeightSym]()));
}
columnDividerDown = (e: React.PointerEvent) => {
@@ -277,30 +278,30 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
const where = [de.x, de.y];
- let targInd = -1;
- let plusOne = 0;
+ let dropInd = -1;
+ let dropAfter = 0;
if (de.complete.docDragData) {
this._docXfs.map((cd, i) => {
const pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap);
const pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height());
- if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) {
- targInd = i;
+ if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) {
+ dropInd = i;
const axis = this.Document._viewType === CollectionViewType.Masonry ? 0 : 1;
- plusOne = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0;
+ dropAfter = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0;
}
});
+ const oldDocs = this.childDocs.length;
if (super.onInternalDrop(e, de)) {
- const newDocs = de.complete.docDragData.droppedDocuments;
+ const newDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= oldDocs);
+
+ //de.complete.docDragData.droppedDocuments;
const docs = this.childDocList;
DragManager.docsBeingDragged = [];
- if (docs) {
- newDocs.map((doc, i) => {
- targInd = targInd === -1 ? docs.length : targInd;
- const srcInd = docs.indexOf(doc);
- if (targInd !== -1) targInd = i === 0 ? docs.indexOf(this.filteredChildren[targInd]) : docs.indexOf(newDocs[0]) + 1;
- docs.splice(srcInd, 1);
- docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
- });
+ if (docs && newDocs.length) {
+ const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter;
+ const offset = newDocs.reduce((off, ndoc) => this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off, 0);
+ newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1));
+ docs.splice(insertInd - offset, 0, ...newDocs);
}
}
}
@@ -351,8 +352,12 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
this.observer = new _global.ResizeObserver(action((entries: any) => {
if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
- const height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))));
- Doc.Layout(doc)._height = Math.max(height, NumCast(doc[this.props.fieldKey + "-height"]));
+ const height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => NumCast(Doc.Layout(doc)._viewScale, 1) * Number(getComputedStyle(r).height.replace("px", "")))));
+ if (this.props.annotationsKey) {
+ doc[this.props.annotationsKey + "-height"] = height;
+ } else {
+ Doc.Layout(doc)._height = height * NumCast(Doc.Layout(doc)._viewScale, 1);
+ }
}
}));
this.observer.observe(ref);
@@ -405,7 +410,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
this.observer = new _global.ResizeObserver(action((entries: any) => {
if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) {
const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
- Doc.Layout(doc)._height = Math.max(height, NumCast(doc[this.props.fieldKey + "-height"]));
+ Doc.Layout(doc)._height = Math.max(height * NumCast(doc[this.props.fieldKey + "-height"]), NumCast(doc[this.props.fieldKey + "-height"]));
}
}));
this.observer.observe(ref);
@@ -465,8 +470,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
}
- @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), NumCast(this.layoutDoc._nativeWidth)); }
- @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), NumCast(this.layoutDoc._nativeHeight)); }
+ @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc)); }
+ @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc)); }
@computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index f3e563422..b27f64ff0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -344,12 +344,16 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
this.props.addDocument(htmlDoc);
if (srcWeb) {
- const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0]?.contentDocument?.getSelection()?.focusNode as any);
+ const iframe = SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0];
+ const focusNode = (iframe?.contentDocument?.getSelection()?.focusNode as any);
if (focusNode) {
- const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
- const x = (rect?.x || 0);
- const y = NumCast(srcWeb._scrollTop) + (rect?.y || 0);
- const anchor = Docs.Create.FreeformDocument([], { _backgroundColor: "transparent", _width: 75, _height: 40, x, y, annotationOn: srcWeb });
+ const rects = iframe?.contentWindow?.getSelection()?.getRangeAt(0).getClientRects();
+ "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
+ const x = (rects && Array.from(rects).reduce((x: any, r: DOMRect) => x === undefined || r.x < x ? r.x : x, undefined as any)) || 0;
+ const y = NumCast(srcWeb._scrollTop) + ((rects && Array.from(rects).reduce((y: any, r: DOMRect) => y === undefined || r.y < y ? r.y : y, undefined as any)) || 0);
+ const r = (rects && Array.from(rects).reduce((x: any, r: DOMRect) => x === undefined || r.x + r.width > x ? r.x + r.width : x, undefined as any)) || 0;
+ const b = NumCast(srcWeb._scrollTop) + ((rects && Array.from(rects).reduce((y: any, r: DOMRect) => y === undefined || r.y + r.height > y ? r.y + r.height : y, undefined as any)) || 0);
+ const anchor = Docs.Create.FreeformDocument([], { _backgroundColor: "transparent", _width: r - x, _height: b - y, x, y, annotationOn: srcWeb });
anchor.context = srcWeb;
const key = Doc.LayoutFieldKey(srcWeb);
Doc.AddDocToList(srcWeb, key + "-annotations", anchor);
@@ -406,7 +410,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.addDocument(alias);
} else {
console.log("Adding ...");
- const newDoc = Docs.Create.WebDocument(uriList, {
+ const newDoc = Docs.Create.WebDocument(uriList.split("#annotations:")[0], {// clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
...options,
_fitWidth: true,
title: uriList.split("#annotations:")[0],
@@ -416,7 +420,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
useCors: true
});
console.log(" ... " + newDoc.title);
- newDoc.data = new WebField(uriList.split("#annotations:")[0]); // clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
console.log(" ... " + this.addDocument(newDoc) + " " + newDoc.title);
}
return;
@@ -479,6 +482,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
} else {
if (text && !text.includes("https://")) {
UndoManager.RunInBatch(() => this.addDocument(Docs.Create.TextDocument(text, { ...options, title: text.substring(0, 20), _width: 400, _height: 315 })), "drop");
+ } else {
+ alert("Document upload failed - possibly an unsupported file type.");
}
}
disposer();
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index edf556c9f..9acbc4f85 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -43,7 +43,6 @@ input.lm_title {
right: 0;
width: 45px;
height: 45px;
- background: white;
transform: translate(20px, 20px) rotate(45deg);
border-radius: 30px;
padding: 2px;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 0c7f39dc7..530595cd0 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -6,7 +6,7 @@ import { clamp } from 'lodash';
import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import * as ReactDOM from 'react-dom';
-import { DataSym, Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { DataSym, Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc";
import { Id } from '../../../fields/FieldSymbols';
import { FieldId } from "../../../fields/RefField";
import { listSpec } from '../../../fields/Schema';
@@ -21,7 +21,7 @@ import { SelectionManager } from '../../util/SelectionManager';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { DocumentView } from "../nodes/DocumentView";
+import { DocumentView, DocAfterFocusFunc } from "../nodes/DocumentView";
import { PresBox, PresMovement } from '../nodes/PresBox';
import { CollectionDockingView } from './CollectionDockingView';
import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
@@ -39,15 +39,14 @@ interface TabDocViewProps {
export class TabDocView extends React.Component<TabDocViewProps> {
_mainCont: HTMLDivElement | null = null;
_tabReaction: IReactionDisposer | undefined;
+
@observable private _panelWidth = 0;
@observable private _panelHeight = 0;
@observable private _isActive: boolean = false;
@observable private _document: Doc | undefined;
@observable private _view: DocumentView | undefined;
- @computed get contentScaling() { return this.ContentScaling(); }
-
- get stack(): any { return (this.props as any).glContainer.parent.parent; }
+ get stack() { return (this.props as any).glContainer.parent.parent; }
get tab() { return (this.props as any).glContainer.tab; }
get view() { return this._view; }
@@ -63,10 +62,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
const titleEle = tab.titleElement[0];
titleEle.size = StrCast(doc.title).length + 3;
titleEle.value = doc.title;
- titleEle.onchange = (e: any) => {
+ titleEle.onchange = undoBatch(action((e: any) => {
titleEle.size = e.currentTarget.value.length + 3;
Doc.GetProto(doc).title = e.currentTarget.value;
- };
+ }));
// shifts the focus to this tab when another tab is dragged over it
tab.element[0].onmouseenter = (e: MouseEvent) => {
if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
@@ -122,29 +121,41 @@ export class TabDocView extends React.Component<TabDocViewProps> {
/**
* Adds a document to the presentation view
**/
- @undoBatch
@action
- public static PinDoc(doc: Doc, unpin = false, audioRange?: boolean) {
+ public static async PinDoc(doc: Doc, unpin = false, audioRange?: boolean) {
if (unpin) console.log('TODO: Remove UNPIN from this location');
//add this new doc to props.Document
const curPres = CurrentUserUtils.ActivePresentation;
if (curPres) {
+ if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
+ const batch = UndoManager.StartBatch("pinning doc");
const pinDoc = Doc.MakeAlias(doc);
pinDoc.presentationTargetDoc = doc;
- pinDoc.title = doc.title;
+ pinDoc.title = doc.title + " - Slide";
pinDoc.presMovement = PresMovement.Zoom;
pinDoc.context = curPres;
- Doc.AddDocToList(curPres, "data", pinDoc);
+ const presArray: Doc[] = PresBox.Instance?.sortArray();
+ const size: number = PresBox.Instance?._selectedArray.size;
+ const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+ Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
if (pinDoc.type === "audio" && !audioRange) {
pinDoc.presStartTime = 0;
pinDoc.presEndTime = doc.duration;
}
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
- const curPresDocView = DocumentManager.Instance.getDocumentView(curPres);
- if (!curPresDocView) {
+ const dview = CollectionDockingView.Instance.props.Document;
+ const fieldKey = CollectionDockingView.Instance.props.fieldKey;
+ const sublists = DocListCast(dview[fieldKey]);
+ const tabs = Cast(sublists[0], Doc, null);
+ const tabdocs = await DocListCastAsync(tabs.data);
+ if (!tabdocs?.includes(curPres)) {
+ tabdocs?.push(curPres); // bcz: Argh! this is annoying. if multiple documents are pinned, this will get called multiple times before the presentation view is drawn. Thus it won't be in the tabdocs list and it will get created multple times. so need to explicilty add the presbox to the list of open tabs
CollectionDockingView.AddSplit(curPres, "right");
}
- DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
+ PresBox.Instance?._selectedArray.clear();
+ pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
+ DocumentManager.Instance.jumpToDocument(doc, false, undefined);
+ batch.end();
}
}
@@ -190,23 +201,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
}
- nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0;
- panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) :
- (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth)
- panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight;
- nativeWidth = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeWidth) || this._panelWidth : 0;
- nativeHeight = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeHeight) || this._panelHeight : 0;
- ContentScaling = () => {
- const nativeH = NumCast(this.layoutDoc?._nativeHeight);
- const nativeW = NumCast(this.layoutDoc?._nativeWidth);
- let scaling = 1;
- if (nativeW && (this.layoutDoc?._fitWidth || this._panelHeight / nativeH > this._panelWidth / nativeW)) {
- scaling = this._panelWidth / nativeW; // width-limited or fitWidth
- } else if (nativeW && nativeH) {
- scaling = this._panelHeight / nativeH; // height-limited
- }
- return scaling;
- }
+ NativeAspect = () => this.nativeAspect;
+ PanelWidth = () => this.panelWidth;
+ PanelHeight = () => this.panelHeight;
+ nativeWidth = () => this._nativeWidth;
+ nativeHeight = () => this._nativeHeight;
+ ContentScaling = () => this.contentScaling;
ScreenToLocalTransform = () => {
if (this._mainCont?.children) {
@@ -216,6 +216,29 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
return Transform.Identity();
}
+ @computed get nativeAspect() {
+ return this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0;
+ }
+ @computed get panelHeight() {
+ return this.NativeAspect() && this.NativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.NativeAspect() : this._panelHeight;
+ }
+ @computed get panelWidth() {
+ return this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), Doc.NativeWidth(this.layoutDoc)), this._panelWidth) :
+ (this.NativeAspect() && this.NativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.NativeAspect() : this._panelWidth);
+ }
+ @computed get _nativeWidth() { return !this.layoutDoc?._fitWidth ? Doc.NativeWidth(this.layoutDoc) || this._panelWidth : 0; }
+ @computed get _nativeHeight() { return !this.layoutDoc?._fitWidth ? Doc.NativeHeight(this.layoutDoc) || this._panelHeight : 0; }
+ @computed get contentScaling() {
+ const nativeW = Doc.NativeWidth(this.layoutDoc);
+ const nativeH = Doc.NativeHeight(this.layoutDoc);
+ let scaling = 1;
+ if (nativeW && (this.layoutDoc?._fitWidth || this._panelHeight / nativeH > this._panelWidth / nativeW)) {
+ scaling = this._panelWidth / nativeW; // width-limited or fitWidth
+ } else if (nativeW && nativeH) {
+ scaling = this._panelHeight / nativeH; // height-limited
+ }
+ return scaling;
+ }
@computed get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.ContentScaling()) / 2 : 0; }
@computed get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.ContentScaling()) / this._panelWidth * 100}% ` : undefined; }
@computed get layoutDoc() { return this._document && Doc.Layout(this._document); }
@@ -265,8 +288,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
return NumCast(Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null)._currentFrame);
}
renderMiniMap() {
- const miniWidth = this.panelWidth() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100;
- const miniHeight = this.panelHeight() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100;
+ const miniWidth = this.PanelWidth() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100;
+ const miniHeight = this.PanelHeight() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100;
const miniLeft = 50 + (NumCast(this._document?._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2;
const miniTop = 50 + (NumCast(this._document?._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2;
const miniSize = this.returnMiniSize();
@@ -313,17 +336,18 @@ export class TabDocView extends React.Component<TabDocViewProps> {
</div>
<Tooltip title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
- <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
+ <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })}
+ style={{ background: CollectionDockingView.Instance.props.backgroundColor?.(this._document, 0) }} >
<FontAwesomeIcon icon={"globe-asia"} size="lg" />
</div>
</Tooltip>
</>;
}
- focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => {
+ focusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, notFocused?: boolean) => {
if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
this.tab.header.parent.setActiveContentItem(this.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)
}
- afterFocus?.();
+ afterFocus?.(false);
}
setView = action((view: DocumentView) => this._view = view);
active = () => this._isActive;
@@ -340,8 +364,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
addDocument={undefined}
removeDocument={undefined}
ContentScaling={this.ContentScaling}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight}
+ PanelWidth={this.PanelWidth}
+ PanelHeight={this.PanelHeight}
NativeHeight={this.nativeHeight() ? this.nativeHeight : undefined}
NativeWidth={this.nativeWidth() ? this.nativeWidth : undefined}
ScreenToLocalTransform={this.ScreenToLocalTransform}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 1dfa5615a..925eb4be6 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -279,21 +279,21 @@ export class TreeView extends React.Component<TreeViewProps> {
getTransform = () => this.refTransform(this._tref.current!);
docWidth = () => {
const layoutDoc = this.layoutDoc;
- const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
- if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 20));
- return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20;
+ const aspect = Doc.NativeAspect(layoutDoc);
+ if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - 20));
+ return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20;
}
docHeight = () => {
const layoutDoc = this.layoutDoc;
const bounds = this.boundsOfCollectionDocument;
return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
- const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
- if (aspect) return this.docWidth() * aspect;
+ const aspect = Doc.NativeAspect(layoutDoc);
+ if (aspect) return this.docWidth() / (aspect || 1);
if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x);
- return layoutDoc._fitWidth ? (!this.doc._nativeHeight ? NumCast(this.props.containingCollection._height) :
- Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
- NumCast(this.props.containingCollection._height)))) :
- NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
+ return layoutDoc._fitWidth ? (!Doc.NativeHeight(this.doc) ? NumCast(this.props.containingCollection._height) :
+ Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc)) /
+ (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containingCollection._height))
+ )) : (layoutDoc[HeightSym]() || 50);
})()));
}
@@ -728,7 +728,7 @@ export class TreeView extends React.Component<TreeViewProps> {
const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
const childLayout = Doc.Layout(pair.layout);
const rowHeight = () => {
- const aspect = NumCast(childLayout._nativeWidth, 0) / NumCast(childLayout._nativeHeight, 0);
+ const aspect = Doc.NativeAspect(childLayout);
return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym]();
};
return <TreeView key={child[Id]}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index bc2cb2d20..edf473a90 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -241,10 +241,10 @@ export function computePivotLayout(
val.docs.forEach((doc, i) => {
const layoutDoc = Doc.Layout(doc);
let wid = pivotAxisWidth;
- let hgt = layoutDoc._nativeWidth ? (NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth)) * pivotAxisWidth : pivotAxisWidth;
+ let hgt = pivotAxisWidth / (Doc.NativeAspect(layoutDoc) || 1);
if (hgt > pivotAxisWidth) {
hgt = pivotAxisWidth;
- wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
+ wid = (Doc.NativeAspect(layoutDoc) || 1) * pivotAxisWidth;
}
docMap.set(doc[Id] + (val.replicas || ""), {
x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.docs.length < numCols ? (numCols - val.docs.length) * pivotAxisWidth / 2 : 0),
@@ -368,10 +368,10 @@ export function computeTimelineLayout(
const stack = findStack(x, stacking);
const layoutDoc = Doc.Layout(doc);
let wid = pivotAxisWidth;
- let hgt = layoutDoc._nativeWidth ? (NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth)) * pivotAxisWidth : pivotAxisWidth;
+ let hgt = pivotAxisWidth / (Doc.NativeAspect(layoutDoc) || 1);
if (hgt > pivotAxisWidth) {
hgt = pivotAxisWidth;
- wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
+ wid = (Doc.NativeAspect(layoutDoc) || 1) * pivotAxisWidth;
}
docMap.set(doc[Id], {
x: x, y: -Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 75cbc20ca..a50b41198 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -12,6 +12,13 @@
border-radius: inherit;
}
+.collectionfreeformview-grid {
+ transform-origin: top left;
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+
.collectionfreeformview-viewdef {
>.collectionFreeFormDocumentView-container {
pointer-events: none;
@@ -57,7 +64,7 @@
min-height: 15px;
text-align: center;
background-color: #69a6db;
- border-radius: 5px;
+ border-radius: 10%;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
font-family: Roboto;
font-weight: 500;
@@ -65,6 +72,13 @@
}
}
+.pathOrder-presPinView {
+ position: absolute;
+ z-index: 190000;
+ border-style: dashed;
+ border-color: #69a5db;
+}
+
.progressivizeButton {
position: absolute;
display: grid;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b32a3bd52..1033050b9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -33,7 +33,7 @@ import { ContextMenu } from "../../ContextMenu";
import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth } from "../../InkingStroke";
import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
import { DocumentLinksButton } from "../../nodes/DocumentLinksButton";
-import { DocumentViewProps } from "../../nodes/DocumentView";
+import { DocumentViewProps, DocAfterFocusFunc } from "../../nodes/DocumentView";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { pageSchema } from "../../nodes/ImageBox";
import { PresBox } from "../../nodes/PresBox";
@@ -46,6 +46,7 @@ import "./CollectionFreeFormView.scss";
import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
+import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
export const panZoomSchema = createSchema({
_panX: "number",
@@ -105,11 +106,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@observable canPanY: boolean = true;
@computed get fitToContentScaling() { return this.fitToContent ? NumCast(this.layoutDoc.fitToContentScaling, 1) : 1; }
- @computed get fitToContent() { return this.props.fitToBox || (this.Document._fitToBox && !this.isAnnotationOverlay); }
+ @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
@computed get parentScaling() { return this.props.ContentScaling && this.fitToContent ? this.props.ContentScaling() : 1; }
@computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); }
- @computed get nativeWidth() { return this.fitToContent ? 0 : returnVal(this.props.NativeWidth?.(), NumCast(this.Document._nativeWidth)); }
- @computed get nativeHeight() { return this.fitToContent ? 0 : returnVal(this.props.NativeHeight?.(), NumCast(this.Document._nativeHeight)); }
+ @computed get nativeWidth() { return this.fitToContent ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.Document)); }
+ @computed get nativeHeight() { return this.fitToContent ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.Document)); }
private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; }
private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
@@ -120,7 +121,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (this.fitToContent) {
const zs = !this.childDocs.length ? 1 :
Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x));
- return mult * (this.props.isAnnotationOverlay ? Math.min(zs, 1) : zs);
+ return mult * zs;
}
return mult * NumCast(this.Document[this.scaleFieldKey], 1);
}
@@ -168,14 +169,23 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (newBox.activeFrame !== undefined) {
const x = newBox.x;
const y = newBox.y;
+ const w = newBox._width;
+ const h = newBox._height;
delete newBox["x-indexed"];
delete newBox["y-indexed"];
+ delete newBox["w-indexed"];
+ delete newBox["h-indexed"];
delete newBox["opacity-indexed"];
+ delete newBox._width;
+ delete newBox._height;
delete newBox.x;
delete newBox.y;
+ delete newBox.opacity;
delete newBox.activeFrame;
newBox.x = x;
newBox.y = y;
+ newBox._width = w;
+ newBox._height = h;
}
}
if (this.Document._currentFrame !== undefined && !this.props.isAnnotationOverlay) {
@@ -202,13 +212,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) {
if (!super.onInternalDrop(e, de)) return false;
+ const refDoc = docDragData.droppedDocuments[0];
const [xpo, ypo] = this.getTransformOverlay().transformPoint(de.x, de.y);
- const z = NumCast(docDragData.droppedDocuments[0].z);
+ const z = NumCast(refDoc.z);
const x = (z ? xpo : xp) - docDragData.offset[0];
const y = (z ? ypo : yp) - docDragData.offset[1];
const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
zsorted.forEach((doc, index) => doc.zIndex = doc.isInkMask ? 5000 : index + 1);
- const dropPos = [NumCast(docDragData.droppedDocuments[0].x), NumCast(docDragData.droppedDocuments[0].y)];
+ const dvals = CollectionFreeFormDocumentView.getValues(refDoc, NumCast(refDoc.activeFrame, 1000));
+ const dropPos = this.Document._currentFrame !== undefined ? [dvals.x, 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);
@@ -219,7 +231,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
d.x = x + NumCast(d.x) - dropPos[0];
d.y = y + NumCast(d.y) - dropPos[1];
}
- const nd = [NumCast(layoutDoc._nativeWidth), NumCast(layoutDoc._nativeHeight)];
+ const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
layoutDoc._width = NumCast(layoutDoc._width, 300);
layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
!d._isBackground && (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
@@ -801,7 +813,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
onPointerWheel = (e: React.WheelEvent): void => {
- if (this.layoutDoc._lockedTransform || this.props.Document.inOverlay || this.props.Document.treeViewOutlineMode) return;
+ if (this.layoutDoc._lockedTransform || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode) return;
if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
e.stopPropagation();
}
@@ -837,7 +849,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
else if (ranges.yrange.max <= (panY - panelDim[1] / 2)) panY = ranges.yrange.min - panelDim[1] / 2;
}
}
- if (!this.layoutDoc._lockedTransform || this.Document.inOverlay) {
+ if (!this.layoutDoc._lockedTransform || CurrentUserUtils.OverlayDocs.includes(this.Document)) {
this.Document._viewTransition = panType;
const scale = this.getLocalTransform().inverse().Scale;
const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
@@ -875,7 +887,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.layoutDoc._panY = NumCast(this.layoutDoc._panY) - newpan[1];
}
- focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean, dontCenter?: boolean) => {
+ focusDocument = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, didFocus?: boolean) => {
const state = HistoryUtil.getState();
// TODO This technically isn't correct if type !== "doc", as
@@ -914,8 +926,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
afterFocus && setTimeout(afterFocus, delay);
} else {
!dontCenter && delay && this.props.focus(this.props.Document);
- // @ts-ignore
- afterFocus(true); // bcz: TODO Aragh -- need to add a parameter to afterFocus() functions to indicate whether the focus function didn't need to scroll
+ afterFocus?.(!dontCenter && delay ? true : false);
}
}
@@ -925,8 +936,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document[this.scaleFieldKey], pt: this.Document._viewTransition };
willZoom && this.setScaleToZoom(layoutdoc, scale);
- const newPanX = (NumCast(doc.x) + doc[WidthSym]() / 2) - (this.isAnnotationOverlay ? (NumCast(this.props.Document._nativeWidth)) / 2 / this.zoomScaling() : 0);
- const newPanY = (NumCast(doc.y) + doc[HeightSym]() / 2) - (this.isAnnotationOverlay ? (NumCast(this.props.Document._nativeHeight)) / 2 / this.zoomScaling() : 0);
+ const newPanX = (NumCast(doc.x) + doc[WidthSym]() / 2) - (this.isAnnotationOverlay ? (Doc.NativeWidth(this.props.Document)) / 2 / this.zoomScaling() : 0);
+ const newPanY = (NumCast(doc.y) + doc[HeightSym]() / 2) - (this.isAnnotationOverlay ? (Doc.NativeHeight(this.props.Document)) / 2 / this.zoomScaling() : 0);
const newState = HistoryUtil.getState();
newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY };
HistoryUtil.pushState(newState);
@@ -936,26 +947,30 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (!doc.z) this.setPan(newPanX, newPanY, doc.focusSpeed || doc.focusSpeed === 0 ? `transform ${doc.focusSpeed}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
}
Doc.BrushDoc(this.props.Document);
- this.props.focus(this.props.Document);
- Doc.linkFollowHighlight(doc);
- const notFocused = newPanX === savedState.px && newPanY === savedState.py;
- afterFocus && setTimeout(() => {
- // @ts-ignore
- if (afterFocus?.(notFocused)) { // bcz: TODO Aragh -- need to add a parameter to afterFocus() functions to indicate whether the focus function didn't need to scroll
- this.Document._panX = savedState.px;
- this.Document._panY = savedState.py;
- this.Document[this.scaleFieldKey] = savedState.s;
- this.Document._viewTransition = savedState.pt;
- }
- }, notFocused ? 0 : 500);
+ const newDidFocus = didFocus || (newPanX !== savedState.px || newPanY !== savedState.py);
+
+ const newAfterFocus = (didFocus: boolean) => {
+ afterFocus && setTimeout(() => {
+ // @ts-ignore
+ if (afterFocus?.(didFocus || (newPanX !== savedState.px || newPanY !== savedState.py))) {
+ this.Document._panX = savedState.px;
+ this.Document._panY = savedState.py;
+ this.Document[this.scaleFieldKey] = savedState.s;
+ this.Document._viewTransition = savedState.pt;
+ }
+ }, newPanX !== savedState.px || newPanY !== savedState.py ? 500 : 0);
+ return false;
+ };
+ this.props.focus(this.props.Document, undefined, undefined, newAfterFocus, undefined, newDidFocus);
+ Doc.linkFollowHighlight(doc);
}
}
setScaleToZoom = (doc: Doc, scale: number = 0.75) => {
- const pw = this.isAnnotationOverlay ? NumCast(this.props.Document._nativeWidth) : this.props.PanelWidth();
- const ph = this.isAnnotationOverlay ? NumCast(this.props.Document._nativeHeight) : this.props.PanelHeight();
+ const pw = this.isAnnotationOverlay ? Doc.NativeWidth(this.props.Document) : this.props.PanelWidth();
+ const ph = this.isAnnotationOverlay ? Doc.NativeHeight(this.props.Document) : this.props.PanelHeight();
pw && ph && (this.Document[this.scaleFieldKey] = scale * Math.min(pw / NumCast(doc._width), ph / NumCast(doc._height)));
}
@@ -979,7 +994,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
LayoutTemplate: childLayout.z ? undefined : this.props.ChildLayoutTemplate,
LayoutTemplateString: childLayout.z ? undefined : this.props.ChildLayoutString,
FreezeDimensions: this.props.freezeChildDimensions,
- layoutKey: StrCast(this.props.Document.childLayoutKey),
setupDragLines: this.setupDragLines,
dontRegisterView: this.props.dontRegisterView,
rootSelected: childData ? this.rootSelected : returnFalse,
@@ -1207,7 +1221,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
(e as any).handlePan = true;
- if (!this.props.Document._noAutoscroll && this._marqueeRef?.current) {
+ if (!this.props.Document._noAutoscroll && !this.props.renderDepth && this._marqueeRef?.current) {
const dragX = e.detail.clientX;
const dragY = e.detail.clientY;
const bounds = this._marqueeRef.current?.getBoundingClientRect();
@@ -1297,7 +1311,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" });
this.props.renderDepth && optionItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
if (!Doc.UserDoc().noviceMode) {
- optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
+ optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
optionItems.push({ description: `${this.Document._freeformLOD ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._freeformLOD = !this.Document._freeformLOD, icon: "table" });
}
@@ -1423,6 +1437,44 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
return false;
});
+
+ chooseGridSpace = (gridSpace: number): number => {
+ const divisions = this.props.PanelWidth() / this.zoomScaling() / gridSpace + 3;
+ return divisions < 60 ? gridSpace : this.chooseGridSpace(gridSpace * 10);
+ }
+
+ @computed get grid() {
+ const gridSpace = this.chooseGridSpace(NumCast(this.layoutDoc["_backgroundGrid-spacing"], 50));
+ const shiftX = (this.props.isAnnotationOverlay ? 0 : -this.panX() % gridSpace - gridSpace) * this.zoomScaling();
+ const shiftY = (this.props.isAnnotationOverlay ? 0 : -this.panY() % gridSpace - gridSpace) * this.zoomScaling();
+ const renderGridSpace = gridSpace * this.zoomScaling();
+ const w = this.props.PanelWidth() + 2 * renderGridSpace;
+ const h = this.props.PanelHeight() + 2 * renderGridSpace;
+ return <canvas className="collectionFreeFormView-grid" width={w} height={h} style={{ transform: `translate(${shiftX}px, ${shiftY}px)` }}
+ ref={(el) => {
+ const ctx = el?.getContext('2d');
+ if (ctx) {
+ const Cx = this.centeringShiftX() % renderGridSpace;
+ const Cy = this.centeringShiftY() % renderGridSpace;
+ ctx.lineWidth = Math.min(1, Math.max(0.5, this.zoomScaling()));
+ ctx.setLineDash(gridSpace > 50 ? [3, 3] : [1, 5]);
+ ctx.clearRect(0, 0, w, h);
+ if (ctx) {
+ ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
+ ctx.beginPath();
+ for (let x = Cx - renderGridSpace; x <= w - Cx; x += renderGridSpace) {
+ ctx.moveTo(x, Cy - h);
+ ctx.lineTo(x, Cy + h);
+ }
+ for (let y = Cy - renderGridSpace; y <= h - Cy; y += renderGridSpace) {
+ ctx.moveTo(Cx - w, y);
+ ctx.lineTo(Cx + w, y);
+ }
+ ctx.stroke();
+ }
+ }
+ }} />;
+ }
@computed get marqueeView() {
return <MarqueeView
{...this.props}
@@ -1436,6 +1488,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
getTransform={this.getTransform}
isAnnotationOverlay={this.isAnnotationOverlay}>
<div ref={this._marqueeRef}>
+ {this.layoutDoc["_backgroundGrid-show"] ? this.grid : (null)}
<CollectionFreeFormViewPannableContents
centeringShiftX={this.centeringShiftX}
centeringShiftY={this.centeringShiftY}
@@ -1452,10 +1505,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
</MarqueeView>;
}
+
@computed get contentScaling() {
if (this.props.annotationsKey && !this.props.forceScaling) return 0;
- const nw = returnVal(this.props.NativeWidth?.(), NumCast(this.Document._nativeWidth));
- const nh = returnVal(this.props.NativeHeight?.(), NumCast(this.Document._nativeHeight));
+ const nw = returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.Document));
+ const nh = returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.Document));
const hscale = nh ? this.props.PanelHeight() / nh : 1;
const wscale = nw ? this.props.PanelWidth() / nw : 1;
return wscale < hscale ? wscale : hscale;
@@ -1624,7 +1678,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
}
@computed get zoomProgressivize() {
- return PresBox.Instance && PresBox.Instance.activeItem && PresBox.Instance.activeItem.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : (null);
+ return PresBox.Instance?.activeItem?.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : (null);
}
@computed get progressivize() {
@@ -1655,6 +1709,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
</>;
}
+
render() {
// trace();
const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none");
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index fd4fa0c7e..cedeb1112 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -54,7 +54,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
<FontAwesomeIcon icon="font" size="lg" />
</button>
</Tooltip>,
- <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin with selected view</div></>} placement="bottom">
+ <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin with selected region</div></>} placement="bottom">
<button
className="antimodeMenu-button"
onPointerDown={this.pinWithView}>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 7c64fd429..7040b5e56 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -25,7 +25,7 @@ import "./MarqueeView.scss";
import React = require("react");
import { Id } from "../../../../fields/FieldSymbols";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import { PresMovement } from "../../nodes/PresBox";
+import { PresBox, PresMovement } from "../../nodes/PresBox";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -393,15 +393,24 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const selected = this.marqueeSelect(false);
const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
if (curPres) {
+ if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
const pinDoc = Doc.MakeAlias(doc);
pinDoc.presentationTargetDoc = doc;
pinDoc.presMovement = PresMovement.Zoom;
pinDoc.context = curPres;
- Doc.AddDocToList(curPres, "data", pinDoc);
+ pinDoc.title = doc.title + " - Slide";
+ const presArray: Doc[] = PresBox.Instance?.sortArray();
+ const size: number = PresBox.Instance?._selectedArray.size;
+ const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+ Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
if (!DocumentManager.Instance.getDocumentView(curPres)) {
CollectionDockingView.AddSplit(curPres, "right");
}
+ PresBox.Instance?._selectedArray.clear();
+ pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Updates selected array
+ const index = PresBox.Instance?.childDocs.indexOf(pinDoc);
+ index && (curPres._itemIndex = index);
if (e instanceof KeyboardEvent ? e.key === "c" : true) {
const x = this.Bounds.left + this.Bounds.width / 2;
const y = this.Bounds.top + this.Bounds.height / 2;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index b99bef15e..6e16137b5 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -213,10 +213,9 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
return this.props.addDocTab(doc, where);
}
getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
- const layoutTemp = this.props.DataDoc ? true : undefined;
return <ContentFittingDocumentView
Document={layout}
- DataDoc={layout.resolvedDataDoc as Doc || (layoutTemp ? layout : undefined)}
+ DataDoc={layout.resolvedDataDoc as Doc}
backgroundColor={this.props.backgroundColor}
LayoutTemplate={this.props.ChildLayoutTemplate}
LayoutTemplateString={this.props.ChildLayoutString}
@@ -290,6 +289,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
return (
<div className={"collectionMulticolumnView_contents"}
style={{
+ width: `calc(100% - ${2 * NumCast(this.props.Document._xMargin)}px)`,
+ height: `calc(100% - ${2 * NumCast(this.props.Document._yMargin)}px)`,
marginLeft: NumCast(this.props.Document._xMargin), marginRight: NumCast(this.props.Document._xMargin),
marginTop: NumCast(this.props.Document._yMargin), marginBottom: NumCast(this.props.Document._yMargin)
}} ref={this.createDashEventsTarget}>