From 6a04f60ce76fbd8274dd9daf285042f9cab16656 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Mon, 21 Jan 2019 21:42:03 -0500
Subject: context menu basics working

---
 src/views/freeformcanvas/FreeFormCanvas.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/views/freeformcanvas/FreeFormCanvas.tsx')

diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx
index de5e88fa1..d7dc0ecaa 100644
--- a/src/views/freeformcanvas/FreeFormCanvas.tsx
+++ b/src/views/freeformcanvas/FreeFormCanvas.tsx
@@ -79,9 +79,9 @@ export class FreeFormCanvas extends React.Component<IProps> {
             <div className="freeformcanvas-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()}>
                 <div className="freeformcanvas" style={{ transform: store.Transform, transformOrigin: '50% 50%' }}>
                     <div className="node-container">
-                        {this.props.store.Docs.map(doc => {
-                            return (<DocumentView key={doc.Id} dvm={new DocumentViewModel(doc)} />);
-                        })}
+                        {/* {this.props.store.Docs.map(doc => {
+                            return (<DocumentView key={doc.Id} parent={null} dvm={new DocumentViewModel(doc)} />);
+                        })} */}
                     </div>
                 </div>
             </div>
-- 
cgit v1.2.3-70-g09d2


From f98e634ae7070cd841bc523514d147195308696c Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 25 Jan 2019 18:34:28 -0500
Subject: got rid of documentviewmodel.  fixed panning/zooming.

---
 src/Main.tsx                                       |  11 +-
 src/documents/Documents.ts                         |  10 +-
 src/fields/Document.ts                             |   3 +-
 src/viewmodels/DocumentViewModel.ts                |  10 --
 .../freeformcanvas/CollectionFreeFormView.tsx      | 150 +++++++++++++--------
 src/views/freeformcanvas/FreeFormCanvas.scss       |  15 ---
 src/views/freeformcanvas/FreeFormCanvas.tsx        |  90 -------------
 src/views/nodes/DocumentView.tsx                   | 118 +++++++++-------
 8 files changed, 176 insertions(+), 231 deletions(-)
 delete mode 100644 src/views/freeformcanvas/FreeFormCanvas.scss
 delete mode 100644 src/views/freeformcanvas/FreeFormCanvas.tsx

(limited to 'src/views/freeformcanvas/FreeFormCanvas.tsx')

diff --git a/src/Main.tsx b/src/Main.tsx
index cb91c33a3..c2275b6a7 100644
--- a/src/Main.tsx
+++ b/src/Main.tsx
@@ -5,7 +5,6 @@ import "normalize.css"
 import { NodeCollectionStore } from './stores/NodeCollectionStore';
 import { StaticTextNodeStore } from './stores/StaticTextNodeStore';
 import { VideoNodeStore } from './stores/VideoNodeStore';
-import { FreeFormCanvas } from './views/freeformcanvas/FreeFormCanvas';
 import { Key, KeyStore as KS, KeyStore } from './fields/Key';
 import { NumberField } from './fields/NumberField';
 import { Document } from './fields/Document';
@@ -27,8 +26,6 @@ const mainNodeCollection = new Array<Document>();
 let mainContainer = Documents.CollectionDocument(mainNodeCollection, {
     x: 0, y: 0, width: window.screen.width, height: window.screen.height
 })
-let mainContvm = new DocumentViewModel(mainContainer);
-mainContvm.IsMainDoc = true;
 
 window.addEventListener("drop", function(e) {
     e.preventDefault();
@@ -43,9 +40,9 @@ document.addEventListener("pointerdown", action(function(e: PointerEvent) {
 }), true)
 
 ReactDOM.render((
-    <div style={{display: "grid", width: "100vw", height: "100vh"}}>
+    <div style={{display: "grid"}}>
         <h1>Dash Web</h1>
-        <DocumentView dvm={mainContvm} parent={undefined} />
+        <DocumentView Document={mainContainer} ContainingCollectionView={undefined} ContainingDocumentView={undefined}/>
         <DocumentDecorations />
         <ContextMenu />
     </div>), document.getElementById('root'));
@@ -75,10 +72,10 @@ runInAction(() => {
     });
     let docset = new Array<Document>(doc1, doc2);
     let doc4 = Documents.CollectionDocument(docset, {
-        x: 100, y: 400
+        x: 0, y: 400
     });
     let doc5 = Documents.ImageDocument("https://static.boredpanda.com/blog/wp-content/uploads/2018/04/5acb63d83493f__700-png.jpg", {
-        x: 650, y: 500
+        x: 1280, y: 500
     });
     let mainNodes = mainContainer.GetFieldT(KeyStore.Data, ListField);
     if (!mainNodes) {
diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts
index 75cc3b491..5fee7343b 100644
--- a/src/documents/Documents.ts
+++ b/src/documents/Documents.ts
@@ -25,6 +25,9 @@ export namespace Documents {
         if(options.height) {
             doc.SetFieldValue(KeyStore.Height, options.height, NumberField);
         }
+        doc.SetFieldValue(KeyStore.Scale, 1, NumberField);
+        doc.SetFieldValue(KeyStore.PanX, 0, NumberField);
+        doc.SetFieldValue(KeyStore.PanY, 0, NumberField);
     }
 
     let textProto:Document;
@@ -35,7 +38,7 @@ export namespace Documents {
             textProto.SetField(KeyStore.Y, new NumberField(0));
             textProto.SetField(KeyStore.Width, new NumberField(300));
             textProto.SetField(KeyStore.Height, new NumberField(150));
-            textProto.SetField(KeyStore.Layout, new TextField("<FieldTextBox doc={dvm.Doc} fieldKey={DataKey} />"));
+            textProto.SetField(KeyStore.Layout, new TextField("<FieldTextBox doc={Document} fieldKey={DataKey} />"));
             textProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data]));
         }
         return textProto;
@@ -75,9 +78,12 @@ export namespace Documents {
             collectionProto = new Document();
             collectionProto.SetField(KeyStore.X, new NumberField(0));
             collectionProto.SetField(KeyStore.Y, new NumberField(0));
+            collectionProto.SetField(KeyStore.Scale, new NumberField(1));
+            collectionProto.SetField(KeyStore.PanX, new NumberField(0));
+            collectionProto.SetField(KeyStore.PanY, new NumberField(0));
             collectionProto.SetField(KeyStore.Width, new NumberField(300));
             collectionProto.SetField(KeyStore.Height, new NumberField(300));
-            collectionProto.SetField(KeyStore.Layout, new TextField('<CollectionFreeFormView dvm={dvm} fieldKey={DataKey} isSelected={isSelected}/>'));
+            collectionProto.SetField(KeyStore.Layout, new TextField('<CollectionFreeFormView Document={Document} fieldKey={DataKey} ContainingDocumentView={ContainingDocumentView} isSelected={isSelected}/>'));
             collectionProto.SetField(KeyStore.LayoutKeys, new ListField([KeyStore.Data]));
         }
         return collectionProto;
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 0bba9c21e..6b1cccaf9 100644
--- a/src/fields/Document.ts
+++ b/src/fields/Document.ts
@@ -31,7 +31,8 @@ export class Document extends Field {
 
     GetFieldValue<T, U extends { Data: T }>(key: Key, ctor: { new(): U }, defaultVal: T): T {
         let val = this.GetField(key);
-        return (val && val instanceof ctor) ? val.Data : defaultVal;
+        let vval = (val && val instanceof ctor) ? val.Data : defaultVal;
+        return vval;
     }
 
     SetField(key: Key, field: Opt<Field>): void {
diff --git a/src/viewmodels/DocumentViewModel.ts b/src/viewmodels/DocumentViewModel.ts
index 21e88f964..008275f3c 100644
--- a/src/viewmodels/DocumentViewModel.ts
+++ b/src/viewmodels/DocumentViewModel.ts
@@ -8,14 +8,4 @@ export class DocumentViewModel {
     get Doc(): Document {
         return this.doc;
     }
-
-    private _isMainDoc = false
-
-    get IsMainDoc(): boolean {
-        return this._isMainDoc;
-    }
-
-    set IsMainDoc(v: boolean) {
-        this._isMainDoc = v;
-    }
 }
\ No newline at end of file
diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/freeformcanvas/CollectionFreeFormView.tsx
index 84b30ac38..383d71d83 100644
--- a/src/views/freeformcanvas/CollectionFreeFormView.tsx
+++ b/src/views/freeformcanvas/CollectionFreeFormView.tsx
@@ -1,8 +1,7 @@
 import { observer } from "mobx-react";
 import { Key, KeyStore } from "../../fields/Key";
-import "./FreeFormCanvas.scss";
 import React = require("react");
-import { action, observable } from "mobx";
+import { action, observable, computed } from "mobx";
 import { Document } from "../../fields/Document";
 import { DocumentViewModel } from "../../viewmodels/DocumentViewModel";
 import { DocumentView } from "../nodes/DocumentView";
@@ -13,85 +12,123 @@ import { DocumentDecorations } from "../../DocumentDecorations";
 import { SelectionManager } from "../../util/SelectionManager";
 import { Documents } from "../../documents/Documents";
 import { ContextMenu } from "../ContextMenu";
+import { Opt } from "../../fields/Field";
 
 interface IProps {
     fieldKey: Key;
-    dvm: DocumentViewModel;
-    isSelected: boolean;
+    Document: Document;
+    ContainingDocumentView: Opt<DocumentView>;
 }
 
 @observer
 export class CollectionFreeFormView extends React.Component<IProps> {
 
-    private _isPointerDown: boolean = false;
-
     constructor(props: IProps) {
         super(props);
     }
 
-    @action
-    onPointerDown = (e: React.PointerEvent): void => {
-        if (!this.props.isSelected && !this.props.dvm.IsMainDoc) {
-            return;
-        }
-
-        if (this.props.dvm.IsMainDoc) {
-            SelectionManager.DeselectAll()
-        }
+    @computed
+    public get active():boolean {
+        var isSelected    = (this.props.ContainingDocumentView != undefined &&  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;
+        return isSelected || childSelected || topMost;
+    }
 
-        e.stopPropagation();
-        if (e.button === 2) {
-            this._isPointerDown = true;
+    _lastX: number = 0;
+    _lastY:number = 0;
+    @action
+    onPointerDown = (e: React.PointerEvent): void => 
+    {
+        if (this.active && e.button === 2) {
+            e.stopPropagation();
+            e.preventDefault();
             document.removeEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointerup", this.onPointerUp);
+            this._lastX = e.pageX;
+            this._lastY = e.pageY;
         }
     }
 
     @action
     onPointerUp = (e: PointerEvent): void => {
+        document.removeEventListener("pointermove", this.onPointerMove);
+        document.removeEventListener("pointerup", this.onPointerUp);
         e.stopPropagation();
-        if (e.button === 2) {
-            this._isPointerDown = false;
-            document.removeEventListener("pointermove", this.onPointerMove);
-            document.removeEventListener("pointerup", this.onPointerUp);
+
+        var topMost = this.props.ContainingDocumentView != undefined && this.props.ContainingDocumentView.props.ContainingCollectionView == undefined;
+        if (topMost) {
+            SelectionManager.DeselectAll()
         }
     }
 
     @action
-    onPointerMove = (e: PointerEvent): void => {
-        e.preventDefault();
-        e.stopPropagation();
-        if (!this._isPointerDown) {
-            return;
+    onPointerMove = (e: PointerEvent): void => 
+    {
+        if (!e.cancelBubble) {
+            e.preventDefault();
+            e.stopPropagation();
+            const doc = this.props.Document;
+            let me = this;
+            let currScale:number = this.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
+            if (me.props.ContainingDocumentView!.props.ContainingDocumentView != undefined) {
+                let pme = me.props.ContainingDocumentView!.props.ContainingDocumentView!.props.Document;
+                currScale = pme.GetFieldValue(KeyStore.Scale, NumberField, Number(0));
+            } 
+            let x = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
+            let y = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
+            doc.SetFieldValue(KeyStore.PanX, x + (e.pageX - this._lastX)/currScale, NumberField);
+            doc.SetFieldValue(KeyStore.PanY, y + (e.pageY - this._lastY)/currScale, NumberField);
+            this._lastX = e.pageX;
+            this._lastY = e.pageY;
+
+            DocumentDecorations.Instance.forceUpdate()
         }
-        const { dvm } = this.props;
-        const doc = dvm.Doc;
+    }
 
-        let x = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
-        let y = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
-        doc.SetFieldValue(KeyStore.PanX, x + e.movementX, NumberField);
-        doc.SetFieldValue(KeyStore.PanY, y + e.movementY, NumberField);
 
-        DocumentDecorations.Instance.forceUpdate()
+    private getLocalPoint(me:DocumentView, inputX: number, inputY: number) {
+        let ContainerX = inputX;
+        let ContainerY = inputY;
+        if (me.props.ContainingDocumentView != undefined) {
+            let pme = me.props.ContainingDocumentView!;
+            let {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy} = this.getLocalPoint(pme, ContainerX, ContainerY);
+            ContainerX = LocalX;
+            ContainerY = LocalY;
+        } 
+
+        let W      = me.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0));
+        let Xx     = me.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0));
+        let Yy     = me.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0));
+        let Ss     = me.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
+        let Panxx  = me.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
+        let Panyy  = me.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
+        let LocalX = W / 2 - (Xx + Panxx) / Ss + (ContainerX - W / 2) / Ss;
+        let LocalY = -(Yy + Panyy) / Ss + ContainerY / Ss;
+
+        return {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY};
     }
 
     @action
-    onPointerWheel = (e: React.WheelEvent): void => {
+    onPointerWheel = (e: React.WheelEvent): void => 
+    {
         e.stopPropagation();
 
-        let scaleAmount = 1 - (e.deltaY / 1000);
-        let currScale = this.props.dvm.Doc.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
-        this.props.dvm.Doc.SetField(KeyStore.Scale, new NumberField(currScale * scaleAmount));
+        let {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY} = this.getLocalPoint(this.props.ContainingDocumentView!, e.pageX, e.pageY);
+
+        var deltaScale  = (1 - (e.deltaY / 1000)) * Ss;
 
-        const panx: number = this.props.dvm.Doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
-        const pany: number = this.props.dvm.Doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
-        let dx = (e.pageX - window.screen.width / 2) * currScale * (scaleAmount - 1)
-        let dy = (e.pageY - window.screen.height / 2) * currScale * (scaleAmount - 1)
+        var newContainerX = LocalX * deltaScale + W/2-W/2 * deltaScale + Panxx + Xx;
+        var newContainerY = LocalY * deltaScale + Panyy+ Yy;
 
-        this.props.dvm.Doc.SetFieldValue(KeyStore.PanX, panx - dx, NumberField);
-        this.props.dvm.Doc.SetFieldValue(KeyStore.PanY, pany - dy, NumberField);
+        let dx = ContainerX - newContainerX;
+        let dy = ContainerY - newContainerY;
+
+        this.props.Document.SetField(KeyStore.Scale, new NumberField(deltaScale));
+        this.props.Document.SetFieldValue(KeyStore.PanX, Panxx+dx, NumberField);
+        this.props.Document.SetFieldValue(KeyStore.PanY, Panyy+dy, NumberField);
 
         DocumentDecorations.Instance.forceUpdate()
     }
@@ -102,8 +139,8 @@ export class CollectionFreeFormView extends React.Component<IProps> {
         let fReader = new FileReader()
         let file = e.dataTransfer.items[0].getAsFile();
         let that = this;
-        const panx: number = this.props.dvm.Doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
-        const pany: number = this.props.dvm.Doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
+        const panx: number = this.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
+        const pany: number = this.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
         let x = e.pageX - panx
         let y = e.pageY - pany
 
@@ -113,10 +150,10 @@ export class CollectionFreeFormView extends React.Component<IProps> {
                 let doc = Documents.ImageDocument(url, {
                     x: x, y: y
                 })
-                let docs = that.props.dvm.Doc.GetFieldT(KeyStore.Data, ListField);
+                let docs = that.props.Document.GetFieldT(KeyStore.Data, ListField);
                 if (!docs) {
                     docs = new ListField<Document>();
-                    that.props.dvm.Doc.SetField(KeyStore.Data, docs)
+                    that.props.Document.SetField(KeyStore.Data, docs)
                 }
                 docs.Data.push(doc);
             }
@@ -129,7 +166,7 @@ export class CollectionFreeFormView extends React.Component<IProps> {
 
     @action
     removeDocument = (doc: Document): void => {
-        const value: Document[] = this.props.dvm.Doc.GetFieldValue(this.props.fieldKey, ListField, [])
+        const value: Document[] = this.props.Document.GetFieldValue(this.props.fieldKey, ListField, [])
         if (value.indexOf(doc) !== -1) {
             value.splice(value.indexOf(doc), 1)
 
@@ -141,14 +178,13 @@ export class CollectionFreeFormView extends React.Component<IProps> {
     onDragOver = (e: React.DragEvent): void => {
         // console.log(e.dataTransfer)
     }
-
     render() {
-        const { fieldKey, dvm } = this.props;
+        const { fieldKey, Document: Document } = this.props;
         
-        const value: Document[] = dvm.Doc.GetFieldValue(fieldKey, ListField, []);
-        const panx: number = dvm.Doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
-        const pany: number = dvm.Doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
-        const currScale: number = dvm.Doc.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
+        const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []);
+        const panx: number = Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0));
+        const pany: number = Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0));
+        const currScale: number = Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1));
         // DocumentDecorations.Instance.forceUpdate()
         return (
             <div className="border" style={{
@@ -160,11 +196,11 @@ export class CollectionFreeFormView extends React.Component<IProps> {
                     height: "calc(100% - 4px)",
                     overflow: "hidden"
                 }} onDrop={this.onDrop} onDragOver={this.onDragOver}>
-                    <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})`, transformOrigin: `50%, 50%`}}>
+                    <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})` , transformOrigin: `left, top`}}>
                         
                         <div className="node-container">
                             {value.map(doc => {
-                                return (<DocumentView key={doc.Id} parent={this} dvm={new DocumentViewModel(doc)} />);
+                                return (<DocumentView key={doc.Id} ContainingCollectionView={this} Document={doc} ContainingDocumentView={this.props.ContainingDocumentView}/>);
                             })}
                         </div>
                     </div>
diff --git a/src/views/freeformcanvas/FreeFormCanvas.scss b/src/views/freeformcanvas/FreeFormCanvas.scss
deleted file mode 100644
index 884ef90e6..000000000
--- a/src/views/freeformcanvas/FreeFormCanvas.scss
+++ /dev/null
@@ -1,15 +0,0 @@
-.freeformcanvas-container {
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    overflow: hidden;
-
-    .freeformcanvas {
-        position: absolute;
-        top: 0;
-        left: 0;
-    }
-}
-
diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx
deleted file mode 100644
index d7dc0ecaa..000000000
--- a/src/views/freeformcanvas/FreeFormCanvas.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import { observer } from "mobx-react";
-import { Key } from "../../fields/Key";
-import { NodeCollectionStore } from "../../stores/NodeCollectionStore";
-import "./FreeFormCanvas.scss";
-import React = require("react");
-import { action } from "mobx";
-import { Document } from "../../fields/Document";
-import {DocumentViewModel} from "../../viewmodels/DocumentViewModel";
-import {DocumentView} from "../nodes/DocumentView";
-import {TextField} from "../../fields/TextField";
-import {ListField} from "../../fields/ListField";
-import {Field} from "../../fields/Field";
-import { SelectionManager } from "../../util/SelectionManager";
-
-interface IProps {
-    store: NodeCollectionStore;
-}
-
-@observer
-export class FreeFormCanvas extends React.Component<IProps> {
-
-    private _isPointerDown: boolean = false;
-
-    constructor(props:IProps) {
-        super(props);
-    }
-
-    @action
-    onPointerDown = (e: React.PointerEvent): void => {
-        e.stopPropagation();
-        if (e.button === 2) {
-            this._isPointerDown = true;
-            document.removeEventListener("pointermove", this.onPointerMove);
-            document.addEventListener("pointermove", this.onPointerMove);
-            document.removeEventListener("pointerup", this.onPointerUp);
-            document.addEventListener("pointerup", this.onPointerUp);
-        }
-
-        SelectionManager.DeselectAll()
-    }
-
-    @action
-    onPointerUp = (e: PointerEvent): void => {
-        e.stopPropagation();
-        if (e.button === 2) {
-            this._isPointerDown = false;
-            document.removeEventListener("pointermove", this.onPointerMove);
-            document.removeEventListener("pointerup", this.onPointerUp);
-        }
-
-        // let doc = this.props.store.Docs[0];
-        // let dataField = doc.GetFieldT(KeyStore.Data, TextField);
-        // let data = dataField ? dataField.Data : "";
-        // this.props.store.Docs[0].SetFieldValue(KeyStore.Data, data + " hello", TextField);
-    }
-
-    @action
-    onPointerMove = (e: PointerEvent): void => {
-        e.stopPropagation();
-        if (!this._isPointerDown) {
-            return;
-        }
-
-        this.props.store.X += e.movementX;
-        this.props.store.Y += e.movementY;
-    }
-
-    @action
-    onPointerWheel = (e: React.WheelEvent): void => {
-        e.stopPropagation();
-
-        let scaleAmount = 1 - (e.deltaY / 1000);
-        this.props.store.Scale *= scaleAmount;
-    }
-
-    render() {
-        let store = this.props.store;
-        return (
-            <div className="freeformcanvas-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()}>
-                <div className="freeformcanvas" style={{ transform: store.Transform, transformOrigin: '50% 50%' }}>
-                    <div className="node-container">
-                        {/* {this.props.store.Docs.map(doc => {
-                            return (<DocumentView key={doc.Id} parent={null} dvm={new DocumentViewModel(doc)} />);
-                        })} */}
-                    </div>
-                </div>
-            </div>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx
index ee6269430..f7d4aa838 100644
--- a/src/views/nodes/DocumentView.tsx
+++ b/src/views/nodes/DocumentView.tsx
@@ -7,7 +7,7 @@ import { TextField } from "../../fields/TextField";
 import { DocumentViewModel } from "../../viewmodels/DocumentViewModel";
 import { ListField } from "../../fields/ListField";
 import { FieldTextBox } from "../nodes/FieldTextBox"
-import { FreeFormCanvas } from "../freeformcanvas/FreeFormCanvas"
+import { Document } from "../../fields/Document";
 import { CollectionFreeFormView } from "../freeformcanvas/CollectionFreeFormView"
 import "./NodeView.scss"
 import { SelectionManager } from "../../util/SelectionManager";
@@ -17,14 +17,19 @@ import { Opt } from "../../fields/Field";
 const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 interface IProps {
-    dvm: DocumentViewModel;
-    parent: Opt<CollectionFreeFormView>;
+    Document:    Document;
+    ContainingCollectionView: Opt<object>;
+    ContainingDocumentView:   Opt<DocumentView>
 }
 
 @observer
 export class DocumentView extends React.Component<IProps> {
     private _mainCont = React.createRef<HTMLDivElement>();
     private _contextMenuCanOpen = false;
+    private _downX:number = 0;
+    private _downY:number = 0;
+    private _lastX:number = 0;
+    private _lastY:number = 0;
 
     get mainCont(): React.RefObject<HTMLDivElement> {
         return this._mainCont
@@ -32,20 +37,20 @@ export class DocumentView extends React.Component<IProps> {
 
     @computed
     get x(): number {
-        return this.props.dvm.Doc.GetFieldValue(KeyStore.X, NumberField, Number(0));
+        return this.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0));
     }
 
     @computed
     get y(): number {
-        return this.props.dvm.Doc.GetFieldValue(KeyStore.Y, NumberField, Number(0));
+        return this.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0));
     }
 
     set x(x: number) {
-        this.props.dvm.Doc.SetFieldValue(KeyStore.X, x, NumberField)
+        this.props.Document.SetFieldValue(KeyStore.X, x, NumberField)
     }
 
     set y(y: number) {
-        this.props.dvm.Doc.SetFieldValue(KeyStore.Y, y, NumberField)
+        this.props.Document.SetFieldValue(KeyStore.Y, y, NumberField)
     }
 
     @computed
@@ -55,35 +60,35 @@ export class DocumentView extends React.Component<IProps> {
 
     @computed
     get width(): number {
-        return this.props.dvm.Doc.GetFieldValue(KeyStore.Width, NumberField, Number(0));
+        return this.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0));
     }
 
     set width(w: number) {
-        this.props.dvm.Doc.SetFieldValue(KeyStore.Width, w, NumberField)
+        this.props.Document.SetFieldValue(KeyStore.Width, w, NumberField)
     }
 
     @computed
     get height(): number {
-        return this.props.dvm.Doc.GetFieldValue(KeyStore.Height, NumberField, Number(0));
+        return this.props.Document.GetFieldValue(KeyStore.Height, NumberField, Number(0));
     }
 
     set height(h: number) {
-        this.props.dvm.Doc.SetFieldValue(KeyStore.Height, h, NumberField)
+        this.props.Document.SetFieldValue(KeyStore.Height, h, NumberField)
     }
 
     @computed
     get layout(): string {
-        return this.props.dvm.Doc.GetFieldValue(KeyStore.Layout, TextField, String("<p>Error loading layout data</p>"));
+        return this.props.Document.GetFieldValue(KeyStore.Layout, TextField, String("<p>Error loading layout data</p>"));
     }
 
     @computed
     get layoutKeys(): Key[] {
-        return this.props.dvm.Doc.GetFieldValue(KeyStore.LayoutKeys, ListField, new Array<Key>());
+        return this.props.Document.GetFieldValue(KeyStore.LayoutKeys, ListField, new Array<Key>());
     }
 
     @computed
     get layoutFields(): Key[] {
-        return this.props.dvm.Doc.GetFieldValue(KeyStore.LayoutFields, ListField, new Array<Key>());
+        return this.props.Document.GetFieldValue(KeyStore.LayoutFields, ListField, new Array<Key>());
     }
 
     @computed
@@ -91,45 +96,59 @@ export class DocumentView extends React.Component<IProps> {
         return SelectionManager.IsSelected(this)
     }
 
-    private _isPointerDown = false;
+    @computed
+    get active() : boolean {
+        return SelectionManager.IsSelected(this) ||  (this.props.ContainingCollectionView instanceof CollectionFreeFormView && this.props.ContainingCollectionView.active);
+    }
 
     onPointerDown = (e: React.PointerEvent): void => {
-        e.stopPropagation();
-
-        if (e.button === 2) {
-            this._isPointerDown = true;
-            this._contextMenuCanOpen = true;
-            document.removeEventListener("pointermove", this.onPointerMove);
-            document.addEventListener("pointermove", this.onPointerMove);
-            document.removeEventListener("pointerup", this.onPointerUp);
-            document.addEventListener("pointerup", this.onPointerUp);
-        }
-        SelectionManager.SelectDoc(this, e.ctrlKey)
+        this._downX = e.pageX;
+        this._downY = e.pageY;
+        this._lastX = e.pageX;
+        this._lastY = e.pageY;
+        this._contextMenuCanOpen = e.button == 2;
+        document.removeEventListener("pointermove", this.onPointerMove);
+        document.addEventListener("pointermove", this.onPointerMove);
+        document.removeEventListener("pointerup", this.onPointerUp);
+        document.addEventListener("pointerup", this.onPointerUp);
     }
 
     onPointerUp = (e: PointerEvent): void => {
-        e.stopPropagation();
-        if (e.button === 2) {
+        document.removeEventListener("pointermove", this.onPointerMove);
+        document.removeEventListener("pointerup", this.onPointerUp);
+        if (!e.cancelBubble) {
+            e.stopPropagation();
             e.preventDefault();
-            this._isPointerDown = false;
-            document.removeEventListener("pointermove", this.onPointerMove);
-            document.removeEventListener("pointerup", this.onPointerUp);
-            console.log(this.x);
-            console.log(this.y)
-            DocumentDecorations.Instance.opacity = 1
+            DocumentDecorations.Instance.opacity = 1;
+            if (this._downX == e.pageX && this._downY == e.pageY) {
+                SelectionManager.SelectDoc(this, e.ctrlKey)
+            }
         }
     }
 
     onPointerMove = (e: PointerEvent): void => {
-        e.stopPropagation();
-        e.preventDefault();
-        if (!this._isPointerDown) {
-            return;
+        if (this.active && !e.cancelBubble) {
+            e.stopPropagation();
+            e.preventDefault();
+            this._contextMenuCanOpen = false
+            let me = this;
+            var dx = e.pageX - this._lastX;
+            var dy = e.pageY - this._lastY;
+            this._lastX = e.pageX;
+            this._lastY = e.pageY;
+            let currScale:number = 1;
+            if (me.props.ContainingDocumentView != undefined) {
+                let pme = me.props.ContainingDocumentView!.props.Document;
+                currScale = pme.GetFieldValue(KeyStore.Scale, NumberField, Number(0)); 
+                if (me.props.ContainingDocumentView!.props.ContainingDocumentView != undefined) {
+                    let pme = me.props.ContainingDocumentView!.props.ContainingDocumentView!.props.Document;
+                    currScale *= pme.GetFieldValue(KeyStore.Scale, NumberField, Number(0));
+                } 
+            } 
+            this.x += dx/currScale;
+            this.y += dy/currScale;
+            DocumentDecorations.Instance.opacity = 0;
         }
-        this._contextMenuCanOpen = false
-        this.x += e.movementX;
-        this.y += e.movementY;
-        DocumentDecorations.Instance.opacity = 0
     }
 
     onDragStart = (e: React.DragEvent<HTMLDivElement>): void => {
@@ -142,8 +161,8 @@ export class DocumentView extends React.Component<IProps> {
     onClick = (e: React.MouseEvent): void => {    }
 
     deleteClicked = (e: React.MouseEvent): void => {
-        if (this.props.parent) {
-            this.props.parent.removeDocument(this.props.dvm.Doc)
+        if (this.props.ContainingCollectionView instanceof CollectionFreeFormView) {
+            this.props.ContainingCollectionView.removeDocument(this.props.Document)
         }
     }
 
@@ -155,7 +174,8 @@ export class DocumentView extends React.Component<IProps> {
             return;
         }
 
-        if (this.props.dvm.IsMainDoc) {
+        var topMost = this.props.ContainingCollectionView == undefined;
+        if (topMost) {
             ContextMenu.Instance.clearItems()
         }
         else {
@@ -169,10 +189,10 @@ export class DocumentView extends React.Component<IProps> {
     }
 
     render() {
-        let doc = this.props.dvm.Doc;
+        let doc = this.props.Document;
         let bindings: any = {
-            dvm: this.props.dvm,
-            isSelected: this.selected
+            Document: this.props.Document,
+            ContainingDocumentView: this
         };
         for (const key of this.layoutKeys) {
             bindings[key.Name + "Key"] = key;
@@ -194,7 +214,7 @@ export class DocumentView extends React.Component<IProps> {
                 onPointerDown={this.onPointerDown}
                 onClick={this.onClick}>
                 <JsxParser
-                    components={{ FieldTextBox, FreeFormCanvas, CollectionFreeFormView }}
+                    components={{ FieldTextBox, CollectionFreeFormView }}
                     bindings={bindings}
                     jsx={this.layout}
                 />
-- 
cgit v1.2.3-70-g09d2

