aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-02-13 04:50:56 -0500
committerTyler Schicke <tyler_schicke@brown.edu>2019-02-13 04:50:56 -0500
commitc93c3e1970c6ecc91b60f1782e82b1bfdc7fef30 (patch)
tree47c30b57d3ec6ac3d1f535e8186c0cf527640010
parent46a4c26dbadefaf981637f79fb5f76e458baac9d (diff)
A lot of stuff working, a lot of other stuff not working
-rw-r--r--.vscode/launch.json6
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/util/SelectionManager.ts12
-rw-r--r--src/client/util/Transform.ts70
-rw-r--r--src/client/views/DocumentDecorations.tsx39
-rw-r--r--src/client/views/Main.tsx1
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx10
-rw-r--r--src/client/views/collections/CollectionFreeFormView.tsx55
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx4
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx10
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx138
-rw-r--r--src/client/views/nodes/DocumentView.tsx184
-rw-r--r--src/client/views/nodes/FieldView.tsx6
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.tsx4
15 files changed, 303 insertions, 240 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 9a0a9afb4..546ede805 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -11,7 +11,11 @@
"sourceMaps": true,
"breakOnLoad": true,
"url": "http://localhost:1050",
- "webRoot": "${workspaceFolder}"
+ "webRoot": "${workspaceFolder}",
+ "skipFiles": [
+ "${workspaceRoot}/node_modules/**/*.js",
+ "${workspaceRoot}/node_modules/**/*.ts",
+ ]
},
{
"type": "node",
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index f4dcce7c8..93b927f8b 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -78,6 +78,8 @@ export namespace DragManager {
dragElement.style.transformOrigin = "0 0";
dragElement.style.zIndex = "1000";
dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`;
+ dragElement.style.width = `${rect.width}px`;
+ dragElement.style.height = `${rect.height}px`;
dragDiv.appendChild(dragElement);
_lastPointerX = dragData["xOffset"] + rect.left;
_lastPointerY = dragData["yOffset"] + rect.top;
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 0759ae110..1a711ae64 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,13 +1,13 @@
-import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView";
import { observable, action } from "mobx";
+import { DocumentView } from "../views/nodes/DocumentView";
export namespace SelectionManager {
class Manager {
@observable
- SelectedDocuments: Array<CollectionFreeFormDocumentView> = [];
+ SelectedDocuments: Array<DocumentView> = [];
@action
- SelectDoc(doc: CollectionFreeFormDocumentView, ctrlPressed: boolean): void {
+ SelectDoc(doc: DocumentView, ctrlPressed: boolean): void {
// if doc is not in SelectedDocuments, add it
if (!ctrlPressed) {
manager.SelectedDocuments = [];
@@ -21,11 +21,11 @@ export namespace SelectionManager {
const manager = new Manager;
- export function SelectDoc(doc: CollectionFreeFormDocumentView, ctrlPressed: boolean): void {
+ export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void {
manager.SelectDoc(doc, ctrlPressed)
}
- export function IsSelected(doc: CollectionFreeFormDocumentView): boolean {
+ export function IsSelected(doc: DocumentView): boolean {
return manager.SelectedDocuments.indexOf(doc) !== -1;
}
@@ -33,7 +33,7 @@ export namespace SelectionManager {
manager.SelectedDocuments = []
}
- export function SelectedDocuments(): Array<CollectionFreeFormDocumentView> {
+ export function SelectedDocuments(): Array<DocumentView> {
return manager.SelectedDocuments;
}
} \ No newline at end of file
diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts
index 3edc8d569..8ae3f837f 100644
--- a/src/client/util/Transform.ts
+++ b/src/client/util/Transform.ts
@@ -23,29 +23,13 @@ export class Transform {
return this;
}
- translated = (x: number, y: number): Transform => {
- return this.copy().translate(x, y);
- }
-
- preTranslate = (x: number, y: number): Transform => {
- this._translateX += x * this._scale;
- this._translateY += y * this._scale;
- return this;
- }
-
- preTranslated = (x: number, y: number): Transform => {
- return this.copy().preTranslate(x, y);
- }
-
scale = (scale: number): Transform => {
this._scale *= scale;
+ this._translateX *= scale;
+ this._translateY *= scale;
return this;
}
- scaled = (scale: number): Transform => {
- return this.copy().scale(scale);
- }
-
scaleAbout = (scale: number, x: number, y: number): Transform => {
this._translateX += x * this._scale - x * this._scale * scale;
this._translateY += y * this._scale - y * this._scale * scale;
@@ -53,21 +37,6 @@ export class Transform {
return this;
}
- scaledAbout = (scale: number, x: number, y: number): Transform => {
- return this.copy().scaleAbout(scale, x, y);
- }
-
- preScale = (scale: number): Transform => {
- this._scale *= scale;
- this._translateX *= scale;
- this._translateY *= scale;
- return this;
- }
-
- preScaled = (scale: number): Transform => {
- return this.copy().preScale(scale);
- }
-
transform = (transform: Transform): Transform => {
this._translateX += transform._translateX * this._scale;
this._translateY += transform._translateY * this._scale;
@@ -75,8 +44,15 @@ export class Transform {
return this;
}
- transformed = (transform: Transform): Transform => {
- return this.copy().transform(transform);
+ preTranslate = (x: number, y: number): Transform => {
+ this._translateX += this._scale * x;
+ this._translateY += this._scale * y;
+ return this;
+ }
+
+ preScale = (scale: number): Transform => {
+ this._scale *= scale;
+ return this;
}
preTransform = (transform: Transform): Transform => {
@@ -86,6 +62,30 @@ export class Transform {
return this;
}
+ translated = (x: number, y: number): Transform => {
+ return this.copy().translate(x, y);
+ }
+
+ preTranslated = (x: number, y: number): Transform => {
+ return this.copy().preTranslate(x, y);
+ }
+
+ scaled = (scale: number): Transform => {
+ return this.copy().scale(scale);
+ }
+
+ scaledAbout = (scale: number, x: number, y: number): Transform => {
+ return this.copy().scaleAbout(scale, x, y);
+ }
+
+ preScaled = (scale: number): Transform => {
+ return this.copy().preScale(scale);
+ }
+
+ transformed = (transform: Transform): Transform => {
+ return this.copy().transform(transform);
+ }
+
preTransformed = (transform: Transform): Transform => {
return this.copy().preTransform(transform);
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 85b44307f..5abe3f5b2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -4,6 +4,8 @@ import { SelectionManager } from "../util/SelectionManager";
import { observer } from "mobx-react";
import './DocumentDecorations.scss'
import { CollectionFreeFormView } from "./collections/CollectionFreeFormView";
+import { KeyStore } from "../../fields/Key";
+import { NumberField } from "../../fields/NumberField";
@observer
export class DocumentDecorations extends React.Component {
@@ -25,9 +27,12 @@ export class DocumentDecorations extends React.Component {
!(element.props.ContainingCollectionView instanceof CollectionFreeFormView)) {
return bounds;
}
- let transform = element.getTransform().inverse();
+ let transform = element.props.GetTransform().inverse();
var [sptX, sptY] = transform.transformPoint(0, 0);
- var [bptX, bptY] = transform.transformDirection(element.width, element.height);
+ // var [bptX, bptY] = transform.transformDirection(element.width, element.height);
+ let doc = element.props.Document;
+ let [bptX, bptY] = [doc.GetNumber(KeyStore.Width, 0), doc.GetNumber(KeyStore.Height, 0)];
+ [bptX, bptY] = transform.transformPoint(bptX, bptY);
return {
x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
@@ -106,16 +111,32 @@ export class DocumentDecorations extends React.Component {
SelectionManager.SelectedDocuments().forEach(element => {
const rect = element.screenRect;
+ // if (rect.width !== 0) {
+ // let scale = element.width / rect.width;
+ // let actualdW = Math.max(element.width + (dW * scale), 20);
+ // let actualdH = Math.max(element.height + (dH * scale), 20);
+ // element.x += dX * (actualdW - element.width);
+ // element.y += dY * (actualdH - element.height);
+ // if (Math.abs(dW) > Math.abs(dH))
+ // element.width = actualdW;
+ // else
+ // element.height = actualdH;
+ // }
if (rect.width !== 0) {
- let scale = element.width / rect.width;
- let actualdW = Math.max(element.width + (dW * scale), 20);
- let actualdH = Math.max(element.height + (dH * scale), 20);
- element.x += dX * (actualdW - element.width);
- element.y += dY * (actualdH - element.height);
+ let doc = element.props.Document;
+ let width = doc.GetOrCreate(KeyStore.Width, NumberField);
+ let height = doc.GetOrCreate(KeyStore.Height, NumberField);
+ let x = doc.GetOrCreate(KeyStore.X, NumberField);
+ let y = doc.GetOrCreate(KeyStore.X, NumberField);
+ let scale = width.Data / rect.width;
+ let actualdW = Math.max(width.Data + (dW * scale), 20);
+ let actualdH = Math.max(height.Data + (dH * scale), 20);
+ x.Data += dX * (actualdW - width.Data);
+ y.Data += dY * (actualdH - height.Data);
if (Math.abs(dW) > Math.abs(dH))
- element.width = actualdW;
+ width.Data = actualdW;
else
- element.height = actualdH;
+ height.Data = actualdH;
}
})
}
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6ca0000b8..c7ad3e249 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -84,6 +84,7 @@ ReactDOM.render((
<DocumentView Document={mainContainer}
AddDocument={undefined} RemoveDocument={undefined} GetTransform={() => Transform.Identity}
Scaling={1}
+ isTopMost={true}
ContainingCollectionView={undefined} DocumentView={undefined} />
<DocumentDecorations />
<ContextMenu />
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index d3e90d11c..c870a9cf0 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -16,6 +16,7 @@ import "./CollectionDockingView.scss";
import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase";
import React = require("react");
import { changeDependenciesStateTo0 } from "mobx/lib/internal";
+import { Utils } from "../../../Utils";
@observer
export class CollectionDockingView extends CollectionViewBase {
@@ -100,6 +101,7 @@ export class CollectionDockingView extends CollectionViewBase {
return (<DocumentView key={value[i].Id} Document={value[i]}
AddDocument={this.addDocument} RemoveDocument={this.removeDocument}
GetTransform={() => Transform.Identity}
+ isTopMost={true}
Scaling={1}
ContainingCollectionView={this} DocumentView={undefined} />);
}
@@ -307,12 +309,16 @@ class RenderClass {
this.render();
}
render() {
- var nativeWidth = this._document.GetNumber(KeyStore.NativeWidth, 0);
+ let nativeWidth = this._document.GetNumber(KeyStore.NativeWidth, 0);
let scaling = nativeWidth > 0 ? this._htmlElement!.clientWidth / nativeWidth : 1;
ReactDOM.render((
<DocumentView key={this._document.Id} Document={this._document}
AddDocument={this._collectionDockingView.addDocument} RemoveDocument={this._collectionDockingView.removeDocument}
- GetTransform={() => Transform.Identity}
+ GetTransform={() => {
+ let { scale, translateX, translateY } = Utils.GetScreenTransform(this._htmlElement);
+ return this._collectionDockingView.props.GetTransform().scale(scale).translate(-translateX, -translateY)
+ }}
+ isTopMost={true}
Scaling={scaling}
ContainingCollectionView={this._collectionDockingView} DocumentView={undefined} />
),
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 975eaaae8..7947b1c51 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -14,6 +14,7 @@ import { NumberField } from "../../../fields/NumberField";
import { Documents } from "../../documents/Documents";
import { FieldWaiting } from "../../../fields/Field";
import { Transform } from "../../util/Transform";
+import { DocumentView } from "../nodes/DocumentView";
@observer
export class CollectionFreeFormView extends CollectionViewBase {
@@ -45,23 +46,21 @@ export class CollectionFreeFormView extends CollectionViewBase {
@action
drop = (e: Event, de: DragManager.DropEvent) => {
- const doc = de.data["document"];
+ const doc: DocumentView = de.data["document"];
var me = this;
- if (doc instanceof CollectionFreeFormDocumentView) {
- if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) {
- doc.props.ContainingCollectionView.removeDocument(doc.props.Document);
- this.addDocument(doc.props.Document);
- }
- const xOffset = de.data["xOffset"] as number || 0;
- const yOffset = de.data["yOffset"] as number || 0;
- const { translateX, translateY } = Utils.GetScreenTransform(this._canvasRef.current!);
- const currScale = this.resizeScaling * this.zoomScaling * this.props.ContainingDocumentView!.ScalingToScreenSpace;
- const screenX = de.x - xOffset;
- const screenY = de.y - yOffset;
- doc.x = (screenX - translateX) / currScale;
- doc.y = (screenY - translateY) / currScale;
- this.bringToFront(doc);
+ if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this) {
+ doc.props.ContainingCollectionView.removeDocument(doc.props.Document);
+ this.addDocument(doc.props.Document);
}
+ const xOffset = de.data["xOffset"] as number || 0;
+ const yOffset = de.data["yOffset"] as number || 0;
+ const transform = doc.props.GetTransform();
+ const screenX = de.x - xOffset;
+ const screenY = de.y - yOffset;
+ const [x, y] = transform.transformPoint(screenX, screenY);
+ doc.props.Document.SetNumber(KeyStore.X, x);
+ doc.props.Document.SetNumber(KeyStore.Y, y);
+ this.bringToFront(doc);
e.stopPropagation();
}
@@ -94,8 +93,8 @@ export class CollectionFreeFormView extends CollectionViewBase {
document.removeEventListener("pointerup", this.onPointerUp);
e.stopPropagation();
if (Math.abs(this._downX - e.clientX) < 3 && Math.abs(this._downY - e.clientY) < 3) {
- if (!SelectionManager.IsSelected(this.props.ContainingDocumentView as CollectionFreeFormDocumentView)) {
- SelectionManager.SelectDoc(this.props.ContainingDocumentView as CollectionFreeFormDocumentView, false);
+ if (!this.props.isSelected()) {
+ this.props.select(false);
}
}
}
@@ -105,11 +104,11 @@ export class CollectionFreeFormView extends CollectionViewBase {
if (!e.cancelBubble && this.active) {
e.preventDefault();
e.stopPropagation();
- let currScale: number = this.props.ContainingDocumentView!.ScalingToScreenSpace;
let x = this.props.DocumentForCollection.GetNumber(KeyStore.PanX, 0);
let y = this.props.DocumentForCollection.GetNumber(KeyStore.PanY, 0);
+ let [dx, dy] = this.props.GetTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
- this.SetPan(x + (e.pageX - this._lastX) / currScale, y + (e.pageY - this._lastY) / currScale);
+ this.SetPan(x + dx, y + dy);
}
this._lastX = e.pageX;
this._lastY = e.pageY;
@@ -124,15 +123,14 @@ export class CollectionFreeFormView extends CollectionViewBase {
// if (modes[e.deltaMode] == 'pixels') coefficient = 50;
// else if (modes[e.deltaMode] == 'lines') coefficient = 1000; // This should correspond to line-height??
let transform = this.getTransform();
- let localTransform = this.getLocalTransform();
- let deltaScale = (1 - (e.deltaY / coefficient)) * transform.Scale;
- let newDeltaScale = this.isAnnotationOverlay ? Math.max(1, deltaScale) : deltaScale;
+ let deltaScale = (1 - (e.deltaY / coefficient));
let [x, y] = transform.transformPoint(e.clientX, e.clientY);
- localTransform.scaleAbout(newDeltaScale, x, y);
+ let localTransform = this.getLocalTransform();
+ localTransform.scaleAbout(deltaScale, x, y);
- this.props.DocumentForCollection.SetNumber(KeyStore.Scale, newDeltaScale);
+ this.props.DocumentForCollection.SetNumber(KeyStore.Scale, localTransform.Scale);
this.SetPan(localTransform.TranslateX, localTransform.TranslateY);
}
@@ -182,7 +180,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
}
@action
- bringToFront(doc: CollectionFreeFormDocumentView) {
+ bringToFront(doc: DocumentView) {
const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props;
const value: Document[] = Document.GetList<Document>(fieldKey, []);
@@ -213,12 +211,12 @@ export class CollectionFreeFormView extends CollectionViewBase {
getTransform = (): Transform => {
const [x, y] = this.translate;
- return this.props.GetTransform().scaled(this.scale).translate(x, y);
+ return this.props.GetTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.getLocalTransform().inverse())
}
getLocalTransform = (): Transform => {
const [x, y] = this.translate;
- return new Transform(x, y, this.scale);
+ return Transform.Identity.scale(this.scale).translate(x, y);
}
render() {
@@ -249,8 +247,9 @@ export class CollectionFreeFormView extends CollectionViewBase {
AddDocument={this.addDocument}
RemoveDocument={this.removeDocument}
GetTransform={this.getTransform}
+ isTopMost={false}
Scaling={1}
- ContainingCollectionView={this} DocumentView={undefined} />);
+ ContainingCollectionView={this} DocumentView={this.props.ContainingDocumentView} />);
})}
</div>
</div>
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index f1e882e20..adae8560e 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -27,7 +27,8 @@ export class CollectionSchemaView extends CollectionViewBase {
let props: FieldViewProps = {
doc: rowProps.value[0],
fieldKey: rowProps.value[1],
- DocumentViewForField: undefined,
+ isSelected: () => false,
+ isTopMost: false
}
let contents = (
<FieldView {...props} />
@@ -110,6 +111,7 @@ export class CollectionSchemaView extends CollectionViewBase {
AddDocument={this.addDocument} RemoveDocument={this.removeDocument}
GetTransform={() => Transform.Identity}//TODO This should probably be an actual transform
Scaling={1}
+ isTopMost={false}
DocumentView={undefined} ContainingCollectionView={this} />
)
} else {
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index cf5bc70c4..2c950c8ae 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -18,6 +18,9 @@ export interface CollectionViewProps {
DocumentForCollection: Document;
ContainingDocumentView: Opt<DocumentView>;
GetTransform: () => Transform;
+ isSelected: () => boolean;
+ isTopMost: boolean;
+ select: (ctrlPressed: boolean) => void;
BackgroundView: Opt<DocumentView>;
Scaling: number;
}
@@ -29,16 +32,15 @@ export class CollectionViewBase extends React.Component<CollectionViewProps> {
public static LayoutString(collectionType: string, fieldKey: string = "DataKey") {
return `<${collectionType} Scaling={Scaling} DocumentForCollection={Document}
- GetTransform={GetTransform} CollectionFieldKey={${fieldKey}}
+ GetTransform={GetTransform} CollectionFieldKey={${fieldKey}} isSelected={isSelected} select={select}
+ isTopMost={isTopMost}
ContainingDocumentView={DocumentView} BackgroundView={BackgroundView} />`;
}
@computed
public get active(): boolean {
var isSelected = (this.props.ContainingDocumentView instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.ContainingDocumentView));
var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this);
- var topMost = this.props.ContainingDocumentView != undefined && (
- this.props.ContainingDocumentView.props.ContainingCollectionView == undefined ||
- this.props.ContainingDocumentView.props.ContainingCollectionView instanceof CollectionDockingView);
+ var topMost = this.props.isTopMost;
return isSelected || childSelected || topMost;
}
@action
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 9cd42a069..54bc7327b 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -14,11 +14,8 @@ import { Transform } from "../../util/Transform";
@observer
-export class CollectionFreeFormDocumentView extends DocumentView {
- private _contextMenuCanOpen = false;
- private _downX: number = 0;
- private _downY: number = 0;
- // private _mainCont = React.createRef<HTMLDivElement>();
+export class CollectionFreeFormDocumentView extends React.Component<DocumentViewProps> {
+ private _mainCont = React.createRef<HTMLDivElement>();
constructor(props: DocumentViewProps) {
super(props);
@@ -95,130 +92,6 @@ export class CollectionFreeFormDocumentView extends DocumentView {
this.props.Document.SetData(KeyStore.ZIndex, h, NumberField)
}
- @action
- dragComplete = (e: DragManager.DragCompleteEvent) => {
- }
-
- @computed
- get active(): boolean {
- return SelectionManager.IsSelected(this) || this.props.ContainingCollectionView === undefined ||
- this.props.ContainingCollectionView.active;
- }
-
- @computed
- get topMost(): boolean {
- return this.props.ContainingCollectionView == undefined || this.props.ContainingCollectionView instanceof CollectionDockingView;
- }
-
- onPointerDown = (e: React.PointerEvent): void => {
- this._downX = e.clientX;
- this._downY = e.clientY;
- var me = this;
- if (e.shiftKey && e.buttons === 1) {
- CollectionDockingView.StartOtherDrag(this._mainCont.current!, this.props.Document);
- e.stopPropagation();
- return;
- }
- this._contextMenuCanOpen = e.button == 2;
- if (this.active && !e.isDefaultPrevented()) {
- e.stopPropagation();
- if (e.buttons === 2) {
- e.preventDefault();
- }
- document.removeEventListener("pointermove", this.onPointerMove)
- document.addEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp)
- document.addEventListener("pointerup", this.onPointerUp);
- }
- }
-
- onPointerMove = (e: PointerEvent): void => {
- if (e.cancelBubble) {
- this._contextMenuCanOpen = false;
- return;
- }
- if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
- this._contextMenuCanOpen = false;
- if (this._mainCont.current != null && !this.topMost) {
- this._contextMenuCanOpen = false;
- const rect = this.screenRect;
- let dragData: { [id: string]: any } = {};
- dragData["document"] = this;
- dragData["xOffset"] = e.x - rect.left;
- dragData["yOffset"] = e.y - rect.top;
- DragManager.StartDrag(this._mainCont.current, dragData, {
- handlers: {
- dragComplete: this.dragComplete,
- },
- hideSource: true
- })
- }
- }
- e.stopPropagation();
- e.preventDefault();
- }
-
- onPointerUp = (e: PointerEvent): void => {
- document.removeEventListener("pointermove", this.onPointerMove)
- document.removeEventListener("pointerup", this.onPointerUp)
- e.stopPropagation();
- if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
- SelectionManager.SelectDoc(this, e.ctrlKey);
- }
- }
-
- openRight = (e: React.MouseEvent): void => {
- CollectionDockingView.AddRightSplit(this.props.Document);
- }
-
- deleteClicked = (e: React.MouseEvent): void => {
- if (this.props.ContainingCollectionView instanceof CollectionFreeFormView) {
- this.props.ContainingCollectionView.removeDocument(this.props.Document)
- }
- }
- @action
- fullScreenClicked = (e: React.MouseEvent): void => {
- CollectionDockingView.OpenFullScreen(this.props.Document);
- ContextMenu.Instance.clearItems();
- ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked });
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
- }
- @action
- closeFullScreenClicked = (e: React.MouseEvent): void => {
- CollectionDockingView.CloseFullScreen();
- ContextMenu.Instance.clearItems();
- ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
- }
-
- @action
- onContextMenu = (e: React.MouseEvent): void => {
- if (!SelectionManager.IsSelected(this)) {
- return;
- }
- e.preventDefault()
-
- if (!this._contextMenuCanOpen) {
- return;
- }
-
- if (this.topMost) {
- ContextMenu.Instance.clearItems()
- ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
- }
- else {
- // DocumentViews should stop propogation of this event
- e.stopPropagation();
-
- ContextMenu.Instance.clearItems();
- ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
- ContextMenu.Instance.addItem({ description: "Open Right", event: this.openRight })
- ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked })
- ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
- SelectionManager.SelectDoc(this, e.ctrlKey);
- }
- }
getTransform = (): Transform => {
return this.props.GetTransform().translated(this.x, this.y);
@@ -234,11 +107,10 @@ export class CollectionFreeFormDocumentView extends DocumentView {
height: freestyling ? this.height : "100%",
position: freestyling ? "absolute" : "relative",
zIndex: freestyling ? this.zIndex : 0,
- }}
- onContextMenu={this.onContextMenu}
- onPointerDown={this.onPointerDown}>
+ backgroundColor: "transparent"
+ }} >
- <DocumentView {...this.props} Scaling={this.width / this.nativeWidth} GetTransform={this.getTransform} DocumentView={this} />
+ <DocumentView {...this.props} Scaling={this.width / this.nativeWidth} GetTransform={this.getTransform} />
</div>
);
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d7ecc6d9d..cb080c08e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -16,6 +16,9 @@ import { ImageBox } from "../nodes/ImageBox";
import "./NodeView.scss";
import React = require("react");
import { Transform } from "../../util/Transform";
+import { SelectionManager } from "../../util/SelectionManager";
+import { DragManager } from "../../util/DragManager";
+import { ContextMenu } from "../ContextMenu";
const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
export interface DocumentViewProps {
@@ -26,24 +29,34 @@ export interface DocumentViewProps {
AddDocument?: (doc: Document) => void;
RemoveDocument?: (doc: Document) => boolean;
GetTransform: () => Transform;
+ isTopMost: boolean;
Scaling: number;
}
@observer
export class DocumentView extends React.Component<DocumentViewProps> {
- protected _mainCont = React.createRef<any>();
+ private _mainCont = React.createRef<HTMLDivElement>();
get MainContent() {
return this._mainCont;
}
+ get screenRect(): ClientRect | DOMRect {
+ if (this._mainCont.current) {
+ return this._mainCont.current.getBoundingClientRect();
+ }
+ return new DOMRect();
+ }
@computed
get layout(): string {
return this.props.Document.GetData(KeyStore.Layout, TextField, String("<p>Error loading layout data</p>"));
}
@computed
- get backgroundLayout(): string {
- return this.props.Document.GetData(KeyStore.BackgroundLayout, TextField, String("<p>Error loading layout data</p>"));
+ get backgroundLayout(): string | undefined {
+ let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField);
+ if (field && field !== "<Waiting>") {
+ return field.Data;
+ }
}
@computed
@@ -56,6 +69,134 @@ export class DocumentView extends React.Component<DocumentViewProps> {
return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>());
}
+ @computed
+ get active(): boolean {
+ return SelectionManager.IsSelected(this) || this.props.ContainingCollectionView === undefined ||
+ this.props.ContainingCollectionView.active;
+ }
+
+ private _contextMenuCanOpen = false;
+ private _downX: number = 0;
+ private _downY: number = 0;
+ onPointerDown = (e: React.PointerEvent): void => {
+ this._downX = e.clientX;
+ this._downY = e.clientY;
+ var me = this;
+ if (e.shiftKey && e.buttons === 1) {
+ CollectionDockingView.StartOtherDrag(this._mainCont.current!, this.props.Document);
+ e.stopPropagation();
+ return;
+ }
+ this._contextMenuCanOpen = e.button == 2;
+ if (this.active && !e.isDefaultPrevented()) {
+ e.stopPropagation();
+ if (e.buttons === 2) {
+ e.preventDefault();
+ }
+ document.removeEventListener("pointermove", this.onPointerMove)
+ document.addEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp)
+ document.addEventListener("pointerup", this.onPointerUp);
+ }
+ }
+
+ @action
+ dragComplete = (e: DragManager.DragCompleteEvent) => {
+ }
+
+ @computed
+ get topMost(): boolean {
+ return this.props.ContainingCollectionView == undefined || this.props.ContainingCollectionView instanceof CollectionDockingView;
+ }
+
+ onPointerMove = (e: PointerEvent): void => {
+ if (e.cancelBubble) {
+ this._contextMenuCanOpen = false;
+ return;
+ }
+ if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
+ this._contextMenuCanOpen = false;
+ if (this._mainCont.current != null && !this.topMost) {
+ this._contextMenuCanOpen = false;
+ const [left, top] = this.props.GetTransform().inverse().transformPoint(0, 0);
+ let dragData: { [id: string]: any } = {};
+ dragData["document"] = this;
+ dragData["xOffset"] = e.x - left;
+ dragData["yOffset"] = e.y - top;
+ DragManager.StartDrag(this._mainCont.current, dragData, {
+ handlers: {
+ dragComplete: this.dragComplete,
+ },
+ hideSource: true
+ })
+ }
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ onPointerUp = (e: PointerEvent): void => {
+ document.removeEventListener("pointermove", this.onPointerMove)
+ document.removeEventListener("pointerup", this.onPointerUp)
+ e.stopPropagation();
+ if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
+ SelectionManager.SelectDoc(this, e.ctrlKey);
+ }
+ }
+
+ openRight = (e: React.MouseEvent): void => {
+ CollectionDockingView.AddRightSplit(this.props.Document);
+ }
+
+ deleteClicked = (e: React.MouseEvent): void => {
+ if (this.props.RemoveDocument) {
+ this.props.RemoveDocument(this.props.Document);
+ }
+ }
+ @action
+ fullScreenClicked = (e: React.MouseEvent): void => {
+ CollectionDockingView.OpenFullScreen(this.props.Document);
+ ContextMenu.Instance.clearItems();
+ ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked });
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
+ }
+ @action
+ closeFullScreenClicked = (e: React.MouseEvent): void => {
+ CollectionDockingView.CloseFullScreen();
+ ContextMenu.Instance.clearItems();
+ ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
+ }
+
+ @action
+ onContextMenu = (e: React.MouseEvent): void => {
+ if (!SelectionManager.IsSelected(this)) {
+ return;
+ }
+ e.preventDefault()
+
+ if (!this._contextMenuCanOpen) {
+ return;
+ }
+
+ if (this.topMost) {
+ ContextMenu.Instance.clearItems()
+ ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
+ }
+ else {
+ // DocumentViews should stop propogation of this event
+ e.stopPropagation();
+
+ ContextMenu.Instance.clearItems();
+ ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked })
+ ContextMenu.Instance.addItem({ description: "Open Right", event: this.openRight })
+ ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked })
+ ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
+ SelectionManager.SelectDoc(this, e.ctrlKey);
+ }
+ }
+
//
// returns the cumulative scaling between the document and the screen
//
@@ -69,9 +210,19 @@ export class DocumentView extends React.Component<DocumentViewProps> {
return 1;
}
+ isSelected = () => {
+ return SelectionManager.IsSelected(this);
+ }
+
+ select = (ctrlPressed: boolean) => {
+ SelectionManager.SelectDoc(this, ctrlPressed)
+ }
+
render() {
let bindings = { ...this.props } as any;
+ bindings.isSelected = this.isSelected;
+ bindings.select = this.select;
for (const key of this.layoutKeys) {
bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data
}
@@ -82,26 +233,29 @@ export class DocumentView extends React.Component<DocumentViewProps> {
let field = this.props.Document.Get(key);
bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field;
}
- if (bindings.DocumentView === undefined) {
- bindings.DocumentView = this; // set the DocumentView to this if it hasn't already been set by a sub-class during its render method.
+ let annotated = null;
+ let backgroundLayout = this.backgroundLayout;
+ if (backgroundLayout) {
+ annotated = <JsxParser
+ components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }}
+ bindings={bindings}
+ jsx={this.backgroundLayout}
+ showWarnings={true}
+ onError={(test: any) => { console.log(test) }}
+ />;
}
- var annotated = <JsxParser
- components={{ FormattedTextBox: FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }}
- bindings={bindings}
- jsx={this.backgroundLayout}
- showWarnings={true}
- onError={(test: any) => { console.log(test) }}
- />;
- bindings["BackgroundView"] = this.backgroundLayout ? annotated : null;
+ bindings.BackgroundView = annotated;
var width = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
var strwidth = width > 0 ? width.toString() + "px" : "100%";
var height = this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
var strheight = height > 0 ? height.toString() + "px" : "100%";
return (
- <div className="node" ref={this._mainCont} style={{ width: strwidth, height: strheight, transformOrigin: "left top", transform: `scale(${this.props.Scaling},${this.props.Scaling})` }}>
+ <div className="node" ref={this._mainCont} style={{ width: strwidth, height: strheight, transformOrigin: "left top", transform: `scale(${this.props.Scaling},${this.props.Scaling})` }}
+ onContextMenu={this.onContextMenu}
+ onPointerDown={this.onPointerDown} >
<JsxParser
- components={{ FormattedTextBox: FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }}
+ components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }}
bindings={bindings}
jsx={this.layout}
showWarnings={true}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 12371eb2e..08de53e1c 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -10,7 +10,6 @@ import { ImageField } from "../../../fields/ImageField";
import { Key } from "../../../fields/Key";
import { FormattedTextBox } from "./FormattedTextBox";
import { ImageBox } from "./ImageBox";
-import { DocumentView } from "./DocumentView";
//
// these properties get assigned through the render() method of the DocumentView when it creates this node.
@@ -20,12 +19,13 @@ import { DocumentView } from "./DocumentView";
export interface FieldViewProps {
fieldKey: Key;
doc: Document;
- DocumentViewForField: Opt<DocumentView>
+ isSelected: () => boolean;
+ isTopMost: boolean;
}
@observer
export class FieldView extends React.Component<FieldViewProps> {
- public static LayoutString(fieldType: string) { return `<${fieldType} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} />`; }
+ public static LayoutString(fieldType: string) { return `<${fieldType} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} isSelected={isSelected} isTopMost={isTopMost} />`; }
@computed
get field(): FieldValue<Field> {
const { doc, fieldKey } = this.props;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index f6bd0c0f8..2e3d396c1 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -110,7 +110,7 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
}
onPointerDown = (e: React.PointerEvent): void => {
let me = this;
- if (e.buttons === 1 && me.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(me.props.DocumentViewForField)) {
+ if (e.buttons === 1 && this.props.isSelected()) {
e.stopPropagation();
}
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 2fa70734d..e1fa26e2f 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -41,7 +41,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
onPointerDown = (e: React.PointerEvent): void => {
if (Date.now() - this._lastTap < 300) {
- if (e.buttons === 1 && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) {
+ if (e.buttons === 1 && this.props.isSelected()) {
e.stopPropagation();
this._downX = e.clientX;
this._downY = e.clientY;
@@ -63,7 +63,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
lightbox = (path: string) => {
const images = [path, "http://www.cs.brown.edu/~bcz/face.gif"];
- if (this._isOpen && this.props.DocumentViewForField instanceof CollectionFreeFormDocumentView && SelectionManager.IsSelected(this.props.DocumentViewForField)) {
+ if (this._isOpen && this.props.isSelected()) {
return (<Lightbox
mainSrc={images[this._photoIndex]}
nextSrc={images[(this._photoIndex + 1) % images.length]}