aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-01-10 23:52:54 -0500
committerTyler Schicke <tyler_schicke@brown.edu>2019-01-10 23:52:54 -0500
commitee068ab30c43125efd2b0ab853531df9777f544f (patch)
tree9560b014b4de30c3a8f1e3d77ae70db27558fe58 /src
parent861d61970afc9e67afbafa64e8c1347a18335077 (diff)
Started adding various controllers
Diffstat (limited to 'src')
-rw-r--r--src/controllers/BasicFieldController.ts36
-rw-r--r--src/controllers/DocumentController.ts107
-rw-r--r--src/controllers/DocumentReferenceController.ts36
-rw-r--r--src/controllers/FieldController.ts45
-rw-r--r--src/controllers/FieldUpdatedArgs.ts27
-rw-r--r--src/controllers/KeyController.ts25
-rw-r--r--src/controllers/NumberController.ts14
-rw-r--r--src/controllers/TextController.ts14
-rw-r--r--src/util/TypedEvent.ts42
-rw-r--r--src/views/freeformcanvas/FreeFormCanvas.tsx12
10 files changed, 356 insertions, 2 deletions
diff --git a/src/controllers/BasicFieldController.ts b/src/controllers/BasicFieldController.ts
new file mode 100644
index 000000000..ff88f8781
--- /dev/null
+++ b/src/controllers/BasicFieldController.ts
@@ -0,0 +1,36 @@
+import { FieldController } from "./FieldController"
+import { FieldUpdatedAction } from "./FieldUpdatedArgs";
+
+export abstract class BasicFieldController<T> extends FieldController {
+ get Data(): T {
+ return this.data;
+ }
+
+ set Data(value: T) {
+ if(this.data === value) {
+ return;
+ }
+ this.data = value;
+
+ this.FieldUpdated.emit({
+ field: this,
+ action: FieldUpdatedAction.Update
+ });
+ }
+
+ constructor(private data: T) {
+ super();
+ }
+
+ TrySetValue(value: any): boolean {
+ if (typeof value == typeof this.data) {
+ this.Data = value;
+ return true;
+ }
+ return false;
+ }
+
+ GetValue(): any {
+ return this.Data;
+ }
+}
diff --git a/src/controllers/DocumentController.ts b/src/controllers/DocumentController.ts
new file mode 100644
index 000000000..0c53a9c43
--- /dev/null
+++ b/src/controllers/DocumentController.ts
@@ -0,0 +1,107 @@
+import { FieldController } from "./FieldController"
+import { KeyController } from "./KeyController"
+import { TypedEvent, Listener, Disposable } from "../util/TypedEvent";
+import { DocumentUpdatedArgs, FieldUpdatedAction } from "./FieldUpdatedArgs";
+
+export class DocumentController extends FieldController {
+ private fields: { [key: string]: { key: KeyController, field: FieldController, disposer: Disposable } } = {};
+ private fieldUpdateHandlers: { [key: string]: TypedEvent<DocumentUpdatedArgs> }
+
+ GetField(key: KeyController): FieldController {
+ if (key.Id in this.fields) {
+ return this.fields[key.Id].field;
+ }
+ return null;
+ }
+
+ SetField(key: KeyController, field: FieldController): void {
+ let oldField: FieldController = null;
+ if (key.Id in this.fields) {
+ let old = this.fields[key.Id];
+ oldField = old.field;
+ old.disposer.dispose();
+ }
+
+ if (oldField === field) {
+ return;
+ }
+
+ if (field === null) {
+ delete this.fields[key.Id];
+ } else {
+ this.fields[key.Id] = {
+ key: key,
+ field: field,
+ disposer: field.FieldUpdated.on((args) => this.DocumentFieldUpdated({
+ action: FieldUpdatedAction.Update,
+ oldValue: null,
+ newValue: field,
+ field: this,
+ fieldArgs: args,
+ key: key
+ }))
+ }
+ }
+
+ let action = oldField === null ? FieldUpdatedAction.Add :
+ (field === null ? FieldUpdatedAction.Remove :
+ FieldUpdatedAction.Replace);
+
+ this.DocumentFieldUpdated({
+ field: this,
+ key: key,
+ oldValue: oldField,
+ newValue: field,
+ fieldArgs: null,
+ action: action
+ })
+ }
+
+ SetFieldValue<T extends FieldController>(key:KeyController, value:any, ctor: {new():T}) : boolean {
+ let field = this.GetField(key);
+ if(field !== null) {
+ return field.TrySetValue(value);
+ } else {
+ field = new ctor();
+ if(field.TrySetValue(value)) {
+ this.SetField(key, field);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private DocumentFieldUpdated(args: DocumentUpdatedArgs) {
+ if (args.key.Id in this.fieldUpdateHandlers) {
+ this.fieldUpdateHandlers[args.key.Id].emit(args);
+ }
+ this.FieldUpdated.emit(args);
+ }
+
+ AddFieldUpdatedHandler(key: KeyController, listener: Listener<DocumentUpdatedArgs>): Disposable {
+ if (!(key.Id in this.fieldUpdateHandlers)) {
+ this.fieldUpdateHandlers[key.Id] = new TypedEvent<DocumentUpdatedArgs>();
+ }
+
+ return this.fieldUpdateHandlers[key.Id].on(listener);
+ }
+
+ RemoveFieldUpdatedHandler(key: KeyController, listener: Listener<DocumentUpdatedArgs>) {
+ if (key.Id in this.fieldUpdateHandlers) {
+ this.fieldUpdateHandlers[key.Id].off(listener);
+ }
+ }
+
+ TrySetValue(value: any): boolean {
+ throw new Error("Method not implemented.");
+ }
+ GetValue() {
+ throw new Error("Method not implemented.");
+ }
+ Copy(): FieldController {
+ throw new Error("Method not implemented.");
+ }
+
+
+} \ No newline at end of file
diff --git a/src/controllers/DocumentReferenceController.ts b/src/controllers/DocumentReferenceController.ts
new file mode 100644
index 000000000..9d5bb7af2
--- /dev/null
+++ b/src/controllers/DocumentReferenceController.ts
@@ -0,0 +1,36 @@
+import { FieldController } from "./FieldController";
+import { DocumentController } from "./DocumentController";
+import { KeyController } from "./KeyController";
+import { DocumentUpdatedArgs } from "./FieldUpdatedArgs";
+
+export class DocumentReferenceController extends FieldController {
+ get Key(): KeyController{
+ return this.key;
+ }
+
+ get Document(): DocumentController {
+ return this.document;
+ }
+
+ constructor(private document: DocumentController, private key: KeyController) {
+ super();
+
+ document.AddFieldUpdatedHandler(key, this.DocFieldUpdated);
+ }
+
+ private DocFieldUpdated(args: DocumentUpdatedArgs):void{
+ this.FieldUpdated.emit(args.fieldArgs);
+ }
+
+ TrySetValue(value: any): boolean {
+ throw new Error("Method not implemented.");
+ }
+ GetValue() {
+ throw new Error("Method not implemented.");
+ }
+ Copy(): FieldController {
+ throw new Error("Method not implemented.");
+ }
+
+
+} \ No newline at end of file
diff --git a/src/controllers/FieldController.ts b/src/controllers/FieldController.ts
new file mode 100644
index 000000000..19205014a
--- /dev/null
+++ b/src/controllers/FieldController.ts
@@ -0,0 +1,45 @@
+import { TypedEvent } from "../util/TypedEvent";
+import { FieldUpdatedArgs } from "./FieldUpdatedArgs";
+import { DocumentReferenceController } from "./DocumentReferenceController";
+
+export abstract class FieldController {
+ Id: string;
+
+ FieldUpdated: TypedEvent<FieldUpdatedArgs>;
+
+ protected DereferenceImpl(): FieldController {
+ return this;
+ }
+ protected DereferenceToRootImpl(): FieldController {
+ let field = this;
+ while(field instanceof DocumentReferenceController) {
+ field = field.Dereference();
+ }
+ return field;
+ }
+
+ Dereference<T extends FieldController = FieldController>(ctor?: { new(): T }): T {
+ let field = this.DereferenceImpl();
+ if (ctor && field instanceof ctor) {
+ return field;
+ } else {
+ return null;
+ }
+ }
+
+ DereferenceToRoot<T extends FieldController = FieldController>(ctor?: { new(): T }): T {
+ let field = this.DereferenceToRootImpl();
+ if (ctor && field instanceof ctor) {
+ return field;
+ } else {
+ return null;
+ }
+ }
+
+ abstract TrySetValue(value: any): boolean;
+
+ abstract GetValue(): any;
+
+ abstract Copy(): FieldController;
+
+} \ No newline at end of file
diff --git a/src/controllers/FieldUpdatedArgs.ts b/src/controllers/FieldUpdatedArgs.ts
new file mode 100644
index 000000000..786a44aa4
--- /dev/null
+++ b/src/controllers/FieldUpdatedArgs.ts
@@ -0,0 +1,27 @@
+import { FieldController } from "./FieldController";
+import { DocumentController } from "./DocumentController";
+import { KeyController } from "./KeyController";
+
+export enum FieldUpdatedAction {
+ Add,
+ Remove,
+ Replace,
+ Update
+}
+
+export interface FieldUpdatedArgs {
+ field: FieldController;
+ action: FieldUpdatedAction;
+}
+
+export interface DocumentUpdatedArgs {
+ field: DocumentController;
+ key: KeyController;
+
+ oldValue: FieldController;
+ newValue: FieldController;
+
+ fieldArgs: FieldUpdatedArgs;
+
+ action: FieldUpdatedAction;
+}
diff --git a/src/controllers/KeyController.ts b/src/controllers/KeyController.ts
new file mode 100644
index 000000000..96e41eded
--- /dev/null
+++ b/src/controllers/KeyController.ts
@@ -0,0 +1,25 @@
+import { FieldController } from "./FieldController"
+
+export class KeyController extends FieldController {
+ get Name():string {
+ return this.name;
+ }
+
+ constructor(private name:string){
+ super();
+ }
+
+ TrySetValue(value: any): boolean {
+ throw new Error("Method not implemented.");
+ }
+
+ GetValue() {
+ return this.Name;
+ }
+
+ Copy(): FieldController {
+ return this;
+ }
+
+
+}
diff --git a/src/controllers/NumberController.ts b/src/controllers/NumberController.ts
new file mode 100644
index 000000000..aeedf025b
--- /dev/null
+++ b/src/controllers/NumberController.ts
@@ -0,0 +1,14 @@
+import { BasicFieldController } from "./BasicFieldController"
+import { FieldUpdatedAction } from "./FieldUpdatedArgs";
+
+export class NumberController extends BasicFieldController<number> {
+ constructor(data: number = 0) {
+ super(data);
+ }
+
+ Copy() {
+ return new NumberController(this.Data);
+ }
+
+
+} \ No newline at end of file
diff --git a/src/controllers/TextController.ts b/src/controllers/TextController.ts
new file mode 100644
index 000000000..5d4b43170
--- /dev/null
+++ b/src/controllers/TextController.ts
@@ -0,0 +1,14 @@
+import { BasicFieldController } from "./BasicFieldController"
+import { FieldUpdatedAction } from "./FieldUpdatedArgs";
+
+export class TextController extends BasicFieldController<string> {
+ constructor(data: string = "") {
+ super(data);
+ }
+
+ Copy() {
+ return new TextController(this.Data);
+ }
+
+
+}
diff --git a/src/util/TypedEvent.ts b/src/util/TypedEvent.ts
new file mode 100644
index 000000000..0714a7f5c
--- /dev/null
+++ b/src/util/TypedEvent.ts
@@ -0,0 +1,42 @@
+export interface Listener<T> {
+ (event: T): any;
+}
+
+export interface Disposable {
+ dispose(): void;
+}
+
+/** passes through events as they happen. You will not get events from before you start listening */
+export class TypedEvent<T> {
+ private listeners: Listener<T>[] = [];
+ private listenersOncer: Listener<T>[] = [];
+
+ on = (listener: Listener<T>): Disposable => {
+ this.listeners.push(listener);
+ return {
+ dispose: () => this.off(listener)
+ };
+ }
+
+ once = (listener: Listener<T>): void => {
+ this.listenersOncer.push(listener);
+ }
+
+ off = (listener: Listener<T>) => {
+ var callbackIndex = this.listeners.indexOf(listener);
+ if (callbackIndex > -1) this.listeners.splice(callbackIndex, 1);
+ }
+
+ emit = (event: T) => {
+ /** Update any general listeners */
+ this.listeners.forEach((listener) => listener(event));
+
+ /** Clear the `once` queue */
+ this.listenersOncer.forEach((listener) => listener(event));
+ this.listenersOncer = [];
+ }
+
+ pipe = (te: TypedEvent<T>): Disposable => {
+ return this.on((e) => te.emit(e));
+ }
+} \ No newline at end of file
diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx
index f02f677a3..d25341cbb 100644
--- a/src/views/freeformcanvas/FreeFormCanvas.tsx
+++ b/src/views/freeformcanvas/FreeFormCanvas.tsx
@@ -41,11 +41,19 @@ export class FreeFormCanvas extends React.Component<IProps> {
this.props.store.Y += e.movementY;
}
+ onPointerWheel = (e: React.WheelEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+
+ 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}>
- <div className="freeformcanvas" style={{ transform: store.Transform }}>
+ <div className="freeformcanvas-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel}>
+ <div className="freeformcanvas" style={{ transform: store.Transform, transformOrigin: '50% 50%' }}>
<NodeContainer store={store} />
</div>
</div>