aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm
diff options
context:
space:
mode:
authorLionel Han <47760119+IGoByJoe@users.noreply.github.com>2020-09-04 19:02:50 -0700
committerLionel Han <47760119+IGoByJoe@users.noreply.github.com>2020-09-04 19:02:50 -0700
commite11c71a94016e3fe2529d0523fd62401baf90093 (patch)
tree3364d6a9ab147247b90ce9e390f4aef945afd0c5 /src/client/views/collections/collectionFreeForm
parent4767a10336309c679da60fd244548414c055ac50 (diff)
parent2ef7900d1210bc0e5261e1d1f8fd1ba5f3a0ee4c (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into new_audio
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx3
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx215
-rw-r--r--src/client/views/collections/collectionFreeForm/FormatShapePane.scss68
-rw-r--r--src/client/views/collections/collectionFreeForm/FormatShapePane.tsx558
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx18
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx72
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.scss731
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx1048
8 files changed, 163 insertions, 2550 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index b00074cc6..bc2cb2d20 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -10,6 +10,7 @@ import { Id, ToString } from "../../../../fields/FieldSymbols";
import { ObjectField } from "../../../../fields/ObjectField";
import { RefField } from "../../../../fields/RefField";
import { listSpec } from "../../../../fields/Schema";
+import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
export interface ViewDefBounds {
type: string;
@@ -359,7 +360,7 @@ export function computeTimelineLayout(
groupNames.push({ type: "text", text: toLabel(Math.ceil(maxTime)), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize, payload: undefined });
}
- const divider = { type: "div", color: Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "dimGray" : "black", x: 0, y: 0, width: panelDim[0], height: -1, payload: undefined };
+ const divider = { type: "div", color: CurrentUserUtils.ActiveDashboard?.darkScheme ? "dimGray" : "black", x: 0, y: 0, width: panelDim[0], height: -1, payload: undefined };
return normalizeResults(panelDim, fontHeight, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
function layoutDocsAtTime(keyDocs: Doc[], key: number) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 46e30f616..306dfe797 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,4 @@
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faEye } from "@fortawesome/free-regular-svg-icons";
-import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc";
@@ -15,7 +12,7 @@ import { ScriptField } from "../../../../fields/ScriptField";
import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
import { TraceMobx } from "../../../../fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils, setupMoveUpEvents } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
@@ -24,10 +21,12 @@ import { DocumentManager } from "../../../util/DocumentManager";
import { DragManager, dropActionType } from "../../../util/DragManager";
import { HistoryUtil } from "../../../util/History";
import { InteractionUtils } from "../../../util/InteractionUtils";
+import { LinkManager } from "../../../util/LinkManager";
+import { SearchUtil } from "../../../util/SearchUtil";
import { SelectionManager } from "../../../util/SelectionManager";
import { SnappingManager } from "../../../util/SnappingManager";
import { Transform } from "../../../util/Transform";
-import { undoBatch, UndoManager } from "../../../util/UndoManager";
+import { undoBatch } from "../../../util/UndoManager";
import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
import { Timeline } from "../../animationtimeline/Timeline";
import { ContextMenu } from "../../ContextMenu";
@@ -37,29 +36,25 @@ import { DocumentLinksButton } from "../../nodes/DocumentLinksButton";
import { DocumentViewProps } from "../../nodes/DocumentView";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { pageSchema } from "../../nodes/ImageBox";
+import { PresBox } from "../../nodes/PresBox";
import { CollectionDockingView } from "../CollectionDockingView";
import { CollectionSubView } from "../CollectionSubView";
import { CollectionViewType } from "../CollectionView";
import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines";
import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
import "./CollectionFreeFormView.scss";
-import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
+import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
-import { PresBox } from "../../nodes/PresBox";
-import { SearchUtil } from "../../../util/SearchUtil";
-import { LinkManager } from "../../../util/LinkManager";
-
-library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
export const panZoomSchema = createSchema({
_panX: "number",
_panY: "number",
- currentTimecode: "number",
+ _currentTimecode: "number",
displayTimecode: "number",
- currentFrame: "number",
+ _currentFrame: "number",
arrangeInit: ScriptField,
- useClusters: "boolean",
+ _useClusters: "boolean",
fitToBox: "boolean",
_xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
_yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
@@ -178,8 +173,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
newBox.y = y;
}
}
- if (this.Document.currentFrame !== undefined && !this.props.isAnnotationOverlay) {
- CollectionFreeFormDocumentView.setupKeyframes(newBoxes, this.Document.currentFrame);
+ if (this.Document._currentFrame !== undefined && !this.props.isAnnotationOverlay) {
+ CollectionFreeFormDocumentView.setupKeyframes(newBoxes, this.Document._currentFrame, true);
}
}
return retVal;
@@ -189,7 +184,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
SelectionManager.DeselectAll();
docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)).map(dv => dv && SelectionManager.SelectDoc(dv, true));
}
- public isCurrent(doc: Doc) { return (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
+ public isCurrent(doc: Doc) { return (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document._currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
public getActiveDocuments = () => {
return this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
@@ -212,9 +207,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
for (let i = 0; i < docDragData.droppedDocuments.length; i++) {
const d = docDragData.droppedDocuments[i];
const layoutDoc = Doc.Layout(d);
- if (this.Document.currentFrame !== undefined) {
+ if (this.Document._currentFrame !== undefined) {
const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
- CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, vals.opacity);
+ CollectionFreeFormDocumentView.setValues(this.Document._currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, vals.scroll, vals.opacity);
} else {
d.x = x + NumCast(d.x) - dropPos[0];
d.y = y + NumCast(d.y) - dropPos[1];
@@ -222,7 +217,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const nd = [NumCast(layoutDoc._nativeWidth), NumCast(layoutDoc._nativeHeight)];
layoutDoc._width = NumCast(layoutDoc._width, 300);
layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
- d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+ d._isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); // bringToFront
}
(docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments);
@@ -261,7 +256,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
- // if (this.props.Document.isBackground) return false;
+ // if (this.props.Document._isBackground) return false;
const [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
if (this.isAnnotationOverlay !== true && de.complete.linkDragData) {
return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp);
@@ -306,8 +301,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@undoBatch
@action
- updateClusters(useClusters: boolean) {
- this.props.Document.useClusters = useClusters;
+ updateClusters(_useClusters: boolean) {
+ this.props.Document._useClusters = _useClusters;
this._clusterSets.length = 0;
this.childLayoutPairs.map(pair => pair.layout).map(c => this.updateCluster(c));
}
@@ -315,7 +310,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
updateClusterDocs(docs: Doc[]) {
const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
- if (this.props.Document.useClusters) {
+ if (this.props.Document._useClusters) {
const docFirst = docs[0];
docs.map(doc => this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)));
const preferredInd = NumCast(docFirst.cluster);
@@ -325,7 +320,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
docFirst.cluster = i;
}
})));
- if (docFirst.cluster === -1 && preferredInd !== -1 && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
+ if (docFirst.cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
docFirst.cluster = preferredInd;
}
this._clusterSets.map((set, i) => {
@@ -338,7 +333,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
doc.cluster = this._clusterSets.length;
this._clusterSets.push([doc]);
});
- } else {
+ } else if (this._clusterSets.length) {
for (let i = this._clusterSets.length; i <= NumCast(docFirst.cluster); i++) !this._clusterSets[i] && this._clusterSets.push([]);
docs.map(doc => this._clusterSets[doc.cluster = NumCast(docFirst.cluster)].push(doc));
}
@@ -350,7 +345,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
updateCluster(doc: Doc) {
const childLayouts = this.childLayoutPairs.map(pair => pair.layout);
- if (this.props.Document.useClusters) {
+ if (this.props.Document._useClusters) {
this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1));
const preferredInd = NumCast(doc.cluster);
doc.cluster = -1;
@@ -359,7 +354,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
doc.cluster = i;
}
}));
- if (doc.cluster === -1 && preferredInd !== -1 && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
+ if (doc.cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) {
doc.cluster = preferredInd;
}
this._clusterSets.map((set, i) => {
@@ -370,7 +365,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (doc.cluster === -1) {
doc.cluster = this._clusterSets.length;
this._clusterSets.push([doc]);
- } else {
+ } else if (this._clusterSets.length) {
for (let i = this._clusterSets.length; i <= doc.cluster; i++) !this._clusterSets[i] && this._clusterSets.push([]);
this._clusterSets[doc.cluster].push(doc);
}
@@ -380,7 +375,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
getClusterColor = (doc: Doc) => {
let clusterColor = this.props.backgroundColor?.(doc, this.props.renderDepth + 1);
const cluster = NumCast(doc.cluster);
- if (this.Document.useClusters) {
+ if (this.Document._useClusters) {
if (this._clusterSets.length <= cluster) {
setTimeout(() => this.updateCluster(doc), 0);
} else {
@@ -389,8 +384,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
clusterColor = colors[cluster % colors.length];
const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
// override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document
- set && set.filter(s => !s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
- set && set.filter(s => s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
+ set && set.filter(s => !s._isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
+ set && set.filter(s => s._isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
}
}
return clusterColor;
@@ -402,7 +397,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if (e.nativeEvent.cancelBubble || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) {
return;
}
- this._hitCluster = this.props.Document.useClusters ? this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)) !== -1 : false;
+ this._hitCluster = this.props.Document._useClusters ? this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)) !== -1 : false;
if (e.button === 0 && (!e.shiftKey || this._hitCluster) && !e.altKey && !e.ctrlKey && this.props.active(true)) {
// if (!this.props.Document.aliasOf && !this.props.ContainingCollectionView) {
@@ -591,7 +586,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
onClick = (e: React.MouseEvent) => {
if (this.layoutDoc.targetScale && (Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
if (Date.now() - this._lastTap < 300) {
- runInAction(() => DocumentLinksButton.StartLink = undefined);
+ runInAction(() => {
+ DocumentLinksButton.StartLink = undefined;
+ DocumentLinksButton.StartLinkView = undefined;
+ });
const docpt = this.getTransform().transformPoint(e.clientX, e.clientY);
this.scaleAtPt(docpt, 1);
e.stopPropagation();
@@ -605,7 +603,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => {
// bcz: theres should be a better way of doing these than referencing these static instances directly
MarqueeOptionsMenu.Instance?.fadeOut(true);// I think it makes sense for the marquee menu to go away when panned. -syip2
- // PDFMenu.Instance.fadeOut(true); (commented out for mobile)
const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true);
@@ -641,7 +638,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
- // panning a workspace
if (!e.cancelBubble) {
const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
const pt = myTouches[0];
@@ -843,14 +839,14 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
bringToFront = action((doc: Doc, sendToBack?: boolean) => {
- if (sendToBack || doc.isBackground) {
+ if (sendToBack || doc._isBackground) {
doc.zIndex = 0;
} else if (doc.isInkMask) {
doc.zIndex = 5000;
} else {
const docs = this.childLayoutPairs.map(pair => pair.layout);
docs.slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
- let zlast = docs.length ? NumCast(docs[docs.length - 1].zIndex) : 1;
+ let zlast = docs.length ? Math.max(docs.length, NumCast(docs[docs.length - 1].zIndex)) : 1;
if (zlast - docs.length > 100) {
for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1;
zlast = docs.length + 1;
@@ -908,10 +904,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document[this.scaleFieldKey], pt: this.Document._viewTransition };
- // if (!willZoom && DocumentView._focusHack.length) {
- // Doc.BrushDoc(this.props.Document);
- // !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1);
- // } else {
if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
// glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
if (!doc.z) this.setPan(newPanX, newPanY, doc.presTransition || doc.presTransition === 0 ? `transform ${doc.presTransition}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
@@ -920,7 +912,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.focus(this.props.Document);
willZoom && this.setScaleToZoom(layoutdoc, scale);
Doc.linkFollowHighlight(doc);
- //}
afterFocus && setTimeout(() => {
if (afterFocus?.()) {
@@ -939,10 +930,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
@computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
- @computed get backgroundActive() { return this.layoutDoc.isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); }
+ @computed get backgroundActive() { return this.layoutDoc._isBackground && (this.props.ContainingCollectionView?.active() || this.props.active()); }
onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
- backgroundHalo = () => BoolCast(this.Document.useClusters);
+ backgroundHalo = () => BoolCast(this.Document._useClusters);
parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.backgroundActive ? true : false;
getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
return {
@@ -975,6 +966,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
ContainingCollectionView: this.props.CollectionView,
ContainingCollectionDoc: this.props.Document,
docFilters: this.docFilters,
+ searchFilterDocs: this.searchFilterDocs,
focus: this.focusDocument,
backgroundColor: this.getClusterColor,
backgroundHalo: this.backgroundHalo,
@@ -1008,8 +1000,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
});
getCalculatedPositions(params: { pair: { layout: Doc, data?: Doc }, index: number, collection: Doc, docs: Doc[], state: any }): PoolData {
const layoutDoc = Doc.Layout(params.pair.layout);
- const { x, y, opacity } = this.Document.currentFrame === undefined ? params.pair.layout :
- CollectionFreeFormDocumentView.getValues(params.pair.layout, this.Document.currentFrame || 0);
+ const { x, y, opacity } = this.Document._currentFrame === undefined ? params.pair.layout :
+ CollectionFreeFormDocumentView.getValues(params.pair.layout, this.Document._currentFrame || 0);
const { z, color, zIndex } = params.pair.layout;
return {
x: NumCast(x), y: NumCast(y), z: Cast(z, "number"), color: StrCast(color), zIndex: Cast(zIndex, "number"),
@@ -1045,7 +1037,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
} else if (viewDef.type === "div") {
return [x, y].some(val => val === undefined) ? undefined :
{
- ele: <div className="collectionFreeform-customDiv" title={viewDef.payload?.join(" ")} key={"div" + x + y + z} onClick={e => this.onViewDefDivClick(e, viewDef)}
+ ele: <div className="collectionFreeform-customDiv" title={viewDef.payload?.join(" ")} key={"div" + x + y + z + viewDef.payload} onClick={e => this.onViewDefDivClick(e, viewDef)}
style={{ width, height, backgroundColor: color, transform }} />,
bounds: viewDef
};
@@ -1140,7 +1132,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.Document[this.scaleFieldKey] = Math.max(1, NumCast(this.props.Document[this.scaleFieldKey]));
}
- this.Document.useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true);
+ this.Document._useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true);
return elements;
}
@@ -1175,7 +1167,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
if ((e as any).handlePan || this.props.isAnnotationOverlay) return;
(e as any).handlePan = true;
- if (this._marqueeRef?.current) {
+ if (!this.props.Document._noAutoscroll && this._marqueeRef?.current) {
const dragX = e.detail.clientX;
const dragY = e.detail.clientY;
const bounds = this._marqueeRef.current?.getBoundingClientRect();
@@ -1252,15 +1244,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
!Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null;
- !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document.useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }) : null;
+ !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null;
!viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" });
const options = ContextMenu.Instance.findByDescription("Options...");
const optionItems = options && "subitems" in options ? options.subitems : [];
!this.props.isAnnotationOverlay && !Doc.UserDoc().noviceMode &&
- optionItems.push({ description: (this.showTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this.showTimeline = !this.showTimeline), icon: faEye });
+ optionItems.push({ description: (this.showTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this.showTimeline = !this.showTimeline), icon: "eye" });
this.props.ContainingCollectionView &&
- optionItems.push({ description: "Undo Collection", event: this.promoteCollection, icon: "table" });
+ optionItems.push({ description: "Move Items Out of Collection", event: this.promoteCollection, icon: "table" });
optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" });
optionItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
if (!Doc.UserDoc().noviceMode) {
@@ -1315,7 +1307,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
@action
- setupDragLines = () => {
+ setupDragLines = (snapToDraggedDoc: boolean = false) => {
const activeDocs = this.getActiveDocuments();
if (activeDocs.length > 50) {
DragManager.SetSnapLines([], []);
@@ -1331,13 +1323,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
};
const snappableDocs: Doc[] = []; // the set of documents in the visible viewport that we will try to snap to;
const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) };
- this.getActiveDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to
+ this.getActiveDocuments().filter(doc => !doc._isBackground && doc.z === undefined).map(doc => isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to
!snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => isDocInView(doc, selRect)); // if not, see if there are background docs to snap to
!snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => isDocInView(doc, otherBounds)); // if not, then why not snap to floating docs
const horizLines: number[] = [];
const vertLines: number[] = [];
- snappableDocs.filter(doc => !DragManager.docsBeingDragged.includes(Cast(doc.rootDocument, Doc, null) || doc)).forEach(doc => {
+ snappableDocs.filter(doc => snapToDraggedDoc || !DragManager.docsBeingDragged.includes(Cast(doc.rootDocument, Doc, null) || doc)).forEach(doc => {
const { left, top, width, height } = docDims(doc);
const topLeftInScreen = this.getTransform().inverse().transformPoint(left, top);
const docSize = this.getTransform().inverse().transformDirection(width, height);
@@ -1349,7 +1341,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
onPointerOver = (e: React.PointerEvent) => {
if (SnappingManager.GetIsDragging()) {
- this.setupDragLines();
+ this.setupDragLines(e.ctrlKey || e.shiftKey);
}
e.stopPropagation();
}
@@ -1406,12 +1398,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
centeringShiftY={this.centeringShiftY}
presPaths={BoolCast(this.Document.presPathView)}
progressivize={BoolCast(this.Document.editProgressivize)}
- zoomProgressivize={BoolCast(this.Document.editZoomProgressivize)}
+ presPinView={BoolCast(this.Document.presPinView)}
transition={Cast(this.layoutDoc._viewTransition, "string", null)}
viewDefDivClick={this.props.viewDefDivClick}
zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
{this.children}
- </CollectionFreeFormViewPannableContents></div>
+ </CollectionFreeFormViewPannableContents>
+ </div>
{this.showTimeline ? <Timeline ref={this._timelineRef} {...this.props} /> : (null)}
</MarqueeView>;
}
@@ -1424,7 +1417,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const wscale = nw ? this.props.PanelWidth() / nw : 1;
return wscale < hscale ? wscale : hscale;
}
- @computed get backgroundEvents() { return this.layoutDoc.isBackground && SnappingManager.GetIsDragging(); }
+ @computed get backgroundEvents() { return this.layoutDoc._isBackground && SnappingManager.GetIsDragging(); }
render() {
TraceMobx();
const clientRect = this._mainCont?.getBoundingClientRect();
@@ -1492,7 +1485,7 @@ interface CollectionFreeFormViewPannableContentsProps {
transition?: string;
presPaths?: boolean;
progressivize?: boolean;
- zoomProgressivize?: boolean;
+ presPinView?: boolean;
}
@observer
@@ -1559,48 +1552,27 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
doc.style.top = toNumber(top, e.movementY) + 'px';
doc.style.left = toNumber(left, e.movementX) + 'px';
}
- this.updateAll(height, width, top, left);
+ // this.updateAll(height, width, top, left);
return false;
}
return true;
}
- @action
- updateAll = (width: number, height: number, top: number, left: number) => {
- const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null);
- const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- this.updateList(targetDoc, activeItem["viewfinder-width-indexed"], width);
- this.updateList(targetDoc, activeItem["viewfinder-height-indexed"], height);
- this.updateList(targetDoc, activeItem["viewfinder-top-indexed"], top);
- this.updateList(targetDoc, activeItem["viewfinder-left-indexed"], left);
- }
-
- @action
- updateList = (doc: Doc, list: any, val: number) => {
- const x: List<number> = list;
- if (x && x.length >= NumCast(doc.currentFrame) + 1) {
- x[NumCast(doc.currentFrame)] = val;
- list = x;
- } else if (doc && x) {
- x.length = NumCast(doc.currentFrame) + 1;
- x[NumCast(doc.currentFrame)] = val;
- list = x;
- }
- }
-
// scale: NumCast(targetDoc._viewScale),
@computed get zoomProgressivizeContainer() {
- const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null);
- const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- if (activeItem && activeItem.zoomProgressivize) {
- const vfLeft: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-left-indexed"]);
- const vfWidth: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-width-indexed"]);
- const vfTop: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-top-indexed"]);
- const vfHeight: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-height-indexed"]);
+ const activeItem = PresBox.Instance.activeItem;
+ // const targetDoc = PresBox.Instance.targetDoc;
+ if (activeItem && activeItem.presPinView && activeItem.id) {
+ const vfLeft: number = NumCast(activeItem.presPinViewX);
+ const vfTop: number = NumCast(activeItem.presPinViewY);
+ const vfWidth: number = 100;
+ const vfHeight: number = 100;
+ console.log(vfTop + " | " + vfLeft);
+ console.log(this.props.presPinView);
return (
<>
- {!activeItem.editZoomProgressivize ? (null) : <div id="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}>
- <div className='resizers'>
+ {!this.props.presPinView ? (null) : <div id="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}>
+ <div className='resizers' key={'resizer' + activeItem.id}>
<div id="resizer-tl" className='resizer top-left' onPointerDown={this.onPointerDown}></div>
<div id="resizer-tr" className='resizer top-right' onPointerDown={this.onPointerDown}></div>
<div id="resizer-bl" className='resizer bottom-left' onPointerDown={this.onPointerDown}></div>
@@ -1613,7 +1585,7 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
}
@computed get zoomProgressivize() {
- return PresBox.Instance && this.props.zoomProgressivize ? this.zoomProgressivizeContainer : (null);
+ return PresBox.Instance && PresBox.Instance.activeItem && PresBox.Instance.activeItem.presPinView && PresBox.Instance.layoutDoc.presStatus === 'edit' ? this.zoomProgressivizeContainer : (null);
}
@computed get progressivize() {
@@ -1622,30 +1594,30 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
@computed get presPaths() {
const presPaths = "presPaths" + (this.props.presPaths ? "" : "-hidden");
- return !(PresBox.Instance) ? (null) : (<>
- {!this.props.presPaths ? (null) : <><div>{PresBox.Instance.order}</div>
- <svg className={presPaths}>
- <defs>
- <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
- <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" />
- </marker>
- <marker id="square" markerWidth="3" markerHeight="3" overflow="visible"
- refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
- <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" />
- </marker>
- <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4"
- orient="auto" overflow="visible">
- <rect x="1" y="1" width="5" height="5" fill="#69a6db" />
- </marker>
-
- <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7"
- orient="auto" overflow="visible">
- <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" />
- </marker>
- </defs>;
- {PresBox.Instance.paths}
- </svg></>}
- </>);
+ return !PresBox.Instance || !this.props.presPaths ? (null) : <>
+ <div key="presorder">{PresBox.Instance.order}</div>
+ <svg key="svg" className={presPaths}>
+ <defs>
+ <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" />
+ </marker>
+ <marker id="square" markerWidth="3" markerHeight="3" overflow="visible"
+ refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+ <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" />
+ </marker>
+ <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4"
+ orient="auto" overflow="visible">
+ <rect x="1" y="1" width="5" height="5" fill="#69a6db" />
+ </marker>
+
+ <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7"
+ orient="auto" overflow="visible">
+ <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" />
+ </marker>
+ </defs>
+ {PresBox.Instance.paths}
+ </svg>
+ </>;
}
render() {
@@ -1659,7 +1631,8 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
return <div className={freeformclass}
style={{
transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`,
- transition: this.props.transition
+ transition: this.props.transition,
+ //willChange: "transform"
}}>
{this.props.children()}
{this.presPaths}
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.scss b/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
deleted file mode 100644
index d49ab27fb..000000000
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
+++ /dev/null
@@ -1,68 +0,0 @@
-.antimodeMenu-button {
- width: 200px;
- position: relative;
- text-align: left;
-
- .color-previewI {
- width: 100%;
- height: 40%;
- }
-
- .color-previewII {
- width: 100%;
- height: 100%;
- }
-}
-
-.antimenu-Buttonup {
- position: absolute;
- width: 20;
- height: 10;
- right: 0;
- padding: 0;
-}
-
-.formatShapePane-inputBtn {
- width: inherit;
- position: absolute;
-}
-
-.btn-group-palette {
- .sketch-picker {
- background: #323232;
- width: 160px !important;
- height: 80% !important;
-
- .flexbox-fit {
- background: #323232;
- }
- }
-}
-
-.btn-group {
- display: grid;
- grid-template-columns: auto auto auto auto;
- /* Make the buttons appear below each other */
-}
-
-.btn-group-palette {
- display: block;
- /* Make the buttons appear below each other */
-}
-
-.btn-draw {
- display: inline;
- /* Make the buttons appear below each other */
-}
-
-.btn2-group {
- display: block;
- background: #323232;
- grid-template-columns: auto;
-
- /* Make the buttons appear below each other */
- .antimodeMenu-button {
- background: #323232;
- display: block;
- }
-} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx b/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
deleted file mode 100644
index 1ffa2fbed..000000000
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.tsx
+++ /dev/null
@@ -1,558 +0,0 @@
-import React = require("react");
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import { Doc, Field, Opt } from "../../../../fields/Doc";
-import { Document } from "../../../../fields/documentSchemas";
-import { InkField } from "../../../../fields/InkField";
-import { BoolCast, Cast, NumCast } from "../../../../fields/Types";
-import { DocumentType } from "../../../documents/DocumentTypes";
-import { SelectionManager } from "../../../util/SelectionManager";
-import AntimodeMenu from "../../AntimodeMenu";
-import "./FormatShapePane.scss";
-import { undoBatch } from "../../../util/UndoManager";
-import { ColorState, SketchPicker } from 'react-color';
-
-@observer
-export default class FormatShapePane extends AntimodeMenu {
- static Instance: FormatShapePane;
-
- private _lastFill = "#D0021B";
- private _lastLine = "#D0021B";
- private _lastDash = "2";
- private _mode = ["fill-drip", "ruler-combined"];
-
- @observable private _subOpen = [false, false];
- @observable private _currMode = "fill-drip";
- @observable _lock = false;
- @observable private _fillBtn = false;
- @observable private _lineBtn = false;
- @observable _controlBtn = false;
- @observable private _controlPoints: { X: number, Y: number }[] = [];
- @observable _currPoint = -1;
-
- getField(key: string) {
- return this.selectedInk?.reduce((p, i) =>
- (p === undefined || (p && p === i.rootDoc[key])) && i.rootDoc[key] !== "0" ? Field.toString(i.rootDoc[key] as Field) : "", undefined as Opt<string>);
- }
-
- @computed get selectedInk() {
- const inks = SelectionManager.SelectedDocuments().filter(i => Document(i.rootDoc).type === DocumentType.INK);
- return inks.length ? inks : undefined;
- }
- @computed get unFilled() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.fillColor ? true : false, true) || false; }
- @computed get unStrokd() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.color ? true : false, true) || false; }
- @computed get solidFil() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.fillColor ? true : false, true) || false; }
- @computed get solidStk() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.color && (!i.rootDoc.strokeDash || i.rootDoc.strokeDash === "0") ? true : false, true) || false; }
- @computed get dashdStk() { return !this.unStrokd && this.getField("strokeDash") || ""; }
- @computed get colorFil() { const ccol = this.getField("fillColor") || ""; ccol && (this._lastFill = ccol); return ccol; }
- @computed get colorStk() { const ccol = this.getField("color") || ""; ccol && (this._lastLine = ccol); return ccol; }
- @computed get widthStk() { return this.getField("strokeWidth") || "1"; }
- @computed get markHead() { return this.getField("strokeStartMarker") || ""; }
- @computed get markTail() { return this.getField("strokeEndMarker") || ""; }
- @computed get shapeHgt() { return this.getField("_height"); }
- @computed get shapeWid() { return this.getField("_width"); }
- @computed get shapeXps() { return this.getField("x"); }
- @computed get shapeYps() { return this.getField("y"); }
- @computed get shapeRot() { return this.getField("rotation"); }
- set unFilled(value) { this.colorFil = value ? "" : this._lastFill; }
- set solidFil(value) { this.unFilled = !value; }
- set colorFil(value) { value && (this._lastFill = value); this.selectedInk?.forEach(i => i.rootDoc.fillColor = value ? value : undefined); }
- set colorStk(value) { value && (this._lastLine = value); this.selectedInk?.forEach(i => i.rootDoc.color = value ? value : undefined); }
- set markHead(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeStartMarker = value); }
- set markTail(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeEndMarker = value); }
- set unStrokd(value) { this.colorStk = value ? "" : this._lastLine; }
- set solidStk(value) { this.dashdStk = ""; this.unStrokd = !value; }
- set dashdStk(value) {
- value && (this._lastDash = value) && (this.unStrokd = false);
- this.selectedInk?.forEach(i => i.rootDoc.strokeDash = value ? this._lastDash : undefined);
- }
- set shapeXps(value) { this.selectedInk?.forEach(i => i.rootDoc.x = Number(value)); }
- set shapeYps(value) { this.selectedInk?.forEach(i => i.rootDoc.y = Number(value)); }
- set shapeRot(value) { this.selectedInk?.forEach(i => i.rootDoc.rotation = Number(value)); }
- set widthStk(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeWidth = Number(value)); }
- set shapeWid(value) {
- this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
- const oldWidth = NumCast(i.rootDoc._width);
- i.rootDoc._width = Number(value);
- this._lock && (i.rootDoc._height = (i.rootDoc._width * NumCast(i.rootDoc._height)) / oldWidth);
- });
- }
- set shapeHgt(value) {
- this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
- const oldHeight = NumCast(i.rootDoc._height);
- i.rootDoc._height = Number(value);
- this._lock && (i.rootDoc._width = (i.rootDoc._height * NumCast(i.rootDoc._width)) / oldHeight);
- });
- }
-
- constructor(props: Readonly<{}>) {
- super(props);
- FormatShapePane.Instance = this;
- this._canFade = false;
- this.Pinned = BoolCast(Doc.UserDoc()["menuFormatShape-pinned"]);
- }
-
- @action
- closePane = () => {
- this.fadeOut(false);
- this.Pinned = false;
- }
-
- @action
- upDownButtons = (dirs: string, field: string) => {
- switch (field) {
- case "rot": this.rotate((dirs === "up" ? .1 : -.1)); break;
- // case "rot": this.selectedInk?.forEach(i => i.rootDoc.rotation = NumCast(i.rootDoc.rotation) + (dirs === "up" ? 0.1 : -0.1)); break;
- case "Xps": this.selectedInk?.forEach(i => i.rootDoc.x = NumCast(i.rootDoc.x) + (dirs === "up" ? 10 : -10)); break;
- case "Yps": this.selectedInk?.forEach(i => i.rootDoc.y = NumCast(i.rootDoc.y) + (dirs === "up" ? 10 : -10)); break;
- case "stk": this.selectedInk?.forEach(i => i.rootDoc.strokeWidth = NumCast(i.rootDoc.strokeWidth) + (dirs === "up" ? .1 : -.1)); break;
- case "wid": this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
- //redraw points
- const oldWidth = NumCast(i.rootDoc._width);
- const oldHeight = NumCast(i.rootDoc._height);
- const oldX = NumCast(i.rootDoc.x);
- const oldY = NumCast(i.rootDoc.y);
- i.rootDoc._width = oldWidth + (dirs === "up" ? 10 : - 10);
- this._lock && (i.rootDoc._height = (i.rootDoc._width / oldWidth * NumCast(i.rootDoc._height)));
- const doc = Document(i.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
- console.log(doc.x, doc.y, doc._height, doc._width);
- const ink = Cast(doc.data, InkField)?.inkData;
- console.log(ink);
- if (ink) {
- const newPoints: { X: number, Y: number }[] = [];
- ink.forEach(i => {
- // (new x — oldx) + (oldxpoint * newWidt)/oldWidth
- const newX = ((doc.x || 0) - oldX) + (i.X * (doc._width || 0)) / oldWidth;
- const newY = ((doc.y || 0) - oldY) + (i.Y * (doc._height || 0)) / oldHeight;
- newPoints.push({ X: newX, Y: newY });
- });
- doc.data = new InkField(newPoints);
- }
- }
- });
- break;
- case "hgt": this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
- const oldWidth = NumCast(i.rootDoc._width);
- const oldHeight = NumCast(i.rootDoc._height);
- const oldX = NumCast(i.rootDoc.x);
- const oldY = NumCast(i.rootDoc.y); i.rootDoc._height = oldHeight + (dirs === "up" ? 10 : - 10);
- this._lock && (i.rootDoc._width = (i.rootDoc._height / oldHeight * NumCast(i.rootDoc._width)));
- const doc = Document(i.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
- console.log(doc.x, doc.y, doc._height, doc._width);
- const ink = Cast(doc.data, InkField)?.inkData;
- console.log(ink);
- if (ink) {
- const newPoints: { X: number, Y: number }[] = [];
- ink.forEach(i => {
- // (new x — oldx) + (oldxpoint * newWidt)/oldWidth
- const newX = ((doc.x || 0) - oldX) + (i.X * (doc._width || 0)) / oldWidth;
- const newY = ((doc.y || 0) - oldY) + (i.Y * (doc._height || 0)) / oldHeight;
- newPoints.push({ X: newX, Y: newY });
- });
- doc.data = new InkField(newPoints);
- }
- }
- });
- break;
- }
- }
-
- @undoBatch
- @action
- addPoints = (x: number, y: number, pts: { X: number, Y: number }[], index: number, control: { X: number, Y: number }[]) => {
- this.selectedInk?.forEach(action(inkView => {
- if (this.selectedInk?.length === 1) {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
- const newPoints: { X: number, Y: number }[] = [];
- var counter = 0;
- for (var k = 0; k < index; k++) {
- control.forEach(pt => (pts[k].X === pt.X && pts[k].Y === pt.Y) && counter++);
- }
- //decide where to put the new coordinate
- const spNum = Math.floor(counter / 2) * 4 + 2;
-
- for (var i = 0; i < spNum; i++) {
- newPoints.push({ X: ink[i].X, Y: ink[i].Y });
- }
- for (var j = 0; j < 4; j++) {
- newPoints.push({ X: x, Y: y });
-
- }
- for (var i = spNum; i < ink.length; i++) {
- newPoints.push({ X: ink[i].X, Y: ink[i].Y });
- }
- this._currPoint = -1;
- doc.data = new InkField(newPoints);
- }
- }
- }
- }));
- }
-
- @undoBatch
- @action
- deletePoints = () => {
- this.selectedInk?.forEach(action(inkView => {
- if (this.selectedInk?.length === 1 && this._currPoint !== -1) {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink && ink.length > 4) {
- const newPoints: { X: number, Y: number }[] = [];
-
- console.log(ink.length, this._currPoint, Math.floor((this._currPoint + 2) / 4));
-
- const toRemove = Math.floor(((this._currPoint + 2) / 4));
- for (var i = 0; i < ink.length; i++) {
- if (Math.floor((i + 2) / 4) !== toRemove) {
- console.log(i, toRemove);
- newPoints.push({ X: ink[i].X, Y: ink[i].Y });
- }
- }
- this._currPoint = -1;
- doc.data = new InkField(newPoints);
- if (newPoints.length === 4) {
- const newerPoints: { X: number, Y: number }[] = [];
- newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
- newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
- newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
- newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
- doc.data = new InkField(newerPoints);
-
- }
- }
- }
- }
- }));
- }
-
- @undoBatch
- @action
- rotate = (angle: number) => {
- const _centerPoints: { X: number, Y: number }[] = [];
- SelectionManager.SelectedDocuments().forEach(action(inkView => {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
- const xs = ink.map(p => p.X);
- const ys = ink.map(p => p.Y);
- const left = Math.min(...xs);
- const top = Math.min(...ys);
- const right = Math.max(...xs);
- const bottom = Math.max(...ys);
- _centerPoints.push({ X: left, Y: top });
- }
- }
- }));
-
- var index = 0;
- SelectionManager.SelectedDocuments().forEach(action(inkView => {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- doc.rotation = Number(doc.rotation) + Number(angle);
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
-
- const newPoints: { X: number, Y: number }[] = [];
- ink.forEach(i => {
- const newX = Math.cos(angle) * (i.X - _centerPoints[index].X) - Math.sin(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].X;
- const newY = Math.sin(angle) * (i.X - _centerPoints[index].X) + Math.cos(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
- newPoints.push({ X: newX, Y: newY });
- });
- doc.data = new InkField(newPoints);
- const xs = newPoints.map(p => p.X);
- const ys = newPoints.map(p => p.Y);
- const left = Math.min(...xs);
- const top = Math.min(...ys);
- const right = Math.max(...xs);
- const bottom = Math.max(...ys);
-
- doc._height = (bottom - top);
- doc._width = (right - left);
- }
- index++;
- }
- }));
- }
-
- @undoBatch
- @action
- control = (xDiff: number, yDiff: number, controlNum: number) => {
- this.selectedInk?.forEach(action(inkView => {
- if (this.selectedInk?.length === 1) {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
-
- const newPoints: { X: number, Y: number }[] = [];
- const order = controlNum % 4;
- for (var i = 0; i < ink.length; i++) {
- if (controlNum === i ||
- (order === 0 && i === controlNum + 1) ||
- (order === 0 && controlNum !== 0 && i === controlNum - 2) ||
- (order === 0 && controlNum !== 0 && i === controlNum - 1) ||
- (order === 3 && i === controlNum - 1) ||
- (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 1) ||
- (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2)
- || ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1))
- ) {
- newPoints.push({ X: ink[i].X - (xDiff * inkView.props.ScreenToLocalTransform().Scale), Y: ink[i].Y - (yDiff * inkView.props.ScreenToLocalTransform().Scale) });
- }
- else {
- newPoints.push({ X: ink[i].X, Y: ink[i].Y });
- }
- }
- const oldx = doc.x;
- const oldy = doc.y;
- const xs = ink.map(p => p.X);
- const ys = ink.map(p => p.Y);
- const left = Math.min(...xs);
- const top = Math.min(...ys);
- doc.data = new InkField(newPoints);
- const xs2 = newPoints.map(p => p.X);
- const ys2 = newPoints.map(p => p.Y);
- const left2 = Math.min(...xs2);
- const top2 = Math.min(...ys2);
- const right2 = Math.max(...xs2);
- const bottom2 = Math.max(...ys2);
- doc._height = (bottom2 - top2);
- doc._width = (right2 - left2);
- //if points move out of bounds
-
- doc.x = oldx - (left - left2);
- doc.y = oldy - (top - top2);
-
- }
- }
- }
- }));
- }
-
- @undoBatch
- @action
- switchStk = (color: ColorState) => {
- const val = String(color.hex);
- this.colorStk = val;
- return true;
- }
-
- @undoBatch
- @action
- switchFil = (color: ColorState) => {
- const val = String(color.hex);
- this.colorFil = val;
- return true;
- }
-
-
- colorPicker(setter: (color: string) => {}, type: string) {
- return <div className="btn-group-palette" key="colorpicker" style={{ width: 160, margin: 10 }}>
- <SketchPicker onChange={type === "stk" ? this.switchStk : this.switchFil} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- color={type === "stk" ? this.colorStk : this.colorFil} />
- </div>;
- }
- inputBox = (key: string, value: any, setter: (val: string) => {}) => {
- return <>
- <input style={{ color: "black", width: 40, position: "absolute", right: 20 }}
- type="text" value={value}
- onChange={undoBatch(action((e) => setter(e.target.value)))}
- autoFocus />
- <button className="antiMenu-Buttonup" key="up1" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))}>
- ˄
- </button>
- <br />
- <button className="antiMenu-Buttonup" key="down1" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} style={{ marginTop: -8 }}>
- ˅
- </button>
- </>;
- }
-
- inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => {
- return <>
- {title1}
- <p style={{ marginTop: -20, right: 70, position: "absolute" }}>{title2}</p>
-
- <input style={{ color: "black", width: 40, position: "absolute", right: 130 }}
- type="text" value={value}
- onChange={e => setter(e.target.value)}
- autoFocus />
- <button className="antiMenu-Buttonup" key="up2" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))} style={{ right: 110 }}>
- ˄
- </button>
- <button className="antiMenu-Buttonup" key="down2" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} style={{ marginTop: 12, right: 110 }}>
- ˅
- </button>
- {title2 === "" ? "" : <>
- <input style={{ color: "black", width: 40, position: "absolute", right: 20 }}
- type="text" value={value2}
- onChange={e => setter2(e.target.value)}
- autoFocus />
- <button className="antiMenu-Buttonup" key="up3" onPointerDown={undoBatch(action(() => this.upDownButtons("up", key2)))}>
- ˄
- </button>
- <br />
- <button className="antiMenu-Buttonup" key="down3" onPointerDown={undoBatch(action(() => this.upDownButtons("down", key2)))} style={{ marginTop: -8 }}>
- ˅
- </button></>}
- </>;
- }
-
-
- colorButton(value: string, setter: () => {}) {
- return <>
- <button className="antimodeMenu-button" key="color" onPointerDown={undoBatch(action(e => setter()))} style={{ position: "relative", marginTop: -5 }}>
- <div className="color-previewII" style={{ backgroundColor: value ?? "121212" }} />
- {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -23, position: "fixed" }}>☒</p> : ""}
- </button>
- </>;
- }
-
- controlPointsButton() {
- return <>
- <button className="antimodeMenu-button" title="Edit points" key="bezier" onPointerDown={action(() => this._controlBtn = this._controlBtn ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._controlBtn ? "black" : "" }}>
- <FontAwesomeIcon icon="bezier-curve" size="lg" />
- </button>
- <button className="antimodeMenu-button" title="Lock ratio" key="ratio" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "relative", marginTop: 10, backgroundColor: this._lock ? "black" : "" }}>
- <FontAwesomeIcon icon="lock" size="lg" />
-
- </button>
- <button className="antimodeMenu-button" key="rotate" title="Rotate 90˚" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "relative", marginTop: 10, fontSize: 15 }}>
- ⟲
- </button>
- <br /> <br />
- </>;
- }
-
- lockRatioButton() {
- return <>
- <button className="antimodeMenu-button" key="lock" onPointerDown={action(() => this._lock = this._lock ? false : true)} style={{ position: "absolute", right: 80, backgroundColor: this._lock ? "black" : "" }}>
- {/* <FontAwesomeIcon icon="bezier-curve" size="lg" /> */}
- <FontAwesomeIcon icon="lock" size="lg" />
-
- </button>
- <br /> <br />
- </>;
- }
-
- rotate90Button() {
- return <>
- <button className="antimodeMenu-button" key="rot" onPointerDown={action(() => this.rotate(Math.PI / 2))} style={{ position: "absolute", right: 80, }}>
- {/* <FontAwesomeIcon icon="bezier-curve" size="lg" /> */}
- ⟲
-
- </button>
- <br /> <br />
- </>;
- }
- @computed get fillButton() { return this.colorButton(this.colorFil, () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
- @computed get lineButton() { return this.colorButton(this.colorStk, () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
-
- @computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); }
- @computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); }
-
- @computed get stkInput() { return this.inputBox("stk", this.widthStk, (val: string) => this.widthStk = val); }
- @computed get dashInput() { return this.inputBox("dsh", this.widthStk, (val: string) => this.widthStk = val); }
-
- @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => this.shapeHgt = val, "H:", "wid", this.shapeWid, (val: string) => this.shapeWid = val, "W:"); }
- @computed get widInput() { return this.inputBox("wid", this.shapeWid, (val: string) => this.shapeWid = val); }
- @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); }
-
- @computed get YpsInput() { return this.inputBox("Yps", this.shapeYps, (val: string) => this.shapeYps = val); }
-
- @computed get controlPoints() { return this.controlPointsButton(); }
- @computed get lockRatio() { return this.lockRatioButton(); }
- @computed get rotate90() { return this.rotate90Button(); }
- @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
-
-
- @computed get propertyGroupItems() {
- const fillCheck = <div key="fill" style={{ display: (this._subOpen[0] && this.selectedInk && this.selectedInk.length >= 1) ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
- Fill:
- {this.fillButton}
- <div style={{ float: "left", width: 100 }} >
- Stroke:
- {this.lineButton}
- </div>
-
- {this._fillBtn ? this.fillPicker : ""}
- {this._lineBtn ? this.linePicker : ""}
- {this._fillBtn || this._lineBtn ? "" : <br />}
- {(this.solidStk || this.dashdStk) ? "Width" : ""}
- {(this.solidStk || this.dashdStk) ? this.stkInput : ""}
-
-
- {(this.solidStk || this.dashdStk) ? <input type="range" defaultValue={Number(this.widthStk)} min={1} max={100} onChange={undoBatch(action((e) => this.widthStk = e.target.value))} /> : (null)}
- <br />
- {(this.solidStk || this.dashdStk) ? <>
- <p style={{ position: "absolute", fontSize: 12 }}>Arrow Head</p>
- <input key="markHead" className="formatShapePane-inputBtn" type="checkbox" checked={this.markHead !== ""} onChange={undoBatch(action(() => this.markHead = this.markHead ? "" : "arrow"))} style={{ position: "absolute", right: 110, width: 20 }} />
- <p style={{ position: "absolute", fontSize: 12, right: 30 }}>Arrow End</p>
- <input key="markTail" className="formatShapePane-inputBtn" type="checkbox" checked={this.markTail !== ""} onChange={undoBatch(action(() => this.markTail = this.markTail ? "" : "arrow"))} style={{ position: "absolute", right: 0, width: 20 }} />
- <br />
- </> : ""}
- Dash: <input key="markHead" className="formatShapePane-inputBtn" type="checkbox" checked={this.dashdStk === "2"} onChange={undoBatch(action(() => this.dashdStk = this.dashdStk === "2" ? "0" : "2"))} style={{ position: "absolute", right: 110, width: 20 }} />
-
-
-
- </div>;
-
-
-
- const sizeCheck =
-
- <div key="sizeCheck" style={{ display: (this._subOpen[1] && this.selectedInk && this.selectedInk.length >= 1) ? "" : "none", width: "inherit", backgroundColor: "#323232", color: "white", }}>
- {this.controlPoints}
- {this.hgtInput}
- {this.XpsInput}
- {this.rotInput}
-
- </div>;
-
-
- const subMenus = this._currMode === "fill-drip" ? [`Appearance`, 'Transform'] : [];
- const menuItems = this._currMode === "fill-drip" ? [fillCheck, sizeCheck] : [];
- const indexOffset = 0;
-
- return <div className="antimodeMenu-sub" key="submenu" style={{ position: "absolute", width: "inherit", top: 60 }}>
- {subMenus.map((subMenu, i) =>
- <div key={subMenu} style={{ width: "inherit" }}>
- <button className="antimodeMenu-button" onPointerDown={action(() => this._subOpen[i + indexOffset] = !this._subOpen[i + indexOffset])}
- style={{ backgroundColor: "121212", position: "relative", width: "inherit" }}>
- {this._subOpen[i + indexOffset] ? "▼" : "▶︎"}
- {subMenu}
- </button>
- {menuItems[i]}
- </div>)}
- </div>;
- }
-
- @computed get closeBtn() {
- return <button className="antimodeMenu-button" key="close" onPointerDown={action(() => this.closePane())} style={{ position: "absolute", right: 0 }}>
- X
- </button>;
- }
-
- @computed get propertyGroupBtn() {
- return <div className="antimodeMenu-button-tab" key="modes">
- {this._mode.map(mode =>
- <button className="antimodeMenu-button" key={mode} onPointerDown={action(() => this._currMode = mode)}
- style={{ backgroundColor: this._currMode === mode ? "121212" : "", position: "relative", top: 30 }}>
- <FontAwesomeIcon icon={mode as IconProp} size="lg" />
- </button>)}
- </div>;
- }
-
- render() {
- return this.getElementVert([this.closeBtn,
- this.propertyGroupItems]);
- }
-} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index f1df7998b..46298ec6f 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -1,13 +1,12 @@
import React = require("react");
-import AntimodeMenu from "../../AntimodeMenu";
-import { observer } from "mobx-react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { unimplementedFunction } from "../../../../Utils";
-import { undoBatch } from "../../../util/UndoManager";
import { Tooltip } from "@material-ui/core";
+import { observer } from "mobx-react";
+import { unimplementedFunction } from "../../../../Utils";
+import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu";
@observer
-export default class MarqueeOptionsMenu extends AntimodeMenu {
+export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
static Instance: MarqueeOptionsMenu;
public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction;
@@ -16,6 +15,7 @@ export default class MarqueeOptionsMenu extends AntimodeMenu {
public inkToText: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction;
public showMarquee: () => void = unimplementedFunction;
public hideMarquee: () => void = unimplementedFunction;
+ public pinWithView: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction;
constructor(props: Readonly<{}>) {
super(props);
@@ -53,6 +53,14 @@ export default class MarqueeOptionsMenu extends AntimodeMenu {
<FontAwesomeIcon icon="font" size="lg" />
</button>
</Tooltip>,
+ <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin to presentation with selected view</div></>} placement="bottom">
+ <button
+ className="antimodeMenu-button"
+ onPointerDown={this.pinWithView}>
+ <FontAwesomeIcon icon="map-pin" size="lg" />
+ <div style={{ position: 'relative', fontSize: 25, fontWeight: 700, transform: 'translate(-4px, -22px)', color: 'rgba(250,250,250,0.55)' }}>V</div>
+ </button>
+ </Tooltip>,
];
return this.getElement(buttons);
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c0b19fcd2..d8e1bcc9c 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,27 +1,28 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc, Opt, DocListCast, DataSym, AclEdit, AclAddonly, AclAdmin } from "../../../../fields/Doc";
-import { GetEffectiveAcl } from "../../../../fields/util";
+import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, DocListCast, Opt } from "../../../../fields/Doc";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
import { RichTextField } from "../../../../fields/RichTextField";
import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
+import { GetEffectiveAcl } from "../../../../fields/util";
import { Utils } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
+import { DocumentManager } from "../../../util/DocumentManager";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
-import { undoBatch } from "../../../util/UndoManager";
+import { undoBatch, UndoManager } from "../../../util/UndoManager";
import { ContextMenu } from "../../ContextMenu";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { PreviewCursor } from "../../PreviewCursor";
+import { CollectionDockingView } from "../CollectionDockingView";
import { SubCollectionViewProps } from "../CollectionSubView";
-import { CollectionView } from "../CollectionView";
-import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
+import { CollectionView, CollectionViewType } from "../CollectionView";
+import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
import "./MarqueeView.scss";
import React = require("react");
-import { ContextMenuItem } from "../../ContextMenuItem";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -75,7 +76,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
if (e.key === "?") {
cm.setDefaultItem("?", (str: string) => this.props.addDocTab(
- Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false, title: "bing", UseCors: true }), "onRight"));
+ Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false, title: "bing", useCors: true }), "add:right"));
cm.displayMenu(this._downX, this._downY);
e.stopPropagation();
@@ -130,6 +131,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const tbox = Docs.Create.TextDocument("", {
_width: 200, _height: 100, x: x, y: y, _autoHeight: true, _fontSize: StrCast(Doc.UserDoc().fontSize),
_fontFamily: StrCast(Doc.UserDoc().fontFamily),
+ _showTitle: Doc.UserDoc().showTitle ? "title" : undefined,
title: "-typed text-"
});
const template = FormattedTextBox.DefaultLayout;
@@ -138,6 +140,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
tbox.layoutKey = "layout_" + StrCast(template.title);
Doc.GetProto(tbox)[StrCast(tbox.layoutKey)] = template;
}
+ FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
this.props.addLiveTextDocument(tbox);
e.stopPropagation();
}
@@ -241,6 +244,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
MarqueeOptionsMenu.Instance.fadeOut(true);
document.removeEventListener("pointerdown", hideMarquee);
+ document.removeEventListener("wheel", hideMarquee);
};
if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100)) {
MarqueeOptionsMenu.Instance.createCollection = this.collection;
@@ -250,7 +254,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
MarqueeOptionsMenu.Instance.showMarquee = this.showMarquee;
MarqueeOptionsMenu.Instance.hideMarquee = this.hideMarquee;
MarqueeOptionsMenu.Instance.jumpTo(e.clientX, e.clientY);
+ MarqueeOptionsMenu.Instance.pinWithView = this.pinWithView;
document.addEventListener("pointerdown", hideMarquee);
+ document.addEventListener("wheel", hideMarquee);
} else {
this.hideMarquee();
}
@@ -349,7 +355,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
}
- getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, isBackground?: boolean) => {
+ getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, _isBackground?: boolean) => {
const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => {
Doc.GetProto(doc).data = new List<Doc>(selected);
Doc.GetProto(doc).title = "nested freeform";
@@ -357,8 +363,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
return doc;
})(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
newCollection.system = undefined;
- newCollection.isBackground = isBackground;
- newCollection.backgroundColor = this.props.isAnnotationOverlay ? "#00000015" : isBackground ? "cyan" : undefined;
+ newCollection._isBackground = _isBackground;
+ newCollection.backgroundColor = this.props.isAnnotationOverlay ? "#00000015" : _isBackground ? "cyan" : undefined;
newCollection._width = this.Bounds.width;
newCollection._height = this.Bounds.height;
newCollection.x = this.Bounds.left;
@@ -381,6 +387,38 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
@undoBatch @action
+ pinWithView = (e: KeyboardEvent | React.PointerEvent | undefined) => {
+ const doc = this.props.Document;
+ const bounds = this.Bounds;
+ const selected = this.marqueeSelect(false);
+ const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
+ if (curPres) {
+ const pinDoc = Doc.MakeAlias(doc);
+ pinDoc.presentationTargetDoc = doc;
+ pinDoc.presZoomButton = true;
+ pinDoc.context = curPres;
+ Doc.AddDocToList(curPres, "data", pinDoc);
+ if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
+ if (!DocumentManager.Instance.getDocumentView(curPres)) {
+ CollectionDockingView.AddSplit(curPres, "right");
+ }
+ if (e instanceof KeyboardEvent ? e.key === "c" : true) {
+ const x = this.Bounds.left + this.Bounds.width / 2;
+ const y = this.Bounds.top + this.Bounds.height / 2;
+ const panelWidth: number = this.props.PanelWidth();
+ const panelHeight: number = this.props.PanelHeight();
+ const scale = Math.min(Number(panelWidth) / this.Bounds.width, Number(panelHeight) / this.Bounds.height);
+ pinDoc.presPinView = true;
+ pinDoc.presPinViewX = x;
+ pinDoc.presPinViewY = y;
+ pinDoc.presPinViewScale = scale;
+ }
+ }
+ MarqueeOptionsMenu.Instance.fadeOut(true);
+ this.hideMarquee();
+ }
+
+ @undoBatch @action
collection = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const bounds = this.Bounds;
const selected = this.marqueeSelect(false);
@@ -492,7 +530,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
d.page = -1;
return d;
});
- const summary = Docs.Create.TextDocument("", { x: bounds.left + bounds.width / 2, y: bounds.top + bounds.height / 2, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
+ const summary = Docs.Create.TextDocument("", { x: bounds.left + bounds.width / 2, y: bounds.top + bounds.height / 2, _showTitle: Doc.UserDoc().showTitle ? "title" : undefined, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
const portal = Doc.MakeAlias(summary);
Doc.GetProto(summary)[Doc.LayoutFieldKey(summary) + "-annotations"] = new List<Doc>(selected);
Doc.GetProto(summary).layout_portal = CollectionView.LayoutString(Doc.LayoutFieldKey(summary) + "-annotations");
@@ -644,7 +682,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
marqueeSelect(selectBackgrounds: boolean = true) {
const selRect = this.Bounds;
const selection: Doc[] = [];
- this.props.activeDocuments().filter(doc => !doc.isBackground && !doc.z).map(doc => {
+ this.props.activeDocuments().filter(doc => !doc._isBackground && !doc.z).map(doc => {
const layoutDoc = Doc.Layout(doc);
const x = NumCast(doc.x);
const y = NumCast(doc.y);
@@ -719,14 +757,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
</div>;
} else {
- //subtracted 250 for offset
var str: string = "";
for (var i = 0; i < this._pointsX.length; i++) {
- var x = 0;
- x = this._pointsX[i] - 250;
- str += x.toString();
+ const pt = this.props.getContainerTransform().transformPoint(this._pointsX[i], this._pointsY[i]);
+ str += pt[0].toString();
str += ",";
- str += this._pointsY[i].toString();
+ str += pt[1].toString();
str += (" ");
}
@@ -747,7 +783,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
render() {
return <div className="marqueeView"
- style={{ overflow: StrCast(this.props.Document._overflow), cursor: MarqueeView.DragMarquee && this ? "crosshair" : "hand" }}
+ style={{ overflow: !this.props.ContainingCollectionView && this.props.annotationsKey ? "visible" : StrCast(this.props.Document._overflow), cursor: MarqueeView.DragMarquee && this ? "crosshair" : "hand" }}
onDragOver={e => e.preventDefault()}
onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
{this._visible ? this.marqueeDiv : null}
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
deleted file mode 100644
index aee28366a..000000000
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ /dev/null
@@ -1,731 +0,0 @@
-.propertiesView {
-
- background-color: rgb(205, 205, 205);
- height: 100%;
- font-family: "Noto Sans";
- cursor: auto;
-
- overflow-x: hidden;
- overflow-y: scroll;
-
- .propertiesView-title {
- background-color: rgb(159, 159, 159);
- text-align: center;
- padding-top: 12px;
- padding-bottom: 12px;
- display: flex;
- font-size: 18px;
- font-weight: bold;
- justify-content: center;
-
- .propertiesView-title-icon {
- width: 20px;
- height: 20px;
- padding-left: 38px;
- margin-top: -5px;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 10px;
-
- &:hover {
- color: grey;
- cursor: pointer;
- }
-
- }
-
- }
-
- .propertiesView-name {
- border-bottom: 1px solid black;
- padding: 8.5px;
- font-size: 12.5px;
-
- &:hover {
- cursor: text;
- }
- }
-
- .propertiesView-settings {
- border-bottom: 1px solid black;
- //padding: 8.5px;
- font-size: 12.5px;
- font-weight: bold;
-
- .propertiesView-settings-title {
- font-weight: bold;
- font-size: 12.5px;
- padding: 4px;
- display: flex;
- color: white;
- padding-left: 8px;
- background-color: rgb(51, 51, 51);
-
- &:hover {
- cursor: pointer;
- }
-
- .propertiesView-settings-title-icon {
- float: right;
- justify-items: right;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 9px;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- .propertiesView-settings-content {
- margin-left: 12px;
- padding-bottom: 10px;
- padding-top: 8px;
- }
-
- }
-
- .propertiesView-sharing {
- border-bottom: 1px solid black;
- //padding: 8.5px;
-
- .propertiesView-sharing-title {
- font-weight: bold;
- font-size: 12.5px;
- padding: 4px;
- display: flex;
- color: white;
- padding-left: 8px;
- background-color: rgb(51, 51, 51);
-
- &:hover {
- cursor: pointer;
- }
-
- .propertiesView-sharing-title-icon {
- float: right;
- justify-items: right;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 9px;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- .propertiesView-sharing-content {
- font-size: 10px;
- padding: 10px;
- margin-left: 5px;
-
- .change-buttons {
- display: flex;
-
- button {
- width: 5;
- height: 5;
- }
-
- input {
- width: 100%;
- }
- }
- }
- }
-
- .propertiesView-appearance {
- border-bottom: 1px solid black;
- //padding: 8.5px;
-
- .propertiesView-appearance-title {
- font-weight: bold;
- font-size: 12.5px;
- padding: 4px;
- display: flex;
- color: white;
- padding-left: 8px;
- background-color: rgb(51, 51, 51);
-
- &:hover {
- cursor: pointer;
- }
-
- .propertiesView-appearance-title-icon {
- float: right;
- justify-items: right;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 9px;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- .propertiesView-appearance-content {
- font-size: 10px;
- padding: 10px;
- margin-left: 5px;
- }
- }
-
- .propertiesView-transform {
- border-bottom: 1px solid black;
- //padding: 8.5px;
-
- .propertiesView-transform-title {
- font-weight: bold;
- font-size: 12.5px;
- padding: 4px;
- display: flex;
- color: white;
- padding-left: 8px;
- background-color: rgb(51, 51, 51);
-
- &:hover {
- cursor: pointer;
- }
-
- .propertiesView-transform-title-icon {
- float: right;
- justify-items: right;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 9px;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- .propertiesView-transform-content {
- font-size: 10px;
- padding: 10px;
- margin-left: 5px;
- }
- }
-
- .notify-button {
- padding: 2px;
- width: 12px;
- height: 12px;
- background-color: black;
- border-radius: 10px;
- padding-left: 2px;
- padding-right: 2px;
- margin-top: 2px;
- margin-left: 3px;
-
- .notify-button-icon {
- width: 6px;
- height: 6.5px;
- margin-left: .5px;
- }
-
- &:hover {
- background-color: rgb(158, 158, 158);
- cursor: pointer;
- }
- }
-
- .expansion-button-icon {
- width: 11px;
- height: 11px;
- color: black;
- margin-left: 27px;
-
- &:hover {
- color: rgb(131, 131, 131);
- cursor: pointer;
- }
- }
-
- .propertiesView-sharingTable {
-
- // whatever's commented out - add it back in when adding the buttons
-
- // border: 1.5px solid black;
- border: 1px solid black;
- padding: 5px; // remove when adding buttons
- border-radius: 6px; // remove when adding buttons
- margin-right: 10px; // remove when adding buttons
- // width: 100%;
- // display: inline-table;
- background-color: #ececec;
- max-height: 130px;
- overflow-y: scroll;
-
- .propertiesView-sharingTable-item {
-
- display: flex;
- // padding: 5px;
- padding: 3px;
- align-items: center;
- border-bottom: 0.5px solid grey;
- cursor: pointer;
-
- &:hover .propertiesView-sharingTable-item-name {
- overflow-x: unset;
- white-space: unset;
- overflow-wrap: break-word;
- }
-
- .propertiesView-sharingTable-item-name {
- font-weight: bold;
- width: 95px;
- overflow-x: hidden;
- display: inline-block;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .propertiesView-sharingTable-item-permission {
- display: flex;
- align-items: flex-end;
- margin-left: auto;
-
- .permissions-select {
- z-index: 1;
- border: none;
- background-color: inherit;
- width: 75px;
- //text-align: justify; // for Edge
- //text-align-last: end;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- &:last-child {
- border-bottom: none;
- }
- }
- }
-
- .propertiesView-fields {
- border-bottom: 1px solid black;
- //padding: 8.5px;
-
- .propertiesView-fields-title {
- font-weight: bold;
- font-size: 12.5px;
- padding: 4px;
- display: flex;
- color: white;
- padding-left: 8px;
- background-color: rgb(51, 51, 51);
-
- &:hover {
- cursor: pointer;
- }
-
- .propertiesView-fields-title-icon {
- float: right;
- justify-items: right;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 9px;
-
- &:hover {
- cursor: pointer;
- }
- }
-
- }
-
- .propertiesView-fields-checkbox {
- float: right;
- height: 20px;
- margin-top: -9px;
-
- .propertiesView-fields-checkbox-text {
- font-size: 7px;
- margin-top: -10px;
- margin-left: 6px;
- }
- }
-
- .propertiesView-fields-content {
- font-size: 10px;
- margin-left: 2px;
- padding: 10px;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- .field {
- display: flex;
- font-size: 7px;
- background-color: #e8e8e8;
- padding-right: 3px;
- border: 0.5px solid grey;
- border-radius: 5px;
- padding-left: 3px;
- }
-
- .uneditable-field {
- display: flex;
- overflow-y: visible;
- margin-bottom: 2px;
-
- &:hover {
- cursor: auto;
- }
- }
-
- .propertiesView-layout {
-
- .propertiesView-layout-title {
- font-weight: bold;
- font-size: 12.5px;
- padding: 4px;
- display: flex;
- color: white;
- padding-left: 8px;
- background-color: rgb(51, 51, 51);
-
- &:hover {
- cursor: pointer;
- }
-
- .propertiesView-layout-title-icon {
- float: right;
- justify-items: right;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 9px;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- .propertiesView-layout-content {
- overflow: hidden;
- padding: 10px;
- }
-
- }
-
- .propertiesView-presTrails {
- border-bottom: 1px solid black;
- //padding: 8.5px;
-
- .propertiesView-presTrails-title {
- font-weight: bold;
- font-size: 12.5px;
- padding: 4px;
- display: flex;
- color: white;
- padding-left: 8px;
- background-color: rgb(51, 51, 51);
-
- &:hover {
- cursor: pointer;
- }
-
- .propertiesView-presTrails-title-icon {
- float: right;
- justify-items: right;
- align-items: flex-end;
- margin-left: auto;
- margin-right: 9px;
-
- &:hover {
- cursor: pointer;
- }
- }
- }
-
- .propertiesView-presTrails-content {
- font-size: 10px;
- padding: 10px;
- margin-left: 5px;
- }
- }
-}
-
-.inking-button {
-
- display: flex;
-
- .inking-button-points {
- background-color: #333333;
- padding: 7px;
- border-radius: 7px;
- margin-right: 32px;
- width: 32;
- height: 32;
- padding-top: 9px;
- margin-left: 18px;
-
- &:hover {
- background: rgb(131, 131, 131);
- transform: scale(1.05);
- cursor: pointer;
- }
- }
-
- .inking-button-lock {
- background-color: #333333;
- padding: 7px;
- border-radius: 7px;
- margin-right: 32px;
- width: 32;
- height: 32;
- padding-top: 9px;
- padding-left: 10px;
-
- &:hover {
- background: rgb(131, 131, 131);
- transform: scale(1.05);
- cursor: pointer;
- }
- }
-
- .inking-button-rotate {
- background-color: #333333;
- padding: 7px;
- border-radius: 7px;
- width: 32;
- height: 32;
- padding-top: 9px;
- padding-left: 10px;
-
- &:hover {
- background: rgb(131, 131, 131);
- transform: scale(1.05);
- cursor: pointer;
- }
- }
-}
-
-.inputBox-duo {
- display: flex;
-}
-
-.inputBox {
-
- margin-top: 10px;
- display: flex;
- height: 19px;
- margin-right: 15px;
-
- .inputBox-title {
- font-size: 12px;
- padding-right: 5px;
- }
-
- .inputBox-input {
- font-size: 10px;
- width: 50px;
- margin-right: 1px;
- border-radius: 3px;
-
- &:hover {
- cursor: pointer;
- }
- }
-
- .inputBox-button {
-
- .inputBox-button-up {
- background-color: #333333;
- height: 9px;
- padding-left: 3px;
- padding-right: 3px;
- padding-top: 1px;
- padding-bottom: 1px;
- border-radius: 1.5px;
-
- &:hover {
- background: rgb(131, 131, 131);
- transform: scale(1.05);
- cursor: pointer;
- }
- }
-
- .inputBox-button-down {
- background-color: #333333;
- height: 9px;
- padding-left: 3px;
- padding-right: 3px;
- padding-top: 1px;
- padding-bottom: 1px;
- border-radius: 1.5px;
-
- &:hover {
- background: rgb(131, 131, 131);
- transform: scale(1.05);
- cursor: pointer;
- }
- }
-
- }
-}
-
-.color-palette {
- width: 160px;
- height: 360;
-}
-
-.strokeAndFill {
- display: flex;
- margin-top: 10px;
-
- .fill {
- margin-right: 40px;
- display: flex;
- padding-bottom: 7px;
- margin-left: 35px;
-
- .fill-title {
- font-size: 12px;
- margin-right: 2px;
- }
-
- .fill-button {
- padding-top: 2px;
- margin-top: -1px;
- }
- }
-
- .stroke {
- display: flex;
-
- .stroke-title {
- font-size: 12px;
- }
-
- .stroke-button {
- padding-top: 2px;
- margin-left: 2px;
- margin-top: -1px;
- }
- }
-}
-
-.propertiesView-presSelected {
- border-top: solid 1px darkgrey;
- width: 100%;
- padding-top: 5px;
- font-family: Roboto;
- font-weight: 500;
- display: inline-flex;
-
- .propertiesView-selectedList {
- border-left: solid 1px darkgrey;
- margin-left: 10px;
- padding-left: 5px;
-
- .selectedList-items {
- font-size: 12;
- font-weight: 300;
- margin-top: 1;
- }
- }
-}
-
-.widthAndDash {
-
- .width {
- .width-top {
- display: flex;
-
- .width-title {
- font-size: 12;
- margin-right: 20px;
- margin-left: 35px;
- text-align: center;
- }
-
- .width-input {
- margin-right: 30px;
- margin-top: -10px;
- }
- }
-
- .width-range {
- margin-right: 1px;
- margin-bottom: 6;
- }
- }
-
- .arrows {
-
- display: flex;
- margin-bottom: 3px;
- margin-left: 4px;
-
- .arrows-head {
-
- display: flex;
- margin-right: 35px;
-
- .arrows-head-title {
- font-size: 10;
- }
-
- .arrows-head-input {
- margin-left: 6px;
- margin-top: 2px;
- }
- }
-
- .arrows-tail {
- display: flex;
-
- .arrows-tail-title {
- font-size: 10;
- }
-
- .arrows-tail-input {
- margin-left: 6px;
- margin-top: 2px;
- }
- }
- }
-
- .dashed {
-
- display: flex;
- margin-left: 64px;
- margin-bottom: 6px;
-
- .dashed-title {
- font-size: 10;
- }
-
- .dashed-input {
- margin-left: 6px;
- margin-top: 2px;
- }
- }
-}
-
-.editable-title {
- border: none;
- padding: 6px;
- padding-bottom: 2px;
-
-
- &:hover {
- border: 0.75px solid rgb(122, 28, 28);
- }
-}
-
-
-.properties-flyout {
- grid-column: 2/4;
-} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
deleted file mode 100644
index 57e968aa7..000000000
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ /dev/null
@@ -1,1048 +0,0 @@
-import React = require("react");
-import { observer } from "mobx-react";
-import "./PropertiesView.scss";
-import { observable, action, computed, runInAction } from "mobx";
-import { Doc, Field, WidthSym, HeightSym, AclSym, AclPrivate, AclReadonly, AclAddonly, AclEdit, AclAdmin, Opt, DocCastAsync } from "../../../../fields/Doc";
-import { ComputedField } from "../../../../fields/ScriptField";
-import { EditableView } from "../../EditableView";
-import { KeyValueBox } from "../../nodes/KeyValueBox";
-import { Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
-import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils } from "../../../../Utils";
-import { Id } from "../../../../fields/FieldSymbols";
-import { Transform } from "../../../util/Transform";
-import { PropertiesButtons } from "../../PropertiesButtons";
-import { SelectionManager } from "../../../util/SelectionManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Tooltip, Checkbox } from "@material-ui/core";
-import SharingManager from "../../../util/SharingManager";
-import { DocumentType } from "../../../documents/DocumentTypes";
-import { SharingPermissions, GetEffectiveAcl } from "../../../../fields/util";
-import { InkField } from "../../../../fields/InkField";
-import { undoBatch, UndoManager } from "../../../util/UndoManager";
-import { ColorState, SketchPicker } from "react-color";
-import "./FormatShapePane.scss";
-import { PresBox } from "../../nodes/PresBox";
-import { DocumentManager } from "../../../util/DocumentManager";
-import FormatShapePane from "./FormatShapePane";
-const higflyout = require("@hig/flyout");
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
-const _global = (window /* browser */ || global /* node */) as any;
-
-// import * as fa from '@fortawesome/free-solid-svg-icons';
-// import { library } from "@fortawesome/fontawesome-svg-core";
-
-// library.add(fa.faPlus, fa.faMinus, fa.faCog);
-
-interface PropertiesViewProps {
- width: number;
- height: number;
- renderDepth: number;
- ScreenToLocalTransform: () => Transform;
- onDown: (event: any) => void;
-}
-
-@observer
-export class PropertiesView extends React.Component<PropertiesViewProps> {
- private _widthUndo?: UndoManager.Batch;
-
- @computed get MAX_EMBED_HEIGHT() { return 200; }
-
- @computed get selectedDocumentView() {
- if (SelectionManager.SelectedDocuments().length) {
- return SelectionManager.SelectedDocuments()[0];
- } else if (PresBox.Instance && PresBox.Instance._selectedArray.length) {
- return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
- } else { return undefined; }
- }
- @computed get isPres(): boolean {
- if (this.selectedDoc?.type === DocumentType.PRES) return true;
- return false;
- }
- @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
- @computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
-
- @observable layoutFields: boolean = false;
-
- @observable openActions: boolean = true;
- @observable openSharing: boolean = true;
- @observable openFields: boolean = true;
- @observable openLayout: boolean = true;
- @observable openAppearance: boolean = true;
- @observable openTransform: boolean = true;
- // @observable selectedUser: string = "";
- // @observable addButtonPressed: boolean = false;
-
- //Pres Trails booleans:
- @observable openPresTransitions: boolean = false;
- @observable openPresProgressivize: boolean = false;
- @observable openAddSlide: boolean = false;
- @observable openSlideOptions: boolean = false;
-
- @observable inActions: boolean = false;
- @observable _controlBtn: boolean = false;
- @observable _lock: boolean = false;
-
- @computed get isInk() { return this.selectedDoc?.type === DocumentType.INK; }
-
- @action
- rtfWidth = () => {
- if (this.selectedDoc) {
- return Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20);
- } else {
- return 0;
- }
- }
- @action
- rtfHeight = () => {
- if (this.selectedDoc) {
- return this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
- } else {
- return 0;
- }
- }
-
- @action
- docWidth = () => {
- if (this.selectedDoc) {
- const layoutDoc = this.selectedDoc;
- const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
- if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.width - 20));
- return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
- } else {
- return 0;
- }
- }
-
- @action
- docHeight = () => {
- if (this.selectedDoc && this.dataDoc) {
- const layoutDoc = this.selectedDoc;
- return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
- const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
- if (aspect) return this.docWidth() * aspect;
- return layoutDoc._fitWidth ? (!this.dataDoc._nativeHeight ? NumCast(this.props.height) :
- Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
- NumCast(this.props.height)))) :
- NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
- })()));
- } else {
- return 0;
- }
- }
-
- @computed get expandedField() {
- if (this.dataDoc && this.selectedDoc) {
- const ids: { [key: string]: string } = {};
- const doc = this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc;
- doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
- const rows: JSX.Element[] = [];
- for (const key of Object.keys(ids).slice().sort()) {
- const contents = doc[key];
- if (key[0] === "#") {
- rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "2px" }} key={key}>
- <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
- &nbsp;
- </div>);
- } else {
- let contentElement: (JSX.Element | null)[] | JSX.Element = [];
- contentElement = <EditableView key="editableView"
- contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
- height={13}
- fontSize={10}
- GetValue={() => Field.toKeyValueString(doc, key)}
- SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
- />;
- rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
- <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
- &nbsp;
- {contentElement}
- </div>);
- }
- }
- rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
- <EditableView
- key="editableView"
- contents={"add key:value or #tags"}
- height={13}
- fontSize={10}
- GetValue={() => ""}
- SetValue={this.setKeyValue} />
- </div>);
- return rows;
- }
- }
-
- @computed get noviceFields() {
- if (this.dataDoc && this.selectedDoc) {
- const ids: { [key: string]: string } = {};
- const doc = this.dataDoc;
- doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
- const rows: JSX.Element[] = [];
- for (const key of Object.keys(ids).slice().sort()) {
- if ((key[0] === key[0].toUpperCase() && key.substring(0, 3) !== "ACL" && key !== "UseCors")
- || key[0] === "#" || key === "author" ||
- key === "creationDate" || key.indexOf("lastModified") !== -1) {
-
- const contents = doc[key];
- if (key[0] === "#") {
- rows.push(<div className="uneditable-field" key={key}>
- <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
- &nbsp;
- </div>);
- } else {
- const value = Field.toString(contents as Field);
- if (key === "author" || key === "creationDate" || key.indexOf("lastModified") !== -1) {
- rows.push(<div className="uneditable-field" key={key}>
- <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ": "}</span>
- <div style={{ whiteSpace: "nowrap", overflowX: "hidden" }}>{value}</div>
- </div>);
- } else {
- let contentElement: (JSX.Element | null)[] | JSX.Element = [];
- contentElement = <EditableView key="editableView"
- contents={contents !== undefined ? Field.toString(contents as Field) : "null"}
- height={13}
- fontSize={10}
- GetValue={() => Field.toKeyValueString(doc, key)}
- SetValue={(value: string) => KeyValueBox.SetField(doc, key, value, true)}
- />;
-
- rows.push(<div style={{ display: "flex", overflowY: "visible", marginBottom: "-1px" }} key={key}>
- <span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ":"}</span>
- &nbsp;
- {contentElement}
- </div>);
- }
- }
- }
- }
- rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
- <EditableView
- key="editableView"
- contents={"add key:value or #tags"}
- height={13}
- fontSize={10}
- GetValue={() => ""}
- SetValue={this.setKeyValue} />
- </div>);
- return rows;
- }
- }
-
- @undoBatch
- setKeyValue = (value: string) => {
- if (this.selectedDoc && this.dataDoc) {
- const doc = this.layoutFields ? Doc.Layout(this.selectedDoc) : this.dataDoc;
- if (value.indexOf(":") !== -1) {
- const newVal = value[0].toUpperCase() + value.substring(1, value.length);
- KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true);
- return true;
- } else if (value[0] === "#") {
- const newVal = value + `:'${value}'`;
- KeyValueBox.SetField(doc, newVal.substring(0, newVal.indexOf(":")), newVal.substring(newVal.indexOf(":") + 1, newVal.length), true);
- return true;
- }
- }
- return false;
- }
-
- @observable transform: Transform = Transform.Identity();
- getTransform = () => this.transform;
- propertiesDocViewRef = (ref: HTMLDivElement) => {
- const observer = new _global.ResizeObserver(action((entries: any) => {
- const cliRect = ref.getBoundingClientRect();
- this.transform = new Transform(-cliRect.x, -cliRect.y, 1);
- }));
- ref && observer.observe(ref);
- }
-
- previewBackground = () => "lightgrey";
- @computed get layoutPreview() {
- if (this.selectedDoc) {
- const layoutDoc = Doc.Layout(this.selectedDoc);
- const panelHeight = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.docHeight;
- const panelWidth = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.docWidth;
- return <div ref={this.propertiesDocViewRef} style={{ pointerEvents: "none", display: "inline-block", height: panelHeight() }} key={this.selectedDoc[Id]}>
- <ContentFittingDocumentView
- Document={layoutDoc}
- DataDoc={this.dataDoc}
- LibraryPath={emptyPath}
- renderDepth={this.props.renderDepth + 1}
- rootSelected={returnFalse}
- treeViewDoc={undefined}
- backgroundColor={this.previewBackground}
- fitToBox={true}
- FreezeDimensions={true}
- NativeWidth={layoutDoc.type ===
- StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
- NativeHeight={layoutDoc.type ===
- StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : returnZero}
- PanelWidth={panelWidth}
- PanelHeight={panelHeight}
- focus={returnFalse}
- ScreenToLocalTransform={this.getTransform}
- docFilters={returnEmptyFilter}
- ContainingCollectionDoc={undefined}
- ContainingCollectionView={undefined}
- addDocument={returnFalse}
- moveDocument={undefined}
- removeDocument={returnFalse}
- parentActive={() => false}
- whenActiveChanged={emptyFunction}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- bringToFront={returnFalse}
- ContentScaling={returnOne}
- dontRegisterView={true}
- dropAction={undefined}
- />
- </div>;
- } else {
- return null;
- }
- }
-
- /**
- * Handles the changing of a user's permissions from the permissions panel.
- */
- @undoBatch
- changePermissions = (e: any, user: string) => {
- SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!);
- }
-
- /**
- * @returns the options for the permissions dropdown.
- */
- getPermissionsSelect(user: string, permission: string) {
- return <select className="permissions-select"
- value={permission}
- onChange={e => this.changePermissions(e, user)}>
- {Object.values(SharingPermissions).map(permission => {
- return (
- <option key={permission} value={permission} selected={this.selectedDoc![`ACL-${user.replace(".", "_")}`] === permission}>
- {permission}
- </option>);
- })}
- </select>;
- }
-
- /**
- * @returns the notification icon. On clicking, it should notify someone of a document been shared with them.
- */
- @computed get notifyIcon() {
- return <Tooltip title={<div className="dash-tooltip">Notify with message</div>}>
- <div className="notify-button">
- <FontAwesomeIcon className="notify-button-icon" icon="bell" color="white" size="sm" />
- </div>
- </Tooltip>;
- }
-
- /**
- * ... next to the owner that opens the main SharingManager interface on click.
- */
- @computed get expansionIcon() {
- return <Tooltip title={<div className="dash-tooltip">{"Show more permissions"}</div>}>
- <div className="expansion-button" onPointerDown={() => {
- if (this.selectedDocumentView) {
- SharingManager.Instance.open(this.selectedDocumentView);
- }
- }}>
- <FontAwesomeIcon className="expansion-button-icon" icon="ellipsis-h" color="black" size="sm" />
- </div>
- </Tooltip>;
- }
-
- /**
- * @returns a row of the permissions panel
- */
- sharingItem(name: string, effectiveAcl: symbol, permission: string) {
- return <div className="propertiesView-sharingTable-item" key={name + permission}
- // style={{ backgroundColor: this.selectedUser === name ? "#bcecfc" : "" }}
- // onPointerDown={action(() => this.selectedUser = this.selectedUser === name ? "" : name)}
- >
- <div className="propertiesView-sharingTable-item-name" style={{ width: name !== "Me" ? "85px" : "80px" }}> {name} </div>
- {/* {name !== "Me" ? this.notifyIcon : null} */}
- <div className="propertiesView-sharingTable-item-permission">
- {effectiveAcl === AclAdmin && permission !== "Owner" ? this.getPermissionsSelect(name, permission) : permission}
- {permission === "Owner" ? this.expansionIcon : null}
- </div>
- </div>;
- }
-
- /**
- * @returns the sharing and permissiosn panel.
- */
- @computed get sharingTable() {
- const AclMap = new Map<symbol, string>([
- [AclPrivate, SharingPermissions.None],
- [AclReadonly, SharingPermissions.View],
- [AclAddonly, SharingPermissions.Add],
- [AclEdit, SharingPermissions.Edit],
- [AclAdmin, SharingPermissions.Admin]
- ]);
-
- const effectiveAcl = GetEffectiveAcl(this.selectedDoc!);
- const tableEntries = [];
-
- // DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => {
- if (this.selectedDoc![AclSym]) {
- for (const [key, value] of Object.entries(this.selectedDoc![AclSym])) {
- const name = key.substring(4).replace("_", ".");
- if (name !== Doc.CurrentUserEmail && name !== this.selectedDoc!.author/* && sidebarUsersDisplayed![name] !== false*/) {
- tableEntries.push(this.sharingItem(name, effectiveAcl, AclMap.get(value)!));
- }
- }
- }
-
- // if (Doc.UserDoc().sidebarUsersDisplayed) {
- // for (const [name, value] of Object.entries(sidebarUsersDisplayed!)) {
- // if (value === true && !this.selectedDoc![`ACL-${name.substring(8).replace(".", "_")}`]) tableEntries.push(this.sharingItem(name.substring(8), effectiveAcl, SharingPermissions.None));
- // }
- // }
- // })
-
- // shifts the current user and the owner to the top of the doc.
- tableEntries.unshift(this.sharingItem("Me", effectiveAcl, Doc.CurrentUserEmail === this.selectedDoc!.author ? "Owner" : StrCast(this.selectedDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`])));
- if (Doc.CurrentUserEmail !== this.selectedDoc!.author) tableEntries.unshift(this.sharingItem(StrCast(this.selectedDoc!.author), effectiveAcl, "Owner"));
-
- return <div className="propertiesView-sharingTable">
- {tableEntries}
- </div>;
- }
-
- @computed get fieldsCheckbox() {
- return <Checkbox
- color="primary"
- onChange={this.toggleCheckbox}
- checked={this.layoutFields}
- />;
- }
-
- @action
- toggleCheckbox = () => {
- this.layoutFields = !this.layoutFields;
- }
-
- @computed get editableTitle() {
- return <div className="editable-title"><EditableView
- key="editableView"
- contents={StrCast(this.selectedDoc?.title)}
- height={25}
- fontSize={14}
- GetValue={() => StrCast(this.selectedDoc?.title)}
- SetValue={this.setTitle} /> </div>;
- }
-
- @undoBatch
- @action
- setTitle = (value: string) => {
- if (this.dataDoc) {
- this.selectedDoc && (this.selectedDoc.title = value);
- KeyValueBox.SetField(this.dataDoc, "title", value, true);
- return true;
- }
- return false;
- }
-
-
- @undoBatch
- @action
- rotate = (angle: number) => {
- const _centerPoints: { X: number, Y: number }[] = [];
- if (this.selectedDoc) {
- const doc = this.selectedDoc;
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
- const xs = ink.map(p => p.X);
- const ys = ink.map(p => p.Y);
- const left = Math.min(...xs);
- const top = Math.min(...ys);
- const right = Math.max(...xs);
- const bottom = Math.max(...ys);
- _centerPoints.push({ X: left, Y: top });
- }
- }
-
- var index = 0;
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- doc.rotation = Number(doc.rotation) + Number(angle);
- const inks = Cast(doc.data, InkField)?.inkData;
- if (inks) {
- const newPoints: { X: number, Y: number }[] = [];
- inks.forEach(ink => {
- const newX = Math.cos(angle) * (ink.X - _centerPoints[index].X) - Math.sin(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].X;
- const newY = Math.sin(angle) * (ink.X - _centerPoints[index].X) + Math.cos(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
- newPoints.push({ X: newX, Y: newY });
- });
- doc.data = new InkField(newPoints);
- const xs = newPoints.map(p => p.X);
- const ys = newPoints.map(p => p.Y);
- const left = Math.min(...xs);
- const top = Math.min(...ys);
- const right = Math.max(...xs);
- const bottom = Math.max(...ys);
-
- doc._height = (bottom - top);
- doc._width = (right - left);
- }
- index++;
- }
- }
- }
-
-
-
- @computed
- get controlPointsButton() {
- return <div className="inking-button">
- <Tooltip title={<div className="dash-tooltip">{"Edit points"}</div>}>
- <div className="inking-button-points" onPointerDown={action(() => FormatShapePane.Instance._controlBtn = !FormatShapePane.Instance._controlBtn)} style={{ backgroundColor: FormatShapePane.Instance._controlBtn ? "black" : "" }}>
- <FontAwesomeIcon icon="bezier-curve" color="white" size="lg" />
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{FormatShapePane.Instance._lock ? "Unlock ratio" : "Lock ratio"}</div>}>
- <div className="inking-button-lock" onPointerDown={action(() => FormatShapePane.Instance._lock = !FormatShapePane.Instance._lock)} >
- <FontAwesomeIcon icon={FormatShapePane.Instance._lock ? "lock" : "unlock"} color="white" size="lg" />
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{"Rotate 90˚"}</div>}>
- <div className="inking-button-rotate" onPointerDown={action(() => this.rotate(Math.PI / 2))}>
- <FontAwesomeIcon icon="undo" color="white" size="lg" />
- </div>
- </Tooltip>
- </div>;
- }
-
- inputBox = (key: string, value: any, setter: (val: string) => {}, title: string) => {
- return <div className="inputBox"
- style={{
- marginRight: title === "X:" ? "19px" : "",
- marginLeft: title === "∠:" ? "39px" : ""
- }}>
- <div className="inputBox-title"> {title} </div>
- <input className="inputBox-input"
- type="text" value={value}
- onChange={e => setter(e.target.value)} />
- <div className="inputBox-button">
- <div className="inputBox-button-up" key="up2"
- onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))} >
- <FontAwesomeIcon icon="caret-up" color="white" size="sm" />
- </div>
- <div className="inputbox-Button-down" key="down2"
- onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} >
- <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
- </div>
- </div>
- </div>;
- }
-
- inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => {
- return <div className="inputBox-duo">
- {this.inputBox(key, value, setter, title1)}
- {title2 === "" ? (null) : this.inputBox(key2, value2, setter2, title2)}
- </div>;
- }
-
- @action
- upDownButtons = (dirs: string, field: string) => {
- switch (field) {
- case "rot": this.rotate((dirs === "up" ? .1 : -.1)); break;
- // case "rot": this.selectedInk?.forEach(i => i.rootDoc.rotation = NumCast(i.rootDoc.rotation) + (dirs === "up" ? 0.1 : -0.1)); break;
- case "Xps": this.selectedDoc && (this.selectedDoc.x = NumCast(this.selectedDoc?.x) + (dirs === "up" ? 10 : -10)); break;
- case "Yps": this.selectedDoc && (this.selectedDoc.y = NumCast(this.selectedDoc?.y) + (dirs === "up" ? 10 : -10)); break;
- case "stk": this.selectedDoc && (this.selectedDoc.strokeWidth = NumCast(this.selectedDoc?.strokeWidth) + (dirs === "up" ? .1 : -.1)); break;
- case "wid":
- const oldWidth = NumCast(this.selectedDoc?._width);
- const oldHeight = NumCast(this.selectedDoc?._height);
- const oldX = NumCast(this.selectedDoc?.x);
- const oldY = NumCast(this.selectedDoc?.y);
- this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === "up" ? 10 : - 10));
- FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth * NumCast(this.selectedDoc?._height)));
- const doc = this.selectedDoc;
- if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
- const newPoints: { X: number, Y: number }[] = [];
- for (var j = 0; j < ink.length; j++) {
- // (new x — oldx) + (oldxpoint * newWidt)/oldWidth
- const newX = (NumCast(doc.x) - oldX) + (ink[j].X * NumCast(doc._width)) / oldWidth;
- const newY = (NumCast(doc.y) - oldY) + (ink[j].Y * NumCast(doc._height)) / oldHeight;
- newPoints.push({ X: newX, Y: newY });
- }
- doc.data = new InkField(newPoints);
- }
- }
- break;
- case "hgt":
- const oWidth = NumCast(this.selectedDoc?._width);
- const oHeight = NumCast(this.selectedDoc?._height);
- const oX = NumCast(this.selectedDoc?.x);
- const oY = NumCast(this.selectedDoc?.y);
- this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === "up" ? 10 : - 10));
- FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight * NumCast(this.selectedDoc?._width)));
- const docu = this.selectedDoc;
- if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) {
- const ink = Cast(docu.data, InkField)?.inkData;
- if (ink) {
- const newPoints: { X: number, Y: number }[] = [];
- for (var j = 0; j < ink.length; j++) {
- // (new x — oldx) + (oldxpoint * newWidt)/oldWidth
- const newX = (NumCast(docu.x) - oX) + (ink[j].X * NumCast(docu._width)) / oWidth;
- const newY = (NumCast(docu.y) - oY) + (ink[j].Y * NumCast(docu._height)) / oHeight;
- newPoints.push({ X: newX, Y: newY });
- }
- docu.data = new InkField(newPoints);
- }
- }
- break;
- }
- }
-
- getField(key: string) {
- //if (this.selectedDoc) {
- return Field.toString(this.selectedDoc?.[key] as Field);
- // } else {
- // return undefined as Opt<string>;
- // }
- }
-
- @computed get shapeXps() { return this.getField("x"); }
- @computed get shapeYps() { return this.getField("y"); }
- @computed get shapeRot() { return this.getField("rotation"); }
- @computed get shapeHgt() { return this.getField("_height"); }
- @computed get shapeWid() { return this.getField("_width"); }
- set shapeXps(value) { this.selectedDoc && (this.selectedDoc.x = Number(value)); }
- set shapeYps(value) { this.selectedDoc && (this.selectedDoc.y = Number(value)); }
- set shapeRot(value) { this.selectedDoc && (this.selectedDoc.rotation = Number(value)); }
- set shapeWid(value) {
- const oldWidth = NumCast(this.selectedDoc?._width);
- this.selectedDoc && (this.selectedDoc._width = Number(value));
- FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth);
- }
- set shapeHgt(value) {
- const oldHeight = NumCast(this.selectedDoc?._height);
- this.selectedDoc && (this.selectedDoc._height = Number(value));
- FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight);
- }
-
- @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => { if (!isNaN(Number(val))) { this.shapeHgt = val; } return true; }, "H:", "wid", this.shapeWid, (val: string) => { if (!isNaN(Number(val))) { this.shapeWid = val; } return true; }, "W:"); }
- @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => { if (val !== "0" && !isNaN(Number(val))) { this.shapeXps = val; } return true; }, "X:", "Yps", this.shapeYps, (val: string) => { if (val !== "0" && !isNaN(Number(val))) { this.shapeYps = val; } return true; }, "Y:"); }
- @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { if (!isNaN(Number(val))) { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; } return true; }, "∠:", "rot", this.shapeRot, (val: string) => { if (!isNaN(Number(val))) { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; } return true; }, ""); }
-
-
- @observable private _fillBtn = false;
- @observable private _lineBtn = false;
-
- private _lastFill = "#D0021B";
- private _lastLine = "#D0021B";
- private _lastDash: any = "2";
-
- @computed get colorFil() { const ccol = this.getField("fillColor") || ""; ccol && (this._lastFill = ccol); return ccol; }
- @computed get colorStk() { const ccol = this.getField("color") || ""; ccol && (this._lastLine = ccol); return ccol; }
- set colorFil(value) { value && (this._lastFill = value); this.selectedDoc && (this.selectedDoc.fillColor = value ? value : undefined); }
- set colorStk(value) { value && (this._lastLine = value); this.selectedDoc && (this.selectedDoc.color = value ? value : undefined); }
-
- colorButton(value: string, type: string, setter: () => {}) {
- // return <div className="properties-flyout" onPointerEnter={e => this.changeScrolling(false)}
- // onPointerLeave={e => this.changeScrolling(true)}>
- // <Flyout anchorPoint={anchorPoints.LEFT_TOP}
- // content={type === "fill" ? this.fillPicker : this.linePicker}>
- return <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
- <div className="color-button-preview" style={{
- backgroundColor: value ?? "121212", width: 15, height: 15,
- display: value === "" || value === "transparent" ? "none" : ""
- }} />
- {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14 }}>☒</p> : ""}
- </div>;
- // </Flyout>
- // </div>;
-
- }
-
- @undoBatch
- @action
- switchStk = (color: ColorState) => {
- const val = String(color.hex);
- this.colorStk = val;
- return true;
- }
- @undoBatch
- @action
- switchFil = (color: ColorState) => {
- const val = String(color.hex);
- this.colorFil = val;
- return true;
- }
-
- colorPicker(setter: (color: string) => {}, type: string) {
- return <SketchPicker onChange={type === "stk" ? this.switchStk : this.switchFil}
- presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505',
- '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B',
- '#FFFFFF', '#f1efeb', 'transparent']}
- color={type === "stk" ? this.colorStk : this.colorFil} />;
- }
-
- @computed get fillButton() { return this.colorButton(this.colorFil, "fill", () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
- @computed get lineButton() { return this.colorButton(this.colorStk, "line", () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
-
- @computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); }
- @computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); }
-
- @computed get strokeAndFill() {
- return <div>
- <div key="fill" className="strokeAndFill">
- <div className="fill">
- <div className="fill-title">Fill:</div>
- <div className="fill-button">{this.fillButton}</div>
- </div>
- <div className="stroke">
- <div className="stroke-title"> Stroke: </div>
- <div className="stroke-button">{this.lineButton}</div>
- </div>
- </div>
- {this._fillBtn ? this.fillPicker : ""}
- {this._lineBtn ? this.linePicker : ""}
- </div>;
- }
-
- @computed get solidStk() { return this.selectedDoc?.color && (!this.selectedDoc?.strokeDash || this.selectedDoc?.strokeDash === "0") ? true : false; }
- @computed get dashdStk() { return this.selectedDoc?.strokeDash || ""; }
- @computed get unStrokd() { return this.selectedDoc?.color ? true : false; }
- @computed get widthStk() { return this.getField("strokeWidth") || "1"; }
- @computed get markHead() { return this.getField("strokeStartMarker") || ""; }
- @computed get markTail() { return this.getField("strokeEndMarker") || ""; }
- set solidStk(value) { this.dashdStk = ""; this.unStrokd = !value; }
- set dashdStk(value) {
- value && (this._lastDash = value) && (this.unStrokd = false);
- this.selectedDoc && (this.selectedDoc.strokeDash = value ? this._lastDash : undefined);
- }
- set widthStk(value) { this.selectedDoc && (this.selectedDoc.strokeWidth = Number(value)); }
- set unStrokd(value) { this.colorStk = value ? "" : this._lastLine; }
- set markHead(value) { this.selectedDoc && (this.selectedDoc.strokeStartMarker = value); }
- set markTail(value) { this.selectedDoc && (this.selectedDoc.strokeEndMarker = value); }
-
-
- @computed get stkInput() { return this.regInput("stk", this.widthStk, (val: string) => this.widthStk = val); }
-
-
- regInput = (key: string, value: any, setter: (val: string) => {}) => {
- return <div className="inputBox">
- <input className="inputBox-input"
- type="text" value={value}
- onChange={e => setter(e.target.value)} />
- <div className="inputBox-button">
- <div className="inputBox-button-up" key="up2"
- onPointerDown={undoBatch(action(() => this.upDownButtons("up", key)))} >
- <FontAwesomeIcon icon="caret-up" color="white" size="sm" />
- </div>
- <div className="inputbox-Button-down" key="down2"
- onPointerDown={undoBatch(action(() => this.upDownButtons("down", key)))} >
- <FontAwesomeIcon icon="caret-down" color="white" size="sm" />
- </div>
- </div>
- </div>;
- }
-
- @computed get widthAndDash() {
- return <div className="widthAndDash">
- <div className="width">
- <div className="width-top">
- <div className="width-title">Width:</div>
- <div className="width-input">{this.stkInput}</div>
- </div>
- <input className="width-range" type="range"
- defaultValue={Number(this.widthStk)} min={1} max={100}
- onChange={(action((e) => this.widthStk = e.target.value))}
- onMouseDown={(e) => { this._widthUndo = UndoManager.StartBatch("width undo"); }}
- onMouseUp={(e) => { this._widthUndo?.end(); this._widthUndo = undefined; }}
- />
- </div>
-
- <div className="arrows">
- <div className="arrows-head">
- <div className="arrows-head-title" >Arrow Head: </div>
- <input key="markHead" className="arrows-head-input" type="checkbox"
- checked={this.markHead !== ""}
- onChange={undoBatch(action(() => this.markHead = this.markHead ? "" : "arrow"))} />
- </div>
- <div className="arrows-tail">
- <div className="arrows-tail-title" >Arrow End: </div>
- <input key="markTail" className="arrows-tail-input" type="checkbox"
- checked={this.markTail !== ""}
- onChange={undoBatch(action(() => this.markTail = this.markTail ? "" : "arrow"))} />
- </div>
- </div>
- <div className="dashed">
- <div className="dashed-title">Dashed Line:</div>
- <input key="markHead" className="dashed-input"
- type="checkbox" checked={this.dashdStk === "2"}
- onChange={this.changeDash} />
- </div>
- </div>;
- }
-
- @undoBatch @action
- changeDash = () => {
- this.dashdStk = this.dashdStk === "2" ? "0" : "2";
- }
-
- @computed get appearanceEditor() {
- return <div className="appearance-editor">
- {this.widthAndDash}
- {this.strokeAndFill}
- </div>;
- }
-
- @computed get transformEditor() {
- return <div className="transform-editor">
- {this.controlPointsButton}
- {this.hgtInput}
- {this.XpsInput}
- {this.rotInput}
- </div>;
- }
-
- /**
- * Handles adding and removing members from the sharing panel
- */
- // handleUserChange = (selectedUser: string, add: boolean) => {
- // if (!Doc.UserDoc().sidebarUsersDisplayed) Doc.UserDoc().sidebarUsersDisplayed = new Doc;
- // DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => {
- // sidebarUsersDisplayed![`display-${selectedUser}`] = add;
- // !add && runInAction(() => this.selectedUser = "");
- // });
- // }
-
- render() {
- if (!this.selectedDoc && !this.isPres) {
- return <div className="propertiesView" style={{ width: this.props.width }}>
- <div className="propertiesView-title" style={{ width: this.props.width }}>
- No Document Selected
- </div>
- </div>;
-
- } else {
- const novice = Doc.UserDoc().noviceMode;
-
- if (this.selectedDoc && !this.isPres) {
- return <div className="propertiesView" style={{
- width: this.props.width,
- //overflowY: this.scrolling ? "scroll" : "visible"
- }} >
- <div className="propertiesView-title" style={{ width: this.props.width }}>
- Properties
- {/* <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
- <FontAwesomeIcon icon="times" color="black" size="sm" />
- </div> */}
- </div>
- <div className="propertiesView-name">
- {this.editableTitle}
- </div>
- <div className="propertiesView-settings" onPointerEnter={() => runInAction(() => { this.inActions = true; })}
- onPointerLeave={action(() => this.inActions = false)}>
- <div className="propertiesView-settings-title"
- onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })}
- style={{ backgroundColor: this.openActions ? "black" : "" }}>
- Actions
- <div className="propertiesView-settings-title-icon">
- <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {!this.openActions ? (null) :
- <div className="propertiesView-settings-content">
- <PropertiesButtons />
- </div>}
- </div>
- <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
- style={{ backgroundColor: this.openSharing ? "black" : "" }}>
- Sharing {"&"} Permissions
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {!this.openSharing ? (null) :
- <div className="propertiesView-sharing-content">
- {this.sharingTable}
- {/* <div className="change-buttons">
- <button
- onPointerDown={action(() => this.addButtonPressed = !this.addButtonPressed)}
- >
- <FontAwesomeIcon icon={fa.faPlus} size={"sm"} style={{ marginTop: -3, marginLeft: -3 }} />
- </button>
- <button
- id="sharingProperties-removeUser"
- onPointerDown={() => this.handleUserChange(this.selectedUser, false)}
- style={{ backgroundColor: this.selectedUser ? "#121721" : "#777777" }}
- ><FontAwesomeIcon icon={fa.faMinus} size={"sm"} style={{ marginTop: -3, marginLeft: -3 }} /></button>
- <button onClick={() => SharingManager.Instance.open(this.selectedDocumentView!)}><FontAwesomeIcon icon={fa.faCog} size={"sm"} style={{ marginTop: -3, marginLeft: -3 }} /></button>
- {this.addButtonPressed ?
- // <input type="text" onKeyDown={this.handleKeyPress} /> :
- <select onChange={e => this.handleUserChange(e.target.value, true)}>
- <option selected disabled hidden>
- Add users
- </option>
- {SharingManager.Instance.users.map(user =>
- (<option value={user.user.email}>
- {user.user.email}
- </option>)
- )}
- {GroupManager.Instance.getAllGroups().map(group =>
- (<option value={StrCast(group.groupName)}>
- {StrCast(group.groupName)}
- </option>))}
- </select> :
- null}
- </div> */}
- </div>}
- </div>
-
- {!this.isInk ? (null) :
- <div className="propertiesView-appearance">
- <div className="propertiesView-appearance-title"
- onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })}
- style={{ backgroundColor: this.openAppearance ? "black" : "" }}>
- Appearance
- <div className="propertiesView-appearance-title-icon">
- <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {!this.openAppearance ? (null) :
- <div className="propertiesView-appearance-content">
- {this.appearanceEditor}
- </div>}
- </div>}
-
- {this.isInk ? <div className="propertiesView-transform">
- <div className="propertiesView-transform-title"
- onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })}
- style={{ backgroundColor: this.openTransform ? "black" : "" }}>
- Transform
- <div className="propertiesView-transform-title-icon">
- <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openTransform ? <div className="propertiesView-transform-content">
- {this.transformEditor}
- </div> : null}
- </div> : null}
-
- <div className="propertiesView-fields">
- <div className="propertiesView-fields-title"
- onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
- style={{ backgroundColor: this.openFields ? "black" : "" }}>
- Fields {"&"} Tags
- <div className="propertiesView-fields-title-icon">
- <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {!novice && this.openFields ? <div className="propertiesView-fields-checkbox">
- {this.fieldsCheckbox}
- <div className="propertiesView-fields-checkbox-text">Layout</div>
- </div> : null}
- {!this.openFields ? (null) :
- <div className="propertiesView-fields-content">
- {novice ? this.noviceFields : this.expandedField}
- </div>}
- </div>
- <div className="propertiesView-layout">
- <div className="propertiesView-layout-title"
- onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}
- style={{ backgroundColor: this.openLayout ? "black" : "" }}>
- Layout
- <div className="propertiesView-layout-title-icon" onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}>
- <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openLayout ? <div className="propertiesView-layout-content" >{this.layoutPreview}</div> : null}
- </div>
- </div>;
- }
- if (this.isPres) {
- const selectedItem: boolean = PresBox.Instance?._selectedArray.length > 0;
- return <div className="propertiesView" style={{ width: this.props.width }}>
- <div className="propertiesView-title" style={{ width: this.props.width }}>
- Presentation
- </div>
- <div className="propertiesView-name">
- {this.editableTitle}
- <div className="propertiesView-presSelected">
- {PresBox.Instance?._selectedArray.length} selected
- <div className="propertiesView-selectedList">
- {PresBox.Instance?.listOfSelected}
- </div>
- </div>
- </div>
- {!selectedItem ? (null) : <div className="propertiesView-presTrails">
- <div className="propertiesView-presTrails-title"
- onPointerDown={action(() => { this.openPresTransitions = !this.openPresTransitions; })}
- style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
- <div className="propertiesView-presTrails-title-icon">
- <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openPresTransitions ? <div className="propertiesView-presTrails-content">
- {PresBox.Instance.transitionDropdown}
- </div> : null}
- </div>}
- {!selectedItem ? (null) : <div className="propertiesView-presTrails">
- <div className="propertiesView-presTrails-title"
- onPointerDown={() => runInAction(() => { this.openPresProgressivize = !this.openPresProgressivize; })}
- style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"tasks"} /> &nbsp; Progressivize
- <div className="propertiesView-presTrails-title-icon">
- <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
- {PresBox.Instance.progressivizeDropdown}
- </div> : null}
- </div>}
- {!selectedItem ? (null) : <div className="propertiesView-presTrails">
- <div className="propertiesView-presTrails-title"
- onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })}
- style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
- <div className="propertiesView-presTrails-title-icon">
- <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openSlideOptions ? <div className="propertiesView-presTrails-content">
- {PresBox.Instance.optionsDropdown}
- </div> : null}
- </div>}
- <div className="propertiesView-presTrails">
- <div className="propertiesView-presTrails-title"
- onPointerDown={() => runInAction(() => { this.openAddSlide = !this.openAddSlide; })}
- style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"plus"} /> &nbsp; Add new slide
- <div className="propertiesView-presTrails-title-icon">
- <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openAddSlide ? <div className="propertiesView-presTrails-content">
- {PresBox.Instance.newDocumentDropdown}
- </div> : null}
- </div>
- {/* <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
- style={{ backgroundColor: this.openSharing ? "black" : "" }}>
- Sharing {"&"} Permissions
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
- </div>
- </div>
- {this.openSharing ? <div className="propertiesView-sharing-content">
- {this.sharingTable}
- </div> : null}
- </div> */}
- </div>;
- }
- }
- }
-} \ No newline at end of file