aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/DocumentDecorations.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-12-21 14:55:48 -0500
committerbobzel <zzzman@gmail.com>2023-12-21 14:55:48 -0500
commit1caba64ee0f32ee8af79263cd4ef2a8bc5d5146e (patch)
tree0fa0e957d1f342fdc6ed4a4b43f5dddfddb1298a /src/client/views/DocumentDecorations.tsx
parent02eb7da95df283606d4275a22d9451cef371c3b5 (diff)
parent2691b951d96f2ce7652acbea9e340b61737b3b57 (diff)
Merge branch 'moreUpgrading' into dataViz-annotations
Diffstat (limited to 'src/client/views/DocumentDecorations.tsx')
-rw-r--r--src/client/views/DocumentDecorations.tsx257
1 files changed, 129 insertions, 128 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d4b474de9..7003485d2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,12 +1,12 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
+import { Tooltip } from '@mui/material';
import { IconButton } from 'browndash-components';
-import { action, computed, observable, runInAction } from 'mobx';
+import { action, computed, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { FaUndo } from 'react-icons/fa';
import { DateField } from '../../fields/DateField';
import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit } from '../../fields/DocSymbols';
import { InkField } from '../../fields/InkField';
import { RichTextField } from '../../fields/RichTextField';
import { ScriptField } from '../../fields/ScriptField';
@@ -33,11 +33,17 @@ import { LightboxView } from './LightboxView';
import { DocumentView, OpenWhereMod } from './nodes/DocumentView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import { ImageBox } from './nodes/ImageBox';
-import React = require('react');
-import _ = require('lodash');
-
+import * as React from 'react';
+import { ObservableReactComponent } from './ObservableReactComponent';
+
+interface DocumentDecorationsProps {
+ PanelWidth: number;
+ PanelHeight: number;
+ boundsLeft: number;
+ boundsTop: number;
+}
@observer
-export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
+export class DocumentDecorations extends ObservableReactComponent<DocumentDecorationsProps> {
static Instance: DocumentDecorations;
private _resizeHdlId = '';
private _keyinput = React.createRef<HTMLInputElement>();
@@ -61,27 +67,27 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
@observable private _showRotCenter = false; // whether to show a draggable green dot that represents the center of rotation
@observable private _rotCenter = [0, 0]; // the center of rotation in object coordinates (0,0) = object center (not top left!)
- constructor(props: any) {
+ constructor(props: React.PropsWithChildren<DocumentDecorationsProps>) {
super(props);
+ makeObservable(this);
+
DocumentDecorations.Instance = this;
document.addEventListener('pointermove', // show decorations whenever pointer moves outside of selection bounds.
action(e => {
const center = {x: (this.Bounds.x+this.Bounds.r)/2, y: (this.Bounds.y+this.Bounds.b)/2};
const {x,y} = Utils.rotPt(e.clientX - center.x,
e.clientY - center.y,
- NumCast(SelectionManager.Views().lastElement()?.screenToLocalTransform().Rotate));
+ NumCast(SelectionManager.Views.lastElement()?.screenToLocalTransform().Rotate));
(this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && //
- (this.Bounds.x > center.x+x + this._resizeBorderWidth / 2 ||
- this.Bounds.r < center.x+x - this._resizeBorderWidth / 2 ||
- this.Bounds.y > center.y+y + this._resizeBorderWidth / 2 ||
- this.Bounds.b < center.y+y - this._resizeBorderWidth / 2)));
+ (this.Bounds.x > center.x+x || this.Bounds.r < center.x+x ||
+ this.Bounds.y > center.y+y || this.Bounds.b < center.y+y )));
})); // prettier-ignore
}
@computed get ClippedBounds() {
const bounds = this.Bounds;
- const leftBounds = this.props.boundsLeft;
- const topBounds = LightboxView.LightboxDoc ? 0 : this.props.boundsTop;
+ const leftBounds = this._props.boundsLeft;
+ const topBounds = LightboxView.LightboxDoc ? 0 : this._props.boundsTop;
bounds.x = Math.max(leftBounds, bounds.x - this._resizeBorderWidth / 2) + this._resizeBorderWidth / 2;
bounds.y = Math.max(topBounds, bounds.y - this._resizeBorderWidth / 2 - this._titleHeight) + this._resizeBorderWidth / 2 + this._titleHeight;
const borderRadiusDraggerWidth = 15;
@@ -93,15 +99,15 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
@computed get Bounds() {
return (LinkFollower.IsFollowing || DocumentView.ExploreMode) ?
{ x: 0, y: 0, r: 0, b: 0 }
- : SelectionManager.Views()
- .filter(dv => dv.props.renderDepth > 0)
+ : SelectionManager.Views
+ .filter(dv => dv._props.renderDepth > 0)
.map(dv => dv.getBounds())
.reduce((bounds, rect) => !rect ? bounds
: { x: Math.min(rect.left, bounds.x),
y: Math.min(rect.top, bounds.y),
r: Math.max(rect.right, bounds.r),
b: Math.max(rect.bottom, bounds.b),
- c: SelectionManager.Views().length === 1 ? rect.center : undefined },
+ c: SelectionManager.Views.length === 1 ? rect.center : undefined },
{ x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE, c: undefined as { X: number; Y: number } | undefined }); // prettier-ignore
}
@@ -115,14 +121,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
UndoManager.RunInBatch(
() =>
titleFieldKey &&
- SelectionManager.Views().forEach(d => {
+ SelectionManager.Views.forEach(d => {
if (titleFieldKey === 'title') {
d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-');
- if (StrCast(d.rootDoc.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) {
- Doc.RemFromMyPublished(d.rootDoc);
+ if (StrCast(d.Document.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) {
+ Doc.RemFromMyPublished(d.Document);
}
- if (!StrCast(d.rootDoc.title).startsWith('@') && this._accumulatedTitle.startsWith('@')) {
- Doc.AddToMyPublished(d.rootDoc);
+ if (!StrCast(d.Document.title).startsWith('@') && this._accumulatedTitle.startsWith('@')) {
+ Doc.AddToMyPublished(d.Document);
}
}
//@ts-ignore
@@ -130,20 +136,20 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
if (titleField.toString().startsWith('<this>')) {
const title = titleField.toString().replace(/<this>\.?/, '');
- const curKey = Doc.LayoutFieldKey(d.rootDoc);
+ const curKey = Doc.LayoutFieldKey(d.Document);
if (curKey !== title) {
if (title) {
if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') {
- d.rootDoc.layout_fieldKey = `layout_${title}`;
- d.rootDoc[`layout_${title}`] = FormattedTextBox.LayoutString(title);
- d.rootDoc[`${title}_nativeWidth`] = d.rootDoc[`${title}_nativeHeight`] = 0;
+ d.Document.layout_fieldKey = `layout_${title}`;
+ d.Document[`layout_${title}`] = FormattedTextBox.LayoutString(title);
+ d.Document[`${title}_nativeWidth`] = d.Document[`${title}_nativeHeight`] = 0;
}
} else {
- d.rootDoc.layout_fieldKey = undefined;
+ d.Document.layout_fieldKey = undefined;
}
}
} else {
- Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true);
+ Doc.SetInPlace(d.Document, titleFieldKey, titleField, true);
}
}),
'edit title'
@@ -159,7 +165,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
};
onContainerDown = (e: React.PointerEvent) => {
- const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views()[0].rootDoc);
+ const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views[0].Document);
if (effectiveLayoutAcl == AclAdmin || effectiveLayoutAcl == AclEdit || effectiveLayoutAcl == AclAugment) {
setupMoveUpEvents(this, e, e => this.onBackgroundMove(true, e), emptyFunction, emptyFunction);
e.stopPropagation();
@@ -167,7 +173,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
};
onTitleDown = (e: React.PointerEvent) => {
- const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views()[0].rootDoc);
+ const effectiveLayoutAcl = GetEffectiveAcl(SelectionManager.Views[0].Document);
if (effectiveLayoutAcl == AclAdmin || effectiveLayoutAcl == AclEdit || effectiveLayoutAcl == AclAugment) {
setupMoveUpEvents(
this,
@@ -190,27 +196,27 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
};
@action
onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => {
- const dragDocView = SelectionManager.Views()[0];
- const effectiveLayoutAcl = GetEffectiveAcl(dragDocView.rootDoc);
+ const dragDocView = SelectionManager.Views[0];
+ const effectiveLayoutAcl = GetEffectiveAcl(dragDocView.Document);
if (effectiveLayoutAcl != AclAdmin && effectiveLayoutAcl != AclEdit && effectiveLayoutAcl != AclAugment) {
return false;
}
const containers = new Set<Doc | undefined>();
- SelectionManager.Views().forEach(v => containers.add(DocCast(v.rootDoc.embedContainer)));
+ SelectionManager.Views.forEach(v => containers.add(DocCast(v.Document.embedContainer)));
if (containers.size > 1) return false;
const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 };
const dragData = new DragManager.DocumentDragData(
- SelectionManager.Views().map(dv => dv.props.Document),
- dragDocView.props.dropAction
+ SelectionManager.Views.map(dv => dv.Document),
+ dragDocView._props.dropAction
);
- dragData.offset = dragDocView.props.ScreenToLocalTransform().transformDirection(e.x - left, e.y - top);
- dragData.moveDocument = dragDocView.props.moveDocument;
- dragData.removeDocument = dragDocView.props.removeDocument;
+ dragData.offset = dragDocView._props.ScreenToLocalTransform().transformDirection(e.x - left, e.y - top);
+ dragData.moveDocument = dragDocView._props.moveDocument;
+ dragData.removeDocument = dragDocView._props.removeDocument;
dragData.isDocDecorationMove = true;
dragData.canEmbed = dragTitle;
this._hidden = true;
DragManager.StartDocumentDrag(
- SelectionManager.Views().map(dv => dv.ContentDiv!),
+ SelectionManager.Views.map(dv => dv.ContentDiv!),
dragData,
e.x,
e.y,
@@ -225,7 +231,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
_deleteAfterIconify = false;
_iconifyBatch: UndoManager.Batch | undefined;
onCloseClick = (forceDeleteOrIconify: boolean | undefined) => {
- const views = SelectionManager.Views().filter(v => v && v.props.renderDepth > 0);
+ const views = SelectionManager.Views.filter(v => v && v._props.renderDepth > 0);
if (forceDeleteOrIconify === false && this._iconifyBatch) return;
this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false;
var iconifyingCount = views.length;
@@ -233,11 +239,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
if ((force || --iconifyingCount === 0) && this._iconifyBatch) {
if (this._deleteAfterIconify) {
views.forEach(iconView => {
- Doc.setNativeView(iconView.props.Document);
- if (iconView.props.Document.activeFrame) {
- iconView.props.Document.opacity = 0; // bcz: hacky ... allows inkMasks and other documents to be "turned off" without removing them from the animated collection which allows them to function properly in a presenation.
+ Doc.setNativeView(iconView.Document);
+ if (iconView.Document.activeFrame) {
+ iconView.Document.opacity = 0; // bcz: hacky ... allows inkMasks and other documents to be "turned off" without removing them from the animated collection which allows them to function properly in a presenation.
} else {
- iconView.props.removeDocument?.(iconView.props.Document);
+ iconView._props.removeDocument?.(iconView.Document);
}
});
views.forEach(SelectionManager.DeselectView);
@@ -258,27 +264,27 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
};
onMaximizeDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, () => DragManager.StartWindowDrag?.(e, [SelectionManager.Views().lastElement().rootDoc]) ?? false, emptyFunction, this.onMaximizeClick, false, false);
+ setupMoveUpEvents(this, e, () => DragManager.StartWindowDrag?.(e, [SelectionManager.Views.lastElement().Document]) ?? false, emptyFunction, this.onMaximizeClick, false, false);
e.stopPropagation();
};
onMaximizeClick = (e: any): void => {
- const selectedDocs = SelectionManager.Views();
+ const selectedDocs = SelectionManager.Views;
if (selectedDocs.length) {
if (e.ctrlKey) {
// open an embedding in a new tab with Ctrl Key
- CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].rootDoc), OpenWhereMod.right);
+ CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].Document), OpenWhereMod.right);
} else if (e.shiftKey) {
// open centered in a new workspace with Shift Key
- const embedding = Doc.MakeEmbedding(selectedDocs[0].rootDoc);
+ const embedding = Doc.MakeEmbedding(selectedDocs[0].Document);
embedding.embedContainer = undefined;
embedding.x = -NumCast(embedding._width) / 2;
embedding.y = -NumCast(embedding._height) / 2;
CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right);
} else if (e.altKey) {
// open same document in new tab
- CollectionDockingView.ToggleSplit(selectedDocs[0].rootDoc, OpenWhereMod.right);
+ CollectionDockingView.ToggleSplit(selectedDocs[0].Document, OpenWhereMod.right);
} else {
- var openDoc = selectedDocs[0].rootDoc;
+ var openDoc = selectedDocs[0].Document;
if (openDoc.layout_fieldKey === 'layout_icon') {
openDoc = DocListCast(openDoc.proto_embeddings).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc);
Doc.deiconifyView(openDoc);
@@ -286,7 +292,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
LightboxView.Instance.SetLightboxDoc(
openDoc,
undefined,
- selectedDocs.slice(1).map(view => view.rootDoc)
+ selectedDocs.slice(1).map(view => view.Document)
);
}
}
@@ -294,11 +300,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
};
onIconifyClick = (): void => {
- SelectionManager.Views().forEach(dv => dv?.iconify());
+ SelectionManager.Views.forEach(dv => dv?.iconify());
SelectionManager.DeselectAll();
};
- onSelectContainerDocClick = () => SelectionManager.Views()?.[0]?.props.docViewPath?.().lastElement()?.select(false);
+ onSelectContainerDocClick = () => SelectionManager.Views?.[0]?._props.docViewPath?.().lastElement()?.select(false);
/**
* sets up events when user clicks on the border radius editor
*/
@@ -313,7 +319,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
const [x, y] = [this.Bounds.x + 3, this.Bounds.y + 3];
const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
const dist = e.clientX < x && e.clientY < y ? 0 : Math.sqrt((e.clientX - x) * (e.clientX - x) + (e.clientY - y) * (e.clientY - y));
- SelectionManager.Docs().map(doc => {
+ SelectionManager.Docs.map(doc => {
const docMax = Math.min(NumCast(doc.width) / 2, NumCast(doc.height) / 2);
const radius = Math.min(1, dist / maxDist) * docMax; // set radius based on ratio of drag distance to half diagonal distance of bounding box
doc.layout_borderRounding = `${radius}px`;
@@ -338,7 +344,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
returnFalse, // don't care about move or up event,
emptyFunction, // just care about whether we get a click event
e => UndoManager.RunInBatch(
- () => SelectionManager.Docs().forEach(doc =>
+ () => SelectionManager.Docs.forEach(doc =>
doc._pointerEvents = (doc._lockedPosition = !doc._lockedPosition)? 'none' : undefined ),
'toggleBackground' ) // prettier-ignore
);
@@ -346,24 +352,24 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
};
setRotateCenter = (seldocview: DocumentView, rotCenter: number[]) => {
- const newloccentern = seldocview.props.ScreenToLocalTransform().transformPoint(rotCenter[0], rotCenter[1]);
+ const newloccentern = seldocview._props.ScreenToLocalTransform().transformPoint(rotCenter[0], rotCenter[1]);
const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2];
- const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.rootDoc._rotation) / 180) * Math.PI);
- seldocview.rootDoc.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
- seldocview.rootDoc.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height);
+ const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI);
+ seldocview.Document.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width);
+ seldocview.Document.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height);
};
@action
onRotateCenterDown = (e: React.PointerEvent): void => {
this._isRotating = true;
- const seldocview = SelectionManager.Views()[0];
+ const seldocview = SelectionManager.Views[0];
setupMoveUpEvents(
this,
e,
(e: PointerEvent, down: number[], delta: number[]) => // return false to keep getting events
this.setRotateCenter(seldocview, [this.rotCenter[0] + delta[0], this.rotCenter[1] + delta[1]]) as any as boolean,
action(e => (this._isRotating = false)), // upEvent
- action(e => (seldocview.rootDoc.rotation_centerX = seldocview.rootDoc.rotation_centerY = 0))
+ action(e => (seldocview.Document.rotation_centerX = seldocview.Document.rotation_centerY = 0))
); // prettier-ignore
};
@@ -372,27 +378,27 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
this._isRotating = true;
const rcScreen = { X: this.rotCenter[0], Y: this.rotCenter[1] };
const rotateUndo = UndoManager.StartBatch('drag rotation');
- const selectedInk = SelectionManager.Views().filter(i => i.ComponentView instanceof InkingStroke);
+ const selectedInk = SelectionManager.Views.filter(i => i.ComponentView instanceof InkingStroke);
const centerPoint = this.rotCenter.slice();
const infos = new Map<Doc, { unrotatedDocPos: { x: number; y: number }; startRotCtr: { x: number; y: number }; accumRot: number }>();
- const seldocview = SelectionManager.Views()[0];
- SelectionManager.Views().forEach(dv => {
- const accumRot = (NumCast(dv.rootDoc._rotation) / 180) * Math.PI;
- const localRotCtr = dv.props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y);
- const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.rootDoc.width) / 2, localRotCtr[1] - NumCast(dv.rootDoc.height) / 2];
+ const seldocview = SelectionManager.Views[0];
+ SelectionManager.Views.forEach(dv => {
+ const accumRot = (NumCast(dv.Document._rotation) / 180) * Math.PI;
+ const localRotCtr = dv._props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y);
+ const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.Document.width) / 2, localRotCtr[1] - NumCast(dv.Document.height) / 2];
const startRotCtr = Utils.rotPt(localRotCtrOffset[0], localRotCtrOffset[1], -accumRot);
- const unrotatedDocPos = { x: NumCast(dv.rootDoc.x) + localRotCtrOffset[0] - startRotCtr.x, y: NumCast(dv.rootDoc.y) + localRotCtrOffset[1] - startRotCtr.y };
- infos.set(dv.rootDoc, { unrotatedDocPos, startRotCtr, accumRot });
+ const unrotatedDocPos = { x: NumCast(dv.Document.x) + localRotCtrOffset[0] - startRotCtr.x, y: NumCast(dv.Document.y) + localRotCtrOffset[1] - startRotCtr.y };
+ infos.set(dv.Document, { unrotatedDocPos, startRotCtr, accumRot });
});
const infoRot = (angle: number, isAbs = false) => {
- SelectionManager.Views().forEach(
+ SelectionManager.Views.forEach(
action(dv => {
- const { unrotatedDocPos, startRotCtr, accumRot } = infos.get(dv.rootDoc)!;
+ const { unrotatedDocPos, startRotCtr, accumRot } = infos.get(dv.Document)!;
const endRotCtr = Utils.rotPt(startRotCtr.x, startRotCtr.y, isAbs ? angle : accumRot + angle);
- infos.set(dv.rootDoc, { unrotatedDocPos, startRotCtr, accumRot: isAbs ? angle : accumRot + angle });
- dv.rootDoc.x = infos.get(dv.rootDoc)!.unrotatedDocPos.x - (endRotCtr.x - startRotCtr.x);
- dv.rootDoc.y = infos.get(dv.rootDoc)!.unrotatedDocPos.y - (endRotCtr.y - startRotCtr.y);
- dv.rootDoc._rotation = ((isAbs ? 0 : NumCast(dv.rootDoc._rotation)) + (angle * 180) / Math.PI) % 360; // Rotation between -360 and 360
+ infos.set(dv.Document, { unrotatedDocPos, startRotCtr, accumRot: isAbs ? angle : accumRot + angle });
+ dv.Document.x = infos.get(dv.Document)!.unrotatedDocPos.x - (endRotCtr.x - startRotCtr.x);
+ dv.Document.y = infos.get(dv.Document)!.unrotatedDocPos.y - (endRotCtr.y - startRotCtr.y);
+ dv.Document._rotation = ((isAbs ? 0 : NumCast(dv.Document._rotation)) + (angle * 180) / Math.PI) % 360; // Rotation between -360 and 360
})
);
};
@@ -412,7 +418,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
return false;
}, // moveEvent
action(() => {
- const oldRotation = NumCast(seldocview.rootDoc._rotation);
+ const oldRotation = NumCast(seldocview.Document._rotation);
const diff = oldRotation - Math.round(oldRotation / 45) * 45;
if (Math.abs(diff) < 5) {
if (selectedInk.length) {
@@ -433,7 +439,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
@action
onPointerDown = (e: React.PointerEvent): void => {
- SnappingManager.SetIsResizing(SelectionManager.Docs().lastElement());
+ SnappingManager.SetIsResizing(SelectionManager.Docs.lastElement());
setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
e.stopPropagation();
DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
@@ -442,7 +448,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
this._offset = { x: this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX, y: this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY };
this._resizeUndo = UndoManager.StartBatch('drag resizing');
this._snapPt = { x: e.pageX, y: e.pageY };
- SelectionManager.Views().forEach(docView => docView.CollectionFreeFormView?.dragStarting(false, false));
+ SelectionManager.Views.forEach(docView => docView.CollectionFreeFormView?.dragStarting(false, false));
};
projectDragToAspect = (e: PointerEvent, docView: DocumentView, fixedAspect: number) => {
@@ -456,12 +462,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
dot = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]);
return [a[0] + atob[0] * t, a[1] + atob[1] * t];
};
- const tl = docView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ const tl = docView._props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
return project([e.clientX + this._offset.x, e.clientY + this._offset.y], tl, [tl[0] + fixedAspect, tl[1] + 1]);
};
onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => {
- const first = SelectionManager.Views()[0];
- const effectiveAcl = GetEffectiveAcl(first.rootDoc);
+ const first = SelectionManager.Views[0];
+ const effectiveAcl = GetEffectiveAcl(first.Document);
if (!(effectiveAcl == AclAdmin || effectiveAcl == AclEdit || effectiveAcl == AclAugment)) return false;
if (!first) return false;
var fixedAspect = Doc.NativeAspect(first.layoutDoc);
@@ -477,10 +483,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
!this._interactionLock && runInAction(async () => { // resize selected docs if we're not in the middle of a resize (ie, throttle input events to frame rate)
this._interactionLock = true;
this._snapPt = thisPt;
- e.ctrlKey && (SelectionManager.Views().forEach(docView => !Doc.NativeHeight(docView.props.Document) && docView.toggleNativeDimensions()));
- const fixedAspect = SelectionManager.Docs().some(this.hasFixedAspect);
+ e.ctrlKey && (SelectionManager.Views.forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions()));
+ const fixedAspect = SelectionManager.Docs.some(this.hasFixedAspect);
const scaleAspect = {x:scale.x === 1 && fixedAspect ? scale.y : scale.x, y: scale.x !== 1 && fixedAspect ? scale.x : scale.y};
- SelectionManager.Views().forEach(docView =>
+ SelectionManager.Views.forEach(docView =>
this.resizeView(docView, refPt, scaleAspect, { dragHdl, ctrlKey:e.ctrlKey })); // prettier-ignore
await new Promise<any>(res => setTimeout(() => res(this._interactionLock = undefined)));
}); // prettier-ignore
@@ -516,7 +522,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
// resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc
//
resizeView = (docView: DocumentView, refPt: number[], scale: { x: number; y: number }, opts: { dragHdl: string; ctrlKey: boolean }) => {
- const doc = docView.rootDoc;
+ const doc = docView.Document;
if (doc.isGroup) {
DocListCast(doc.data)
.map(member => DocumentManager.Instance.getDocumentView(member, docView)!)
@@ -524,7 +530,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
doc.xPadding = NumCast(doc.xPadding) * scale.x;
doc.yPadding = NumCast(doc.yPadding) * scale.y;
} else {
- const refCent = docView.props.ScreenToLocalTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move)
+ const refCent = docView._props.ScreenToLocalTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move)
const [nwidth, nheight] = [docView.nativeWidth, docView.nativeHeight];
const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)];
@@ -551,8 +557,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
if (setData) Doc.SetNativeHeight(Doc.GetProto(doc), NumCast(doc._nativeHeight));
}
- doc._width = NumCast(doc._width) * scale.x;
- doc._height = NumCast(doc._height) * scale.y;
+ doc._width = Math.max(1, NumCast(doc._width) * scale.x);
+ doc._height = Math.max(1, NumCast(doc._height) * scale.y);
const { deltaX, deltaY } = this.realignRefPt(doc, refCent, initWidth, initHeight);
doc.x = NumCast(doc.x) + deltaX;
doc.y = NumCast(doc.y) + deltaY;
@@ -594,7 +600,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
this._resizeUndo?.end();
// detect layout_autoHeight gesture and apply
- SelectionManager.Docs().forEach(doc => NumCast(doc._height) < 20 && (doc._layout_autoHeight = true));
+ SelectionManager.Docs.forEach(doc => NumCast(doc._height) < 20 && (doc._layout_autoHeight = true));
//need to change points for resize, or else rotation/control points will fail.
this._inkDragDocs
.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
@@ -611,26 +617,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
@computed
get selectionTitle(): string {
- if (SelectionManager.Views().length === 1) {
- const selected = SelectionManager.Views()[0];
- if (selected.ComponentView?.getTitle?.()) {
- return selected.ComponentView.getTitle();
- }
+ if (SelectionManager.Views.length === 1) {
+ const selected = SelectionManager.Views[0];
if (this._titleControlString.startsWith('=')) {
- return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.rootDoc, this: selected.layoutDoc }, console.log).result?.toString() || '';
+ return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.Document, this: selected.layoutDoc }, console.log).result?.toString() || '';
}
if (this._titleControlString.startsWith('#')) {
- return Field.toString(selected.props.Document[this._titleControlString.substring(1)] as Field) || '-unset-';
+ return Field.toString(selected.Document[this._titleControlString.substring(1)] as Field) || '-unset-';
}
return this._accumulatedTitle;
}
- return SelectionManager.Views().length > 1 ? '-multiple-' : '-unset-';
+ return SelectionManager.Views.length > 1 ? '-multiple-' : '-unset-';
}
@computed get rotCenter() {
- const lastView = SelectionManager.Views().lastElement();
+ const lastView = SelectionManager.Views.lastElement();
if (lastView) {
- const invXf = lastView.props.ScreenToLocalTransform().inverse();
+ const invXf = lastView._props.ScreenToLocalTransform().inverse();
const seldoc = lastView.layoutDoc;
const loccenter = Utils.rotPt(NumCast(seldoc.rotation_centerX) * NumCast(seldoc._width), NumCast(seldoc.rotation_centerY) * NumCast(seldoc._height), invXf.Rotate);
return invXf.transformPoint(loccenter.x + NumCast(seldoc._width) / 2, loccenter.y + NumCast(seldoc._height) / 2);
@@ -640,31 +643,31 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
render() {
const { b, r, x, y } = this.Bounds;
- const seldocview = SelectionManager.Views().lastElement();
- if (SnappingManager.GetIsDragging() || r - x < 1 || x === Number.MAX_VALUE || !seldocview || this._hidden || isNaN(r) || isNaN(b) || isNaN(x) || isNaN(y)) {
+ const seldocview = SelectionManager.Views.lastElement();
+ if (SnappingManager.IsDragging || r - x < 1 || x === Number.MAX_VALUE || !seldocview || this._hidden || isNaN(r) || isNaN(b) || isNaN(x) || isNaN(y)) {
setTimeout(action(() => (this._showNothing = true)));
return null;
}
// sharing
- const acl = GetEffectiveAcl(!this._showLayoutAcl ? Doc.GetProto(seldocview.rootDoc) : seldocview.rootDoc);
+ const acl = GetEffectiveAcl(!this._showLayoutAcl ? Doc.GetProto(seldocview.Document) : seldocview.Document);
const docShareMode = HierarchyMapping.get(acl)!.name;
const shareMode = StrCast(docShareMode);
var shareSymbolIcon = ReverseHierarchyMap.get(shareMode)?.image;
// hide the decorations if the parent chooses to hide it or if the document itself hides it
- const hideDecorations = SnappingManager.GetIsResizing() || seldocview.props.hideDecorations || seldocview.rootDoc.layout_hideDecorations;
+ const hideDecorations = SnappingManager.IsResizing || seldocview._props.hideDecorations || seldocview.Document.layout_hideDecorations;
const hideResizers =
- ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
- const hideTitle = this._showNothing || hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
- const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
+ ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.Document)) || hideDecorations || seldocview._props.hideResizeHandles || seldocview.Document.layout_hideResizeHandles || this._isRounding || this._isRotating;
+ const hideTitle = this._showNothing || hideDecorations || seldocview._props.hideDecorationTitle || seldocview.Document.layout_hideDecorationTitle || this._isRounding || this._isRotating;
+ const hideDocumentButtonBar = hideDecorations || seldocview._props.hideDocumentButtonBar || seldocview.Document.layout_hideDocumentButtonBar || this._isRounding || this._isRotating;
// if multiple documents have been opened at the same time, then don't show open button
const hideOpenButton =
this._showNothing ||
hideDecorations ||
- seldocview.props.hideOpenButton ||
- seldocview.rootDoc.layout_hideOpenButton ||
- SelectionManager.Views().some(docView => docView.rootDoc._dragOnlyWithinContainer || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) ||
+ seldocview._props.hideOpenButton ||
+ seldocview.Document.layout_hideOpenButton ||
+ SelectionManager.Views.some(docView => docView.Document._dragOnlyWithinContainer || docView.Document.isGroup || docView.Document.layout_hideOpenButton) ||
this._isRounding ||
this._isRotating;
const hideDeleteButton =
@@ -672,11 +675,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
hideDecorations ||
this._isRounding ||
this._isRotating ||
- seldocview.props.hideDeleteButton ||
- seldocview.rootDoc.hideDeleteButton ||
- SelectionManager.Views().some(docView => {
- const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit;
- return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin;
+ seldocview._props.hideDeleteButton ||
+ seldocview.Document.hideDeleteButton ||
+ SelectionManager.Views.some(docView => {
+ const collectionAcl = docView._props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView._props.docViewPath().lastElement().dataDoc) : AclEdit;
+ return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.Document) !== AclAdmin;
});
const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
<Tooltip key={key} title={<div className="dash-tooltip">{title}</div>} placement="top">
@@ -688,13 +691,13 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
const bounds = this.ClippedBounds;
const useLock = bounds.r - bounds.x > 135 && seldocview.CollectionFreeFormDocumentView;
- const useRotation = !hideResizers && seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate?
- const rotation = SelectionManager.Views().length == 1 ? seldocview.screenToLocalTransform().inverse().RotateDeg : 0;
+ const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate?
+ const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToLocalTransform().inverse().RotateDeg : 0;
// Radius constants
const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
- const borderRadius = numberValue(Cast(seldocview.rootDoc.layout_borderRounding, 'string', null));
- const docMax = Math.min(NumCast(seldocview.rootDoc.width) / 2, NumCast(seldocview.rootDoc.height) / 2);
+ const borderRadius = numberValue(Cast(seldocview.Document.layout_borderRounding, 'string', null));
+ const docMax = Math.min(NumCast(seldocview.Document.width) / 2, NumCast(seldocview.Document.height) / 2);
const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
const radiusHandle = (borderRadius / docMax) * maxDist;
const radiusHandleLocation = Math.min(radiusHandle, maxDist);
@@ -742,7 +745,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
{sharingMenu}
{!useLock ? null : (
<Tooltip key="lock" title={<div className="dash-tooltip">toggle ability to interact with document</div>} placement="top">
- <div className="documentDecorations-lock" style={{ color: seldocview.rootDoc._lockedPosition ? 'red' : undefined }} onPointerDown={this.onLockDown}>
+ <div className="documentDecorations-lock" style={{ color: seldocview.Document._lockedPosition ? 'red' : undefined }} onPointerDown={this.onLockDown}>
<FontAwesomeIcon size="sm" icon="lock" />
</div>
</Tooltip>
@@ -751,7 +754,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
);
const centery = hideTitle ? 0 : this._titleHeight;
const transformOrigin = `${50}% calc(50% + ${centery / 2}px)`;
- const freeformDoc = SelectionManager.Views().some(v => v.CollectionFreeFormDocumentView);
+ const freeformDoc = SelectionManager.Views.some(v => v.CollectionFreeFormDocumentView);
return (
<div className="documentDecorations" style={{ display: this._showNothing && !freeformDoc ? 'none' : undefined }}>
<div
@@ -762,9 +765,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
left: bounds.x - this._resizeBorderWidth / 2,
top: bounds.y - this._resizeBorderWidth / 2,
transformOrigin,
- background: SnappingManager.GetShiftKey() ? undefined : 'yellow',
- pointerEvents: SnappingManager.GetShiftKey() || DocumentView.Interacting ? 'none' : 'all',
- display: SelectionManager.Views().length <= 1 || hideDecorations ? 'none' : undefined,
+ background: SnappingManager.ShiftKey ? undefined : 'yellow',
+ pointerEvents: SnappingManager.ShiftKey || DocumentView.Interacting ? 'none' : 'all',
+ display: SelectionManager.Views.length <= 1 || hideDecorations ? 'none' : undefined,
transform: `rotate(${rotation}deg)`,
}}
onPointerDown={this.onBackgroundDown}
@@ -801,11 +804,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
<div key="bl" className="documentDecorations-bottomLeftResizer" onPointerDown={this.onPointerDown} />
<div key="b" className="documentDecorations-bottomResizer" onPointerDown={this.onPointerDown} />
<div key="br" className="documentDecorations-bottomRightResizer" onPointerDown={this.onPointerDown} />
- {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement()
- ? null
- : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')}
</>
)}
+ {seldocview._props.renderDepth <= 1 || !seldocview._props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')}
{useRounding && (
<div
className="documentDecorations-borderRadius"
@@ -823,7 +824,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
style={{
transform: `translate(${-this._resizeBorderWidth / 2 + 10}px, ${this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `,
}}>
- <DocumentButtonBar views={SelectionManager.Views} />
+ <DocumentButtonBar views={() => SelectionManager.Views} />
</div>
)}
</div>