aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/CurrentUserUtils.ts4
-rw-r--r--src/client/views/InkControlPtHandles.tsx268
-rw-r--r--src/client/views/InkTangentHandles.tsx114
-rw-r--r--src/client/views/InkingStroke.tsx24
-rw-r--r--src/client/views/MainView.tsx2
-rw-r--r--src/client/views/PropertiesView.tsx14
-rw-r--r--src/client/views/collections/CollectionMenu.tsx9
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx2
-rw-r--r--src/client/views/collections/TabDocView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx54
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx1
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx28
-rw-r--r--src/client/views/nodes/DocumentView.tsx16
-rw-r--r--src/client/views/nodes/button/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx38
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx118
-rw-r--r--src/fields/util.ts1
17 files changed, 345 insertions, 352 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3d95cb947..67c730089 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -258,7 +258,7 @@ export class CurrentUserUtils {
}[] = [
{key: "Note", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _autoHeight: true }},
{key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200 }},
- {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100 }},
+ {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100, _fitWidth: true }},
{key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }},
{key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }},
{key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }},
@@ -669,7 +669,7 @@ export class CurrentUserUtils {
title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}},
{ title: "Pin", icon: "map-pin", toolTip: "Pin View to Trail", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "tab")'}, width: 20, scripts: { onClick: 'pinWithView(_readOnly_, altKey)'}},
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
- { title: "Num",icon: "",toolTip: "Frame Number (click to toggle edit mode)",btnType: ButtonType.TextButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { script: '{ return curKeyFrame(_readOnly_);}'}},
+ { title: "Num",icon: "",toolTip: "Frame Number (click to toggle edit mode)",btnType: ButtonType.TextButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
{ title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
{ title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, funcs: {hidden: '!SelectionManager_selectedDocType()'}, ignoreClick: true, width: 20, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected
{ title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, funcs: {hidden: '!SelectionManager_selectedDocType()'}, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}},
diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx
index d036a636a..9447b2e72 100644
--- a/src/client/views/InkControlPtHandles.tsx
+++ b/src/client/views/InkControlPtHandles.tsx
@@ -1,23 +1,23 @@
-import React = require("react");
-import { action, observable } from "mobx";
-import { observer } from "mobx-react";
-import { Doc } from "../../fields/Doc";
-import { ControlPoint, InkData, PointData, InkField } from "../../fields/InkField";
-import { List } from "../../fields/List";
-import { listSpec } from "../../fields/Schema";
-import { Cast, NumCast } from "../../fields/Types";
-import { setupMoveUpEvents, returnFalse } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { UndoManager } from "../util/UndoManager";
-import { Colors } from "./global/globalEnums";
-import { InkingStroke } from "./InkingStroke";
-import { InkStrokeProperties } from "./InkStrokeProperties";
-import { DocumentView } from "./nodes/DocumentView";
-import { SelectionManager } from "../util/SelectionManager";
+import React = require('react');
+import { action, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc } from '../../fields/Doc';
+import { ControlPoint, InkData, PointData, InkField } from '../../fields/InkField';
+import { List } from '../../fields/List';
+import { listSpec } from '../../fields/Schema';
+import { Cast, NumCast } from '../../fields/Types';
+import { setupMoveUpEvents, returnFalse } from '../../Utils';
+import { Transform } from '../util/Transform';
+import { UndoManager } from '../util/UndoManager';
+import { Colors } from './global/globalEnums';
+import { InkingStroke } from './InkingStroke';
+import { InkStrokeProperties } from './InkStrokeProperties';
+import { DocumentView } from './nodes/DocumentView';
+import { SelectionManager } from '../util/SelectionManager';
export interface InkControlProps {
inkDoc: Doc;
- inkView: DocumentView;
+ inkView: InkingStroke;
inkCtrlPoints: InkData;
screenCtrlPoints: InkData;
screenSpaceLineWidth: number;
@@ -26,16 +26,16 @@ export interface InkControlProps {
@observer
export class InkControlPtHandles extends React.Component<InkControlProps> {
-
@observable private _overControl = -1;
-
- @observable controlUndo: UndoManager.Batch | undefined;
+ get docView() {
+ return this.props.inkView.props.docViewPath().lastElement();
+ }
componentDidMount() {
- document.addEventListener("keydown", this.onDelete, true);
+ document.addEventListener('keydown', this.onDelete, true);
}
componentWillUnmount() {
- document.removeEventListener("keydown", this.onDelete, true);
+ document.removeEventListener('keydown', this.onDelete, true);
}
/**
* Handles the movement of a selected control point when the user clicks and drags.
@@ -43,30 +43,32 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
*/
@action
onControlDown = (e: React.PointerEvent, controlIndex: number): void => {
- const ptFromScreen = this.props.inkView.ComponentView?.ptFromScreen;
+ const ptFromScreen = this.props.inkView.ptFromScreen;
if (ptFromScreen) {
const order = controlIndex % 4;
const handleIndexA = ((order === 3 ? controlIndex - 1 : controlIndex - 2) + this.props.inkCtrlPoints.length) % this.props.inkCtrlPoints.length;
const handleIndexB = (order === 3 ? controlIndex + 2 : controlIndex + 1) % this.props.inkCtrlPoints.length;
- const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec("number"));
+ const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec('number'));
const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex;
if (!wasSelected) InkStrokeProperties.Instance._currentPoint = -1;
const origInk = this.props.inkCtrlPoints.slice();
- setupMoveUpEvents(this, e,
+ setupMoveUpEvents(
+ this,
+ e,
action((e: PointerEvent, down: number[], delta: number[]) => {
- if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("drag ink ctrl pt");
+ if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('drag ink ctrl pt');
const inkMoveEnd = ptFromScreen({ X: delta[0], Y: delta[1] });
const inkMoveStart = ptFromScreen({ X: 0, Y: 0 });
- InkStrokeProperties.Instance.moveControlPtHandle(this.props.inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex, origInk);
+ InkStrokeProperties.Instance.moveControlPtHandle(this.docView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex, origInk);
return false;
}),
action(() => {
- if (this.controlUndo) {
- InkStrokeProperties.Instance.snapControl(this.props.inkView, controlIndex);
+ if (this.props.inkView.controlUndo) {
+ InkStrokeProperties.Instance.snapControl(this.docView, controlIndex);
}
- this.controlUndo?.end();
- this.controlUndo = undefined;
- UndoManager.FilterBatches(["data", "x", "y", "width", "height"]);
+ this.props.inkView.controlUndo?.end();
+ this.props.inkView.controlUndo = undefined;
+ UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']);
}),
action((e: PointerEvent, doubleTap: boolean | undefined) => {
const equivIndex = controlIndex === 0 ? this.props.inkCtrlPoints.length - 1 : controlIndex === this.props.inkCtrlPoints.length - 1 ? 0 : controlIndex;
@@ -76,44 +78,52 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
else this.props.inkDoc.brokenInkIndices = new List<number>([controlIndex]);
} else {
if (brokenIndices?.includes(equivIndex)) {
- if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("make smooth");
- InkStrokeProperties.Instance.snapHandleTangent(this.props.inkView, equivIndex, handleIndexA, handleIndexB);
+ if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth');
+ InkStrokeProperties.Instance.snapHandleTangent(this.docView, equivIndex, handleIndexA, handleIndexB);
}
if (equivIndex !== controlIndex && brokenIndices?.includes(controlIndex)) {
- if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("make smooth");
- InkStrokeProperties.Instance.snapHandleTangent(this.props.inkView, controlIndex, handleIndexA, handleIndexB);
+ if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth');
+ InkStrokeProperties.Instance.snapHandleTangent(this.docView, controlIndex, handleIndexA, handleIndexB);
}
}
- this.controlUndo?.end();
- this.controlUndo = undefined;
+ this.props.inkView.controlUndo?.end();
+ this.props.inkView.controlUndo = undefined;
}
this.changeCurrPoint(controlIndex);
- }), undefined, undefined, () => wasSelected && this.changeCurrPoint(-1));
+ }),
+ undefined,
+ undefined,
+ () => wasSelected && this.changeCurrPoint(-1)
+ );
}
- }
+ };
/**
* Updates whether a user has hovered over a particular control point or point that could be added
* on click.
*/
- @action onEnterControl = (i: number) => { this._overControl = i; };
- @action onLeaveControl = () => { this._overControl = -1; };
+ @action onEnterControl = (i: number) => {
+ this._overControl = i;
+ };
+ @action onLeaveControl = () => {
+ this._overControl = -1;
+ };
/**
* Deletes the currently selected point.
*/
@action
onDelete = (e: KeyboardEvent) => {
- if (["-", "Backspace", "Delete"].includes(e.key)) {
- InkStrokeProperties.Instance.deletePoints(this.props.inkView, e.shiftKey);
+ if (['-', 'Backspace', 'Delete'].includes(e.key)) {
+ InkStrokeProperties.Instance.deletePoints(this.docView, e.shiftKey);
e.stopPropagation();
}
- }
+ };
/**
* Changes the current selected control point.
*/
@action
- changeCurrPoint = (i: number) => InkStrokeProperties.Instance._currentPoint = i
+ changeCurrPoint = (i: number) => (InkStrokeProperties.Instance._currentPoint = i);
render() {
// Accessing the current ink's data and extracting all control points.
@@ -133,101 +143,115 @@ export class InkControlPtHandles extends React.Component<InkControlProps> {
const closed = InkingStroke.IsClosed(inkData);
const nearestScreenPt = this.props.nearestScreenPt();
- const TagType = (broken?: boolean) => broken ? "rect" : "circle";
- const hdl = (control: { X: number, Y: number, I: number }, scale: number, color: string) => {
- const broken = Cast(this.props.inkDoc.brokenInkIndices, listSpec("number"))?.includes(control.I);
+ const TagType = (broken?: boolean) => (broken ? 'rect' : 'circle');
+ const hdl = (control: { X: number; Y: number; I: number }, scale: number, color: string) => {
+ const broken = Cast(this.props.inkDoc.brokenInkIndices, listSpec('number'))?.includes(control.I);
const Tag = TagType((control.I === 0 || control.I === inkData.length - 1) && !closed) as keyof JSX.IntrinsicElements;
- return <Tag key={control.I.toString() + scale}
- x={control.X - this.props.screenSpaceLineWidth * 2 * scale}
- y={control.Y - this.props.screenSpaceLineWidth * 2 * scale}
- cx={control.X}
- cy={control.Y}
- r={this.props.screenSpaceLineWidth * 2 * scale}
- opacity={this.controlUndo ? 0.15 : 1}
- height={this.props.screenSpaceLineWidth * 4 * scale}
- width={this.props.screenSpaceLineWidth * 4 * scale}
- strokeWidth={this.props.screenSpaceLineWidth / 2}
- stroke={Colors.MEDIUM_BLUE}
- fill={broken ? Colors.MEDIUM_BLUE : color}
- onPointerDown={(e: React.PointerEvent) => this.onControlDown(e, control.I)}
- onMouseEnter={() => this.onEnterControl(control.I)}
- onMouseLeave={this.onLeaveControl}
- pointerEvents="all"
- cursor="default"
- />;
- };
- return (<svg>
- {!nearestScreenPt ? (null) :
- <circle key={"npt"}
- cx={nearestScreenPt.X}
- cy={nearestScreenPt.Y}
- r={this.props.screenSpaceLineWidth * 2}
- fill={"#00007777"}
- stroke={"#00007777"}
- strokeWidth={0}
- pointerEvents="none"
+ return (
+ <Tag
+ key={control.I.toString() + scale}
+ x={control.X - this.props.screenSpaceLineWidth * 2 * scale}
+ y={control.Y - this.props.screenSpaceLineWidth * 2 * scale}
+ cx={control.X}
+ cy={control.Y}
+ r={this.props.screenSpaceLineWidth * 2 * scale}
+ opacity={this.props.inkView.controlUndo ? 0.15 : 1}
+ height={this.props.screenSpaceLineWidth * 4 * scale}
+ width={this.props.screenSpaceLineWidth * 4 * scale}
+ strokeWidth={this.props.screenSpaceLineWidth / 2}
+ stroke={Colors.MEDIUM_BLUE}
+ fill={broken ? Colors.MEDIUM_BLUE : color}
+ onPointerDown={(e: React.PointerEvent) => this.onControlDown(e, control.I)}
+ onMouseEnter={() => this.onEnterControl(control.I)}
+ onMouseLeave={this.onLeaveControl}
+ pointerEvents="all"
+ cursor="default"
/>
- }
- {sreenCtrlPoints.map(control => hdl(control, this._overControl !== control.I ? 1 : 3 / 2, Colors.WHITE))}
- </svg>
+ );
+ };
+ return (
+ <svg>
+ {!nearestScreenPt ? null : <circle key={'npt'} cx={nearestScreenPt.X} cy={nearestScreenPt.Y} r={this.props.screenSpaceLineWidth * 2} fill={'#00007777'} stroke={'#00007777'} strokeWidth={0} pointerEvents="none" />}
+ {sreenCtrlPoints.map(control => hdl(control, this._overControl !== control.I ? 1 : 3 / 2, Colors.WHITE))}
+ </svg>
);
}
}
-
export interface InkEndProps {
inkDoc: Doc;
- inkView: DocumentView;
+ inkView: InkingStroke;
screenSpaceLineWidth: number;
startPt: PointData;
endPt: PointData;
}
@observer
export class InkEndPtHandles extends React.Component<InkEndProps> {
- @observable controlUndo: UndoManager.Batch | undefined;
@observable _overStart: boolean = false;
@observable _overEnd: boolean = false;
@action
- dragRotate = (e: React.PointerEvent, p1: () => { X: number, Y: number }, p2: () => { X: number, Y: number }) => {
- setupMoveUpEvents(this, e, (e) => {
- if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch("stretch ink");
- // compute stretch factor by finding scaling along axis between start and end points
- const v1 = { X: p1().X - p2().X, Y: p1().Y - p2().Y };
- const v2 = { X: e.clientX - p2().X, Y: e.clientY - p2().Y };
- const v1len = Math.sqrt(v1.X * v1.X + v1.Y * v1.Y);
- const v2len = Math.sqrt(v2.X * v2.X + v2.Y * v2.Y);
- const scaling = v2len / v1len;
- const v1n = { X: v1.X / v1len, Y: v1.Y / v1len };
- const v2n = { X: v2.X / v2len, Y: v2.Y / v2len };
- const angle = Math.acos(v1n.X * v2n.X + v1n.Y * v2n.Y) * Math.sign(v1.X * v2.Y - v2.X * v1.Y);
- InkStrokeProperties.Instance.stretchInk(SelectionManager.Views(), scaling, p2(), v1n, e.shiftKey);
- InkStrokeProperties.Instance.rotateInk(SelectionManager.Views(), angle, p2());
- return false;
- }, action(() => {
- this.controlUndo?.end();
- this.controlUndo = undefined;
- UndoManager.FilterBatches(["data", "x", "y", "width", "height"]);
- }), returnFalse);
- }
+ dragRotate = (e: React.PointerEvent, p1: () => { X: number; Y: number }, p2: () => { X: number; Y: number }) => {
+ setupMoveUpEvents(
+ this,
+ e,
+ action(e => {
+ if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('stretch ink');
+ // compute stretch factor by finding scaling along axis between start and end points
+ const v1 = { X: p1().X - p2().X, Y: p1().Y - p2().Y };
+ const v2 = { X: e.clientX - p2().X, Y: e.clientY - p2().Y };
+ const v1len = Math.sqrt(v1.X * v1.X + v1.Y * v1.Y);
+ const v2len = Math.sqrt(v2.X * v2.X + v2.Y * v2.Y);
+ const scaling = v2len / v1len;
+ const v1n = { X: v1.X / v1len, Y: v1.Y / v1len };
+ const v2n = { X: v2.X / v2len, Y: v2.Y / v2len };
+ const angle = Math.acos(v1n.X * v2n.X + v1n.Y * v2n.Y) * Math.sign(v1.X * v2.Y - v2.X * v1.Y);
+ InkStrokeProperties.Instance.stretchInk(SelectionManager.Views(), scaling, p2(), v1n, e.shiftKey);
+ InkStrokeProperties.Instance.rotateInk(SelectionManager.Views(), angle, p2());
+ return false;
+ }),
+ action(() => {
+ this.props.inkView.controlUndo?.end();
+ this.props.inkView.controlUndo = undefined;
+ UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']);
+ }),
+ returnFalse
+ );
+ };
render() {
- const hdl = (key: string, pt: PointData, dragFunc: (e: React.PointerEvent) => void) => <circle key={key}
- cx={pt.X}
- cy={pt.Y}
- r={this.props.screenSpaceLineWidth * 2}
- fill={this._overStart ? "#aaaaaa" : "#99999977"}
- stroke={"#00007777"}
- strokeWidth={0}
- onPointerLeave={action(() => this._overStart = false)}
- onPointerEnter={action(() => this._overStart = true)}
- onPointerDown={dragFunc}
- pointerEvents="all"
- />;
- return (<svg>
- {hdl("start", this.props.startPt, (e: React.PointerEvent) => this.dragRotate(e, () => this.props.startPt, () => this.props.endPt))}
- {hdl("end", this.props.endPt, (e: React.PointerEvent) => this.dragRotate(e, () => this.props.endPt, () => this.props.startPt))}
- </svg>
+ const hdl = (key: string, pt: PointData, dragFunc: (e: React.PointerEvent) => void) => (
+ <circle
+ key={key}
+ cx={pt.X}
+ cy={pt.Y}
+ r={this.props.screenSpaceLineWidth * 2}
+ fill={this._overStart ? '#aaaaaa' : '#99999977'}
+ stroke={'#00007777'}
+ strokeWidth={0}
+ onPointerLeave={action(() => (this._overStart = false))}
+ onPointerEnter={action(() => (this._overStart = true))}
+ onPointerDown={dragFunc}
+ pointerEvents="all"
+ />
+ );
+ return (
+ <svg>
+ {hdl('start', this.props.startPt, (e: React.PointerEvent) =>
+ this.dragRotate(
+ e,
+ () => this.props.startPt,
+ () => this.props.endPt
+ )
+ )}
+ {hdl('end', this.props.endPt, (e: React.PointerEvent) =>
+ this.dragRotate(
+ e,
+ () => this.props.endPt,
+ () => this.props.startPt
+ )
+ )}
+ </svg>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/InkTangentHandles.tsx b/src/client/views/InkTangentHandles.tsx
index ae35bc980..c4a2f603e 100644
--- a/src/client/views/InkTangentHandles.tsx
+++ b/src/client/views/InkTangentHandles.tsx
@@ -1,21 +1,21 @@
-import React = require("react");
-import { action } from "mobx";
-import { observer } from "mobx-react";
-import { Doc } from "../../fields/Doc";
-import { HandleLine, HandlePoint, InkData } from "../../fields/InkField";
-import { List } from "../../fields/List";
-import { listSpec } from "../../fields/Schema";
-import { Cast } from "../../fields/Types";
-import { emptyFunction, setupMoveUpEvents } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { UndoManager } from "../util/UndoManager";
-import { Colors } from "./global/globalEnums";
-import { InkingStroke } from "./InkingStroke";
-import { InkStrokeProperties } from "./InkStrokeProperties";
-import { DocumentView } from "./nodes/DocumentView";
+import React = require('react');
+import { action } from 'mobx';
+import { observer } from 'mobx-react';
+import { Doc } from '../../fields/Doc';
+import { HandleLine, HandlePoint, InkData } from '../../fields/InkField';
+import { List } from '../../fields/List';
+import { listSpec } from '../../fields/Schema';
+import { Cast } from '../../fields/Types';
+import { emptyFunction, setupMoveUpEvents } from '../../Utils';
+import { Transform } from '../util/Transform';
+import { UndoManager } from '../util/UndoManager';
+import { Colors } from './global/globalEnums';
+import { InkingStroke } from './InkingStroke';
+import { InkStrokeProperties } from './InkStrokeProperties';
+import { DocumentView } from './nodes/DocumentView';
export interface InkHandlesProps {
inkDoc: Doc;
- inkView: DocumentView;
+ inkView: InkingStroke;
screenCtrlPoints: InkData;
screenSpaceLineWidth: number;
ScreenToLocalTransform: () => Transform;
@@ -23,49 +23,51 @@ export interface InkHandlesProps {
@observer
export class InkTangentHandles extends React.Component<InkHandlesProps> {
+ get docView() {
+ return this.props.inkView.props.docViewPath().lastElement();
+ }
/**
* Handles the movement of a selected handle point when the user clicks and drags.
* @param handleNum The index of the currently selected handle point.
*/
onHandleDown = (e: React.PointerEvent, handleIndex: number): void => {
- const ptFromScreen = this.props.inkView.ComponentView?.ptFromScreen;
- if (!ptFromScreen) return;
- const screenScale = this.props.ScreenToLocalTransform().Scale;
- var controlUndo: UndoManager.Batch | undefined;
const order = handleIndex % 4;
const oppositeHandleRawIndex = order === 1 ? handleIndex - 3 : handleIndex + 3;
const oppositeHandleIndex = (oppositeHandleRawIndex < 0 ? this.props.screenCtrlPoints.length + oppositeHandleRawIndex : oppositeHandleRawIndex) % this.props.screenCtrlPoints.length;
const controlIndex = (order === 1 ? handleIndex - 1 : handleIndex + 2) % this.props.screenCtrlPoints.length;
- setupMoveUpEvents(this, e,
+ setupMoveUpEvents(
+ this,
+ e,
(e: PointerEvent, down: number[], delta: number[]) => {
- if (!controlUndo) controlUndo = UndoManager.StartBatch("DocDecs move tangent");
+ if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('DocDecs move tangent');
if (e.altKey) this.onBreakTangent(controlIndex);
- const inkMoveEnd = ptFromScreen({ X: delta[0], Y: delta[1] });
- const inkMoveStart = ptFromScreen({ X: 0, Y: 0 });
- InkStrokeProperties.Instance.moveTangentHandle(this.props.inkView, -(inkMoveEnd.X - inkMoveStart.X), -(inkMoveEnd.Y - inkMoveStart.Y), handleIndex, oppositeHandleIndex, controlIndex);
+ const inkMoveEnd = this.props.inkView.ptFromScreen({ X: delta[0], Y: delta[1] });
+ const inkMoveStart = this.props.inkView.ptFromScreen({ X: 0, Y: 0 });
+ InkStrokeProperties.Instance.moveTangentHandle(this.docView, -(inkMoveEnd.X - inkMoveStart.X), -(inkMoveEnd.Y - inkMoveStart.Y), handleIndex, oppositeHandleIndex, controlIndex);
return false;
- }, () => {
- controlUndo?.end();
- UndoManager.FilterBatches(["data", "x", "y", "width", "height"]);
- }, emptyFunction
+ },
+ () => {
+ this.props.inkView.controlUndo?.end();
+ UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']);
+ },
+ emptyFunction
);
- }
+ };
/**
- * Breaks tangent handle movement when ‘Alt’ key is held down. Adds the current handle index and
+ * Breaks tangent handle movement when ‘Alt’ key is held down. Adds the current handle index and
* its matching (opposite) handle to a list of broken handle indices.
* @param handleNum The index of the currently selected handle point.
*/
@action
onBreakTangent = (controlIndex: number) => {
const closed = InkingStroke.IsClosed(this.props.screenCtrlPoints);
- const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec("number"));
- if (!brokenIndices?.includes(controlIndex) &&
- ((controlIndex > 0 && controlIndex < this.props.screenCtrlPoints.length - 1) || closed)) {
+ const brokenIndices = Cast(this.props.inkDoc.brokenInkIndices, listSpec('number'));
+ if (!brokenIndices?.includes(controlIndex) && ((controlIndex > 0 && controlIndex < this.props.screenCtrlPoints.length - 1) || closed)) {
if (brokenIndices) brokenIndices.push(controlIndex);
else this.props.inkDoc.brokenInkIndices = new List<number>([controlIndex]);
}
- }
+ };
render() {
// Accessing the current ink's data and extracting all handle points and handle lines.
@@ -81,10 +83,18 @@ export class InkTangentHandles extends React.Component<InkHandlesProps> {
// Adding first and last (single) handle lines.
if (closed) {
tangentLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[0].X, Y2: data[0].Y, X3: data[1].X, Y3: data[1].Y, dot1: 0, dot2: data.length - 1 });
- }
- else {
+ } else {
tangentLines.push({ X1: data[0].X, Y1: data[0].Y, X2: data[0].X, Y2: data[0].Y, X3: data[1].X, Y3: data[1].Y, dot1: 0, dot2: 0 });
- tangentLines.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[data.length - 1].X, Y2: data[data.length - 1].Y, X3: data[data.length - 1].X, Y3: data[data.length - 1].Y, dot1: data.length - 1, dot2: data.length - 1 });
+ tangentLines.push({
+ X1: data[data.length - 2].X,
+ Y1: data[data.length - 2].Y,
+ X2: data[data.length - 1].X,
+ Y2: data[data.length - 1].Y,
+ X3: data[data.length - 1].X,
+ Y3: data[data.length - 1].Y,
+ dot1: data.length - 1,
+ dot2: data.length - 1,
+ });
}
for (let i = 2; i < data.length - 4; i += 4) {
tangentLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 1].X, Y2: data[i + 1].Y, X3: data[i + 3].X, Y3: data[i + 3].Y, dot1: i + 1, dot2: i + 2 });
@@ -94,7 +104,7 @@ export class InkTangentHandles extends React.Component<InkHandlesProps> {
return (
<>
- {tangentHandles.map((pts, i) =>
+ {tangentHandles.map((pts, i) => (
<svg height="10" width="10" key={`hdl${i}`}>
<circle
cx={pts.X}
@@ -106,25 +116,31 @@ export class InkTangentHandles extends React.Component<InkHandlesProps> {
onPointerDown={e => this.onHandleDown(e, pts.I)}
pointerEvents="all"
cursor="default"
- display={(pts.dot1 === InkStrokeProperties.Instance._currentPoint || pts.dot2 === InkStrokeProperties.Instance._currentPoint) ? "inherit" : "none"} />
- </svg>)}
+ display={pts.dot1 === InkStrokeProperties.Instance._currentPoint || pts.dot2 === InkStrokeProperties.Instance._currentPoint ? 'inherit' : 'none'}
+ />
+ </svg>
+ ))}
{tangentLines.map((pts, i) => {
- const tangentLine = (x1: number, y1: number, x2: number, y2: number) =>
+ const tangentLine = (x1: number, y1: number, x2: number, y2: number) => (
<line
x1={x1}
y1={y1}
x2={x2}
y2={y2}
stroke={Colors.MEDIUM_BLUE}
- strokeDasharray={"1 1"}
+ strokeDasharray={'1 1'}
strokeWidth={1}
- display={(pts.dot1 === InkStrokeProperties.Instance._currentPoint || pts.dot2 === InkStrokeProperties.Instance._currentPoint) ? "inherit" : "none"} />;
- return <svg height="100" width="100" key={`line${i}`}>
- {tangentLine(pts.X1, pts.Y1, pts.X2, pts.Y2)}
- {tangentLine(pts.X2, pts.Y2, pts.X3, pts.Y3)}
- </svg>;
+ display={pts.dot1 === InkStrokeProperties.Instance._currentPoint || pts.dot2 === InkStrokeProperties.Instance._currentPoint ? 'inherit' : 'none'}
+ />
+ );
+ return (
+ <svg height="100" width="100" key={`line${i}`}>
+ {tangentLine(pts.X1, pts.Y1, pts.X2, pts.Y2)}
+ {tangentLine(pts.X2, pts.Y2, pts.X3, pts.Y3)}
+ </svg>
+ );
})}
</>
);
}
-} \ No newline at end of file
+}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 8291ff3f1..76c1aa80a 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -124,6 +124,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
public static toggleMask = action((inkDoc: Doc) => {
inkDoc.isInkMask = !inkDoc.isInkMask;
});
+ @observable controlUndo: UndoManager.Batch | undefined;
/**
* Drags the a simple bezier segment of the stroke.
* Also adds a control point when double clicking on the stroke.
@@ -143,15 +144,15 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
const { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY });
const controlIndex = nearestSeg;
const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex;
- var controlUndo: UndoManager.Batch | undefined;
const isEditing = InkStrokeProperties.Instance._controlButton && this.props.isSelected();
+ this.controlUndo = undefined;
setupMoveUpEvents(
this,
e,
!isEditing
? returnFalse
: action((e: PointerEvent, down: number[], delta: number[]) => {
- if (!controlUndo) controlUndo = UndoManager.StartBatch('drag ink ctrl pt');
+ if (!this.controlUndo) this.controlUndo = UndoManager.StartBatch('drag ink ctrl pt');
const inkMoveEnd = this.ptFromScreen({ X: delta[0], Y: delta[1] });
const inkMoveStart = this.ptFromScreen({ X: 0, Y: 0 });
InkStrokeProperties.Instance.moveControlPtHandle(inkView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex);
@@ -161,8 +162,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
!isEditing
? returnFalse
: action(() => {
- controlUndo?.end();
- controlUndo = undefined;
+ this.controlUndo?.end();
+ this.controlUndo = undefined;
UndoManager.FilterBatches(['data', 'x', 'y', 'width', 'height']);
}),
action((e: PointerEvent, doubleTap: boolean | undefined) => {
@@ -304,7 +305,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
return SnappingManager.GetIsDragging() ? null : !InkStrokeProperties.Instance._controlButton ? (
!this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : (
<div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
- <InkEndPtHandles inkView={this.props.docViewPath().lastElement()} inkDoc={inkDoc} startPt={screenPts[0]} endPt={screenPts.lastElement()} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
+ <InkEndPtHandles inkView={this} inkDoc={inkDoc} startPt={screenPts[0]} endPt={screenPts.lastElement()} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
</div>
)
) : (
@@ -331,15 +332,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
1.0,
false
)}
- <InkControlPtHandles
- inkView={this.props.docViewPath().lastElement()}
- inkDoc={inkDoc}
- inkCtrlPoints={inkData}
- screenCtrlPoints={screenHdlPts}
- nearestScreenPt={this.nearestScreenPt}
- screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth}
- />
- <InkTangentHandles inkView={this.props.docViewPath().lastElement()} inkDoc={inkDoc} screenCtrlPoints={screenHdlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.screenToLocal} />
+ <InkControlPtHandles inkView={this} inkDoc={inkDoc} inkCtrlPoints={inkData} screenCtrlPoints={screenHdlPts} nearestScreenPt={this.nearestScreenPt} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} />
+ <InkTangentHandles inkView={this} inkDoc={inkDoc} screenCtrlPoints={screenHdlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} ScreenToLocalTransform={this.screenToLocal} />
</div>
);
};
@@ -389,7 +383,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
1.0,
false
);
- const highlight = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting);
+ const highlight = !this.controlUndo && this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting);
const highlightIndex = highlight?.highlightIndex;
const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent');
// Invisible polygonal line that enables the ink to be selected by the user.
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 895ed9bda..625dc2748 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -606,7 +606,7 @@ export class MainView extends React.Component {
@computed get mainDocView() {
return (
<>
- {this._hideUI ? null : this.headerBarDocView}
+ {this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView}
<DocumentView
key="main"
Document={this.mainContainer!}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index a2bc37095..203b42cbc 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1814,12 +1814,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
{!selectedItem ? null : (
<div className="propertiesView-presTrails">
- <div
- className="propertiesView-presTrails-title"
- onPointerDown={action(() => {
- this.openPresTransitions = !this.openPresTransitions;
- })}
- style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
+ <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openPresTransitions = !this.openPresTransitions))} style={{ backgroundColor: this.openPresTransitions ? 'black' : '' }}>
&nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={'rocket'} /> &nbsp; Transitions
<div className="propertiesView-presTrails-title-icon">
<FontAwesomeIcon icon={this.openPresTransitions ? 'caret-down' : 'caret-right'} size="lg" color="white" />
@@ -1830,12 +1825,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
)}
{!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? null : (
<div className="propertiesView-presTrails">
- <div
- className="propertiesView-presTrails-title"
- onPointerDown={action(() => {
- this.openSlideOptions = !this.openSlideOptions;
- })}
- style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
+ <div className="propertiesView-presTrails-title" onPointerDown={action(() => (this.openSlideOptions = !this.openSlideOptions))} style={{ backgroundColor: this.openSlideOptions ? 'black' : '' }}>
&nbsp; <FontAwesomeIcon style={{ alignSelf: 'center' }} icon={type === DocumentType.AUDIO ? 'file-audio' : 'file-video'} /> &nbsp; {type === DocumentType.AUDIO ? 'Audio Options' : 'Video Options'}
<div className="propertiesView-presTrails-title-icon">
<FontAwesomeIcon icon={this.openSlideOptions ? 'caret-down' : 'caret-right'} size="lg" color="white" />
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index e2594b6ae..c83f4e689 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -15,6 +15,7 @@ import { RichTextField } from '../../../fields/RichTextField';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
+import { GestureUtils } from '../../../pen-gestures/GestureUtils';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
@@ -40,7 +41,7 @@ import { CollectionLinearView } from './collectionLinear';
import './CollectionMenu.scss';
import { COLLECTION_BORDER_WIDTH } from './CollectionView';
import { TabDocView } from './TabDocView';
-import { GestureUtils } from '../../../pen-gestures/GestureUtils';
+import { CollectionFreeFormView } from './collectionFreeForm';
interface CollectionMenuProps {
panelHeight: () => number;
@@ -733,7 +734,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
doc._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
}
- CollectionFreeFormDocumentView.updateKeyframe(undefined, childDocs, currentFrame || 0);
+ CollectionFreeFormView.updateKeyframe(undefined, [...childDocs, doc], currentFrame || 0);
doc._currentFrame = newFrame === undefined ? 0 : Math.max(0, newFrame);
}
}
@@ -747,7 +748,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
this.document._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
}
- this._keyTimer = CollectionFreeFormDocumentView.updateKeyframe(this._keyTimer, this.childDocs, currentFrame || 0);
+ this._keyTimer = CollectionFreeFormView.updateKeyframe(this._keyTimer, [...this.childDocs, this.document], currentFrame || 0);
this.document._currentFrame = Math.max(0, (currentFrame || 0) + 1);
this.document.lastFrame = Math.max(NumCast(this.document._currentFrame), NumCast(this.document.lastFrame));
};
@@ -759,7 +760,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
this.document._currentFrame = 0;
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
}
- this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, this.childDocs.slice());
+ this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, [...this.childDocs, this.document], 1000);
this.document._currentFrame = Math.max(0, (currentFrame || 0) - 1);
};
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 456f2a13d..330e116d1 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -265,7 +265,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
const dropAction = StrCast(this.doc.childDropAction) as dropActionType;
const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false;
- if (this.treeChildren.length < this._renderCount) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20))));
+ if (this._renderCount < this.treeChildren.length) setTimeout(action(() => (this._renderCount = Math.min(this.treeChildren.length, this._renderCount + 20))));
return TreeView.GetChildElements(
this.treeChildren,
this,
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index d6bc0a4b2..fa648eb44 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -248,7 +248,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
return;
}
const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false);
- const pinDoc = Doc.MakeDelegate(anchorDoc ?? doc);
+ const pinDoc = anchorDoc && anchorDoc !== doc ? anchorDoc : Doc.MakeDelegate(doc);
pinDoc.presentationTargetDoc = anchorDoc ?? doc;
pinDoc.title = doc.title + ' - Slide';
pinDoc.data = new List<Doc>(); // the children of the alias' layout are the presentation slide children. the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4d6e0dff2..e5b4b76a8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -54,6 +54,7 @@ import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
import React = require('react');
import { DocumentDecorations } from '../../DocumentDecorations';
+import { PresEffect } from '../../nodes/trails';
export type collectionFreeformViewProps = {
annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox)
@@ -150,7 +151,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
? { x: cb[0], y: cb[1], r: cb[2], b: cb[3] }
: this.props.contentBounds?.() ??
aggregateBounds(
- this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!),
+ this._layoutElements.filter(e => e.bounds && e.bounds.width && !e.bounds.z).map(e => e.bounds!),
NumCast(this.layoutDoc._xPadding, 10),
NumCast(this.layoutDoc._yPadding, 10)
);
@@ -185,6 +186,32 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
_keyTimer: NodeJS.Timeout | undefined;
+
+ public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration: number) {
+ if (timer) clearTimeout(timer);
+ return DocumentView.SetViewTransition(docs, 'all', duration, undefined, true);
+ }
+ public static updateKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], time: number) {
+ if (timer) clearTimeout(timer);
+ const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, undefined, true);
+ const timecode = Math.round(time);
+ docs.forEach(doc => {
+ CollectionFreeFormDocumentView.animFields.forEach(val => {
+ const findexed = Cast(doc[`${val.key}-indexed`], listSpec('number'), null);
+ findexed?.length <= timecode + 1 && findexed.push(undefined as any as number);
+ });
+ CollectionFreeFormDocumentView.animStringFields.forEach(val => {
+ const findexed = Cast(doc[`${val}-indexed`], listSpec('string'), null);
+ findexed?.length <= timecode + 1 && findexed.push(undefined as any as string);
+ });
+ CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => {
+ const findexed = Cast(doc[`${val}-indexed`], listSpec(InkField), null);
+ findexed?.length <= timecode + 1 && findexed.push(undefined as any);
+ });
+ });
+ return newTimer;
+ }
+
changeKeyFrame = (back = false) => {
const currentFrame = Cast(this.Document._currentFrame, 'number', null);
if (currentFrame === undefined) {
@@ -192,10 +219,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0);
}
if (back) {
- this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, this.childDocs.slice());
+ this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, [...this.childDocs, this.layoutDoc], 1000);
this.Document._currentFrame = Math.max(0, (currentFrame || 0) - 1);
} else {
- this._keyTimer = CollectionFreeFormDocumentView.updateKeyframe(this._keyTimer, this.childDocs, currentFrame || 0);
+ this._keyTimer = CollectionFreeFormView.updateKeyframe(this._keyTimer, [...this.childDocs, this.layoutDoc], currentFrame || 0);
this.Document._currentFrame = Math.max(0, (currentFrame || 0) + 1);
this.Document.lastFrame = Math.max(NumCast(this.Document._currentFrame), NumCast(this.Document.lastFrame));
}
@@ -1204,7 +1231,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
// focus on the document in the collection
const didMove = !cantTransform && !doc.z && (panX !== savedState.panX || panY !== savedState.panY || scale !== savedState.scale);
- const focusSpeed = options?.instant ? 0 : didMove ? options.zoomTime ?? 500 : 0;
+ const focusSpeed = options?.instant ? 0 : didMove || DocCast(options.effect)?.presEffect !== PresEffect.None ? options.zoomTime ?? 500 : 0;
// glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
if (didMove) {
options.zoomScale && scale && (this.Document[this.scaleFieldKey] = scale);
@@ -1392,12 +1419,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
});
getCalculatedPositions(params: { pair: { layout: Doc; data?: Doc }; index: number; collection: Doc }): PoolData {
- const curFrame = Cast(this.Document._currentFrame, 'number');
const childDoc = params.pair.layout;
const childDocLayout = Doc.Layout(childDoc);
+ const layoutFrameNumber = Cast(this.Document._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+ const contentFrameNumber = Cast(childDocLayout._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
const { z, zIndex } = childDoc;
- const { backgroundColor, color } = curFrame === undefined ? { backgroundColor: undefined, color: undefined } : CollectionFreeFormDocumentView.getStringValues(childDoc, curFrame);
- const { x, y, opacity } = curFrame === undefined ? { x: childDoc.x, y: childDoc.y, opacity: this.props.childOpacity?.() } : CollectionFreeFormDocumentView.getValues(childDoc, curFrame);
+ const { backgroundColor, color } = contentFrameNumber === undefined ? { backgroundColor: undefined, color: undefined } : CollectionFreeFormDocumentView.getStringValues(childDoc, contentFrameNumber);
+ const { x, y, opacity } = layoutFrameNumber === undefined ? { x: childDoc.x, y: childDoc.y, opacity: this.props.childOpacity?.() } : CollectionFreeFormDocumentView.getValues(childDoc, layoutFrameNumber);
return {
x: Number.isNaN(NumCast(x)) ? 0 : NumCast(x),
y: Number.isNaN(NumCast(y)) ? 0 : NumCast(y),
@@ -1543,13 +1571,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const elements = computedElementData.slice();
Array.from(newPool.entries())
.filter(entry => this.isCurrent(entry[1].pair.layout))
- .forEach((entry, i) =>
+ .forEach((entry, i) => {
+ const childData: ViewDefBounds = this.childDataProvider(entry[1].pair.layout, entry[1].replica);
+ const childSize = this.childSizeProvider(entry[1].pair.layout, entry[1].replica);
elements.push({
ele: this.getChildDocView(entry[1]),
- bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica),
+ bounds: childData.opacity === 0 ? { ...childData, width: 0, height: 0 } : { ...childData, width: childSize.width, height: childSize.height },
inkMask: BoolCast(entry[1].pair.layout.isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1,
- })
- );
+ });
+ });
if (this.props.isAnnotationOverlay && this.props.Document[this.scaleFieldKey]) {
// don't zoom out farther than 1-1 if it's a bounded item (image, video, pdf), otherwise don't allow zooming in closer than 1-1 if it's a text sidebar
@@ -1988,7 +2018,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
zoomScaling={this.zoomScaling}
presPaths={this.showPresPaths}
presPinView={BoolCast(this.Document.presPinView)}
- transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', null)}
+ transition={this._panZoomTransition ? `transform ${this._panZoomTransition}ms` : Cast(this.layoutDoc._viewTransition, 'string', Cast(this.props.DocumentView?.()?.rootDoc._viewTransition, 'string', null))}
viewDefDivClick={this.props.viewDefDivClick}>
{this.children}
</CollectionFreeFormViewPannableContents>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index bc3b17cd9..bd33c4d80 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -397,6 +397,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
newCollection.forceActive = makeGroup;
newCollection.x = this.Bounds.left;
newCollection.y = this.Bounds.top;
+ newCollection.fitwidth = true;
selected.forEach(d => (d.context = newCollection));
this.hideMarquee();
return newCollection;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index f8ef87fb1..ba510e1dc 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -40,6 +40,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
{ key: '_rotation', val: 0 },
{ key: '_scrollTop' },
{ key: 'opacity', val: 1 },
+ { key: '_currentFrame' },
+ { key: 'viewScale', val: 1 },
{ key: 'viewScale', val: 1 },
{ key: 'panX' },
{ key: 'panY' },
@@ -115,32 +117,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
});
}
- public static updateKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], time: number, targetDoc?: Doc) {
- if (timer) clearTimeout(timer);
- const newTimer = DocumentView.SetViewTransition(docs, 'all', 1000, undefined, true);
- const timecode = Math.round(time);
- docs.forEach(doc => {
- CollectionFreeFormDocumentView.animFields.forEach(val => {
- const findexed = Cast(doc[`${val.key}-indexed`], listSpec('number'), null);
- findexed?.length <= timecode + 1 && findexed.push(undefined as any as number);
- });
- CollectionFreeFormDocumentView.animStringFields.forEach(val => {
- const findexed = Cast(doc[`${val}-indexed`], listSpec('string'), null);
- findexed?.length <= timecode + 1 && findexed.push(undefined as any as string);
- });
- CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => {
- const findexed = Cast(doc[`${val}-indexed`], listSpec(InkField), null);
- findexed?.length <= timecode + 1 && findexed.push(undefined as any);
- });
- });
- return newTimer;
- }
-
- public static gotoKeyframe(timer: NodeJS.Timeout | undefined, docs: Doc[], duration = 1000) {
- if (timer) clearTimeout(timer);
- return DocumentView.SetViewTransition(docs, 'all', duration, undefined, true);
- }
-
public static setupZoom(doc: Doc, targDoc: Doc) {
const width = new List<number>();
const height = new List<number>();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3d89566ee..c3b0412de 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -17,7 +17,7 @@ import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from
import { AudioField } from '../../../fields/URLField';
import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
import { MobileInterface } from '../../../mobile/MobileInterface';
-import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, isTargetChildOf as isParentOf, lightOrDark, OmitKeys, returnEmptyString, returnFalse, returnNone, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils';
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { DocServer } from '../../DocServer';
import { Docs, DocUtils } from '../../documents/Documents';
@@ -252,6 +252,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
private _disposers: { [name: string]: IReactionDisposer } = {};
private _downX: number = 0;
private _downY: number = 0;
+ private _downTime: number = 0;
private _firstX: number = -1;
private _firstY: number = -1;
private _lastTap: number = 0;
@@ -610,7 +611,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
let preventDefault = true;
const isScriptBox = () => StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name);
(this.rootDoc._raiseWhenDragged === undefined ? DragManager.GetRaiseWhenDragged() : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
- if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {
+ if (this._doubleTap && (![DocumentType.FONTICON, DocumentType.PRES].includes(this.props.Document.type as any) || this.onDoubleClickHandler)) {
// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
if (this._timeout) {
clearTimeout(this._timeout);
@@ -718,6 +719,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
);
this._downX = e.clientX;
this._downY = e.clientY;
+ this._downTime = Date.now();
if ((Doc.ActiveTool === InkTool.None || this.props.addDocTab === returnFalse) && !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) {
// if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking
if (
@@ -777,11 +779,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._cursorTimer && clearTimeout(this._cursorTimer);
this._cursorPress = false;
+ const now = Date.now();
if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log);
- } else {
- const now = Date.now();
- console.log(now - this._lastTap);
+ } else if (now - this._downTime < 300) {
this._doubleTap = now - this._lastTap < 600 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2;
// bcz: this is a placeholder. documents, when selected, should stopPropagation on doubleClicks if they want to keep the DocumentView from getting them
if (!this.props.isSelected(true) || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this.rootDoc.type) as any)) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
@@ -1154,7 +1155,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
className="documentView-contentsView"
style={{
pointerEvents:
- (this.props.pointerEvents?.() as any) ?? this.rootDoc.layoutKey === 'layout_icon'
+ this.opacity === 0
+ ? 'none'
+ : (this.props.pointerEvents?.() as any) ?? this.rootDoc.layoutKey === 'layout_icon'
? 'none'
: (this.props.contentPointerEvents as any)
? (this.props.contentPointerEvents as any)
@@ -1181,6 +1184,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
<DocumentContentsView
key={1}
{...this.props}
+ pointerEvents={this.opacity === 0 ? returnNone : this.props.pointerEvents}
docViewPath={this.props.viewPath}
thumbShown={this.thumbShown}
isHovering={this.props.isHovering}
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index b352f3790..93761633c 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -179,7 +179,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
className="list-item"
key={`${value}`}
style={{
- backgroundColor: value === checkResult ? Colors.LIGHT_BLUE : undefined,
+ backgroundColor: value.toString() === checkResult ? Colors.LIGHT_BLUE : undefined,
}}
onClick={() => setValue(value)}>
{value}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index e07517113..929bf1230 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1,10 +1,10 @@
import React = require('react');
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
-import { action, computed, IReactionDisposer, observable, ObservableSet, observe, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { ColorState, SketchPicker } from 'react-color';
-import { AnimationSym, Doc, DocListCast, FieldResult, HighlightSym, Opt, StrListCast } from '../../../../fields/Doc';
+import { AnimationSym, Doc, DocListCast, FieldResult, Opt, StrListCast } from '../../../../fields/Doc';
import { Copy, Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
@@ -14,7 +14,7 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Ty
import { AudioField } from '../../../../fields/URLField';
import { emptyFunction, emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils';
import { DocServer } from '../../../DocServer';
-import { Docs, DocumentOptions } from '../../../documents/Documents';
+import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
@@ -23,19 +23,17 @@ import { SettingsManager } from '../../../util/SettingsManager';
import { undoBatch, UndoManager } from '../../../util/UndoManager';
import { CollectionDockingView } from '../../collections/CollectionDockingView';
import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm';
+import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline';
import { CollectionView } from '../../collections/CollectionView';
import { TabDocView } from '../../collections/TabDocView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
-import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentView';
import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
-import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline';
-import { PresElementBox } from './PresElementBox';
const { Howl } = require('howler');
export interface PinProps {
@@ -296,7 +294,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (context) {
const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.ComponentView as CollectionFreeFormView;
if (ffview?.childDocs) {
- this._keyTimer = CollectionFreeFormDocumentView.gotoKeyframe(this._keyTimer, ffview.childDocs.slice(), transTime);
+ this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, ffview.childDocs, transTime);
context._currentFrame = NumCast(activeFrame);
}
}
@@ -598,7 +596,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
tagDoc.opacity = 1;
}
}
- const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex);
+ const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex) ?? itemIndexes.slice().reverse().lastElement();
if (curDoc.presHideBefore && index === hidingIndBef) {
if (index > this.itemIndex) {
tagDoc.opacity = 0;
@@ -606,10 +604,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
tagDoc.opacity = 1;
}
}
- const hidingIndAft = itemIndexes
- .slice()
- .reverse()
- .find(item => item < this.itemIndex);
+ const hidingIndAft =
+ itemIndexes
+ .slice()
+ .reverse()
+ .find(item => item <= this.itemIndex) ?? itemIndexes.lastElement();
if (curDoc.presHideAfter && index === hidingIndAft) {
if (index < this.itemIndex) {
tagDoc.opacity = 0;
@@ -875,7 +874,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@action
selectElement = async (doc: Doc, noNav = false) => {
CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.());
- !noNav && this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
+ if (noNav) {
+ const index = this.childDocs.indexOf(doc);
+ if (index >= 0 && index < this.childDocs.length) {
+ this.rootDoc._itemIndex = index;
+ }
+ } else this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
this.updateCurrentPresentation(DocCast(doc.context));
};
@@ -911,19 +915,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//regular click
@action
- regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, selectPres = true, noNav = false) => {
+ regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, noNav: boolean, selectPres = true) => {
this.clearSelectedArray();
this.addToSelectedArray(doc);
this._eleArray.splice(0, this._eleArray.length, ref);
this._dragArray.splice(0, this._dragArray.length, drag);
- focus && this.selectElement(doc, noNav);
+ this.selectElement(doc, noNav);
selectPres && this.selectPres();
};
- modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean, noNav: boolean = false) => {
+ modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, noNav: boolean, cmdClick: boolean, shiftClick: boolean) => {
if (cmdClick) this.multiSelect(doc, ref, drag);
else if (shiftClick) this.shiftSelect(doc, ref, drag);
- else this.regularSelect(doc, ref, drag, focus, noNav);
+ else this.regularSelect(doc, ref, drag, noNav);
};
static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance?.keyEvents(e);
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index f265c1315..40535c8cb 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -139,7 +139,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
onClick={e => {
e.stopPropagation();
e.preventDefault();
- this.presBoxView?.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
+ this.presBoxView?.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, e.shiftKey || e.ctrlKey || e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
this.presExpandDocumentClick();
}}>
<div className="presItem-groupNum">{`${ind + 1}.`}</div>
@@ -177,22 +177,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const element = e.target as any;
e.stopPropagation();
e.preventDefault();
- if (element && !(e.ctrlKey || e.metaKey)) {
- if (this.selectedArray?.has(this.rootDoc)) {
- this.selectedArray.size === 1 && this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false);
- setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
- } else {
- setupMoveUpEvents(
- this,
- e,
- (e: PointerEvent) => {
- this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false);
- return this.startDrag(e);
- },
- emptyFunction,
- emptyFunction
- );
- }
+ if (element && !(e.ctrlKey || e.metaKey || e.button === 2)) {
+ this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true, false);
+ setupMoveUpEvents(this, e, this.startDrag, emptyFunction, e => {
+ e.stopPropagation();
+ e.preventDefault();
+ this.presBoxView?.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, e.shiftKey || e.ctrlKey || e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
+ this.presBoxView?.activeItem && this.showRecording(this.presBoxView?.activeItem);
+ });
}
};
@@ -314,50 +306,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
/**
* Method called for updating the view of the currently selected document
*
- * @param targetDoc
+ * @param presTargetDoc
* @param activeItem
*/
@undoBatch
@action
- updateCapturedViewContents = (targetDoc: Doc, activeItem: Doc) => {
- switch (targetDoc.type) {
- case DocumentType.PDF:
- case DocumentType.WEB:
- case DocumentType.RTF:
- const scroll = targetDoc._scrollTop;
- activeItem.presPinViewScroll = scroll;
- if (targetDoc.type === DocumentType.RTF) {
- activeItem.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof RichTextField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as RichTextField)[Copy]() : targetDoc.text;
- }
- break;
- case DocumentType.INK:
- activeItem.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof InkField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as InkField)[Copy]() : targetDoc.data;
- break;
- case DocumentType.VID:
- case DocumentType.AUDIO:
- activeItem.presStartTime = targetDoc._currentTimecode;
- break;
- case DocumentType.COMPARISON:
- const clipWidth = targetDoc._clipWidth;
- activeItem.presPinClipWidth = clipWidth;
- break;
- case DocumentType.COL:
- activeItem.presPinLayoutData = new List<string>(DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) })));
- default:
- const bestView = DocumentManager.Instance.getFirstDocumentView(targetDoc);
- if (activeItem.presPinViewBounds && bestView) {
- const bounds = MarqueeView.CurViewBounds(targetDoc, bestView.props.PanelWidth(), bestView.props.PanelHeight());
- activeItem.presPinView = true;
- activeItem.presPinViewScale = NumCast(targetDoc._viewScale, 1);
- activeItem.presPinViewX = bounds.left + bounds.width / 2;
- activeItem.presPinViewY = bounds.top + bounds.height / 2;
- activeItem.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
- } else {
- activeItem.presPinViewX = targetDoc._panX;
- activeItem.presPinViewY = targetDoc._panY;
- activeItem.presPinViewScale = targetDoc._viewScale;
- }
- }
+ updateCapturedViewContents = (presTargetDoc: Doc, activeItem: Doc) => {
+ const target = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc;
+ PresBox.pinDocView(activeItem, { pinDocContent: true, pinData: PresBox.pinDataTypes(target) }, target);
};
@computed get recordingIsInOverlay() {
@@ -465,24 +421,26 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const activeItem: Doc = this.rootDoc;
const items: JSX.Element[] = [];
- if (activeItem.presPinLayout) {
- items.push(
- <Tooltip key="slide" title={<div className="dash-tooltip">Update captured doc layout</div>}>
- <div className="slideButton" onClick={() => this.updateCapturedContainerLayout(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}>
- L
- </div>
- </Tooltip>
- );
- }
- if (activeItem.presPinData || activeItem.presPinView) {
- items.push(
- <Tooltip key="flex" title={<div className="dash-tooltip">Update captured doc content</div>}>
- <div className="slideButton" onClick={() => this.updateCapturedViewContents(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}>
- C
- </div>
- </Tooltip>
- );
- }
+ items.push(
+ <Tooltip key="slide" title={<div className="dash-tooltip">Update captured doc layout</div>}>
+ <div
+ className="slideButton"
+ onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedContainerLayout(targetDoc, activeItem), true)}
+ style={{ opacity: activeItem.presPinLayout ? 1 : 0.5, fontWeight: 700, display: 'flex' }}>
+ L
+ </div>
+ </Tooltip>
+ );
+ items.push(
+ <Tooltip key="flex" title={<div className="dash-tooltip">Update captured doc content</div>}>
+ <div
+ className="slideButton"
+ onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedViewContents(targetDoc, activeItem))}
+ style={{ opacity: activeItem.presPinData || activeItem.presPinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}>
+ C
+ </div>
+ </Tooltip>
+ );
if (!Doc.noviceMode) {
items.push(
<Tooltip key="slash" title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}>
@@ -557,15 +515,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
paddingTop: NumCast(this.layoutDoc._yPadding, this.props.yPadding),
paddingBottom: NumCast(this.layoutDoc._yPadding, this.props.yPadding),
}}
- onClick={e => {
- e.stopPropagation();
- e.preventDefault();
- this.presBoxView?.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
- this.showRecording(activeItem);
- }}
onDoubleClick={action(e => {
this.toggleProperties();
- this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
+ this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
})}
onPointerOver={this.onPointerOver}
onPointerLeave={this.onPointerLeave}
@@ -599,7 +551,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
onPointerDown={e => {
e.stopPropagation();
if (this._itemRef.current && this._dragRef.current) {
- this.presBoxView?.modifierSelect(activeItem, this._itemRef.current, this._dragRef.current, false, false, false, true);
+ this.presBoxView?.modifierSelect(activeItem, this._itemRef.current, this._dragRef.current, true, false, false);
}
}}
onClick={e => e.stopPropagation()}>{`${this.indexInPres + 1}. `}</div>
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 3a7484cfd..6024705ec 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -1,3 +1,4 @@
+import { forEach } from 'lodash';
import { $mobx, action, observable, runInAction, trace } from 'mobx';
import { computedFn } from 'mobx-utils';
import { DocServer } from '../client/DocServer';