Skip to content
Snippets Groups Projects
Commit fd3aade5 authored by David Sehnal's avatar David Sehnal
Browse files

mol-state and mol-plugin refactoring

parent 81bf0083
No related branches found
No related tags found
No related merge requests found
......@@ -4,32 +4,28 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { State, StateTree, StateSelection, Transformer } from 'mol-state';
import { StateTree, StateSelection, Transformer } from 'mol-state';
import Canvas3D from 'mol-canvas3d/canvas3d';
import { StateTransforms } from './state/transforms';
import { PluginStateObjects as SO } from './state/objects';
import { RxEventHelper } from 'mol-util/rx-event-helper';
import { PluginState } from './state';
export class PluginContext {
private disposed = false;
private _events = new RxEventHelper();
private ev = RxEventHelper.create();
state = {
data: State.create(new SO.Root({ label: 'Root' }, { })),
// behaviour: State,
// plugin: State
};
readonly state = new PluginState();
// TODO: better events
events = {
stateUpdated: this._events.create<undefined>()
readonly events = {
stateUpdated: this.ev<undefined>()
};
canvas3d: Canvas3D;
readonly canvas3d: Canvas3D;
initViewer(canvas: HTMLCanvasElement, container: HTMLDivElement) {
try {
this.canvas3d = Canvas3D.create(canvas, container);
(this.canvas3d as Canvas3D) = Canvas3D.create(canvas, container);
this.canvas3d.animate();
console.log('canvas3d created');
return true;
......@@ -42,7 +38,8 @@ export class PluginContext {
dispose() {
if (this.disposed) return;
this.canvas3d.dispose();
this._events.dispose();
this.ev.dispose();
this.state.dispose();
this.disposed = true;
}
......@@ -60,9 +57,8 @@ export class PluginContext {
}
async _test_updateStateData(tree: StateTree) {
const newState = await State.update(this.state.data, tree).run(p => console.log(p), 250);
this.state.data = newState;
console.log(newState);
await this.state.data.update(tree).run(p => console.log(p), 250);
console.log(this.state.data);
this.events.stateUpdated.next();
}
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { State } from 'mol-state';
import { PluginStateObjects as SO } from './state/objects';
export { PluginState }
class PluginState {
readonly data = State.create(new SO.Root({ label: 'Root' }, { }));
getSnapshot(): PluginState.Snapshot {
throw 'nyi';
}
setSnapshot(snapshot: PluginState.Snapshot) {
throw 'nyi';
}
setDataSnapshot(snapshot: State.Snapshot) {
throw 'nyi';
}
dispose() {
this.data.dispose();
}
}
namespace PluginState {
export interface Snapshot { }
}
......@@ -4,45 +4,37 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Subject } from 'rxjs'
import { StateObject } from './object';
import { Transform } from './transform';
import { RxEventHelper } from 'mol-util/rx-event-helper';
interface StateContext {
events: {
export { StateContext }
class StateContext {
private ev = RxEventHelper.create();
events = {
object: {
stateChanged: Subject<{ ref: Transform.Ref }>,
propsChanged: Subject<{ ref: Transform.Ref, newProps: unknown }>,
stateChanged: this.ev<{ ref: Transform.Ref }>(),
propsChanged: this.ev<{ ref: Transform.Ref, newProps: unknown }>(),
updated: Subject<{ ref: Transform.Ref, obj?: StateObject }>,
replaced: Subject<{ ref: Transform.Ref, oldObj?: StateObject, newObj?: StateObject }>,
created: Subject<{ ref: Transform.Ref, obj: StateObject }>,
removed: Subject<{ ref: Transform.Ref, obj?: StateObject }>,
updated: this.ev<{ ref: Transform.Ref, obj?: StateObject }>(),
replaced: this.ev<{ ref: Transform.Ref, oldObj?: StateObject, newObj?: StateObject }>(),
created: this.ev<{ ref: Transform.Ref, obj: StateObject }>(),
removed: this.ev<{ ref: Transform.Ref, obj?: StateObject }>(),
},
warn: Subject<string>
},
globalContext: unknown,
defaultObjectProps: unknown
}
namespace StateContext {
export function create(params: { globalContext: unknown, defaultObjectProps: unknown }): StateContext {
return {
events: {
object: {
stateChanged: new Subject(),
propsChanged: new Subject(),
updated: new Subject(),
replaced: new Subject(),
created: new Subject(),
removed: new Subject()
},
warn: new Subject()
},
globalContext: params.globalContext,
defaultObjectProps: params.defaultObjectProps
}
warn: this.ev<string>()
};
readonly globalContext: unknown;
readonly defaultObjectProps: unknown;
dispose() {
this.ev.dispose();
}
}
export { StateContext }
\ No newline at end of file
constructor(params: { globalContext: unknown, defaultObjectProps: unknown }) {
this.globalContext = params.globalContext;
this.defaultObjectProps = params.defaultObjectProps;
}
}
\ No newline at end of file
......@@ -13,23 +13,50 @@ import { StateContext } from './context';
import { UUID } from 'mol-util';
import { RuntimeContext, Task } from 'mol-task';
export interface State {
tree: StateTree,
objects: State.Objects,
context: StateContext
}
export { State }
export namespace State {
export type Ref = Transform.Ref
export type Objects = Map<Ref, StateObject.Node>
class State {
private _tree: StateTree = StateTree.create();
get tree() { return this._tree; }
export function create(rootObject: StateObject, params?: { globalContext?: unknown, defaultObjectProps: unknown }) {
const tree = StateTree.create();
const objects: Objects = new Map();
readonly objects: State.Objects = new Map();
readonly context: StateContext;
getSnapshot(): State.Snapshot {
throw 'nyi';
}
setSnapshot(snapshot: State.Snapshot): void {
throw 'nyi';
}
dispose() {
this.context.dispose();
}
update(tree: StateTree): Task<void> {
return Task.create('Update Tree', taskCtx => {
const oldTree = this._tree;
this._tree = tree;
const ctx: UpdateContext = {
stateCtx: this.context,
taskCtx,
oldTree,
tree: tree,
objects: this.objects
};
// TODO: have "cancelled" error? Or would this be handled automatically?
return update(ctx);
});
}
constructor(rootObject: StateObject, params?: { globalContext?: unknown, defaultObjectProps: unknown }) {
const tree = this._tree;
const root = tree.getValue(tree.rootRef)!;
const defaultObjectProps = (params && params.defaultObjectProps) || { }
objects.set(tree.rootRef, {
this.objects.set(tree.rootRef, {
ref: tree.rootRef,
obj: rootObject,
state: StateObject.StateType.Ok,
......@@ -37,30 +64,37 @@ export namespace State {
props: { ...defaultObjectProps }
});
return {
tree,
objects,
context: StateContext.create({
globalContext: params && params.globalContext,
defaultObjectProps
})
};
this.context = new StateContext({
globalContext: params && params.globalContext,
defaultObjectProps
});
}
}
export function update(state: State, tree: StateTree): Task<State> {
return Task.create('Update Tree', taskCtx => {
const ctx: UpdateContext = {
stateCtx: state.context,
taskCtx,
oldTree: state.tree,
tree: tree,
objects: state.objects
};
return _update(ctx);
})
namespace State {
export type Objects = Map<Transform.Ref, StateObject.Node>
export interface Snapshot {
readonly tree: StateTree,
readonly props: { [key: string]: unknown }
}
async function _update(ctx: UpdateContext): Promise<State> {
export function create(rootObject: StateObject, params?: { globalContext?: unknown, defaultObjectProps: unknown }) {
return new State(rootObject, params);
}
}
type Ref = Transform.Ref
interface UpdateContext {
stateCtx: StateContext,
taskCtx: RuntimeContext,
oldTree: StateTree,
tree: StateTree,
objects: State.Objects
}
async function update(ctx: UpdateContext) {
const roots = findUpdateRoots(ctx.objects, ctx.tree);
const deletes = findDeletes(ctx);
for (const d of deletes) {
......@@ -73,23 +107,9 @@ export namespace State {
for (const root of roots) {
await updateSubtree(ctx, root);
}
return {
tree: ctx.tree,
objects: ctx.objects,
context: ctx.stateCtx
};
}
interface UpdateContext {
stateCtx: StateContext,
taskCtx: RuntimeContext,
oldTree: StateTree,
tree: StateTree,
objects: Objects
}
function findUpdateRoots(objects: Objects, tree: StateTree) {
function findUpdateRoots(objects: State.Objects, tree: StateTree) {
const findState = {
roots: [] as Ref[],
objects
......@@ -165,7 +185,7 @@ export namespace State {
}
}
function findAncestor(tree: StateTree, objects: Objects, root: Ref, types: { type: StateObject.Type }[]): StateObject {
function findAncestor(tree: StateTree, objects: State.Objects, root: Ref, types: { type: StateObject.Type }[]): StateObject {
let current = tree.nodes.get(root)!;
while (true) {
current = tree.nodes.get(current.parent)!;
......@@ -260,5 +280,4 @@ export namespace State {
return Transformer.UpdateResult.Recreate;
}
return runTask(transformer.definition.update({ a, oldParams, b, newParams }, ctx.stateCtx.globalContext), ctx.taskCtx);
}
}
}
\ No newline at end of file
......@@ -6,14 +6,34 @@
import { Subject } from 'rxjs';
export class RxEventHelper {
export { RxEventHelper }
interface RxEventHelper {
<T>(): Subject<T>,
dispose(): void
}
namespace RxEventHelper {
export function create(): RxEventHelper {
const helper = new _RxEventHelper();
const ret: RxEventHelper = (<T>() => helper.create<T>()) as RxEventHelper;
ret.dispose = () => helper.dispose();
return ret;
}
}
class _RxEventHelper {
private _eventList: Subject<any>[] = [];
private _disposed = false;
create<T>() {
const s = new Subject<T>();
this._eventList.push(s);
return s;
}
dispose() {
if (this._disposed) return;
for (const e of this._eventList) e.complete();
this._disposed = true;
}
}
\ No newline at end of file
......@@ -90,9 +90,9 @@ export async function testState() {
printTTree(tree1);
printTTree(tree2);
const state1 = await State.update(state, tree1).run();
await state.update(tree1).run();
console.log('----------------');
console.log(util.inspect(state1.objects, true, 3, true));
console.log(util.inspect(state.objects, true, 3, true));
console.log('----------------');
const jsonString = JSON.stringify(StateTree.toJSON(tree2), null, 2);
......@@ -103,13 +103,13 @@ export async function testState() {
printTTree(treeFromJson);
console.log('----------------');
const state2 = await State.update(state1, treeFromJson).run();
console.log(util.inspect(state2.objects, true, 3, true));
await state.update(treeFromJson).run();
console.log(util.inspect(state.objects, true, 3, true));
console.log('----------------');
const q = StateSelection.byRef('square').parent();
const sel = StateSelection.select(q, state2);
const sel = StateSelection.select(q, state);
console.log(sel);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment