Browse Source

Merge branch 'master' into gl-lines

# Conflicts:
#	src/mol-geo/geometry/geometry.ts
#	src/mol-geo/geometry/lines/lines.ts
#	src/mol-geo/geometry/points/points.ts
#	src/mol-repr/structure/representation/cartoon.ts
#	src/mol-repr/structure/visual/inter-unit-link-cylinder.ts
#	src/mol-repr/structure/visual/polymer-backbone-cylinder.ts
#	src/mol-repr/structure/visual/polymer-direction-wedge.ts
#	src/mol-repr/structure/visual/polymer-gap-cylinder.ts
#	src/mol-repr/structure/visual/polymer-trace-mesh.ts
#	src/mol-repr/structure/visual/util/link.ts
#	src/mol-repr/volume/index.ts
Alexander Rose 6 years ago
parent
commit
c71aeb76d4
64 changed files with 717 additions and 448 deletions
  1. 4 4
      src/apps/canvas/component/representation.tsx
  2. 2 2
      src/mol-app/component/parameter/boolean.tsx
  3. 2 2
      src/mol-app/component/parameter/multi-select.tsx
  4. 2 2
      src/mol-app/component/parameter/number.tsx
  5. 2 2
      src/mol-app/component/parameter/range.tsx
  6. 2 2
      src/mol-app/component/parameter/select.tsx
  7. 2 2
      src/mol-app/component/parameter/text.tsx
  8. 4 4
      src/mol-app/component/parameters.tsx
  9. 6 6
      src/mol-geo/geometry/direct-volume/direct-volume.ts
  10. 15 15
      src/mol-geo/geometry/geometry.ts
  11. 3 3
      src/mol-geo/geometry/lines/lines.ts
  12. 5 5
      src/mol-geo/geometry/mesh/mesh.ts
  13. 5 5
      src/mol-geo/geometry/points/points.ts
  14. 7 7
      src/mol-model/structure/structure/unit/gaussian-density.ts
  15. 21 0
      src/mol-plugin/behaviour.ts
  16. 2 0
      src/mol-plugin/command.ts
  17. 47 17
      src/mol-plugin/context.ts
  18. 38 0
      src/mol-plugin/state.ts
  19. 2 2
      src/mol-plugin/state/base.ts
  20. 26 6
      src/mol-plugin/state/transforms/data.ts
  21. 89 10
      src/mol-plugin/state/transforms/model.ts
  22. 7 5
      src/mol-plugin/state/transforms/visuals.ts
  23. 8 1
      src/mol-plugin/ui/tree.tsx
  24. 4 4
      src/mol-repr/index.ts
  25. 3 3
      src/mol-repr/shape/index.ts
  26. 5 5
      src/mol-repr/structure/complex-visual.ts
  27. 8 8
      src/mol-repr/structure/index.ts
  28. 2 2
      src/mol-repr/structure/representation/backbone.ts
  29. 6 6
      src/mol-repr/structure/representation/ball-and-stick.ts
  30. 5 5
      src/mol-repr/structure/representation/carbohydrate.ts
  31. 4 4
      src/mol-repr/structure/representation/cartoon.ts
  32. 4 4
      src/mol-repr/structure/representation/distance-restraint.ts
  33. 3 3
      src/mol-repr/structure/representation/molecular-surface.ts
  34. 2 2
      src/mol-repr/structure/representation/point.ts
  35. 2 2
      src/mol-repr/structure/representation/spacefill.ts
  36. 7 7
      src/mol-repr/structure/units-visual.ts
  37. 5 5
      src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts
  38. 5 5
      src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts
  39. 4 4
      src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts
  40. 5 5
      src/mol-repr/structure/visual/element-point.ts
  41. 6 6
      src/mol-repr/structure/visual/element-sphere.ts
  42. 5 5
      src/mol-repr/structure/visual/gaussian-density-point.ts
  43. 2 2
      src/mol-repr/structure/visual/gaussian-density-volume.ts
  44. 2 2
      src/mol-repr/structure/visual/gaussian-surface-mesh.ts
  45. 5 5
      src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
  46. 2 2
      src/mol-repr/structure/visual/inter-unit-link-cylinder.ts
  47. 5 5
      src/mol-repr/structure/visual/intra-unit-link-cylinder.ts
  48. 2 2
      src/mol-repr/structure/visual/nucleotide-block-mesh.ts
  49. 4 4
      src/mol-repr/structure/visual/polymer-backbone-cylinder.ts
  50. 5 5
      src/mol-repr/structure/visual/polymer-direction-wedge.ts
  51. 8 8
      src/mol-repr/structure/visual/polymer-gap-cylinder.ts
  52. 7 7
      src/mol-repr/structure/visual/polymer-trace-mesh.ts
  53. 6 6
      src/mol-repr/structure/visual/util/link.ts
  54. 2 2
      src/mol-repr/volume/direct-volume.ts
  55. 4 4
      src/mol-repr/volume/index.ts
  56. 4 4
      src/mol-repr/volume/isosurface-mesh.ts
  57. 26 34
      src/mol-state/context.ts
  58. 1 2
      src/mol-state/object.ts
  59. 89 57
      src/mol-state/state.ts
  60. 20 15
      src/mol-state/transformer.ts
  61. 93 0
      src/mol-util/param-definition.ts
  62. 0 90
      src/mol-util/parameter.ts
  63. 39 0
      src/mol-util/rx-event-helper.ts
  64. 5 5
      src/perf-tests/state.ts

+ 4 - 4
src/apps/canvas/component/representation.tsx

@@ -7,7 +7,7 @@
 import * as React from 'react'
 import Canvas3D from 'mol-canvas3d/canvas3d';
 import { App } from '../app';
-import { Params } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Representation } from 'mol-repr';
 import { ParametersComponent } from 'mol-app/component/parameters';
 import { ColorTheme } from 'mol-theme/color';
@@ -17,18 +17,18 @@ import { ColorThemeComponent } from 'mol-app/component/color-theme';
 export interface RepresentationComponentProps {
     app: App
     canvas3d: Canvas3D
-    repr: Representation<Params>
+    repr: Representation<PD.Params>
 }
 
 export interface RepresentationComponentState {
     label: string
-    reprParams: Params
+    reprParams: PD.Params
     reprProps: Readonly<{}>
 }
 
 export class RepresentationComponent extends React.Component<RepresentationComponentProps, RepresentationComponentState> {
 
-    private stateFromRepr(repr: Representation<Params>) {
+    private stateFromRepr(repr: Representation<PD.Params>) {
         return {
             label: this.props.repr.label,
             reprParams: this.props.repr.params,

+ 2 - 2
src/mol-app/component/parameter/boolean.tsx

@@ -5,10 +5,10 @@
  */
 
 import * as React from 'react'
-import { BooleanParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface BooleanParamComponentProps {
-    param: BooleanParam
+    param: PD.Boolean
     value: boolean
     onChange(v: boolean): void
 }

+ 2 - 2
src/mol-app/component/parameter/multi-select.tsx

@@ -5,10 +5,10 @@
  */
 
 import * as React from 'react'
-import { MultiSelectParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface MultiSelectParamComponentProps<T extends string> {
-    param: MultiSelectParam<T>
+    param: PD.MultiSelect<T>
     value: T[]
     onChange(v: T[]): void
 }

+ 2 - 2
src/mol-app/component/parameter/number.tsx

@@ -5,10 +5,10 @@
  */
 
 import * as React from 'react'
-import { NumberParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface NumberParamComponentProps {
-    param: NumberParam
+    param: PD.Numeric
     value: number
     onChange(v: number): void
 }

+ 2 - 2
src/mol-app/component/parameter/range.tsx

@@ -5,10 +5,10 @@
  */
 
 import * as React from 'react'
-import { RangeParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface RangeParamComponentProps {
-    param: RangeParam
+    param: PD.Range
     value: number
     onChange(v: number): void
 }

+ 2 - 2
src/mol-app/component/parameter/select.tsx

@@ -5,10 +5,10 @@
  */
 
 import * as React from 'react'
-import { SelectParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface SelectParamComponentProps<T extends string> {
-    param: SelectParam<T>
+    param: PD.Select<T>
     value: T
     onChange(v: T): void
 }

+ 2 - 2
src/mol-app/component/parameter/text.tsx

@@ -5,10 +5,10 @@
  */
 
 import * as React from 'react'
-import { TextParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface TextParamComponentProps {
-    param: TextParam
+    param: PD.Text
     value: string
     onChange(v: string): void
 }

+ 4 - 4
src/mol-app/component/parameters.tsx

@@ -5,7 +5,7 @@
  */
 
 import * as React from 'react'
-import { Param, Params } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { BooleanParamComponent } from './parameter/boolean';
 import { NumberParamComponent } from './parameter/number';
 import { RangeParamComponent } from './parameter/range';
@@ -13,7 +13,7 @@ import { SelectParamComponent } from './parameter/select';
 import { MultiSelectParamComponent } from './parameter/multi-select';
 import { TextParamComponent } from './parameter/text';
 
-interface ParametersProps<P extends Params> {
+interface ParametersProps<P extends PD.Params> {
     params: P
     values: { [k in keyof P]: P[k]['defaultValue'] }
     onChange<K extends keyof P>(k: K, v: P[K]['defaultValue']): void
@@ -21,7 +21,7 @@ interface ParametersProps<P extends Params> {
 
 type ParametersState = {}
 
-function getParamComponent<P extends Param>(p: Param, value: P['defaultValue'], onChange: (v: P['defaultValue']) => void) {
+function getParamComponent<P extends PD.Any>(p: PD.Any, value: P['defaultValue'], onChange: (v: P['defaultValue']) => void) {
     switch (p.type) {
         case 'boolean':
             return <BooleanParamComponent param={p} value={value} onChange={onChange} />
@@ -39,7 +39,7 @@ function getParamComponent<P extends Param>(p: Param, value: P['defaultValue'],
     return ''
 }
 
-export class ParametersComponent<P extends Params> extends React.Component<ParametersProps<P>, ParametersState> {
+export class ParametersComponent<P extends PD.Params> extends React.Component<ParametersProps<P>, ParametersState> {
     onChange(k: string, value: any) {
         this.props.onChange(k, value)
     }

+ 6 - 6
src/mol-geo/geometry/direct-volume/direct-volume.ts

@@ -7,7 +7,7 @@
 import { RuntimeContext } from 'mol-task'
 import { ValueCell } from 'mol-util'
 import { Sphere3D, Box3D } from 'mol-math/geometry'
-import { paramDefaultValues, RangeParam, SelectParam, TextParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { DirectVolumeValues } from 'mol-gl/renderable/direct-volume';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { Box } from '../../primitive/box';
@@ -67,12 +67,12 @@ export namespace DirectVolume {
 
     export const Params = {
         ...Geometry.Params,
-        isoValueAbsolute: RangeParam('Iso Value Absolute', '', 0.22, -1, 1, 0.01),
-        isoValueRelative: RangeParam('Iso Value Relative', '', 2, -10, 10, 0.1),
-        renderMode: SelectParam('Render Mode', '', 'isosurface', RenderModeOptions),
-        controlPoints: TextParam('Control Points', '', '0.19:0.1, 0.2:0.5, 0.21:0.1, 0.4:0.3'),
+        isoValueAbsolute: PD.Range('Iso Value Absolute', '', 0.22, -1, 1, 0.01),
+        isoValueRelative: PD.Range('Iso Value Relative', '', 2, -10, 10, 0.1),
+        renderMode: PD.Select('Render Mode', '', 'isosurface', RenderModeOptions),
+        controlPoints: PD.Text('Control Points', '', '0.19:0.1, 0.2:0.5, 0.21:0.1, 0.4:0.3'),
     }
-    export const DefaultProps = paramDefaultValues(Params)
+    export const DefaultProps = PD.getDefaultValues(Params)
     export type Props = typeof DefaultProps
 
     export async function createValues(ctx: RuntimeContext, directVolume: DirectVolume, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<DirectVolumeValues> {

+ 15 - 15
src/mol-geo/geometry/geometry.ts

@@ -15,7 +15,7 @@ import { LocationIterator } from '../util/location-iterator';
 import { ColorType, getColorThemeProps } from './color-data';
 import { SizeType, getSizeThemeProps } from './size-data';
 import { Lines } from './lines/lines';
-import { paramDefaultValues, RangeParam, BooleanParam, SelectParam, ColorParam, NumberParam } from 'mol-util/parameter'
+import { ParamDefinition as PD } from 'mol-util/param-definition'
 import { DirectVolume } from './direct-volume/direct-volume';
 import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 
@@ -72,21 +72,21 @@ export namespace Geometry {
     //
 
     export const Params = {
-        alpha: RangeParam('Opacity', '', 1, 0, 1, 0.01),
-        visible: BooleanParam('Visible', '', true),
-        depthMask: BooleanParam('Depth Mask', '', true),
-        useFog: BooleanParam('Use Fog', '', false),
-        quality: SelectParam<VisualQuality>('Quality', '', 'auto', VisualQualityOptions),
-
-        colorTheme: SelectParam<ColorThemeName>('Color Theme', '', 'uniform', ColorThemeOptions),
-        colorList: SelectParam<ColorScaleName>('Color Scale', '', 'default', ColorScaleOptions),
-        colorValue: ColorParam('Color Value', '', Color(0xCCCCCC)),
-
-        sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-        sizeValue: NumberParam('Size Value', '', 1, 0, 20, 0.1),
-        sizeFactor: NumberParam('Size Factor', '', 1, 0, 10, 0.1),
+        alpha: PD.Range('Opacity', '', 1, 0, 1, 0.01),
+        visible: PD.Boolean('Visible', '', true),
+        depthMask: PD.Boolean('Depth Mask', '', true),
+        useFog: PD.Boolean('Use Fog', '', false),
+        quality: PD.Select<VisualQuality>('Quality', '', 'auto', VisualQualityOptions),
+
+        colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'uniform', ColorThemeOptions),
+        colorList: PD.Select<ColorScaleName>('Color Scale', '', 'default', ColorScaleOptions),
+        colorValue: PD.Color('Color Value', '', Color(0xCCCCCC)),
+
+        sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+        sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+        sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
     }
-    export const DefaultProps = paramDefaultValues(Params)
+    export const DefaultProps = PD.getDefaultValues(Params)
     export type Props = typeof DefaultProps
 
     export type Counts = { drawCount: number, groupCount: number, instanceCount: number }

+ 3 - 3
src/mol-geo/geometry/lines/lines.ts

@@ -17,7 +17,7 @@ import { LocationIterator } from '../../util/location-iterator';
 import { LinesValues } from 'mol-gl/renderable/lines';
 import { Mesh } from '../mesh/mesh';
 import { LinesBuilder } from './lines-builder';
-import { BooleanParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 /** Wide line */
 export interface Lines {
@@ -92,9 +92,9 @@ export namespace Lines {
 
     export const Params = {
         ...Geometry.Params,
-        lineSizeAttenuation: BooleanParam('Line Size Attenuation', '', false),
+        lineSizeAttenuation: PD.Boolean('Line Size Attenuation', '', false),
     }
-    export const DefaultProps = paramDefaultValues(Params)
+    export const DefaultProps = PD.getDefaultValues(Params)
     export type Props = typeof DefaultProps
 
     export async function createValues(ctx: RuntimeContext, lines: Lines, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<LinesValues> {

+ 5 - 5
src/mol-geo/geometry/mesh/mesh.ts

@@ -16,7 +16,7 @@ import { TransformData } from '../transform-data';
 import { LocationIterator } from '../../util/location-iterator';
 import { createColors } from '../color-data';
 import { ChunkedArray } from 'mol-data/util';
-import { BooleanParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface Mesh {
     readonly kind: 'mesh',
@@ -339,11 +339,11 @@ export namespace Mesh {
 
     export const Params = {
         ...Geometry.Params,
-        doubleSided: BooleanParam('Double Sided', '', false),
-        flipSided: BooleanParam('Flip Sided', '', false),
-        flatShaded: BooleanParam('Flat Shaded', '', false),
+        doubleSided: PD.Boolean('Double Sided', '', false),
+        flipSided: PD.Boolean('Flip Sided', '', false),
+        flatShaded: PD.Boolean('Flat Shaded', '', false),
     }
-    export const DefaultProps = paramDefaultValues(Params)
+    export const DefaultProps = PD.getDefaultValues(Params)
     export type Props = typeof DefaultProps
 
     export async function createValues(ctx: RuntimeContext, mesh: Mesh, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<MeshValues> {

+ 5 - 5
src/mol-geo/geometry/points/points.ts

@@ -15,7 +15,7 @@ import { createMarkers } from '../marker-data';
 import { createSizes } from '../size-data';
 import { TransformData } from '../transform-data';
 import { LocationIterator } from '../../util/location-iterator';
-import { BooleanParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 /** Point cloud */
 export interface Points {
@@ -54,11 +54,11 @@ export namespace Points {
 
     export const Params = {
         ...Geometry.Params,
-        pointSizeAttenuation: BooleanParam('Point Size Attenuation', '', false),
-        pointFilledCircle: BooleanParam('Point Filled Circle', '', false),
-        pointEdgeBleach: NumberParam('Point Edge Bleach', '', 0.2, 0, 1, 0.05),
+        pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false),
+        pointFilledCircle: PD.Boolean('Point Filled Circle', '', false),
+        pointEdgeBleach: PD.Numeric('Point Edge Bleach', '', 0.2, 0, 1, 0.05),
     }
-    export const DefaultProps = paramDefaultValues(Params)
+    export const DefaultProps = PD.getDefaultValues(Params)
     export type Props = typeof DefaultProps
 
     export async function createValues(ctx: RuntimeContext, points: Points, transform: TransformData, locationIt: LocationIterator, theme: Theme, props: Props): Promise<PointsValues> {

+ 7 - 7
src/mol-model/structure/structure/unit/gaussian-density.ts

@@ -9,19 +9,19 @@ import { SizeTheme } from 'mol-theme/size';
 import { GaussianDensity } from 'mol-math/geometry/gaussian-density';
 import { Task, RuntimeContext } from 'mol-task';
 import { DensityData } from 'mol-math/geometry';
-import { NumberParam, paramDefaultValues, BooleanParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { GaussianDensityTexture } from 'mol-math/geometry/gaussian-density/gpu';
 import { Texture } from 'mol-gl/webgl/texture';
 import { WebGLContext } from 'mol-gl/webgl/context';
 
 export const GaussianDensityParams = {
-    resolution: NumberParam('Resolution', '', 1, 0.1, 10, 0.1),
-    radiusOffset: NumberParam('Radius Offset', '', 0, 0, 10, 0.1),
-    smoothness: NumberParam('Smoothness', '', 1.5, 0.5, 2.5, 0.1),
-    useGpu: BooleanParam('Use GPU', '', true),
-    ignoreCache: BooleanParam('Ignore Cache', '', false),
+    resolution: PD.Numeric('Resolution', '', 1, 0.1, 10, 0.1),
+    radiusOffset: PD.Numeric('Radius Offset', '', 0, 0, 10, 0.1),
+    smoothness: PD.Numeric('Smoothness', '', 1.5, 0.5, 2.5, 0.1),
+    useGpu: PD.Boolean('Use GPU', '', true),
+    ignoreCache: PD.Boolean('Ignore Cache', '', false),
 }
-export const DefaultGaussianDensityProps = paramDefaultValues(GaussianDensityParams)
+export const DefaultGaussianDensityProps = PD.getDefaultValues(GaussianDensityParams)
 export type GaussianDensityProps = typeof DefaultGaussianDensityProps
 
 function getConformation(unit: Unit) {

+ 21 - 0
src/mol-plugin/behaviour.ts

@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+export { PluginBehaviour }
+
+interface PluginBehaviour<P> {
+    register(): void,
+    unregister(): void,
+
+    /** Update params in place. Optionally return a promise if it depends on an async action. */
+    update(params: P): void | Promise<void>
+}
+
+namespace PluginBehaviour {
+    export interface Ctor<P> {
+        create(params: P): PluginBehaviour<P>
+    }
+}

+ 2 - 0
src/mol-plugin/command.ts

@@ -0,0 +1,2 @@
+// TODO: command interface and queue.
+// How to handle command resolving? Track how many subscriptions a command has?

+ 47 - 17
src/mol-plugin/context.ts

@@ -4,29 +4,29 @@
  * @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 { Subject } from 'rxjs';
 import { PluginStateObjects as SO } from './state/objects';
+import { RxEventHelper } from 'mol-util/rx-event-helper';
+import { PluginState } from './state';
+import { MolScriptBuilder } from 'mol-script/language/builder';
 
 export class PluginContext {
-    state = {
-        data: State.create(new SO.Root({ label: 'Root' }, { })),
-        // behaviour: State,
-        // plugin: State
-    };
+    private disposed = false;
+    private ev = RxEventHelper.create();
+
+    readonly state = new PluginState(this);
 
-    // TODO: better events
-    events = {
-        stateUpdated: new Subject<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;
@@ -36,13 +36,44 @@ export class PluginContext {
         }
     }
 
+    /**
+     * This should be used in all transform related request so that it could be "spoofed" to allow
+     * "static" access to resources.
+     */
+    async fetch(url: string, type: 'string' | 'binary' = 'string'): Promise<string | Uint8Array> {
+        const req = await fetch(url);
+        return type === 'string' ? await req.text() : new Uint8Array(await req.arrayBuffer());
+    }
+
+    dispose() {
+        if (this.disposed) return;
+        this.canvas3d.dispose();
+        this.ev.dispose();
+        this.state.dispose();
+        this.disposed = true;
+    }
+
     _test_createState(url: string) {
         const b = StateTree.build(this.state.data.tree);
+
+        const query = MolScriptBuilder.struct.generator.atomGroups({
+            // 'atom-test': MolScriptBuilder.core.rel.eq([
+            //     MolScriptBuilder.struct.atomProperty.macromolecular.label_comp_id(),
+            //     MolScriptBuilder.es('C')
+            // ]),
+            'residue-test': MolScriptBuilder.core.rel.eq([
+                MolScriptBuilder.struct.atomProperty.macromolecular.label_comp_id(),
+                'ALA'
+            ])
+        });
+
         const newTree = b.toRoot()
             .apply(StateTransforms.Data.Download, { url })
             .apply(StateTransforms.Data.ParseCif)
-            .apply(StateTransforms.Model.CreateModelsFromMmCif, {}, { ref: 'models' })
+            .apply(StateTransforms.Model.ParseModelsFromMmCif, {}, { ref: 'models' })
             .apply(StateTransforms.Model.CreateStructureFromModel, { modelIndex: 0 }, { ref: 'structure' })
+            .apply(StateTransforms.Model.CreateStructureAssembly)
+            .apply(StateTransforms.Model.CreateStructureSelection, { query, label: 'ALA residues' })
             .apply(StateTransforms.Visuals.CreateStructureRepresentation)
             .getTree();
 
@@ -50,9 +81,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();
     }
 
@@ -66,7 +96,7 @@ export class PluginContext {
         this.state.data.context.events.object.updated.subscribe(o => {
             const oo = o.obj;
             if (!SO.StructureRepresentation3D.is(oo)) return;
-            console.log('adding repr', oo.data.repr);
+            console.log('updating repr', oo.data.repr);
             this.canvas3d.add(oo.data.repr);
             this.canvas3d.requestDraw(true);
         });

+ 38 - 0
src/mol-plugin/state.ts

@@ -0,0 +1,38 @@
+/**
+ * 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;
+
+    getSnapshot(): PluginState.Snapshot {
+        throw 'nyi';
+    }
+
+    setSnapshot(snapshot: PluginState.Snapshot) {
+        throw 'nyi';
+    }
+
+    setDataSnapshot(snapshot: State.Snapshot) {
+        throw 'nyi';
+    }
+
+    dispose() {
+        this.data.dispose();
+    }
+
+    constructor(globalContext: unknown) {
+        this.data = State.create(new SO.Root({ label: 'Root' }, { }), { globalContext });
+    }
+}
+
+namespace PluginState {
+    export interface Snapshot { }
+}

+ 2 - 2
src/mol-plugin/state/base.ts

@@ -11,11 +11,11 @@ export type TypeClass = 'root' | 'data' | 'prop'
 export namespace PluginStateObject {
     export type TypeClass = 'Root' | 'Group' | 'Data' | 'Object' | 'Representation' | 'Behaviour'
     export interface TypeInfo { name: string, shortName: string, description: string, typeClass: TypeClass }
-    export interface Props { label: string, desctiption?: string }
+    export interface Props { label: string, description?: string }
 
     export const Create = StateObject.factory<TypeInfo, Props>();
 }
 
 export namespace PluginStateTransform {
     export const Create = Transformer.factory('ms-plugin');
-}
+}

+ 26 - 6
src/mol-plugin/state/transforms/data.ts

@@ -8,24 +8,44 @@ import { PluginStateTransform } from '../base';
 import { PluginStateObjects as SO } from '../objects';
 import { Task } from 'mol-task';
 import CIF from 'mol-io/reader/cif'
+import { PluginContext } from 'mol-plugin/context';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
-export const Download = PluginStateTransform.Create<SO.Root, SO.Data.String | SO.Data.Binary, { url: string, isBinary?: boolean, label?: string }>({
+export { Download }
+namespace Download { export interface Params { url: string, isBinary?: boolean, label?: string } }
+const Download = PluginStateTransform.Create<SO.Root, SO.Data.String | SO.Data.Binary, Download.Params>({
     name: 'download',
+    display: {
+        name: 'Download',
+        description: 'Download string or binary data from the specified URL'
+    },
     from: [SO.Root],
     to: [SO.Data.String, SO.Data.Binary],
-    apply({ params: p }) {
+    params: {
+        controls: () => ({
+            url: PD.Text('URL', 'Resource URL. Must be the same domain or support CORS.', ''),
+            isBinary: PD.Boolean('Binary', 'If true, download data as binary (string otherwise)', false)
+        })
+    },
+    apply({ params: p }, globalCtx: PluginContext) {
         return Task.create('Download', async ctx => {
             // TODO: track progress
-            const req = await fetch(p.url);
+            const data = await globalCtx.fetch(p.url, p.isBinary ? 'binary' : 'string');
             return p.isBinary
-                ? new SO.Data.Binary({ label: p.label ? p.label : p.url }, new Uint8Array(await req.arrayBuffer()))
-                : new SO.Data.String({ label: p.label ? p.label : p.url }, await req.text());
+                ? new SO.Data.Binary({ label: p.label ? p.label : p.url }, data as Uint8Array)
+                : new SO.Data.String({ label: p.label ? p.label : p.url }, data as string);
         });
     }
 });
 
-export const ParseCif = PluginStateTransform.Create<SO.Data.String | SO.Data.Binary, SO.Data.Cif, { }>({
+export { ParseCif }
+namespace ParseCif { export interface Params { } }
+const ParseCif = PluginStateTransform.Create<SO.Data.String | SO.Data.Binary, SO.Data.Cif, ParseCif.Params>({
     name: 'parse-cif',
+    display: {
+        name: 'Parse CIF',
+        description: 'Parse CIF from String or Binary data'
+    },
     from: [SO.Data.String, SO.Data.Binary],
     to: [SO.Data.Cif],
     apply({ a }) {

+ 89 - 10
src/mol-plugin/state/transforms/model.ts

@@ -7,13 +7,31 @@
 import { PluginStateTransform } from '../base';
 import { PluginStateObjects as SO } from '../objects';
 import { Task } from 'mol-task';
-import { Model, Format, Structure } from 'mol-model/structure';
+import { Model, Format, Structure, ModelSymmetry, StructureSymmetry, QueryContext, StructureSelection } from 'mol-model/structure';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import Expression from 'mol-script/language/expression';
+import { compile } from 'mol-script/runtime/query/compiler';
 
-export const CreateModelsFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Models, { blockHeader?: string }>({
-    name: 'create-models-from-mmcif',
+export { ParseModelsFromMmCif }
+namespace ParseModelsFromMmCif { export interface Params { blockHeader?: string } }
+const ParseModelsFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO.Models, ParseModelsFromMmCif.Params>({
+    name: 'parse-models-from-mmcif',
+    display: {
+        name: 'Models from mmCIF',
+        description: 'Identify and create all separate models in the specified CIF data block'
+    },
     from: [SO.Data.Cif],
     to: [SO.Models],
-    defaultParams: a => ({ blockHeader: a.data.blocks[0].header }),
+    params: {
+        default: a => ({ blockHeader: a.data.blocks[0].header }),
+        controls(a) {
+            const { blocks } = a.data;
+            if (blocks.length === 0) return {};
+            return {
+                blockHeader: PD.Select('Header', 'Header of the block to parse', blocks[0].header, blocks.map(b => [b.header, b.header] as [string, string]))
+            };
+        }
+    },
     apply({ a, params }) {
         return Task.create('Parse mmCIF', async ctx => {
             const header = params.blockHeader || a.data.blocks[0].header;
@@ -27,15 +45,76 @@ export const CreateModelsFromMmCif = PluginStateTransform.Create<SO.Data.Cif, SO
     }
 });
 
-export const CreateStructureFromModel = PluginStateTransform.Create<SO.Models, SO.Structure, { modelIndex: number }>({
-    name: 'structure-from-model',
+export { CreateStructureFromModel }
+namespace CreateStructureFromModel { export interface Params { modelIndex: number } }
+const CreateStructureFromModel = PluginStateTransform.Create<SO.Models, SO.Structure, CreateStructureFromModel.Params>({
+    name: 'create-structure-from-model',
+    display: {
+        name: 'Structure from Model',
+        description: 'Create a molecular structure from the specified model.'
+    },
     from: [SO.Models],
     to: [SO.Structure],
-    defaultParams: () => ({ modelIndex: 0 }),
+    params: {
+        default: () => ({ modelIndex: 0 }),
+        controls: a => ({ modelIndex: PD.Range('Model Index', 'Model Index', 0, 0, Math.max(0, a.data.length - 1), 1) })
+    },
     apply({ a, params }) {
         if (params.modelIndex < 0 || params.modelIndex >= a.data.length) throw new Error(`Invalid modelIndex ${params.modelIndex}`);
-        // TODO: make Structure.ofModel async?
         const s = Structure.ofModel(a.data[params.modelIndex]);
-        return new SO.Structure({ label: `${a.data[params.modelIndex].label} (model ${s.models[0].modelNum})`, desctiption: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` }, s);
+        return new SO.Structure({ label: `Model ${s.models[0].modelNum}`, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` }, s);
     }
-});
+});
+
+
+export { CreateStructureAssembly }
+namespace CreateStructureAssembly { export interface Params { /** if not specified, use the 1st */ id?: string } }
+const CreateStructureAssembly = PluginStateTransform.Create<SO.Structure, SO.Structure, CreateStructureAssembly.Params>({
+    name: 'create-structure-assembly',
+    display: {
+        name: 'Structure Assembly',
+        description: 'Create a molecular structure assembly.'
+    },
+    from: [SO.Structure],
+    to: [SO.Structure],
+    params: {
+        default: () => ({ id: void 0 }),
+        controls(a) {
+            const { model } = a.data;
+            const ids = model.symmetry.assemblies.map(a => [a.id, a.id] as [string, string]);
+            return { id: PD.Select('Asm Id', 'Assembly Id', ids.length ? ids[0][0] : '', ids) };
+        }
+    },
+    isApplicable: a => a.data.models.length === 1 && a.data.model.symmetry.assemblies.length > 0,
+    apply({ a, params }) {
+        return Task.create('Build Assembly', async ctx => {
+            let id = params.id;
+            const model = a.data.model;
+            if (!id && model.symmetry.assemblies.length) id = model.symmetry.assemblies[0].id;
+            const asm = ModelSymmetry.findAssembly(a.data.model, id || '');
+            if (!asm) throw new Error(`Assembly '${id}' not found`);
+
+            const s = await StructureSymmetry.buildAssembly(a.data, id!).runInContext(ctx);
+            return new SO.Structure({ label: `Assembly ${id}`, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` }, s);
+        })
+    }
+});
+
+export { CreateStructureSelection }
+namespace CreateStructureSelection { export interface Params { query: Expression, label?: string } }
+const CreateStructureSelection = PluginStateTransform.Create<SO.Structure, SO.Structure, CreateStructureSelection.Params>({
+    name: 'create-structure-selection',
+    display: {
+        name: 'Structure Selection',
+        description: 'Create a molecular structure from the specified model.'
+    },
+    from: [SO.Structure],
+    to: [SO.Structure],
+    apply({ a, params }) {
+        // TODO: use cache, add "update"
+        const compiled = compile<StructureSelection>(params.query);
+        const result = compiled(new QueryContext(a.data));
+        const s = StructureSelection.unionStructure(result);
+        return new SO.Structure({ label: `${params.label || 'Selection'}`, description: s.elementCount === 1 ? '1 element' : `${s.elementCount} elements` }, s);
+    }
+});

+ 7 - 5
src/mol-plugin/state/transforms/visuals.ts

@@ -8,17 +8,19 @@ import { Transformer } from 'mol-state';
 import { Task } from 'mol-task';
 import { PluginStateTransform } from '../base';
 import { PluginStateObjects as SO } from '../objects';
-import { CartoonRepresentation, DefaultCartoonProps } from 'mol-repr/structure/representation/cartoon';
+//import { CartoonRepresentation, DefaultCartoonProps } from 'mol-repr/structure/representation/cartoon';
+import { BallAndStickRepresentation, DefaultBallAndStickProps } from 'mol-repr/structure/representation/ball-and-stick';
 
-export const CreateStructureRepresentation = PluginStateTransform.Create<SO.Structure, SO.StructureRepresentation3D, { }>({
+export { CreateStructureRepresentation }
+namespace CreateStructureRepresentation { export interface Params { } }
+const CreateStructureRepresentation = PluginStateTransform.Create<SO.Structure, SO.StructureRepresentation3D, CreateStructureRepresentation.Params>({
     name: 'create-structure-representation',
     from: [SO.Structure],
     to: [SO.StructureRepresentation3D],
-    defaultParams: () => ({ modelIndex: 0 }),
     apply({ a, params }) {
         return Task.create('Structure Representation', async ctx => {
-            const repr = CartoonRepresentation();
-            await repr.createOrUpdate({ /* TODO add `webgl: WebGLContext` */ }, { ...DefaultCartoonProps }, a.data).runInContext(ctx);
+            const repr = BallAndStickRepresentation(); // CartoonRepresentation();
+            await repr.createOrUpdate({ /* TODO add `webgl: WebGLContext` */ }, DefaultBallAndStickProps, a.data).runInContext(ctx);
             return new SO.StructureRepresentation3D({ label: 'Cartoon' }, { repr });
         });
     },

+ 8 - 1
src/mol-plugin/ui/tree.tsx

@@ -7,6 +7,7 @@
 import * as React from 'react';
 import { PluginContext } from '../context';
 import { PluginStateObject } from 'mol-plugin/state/base';
+import { StateObject } from 'mol-state'
 
 export class Tree extends React.Component<{ plugin: PluginContext }, { }> {
 
@@ -25,8 +26,14 @@ export class TreeNode extends React.Component<{ plugin: PluginContext, nodeRef:
     render() {
         const n = this.props.plugin.state.data.tree.nodes.get(this.props.nodeRef)!;
         const obj = this.props.plugin.state.data.objects.get(this.props.nodeRef)!;
+        if (!obj.obj) {
+            return <div style={{ borderLeft: '1px solid black', paddingLeft: '5px' }}>
+                {StateObject.StateType[obj.state]} {obj.errorText}
+            </div>;
+        }
+        const props = obj.obj!.props as PluginStateObject.Props;
         return <div style={{ borderLeft: '1px solid black', paddingLeft: '5px' }}>
-            {(obj.obj!.props as PluginStateObject.Props).label}
+            {props.label} {props.description ? <small>{props.description}</small> : void 0}
             {n.children.size === 0
                 ? void 0
                 : <div style={{ marginLeft: '10px' }}>{n.children.map(c => <TreeNode plugin={this.props.plugin} nodeRef={c!} key={c} />)}</div>

+ 4 - 4
src/mol-repr/index.ts

@@ -9,7 +9,7 @@ import { RenderObject } from 'mol-gl/render-object'
 import { PickingId } from '../mol-geo/geometry/picking';
 import { Loci, isEmptyLoci, EmptyLoci } from 'mol-model/loci';
 import { MarkerAction } from '../mol-geo/geometry/marker-data';
-import { Params, MultiSelectParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { WebGLContext } from 'mol-gl/webgl/context';
 import { getQualityProps } from './util';
 import { Theme } from 'mol-geo/geometry/geometry';
@@ -26,7 +26,7 @@ export interface RepresentationContext {
 
 export interface Representation<D, P extends RepresentationProps = {}> {
     readonly label: string
-    readonly params: Params
+    readonly params: PD.Params
     readonly renderObjects: ReadonlyArray<RenderObject>
     readonly props: Readonly<P>
     createOrUpdate: (ctx: RepresentationContext, props?: Partial<P>, data?: D) => Task<void>
@@ -36,7 +36,7 @@ export interface Representation<D, P extends RepresentationProps = {}> {
 }
 
 export namespace Representation {
-    export function createMulti<D, P extends RepresentationProps = {}>(label: string, params: Params, defaultProps: P, reprList: Representation<D, P>[]): Representation<D, P> {
+    export function createMulti<D, P extends RepresentationProps = {}>(label: string, params: PD.Params, defaultProps: P, reprList: Representation<D, P>[]): Representation<D, P> {
         let currentProps: P
         let currentData: D
 
@@ -44,7 +44,7 @@ export namespace Representation {
         for (let i = 0, il = reprList.length; i < il; ++i) {
             visualsOptions.push([ i.toString(), reprList[i].label ])
         }
-        params['visuals'] = MultiSelectParam<string>('Visuals', '', ['surface'], visualsOptions)
+        params['visuals'] = PD.MultiSelect<string>('Visuals', '', ['surface'], visualsOptions)
 
         if (!defaultProps.visuals) {
             defaultProps.visuals = reprList.map((r, i) => i.toString())

+ 3 - 3
src/mol-repr/shape/index.ts

@@ -12,7 +12,7 @@ import { ValueCell } from 'mol-util';
 import { ColorThemeName, ColorThemeOptions } from 'mol-theme/color';
 import { Shape } from 'mol-model/shape';
 import { OrderedSet, Interval } from 'mol-data/int';
-import { paramDefaultValues, SelectParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { createIdentityTransform } from 'mol-geo/geometry/transform-data';
 import { createRenderableState, createTheme } from 'mol-geo/geometry/geometry';
@@ -24,9 +24,9 @@ export interface ShapeRepresentation<P extends RepresentationProps = {}> extends
 
 export const ShapeParams = {
     ...Mesh.Params,
-    colorTheme: SelectParam<ColorThemeName>('Color Theme', '', 'shape-group', ColorThemeOptions)
+    colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'shape-group', ColorThemeOptions)
 }
-export const DefaultShapeProps = paramDefaultValues(ShapeParams)
+export const DefaultShapeProps = PD.getDefaultValues(ShapeParams)
 export type ShapeProps = typeof DefaultShapeProps
 
 // TODO

+ 5 - 5
src/mol-repr/structure/complex-visual.ts

@@ -12,7 +12,7 @@ import { StructureProps, StructureMeshParams, StructureParams } from './index';
 import { deepEqual, ValueCell } from 'mol-util';
 import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci';
 import { Interval } from 'mol-data/int';
-import { MultiSelectParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { RenderableValues } from 'mol-gl/renderable/schema';
 import { createSizes } from 'mol-geo/geometry/size-data';
 import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry';
@@ -27,9 +27,9 @@ export interface  ComplexVisual<P extends StructureProps> extends Visual<Structu
 
 const ComplexParams = {
     ...StructureParams,
-    unitKinds: MultiSelectParam<UnitKind>('Unit Kind', '', ['atomic', 'spheres'], UnitKindOptions),
+    unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', ['atomic', 'spheres'], UnitKindOptions),
 }
-const DefaultComplexProps = paramDefaultValues(ComplexParams)
+const DefaultComplexProps = PD.getDefaultValues(ComplexParams)
 type ComplexProps = typeof DefaultComplexProps
 
 type ComplexRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderObject | DirectVolumeRenderObject
@@ -168,9 +168,9 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual
 
 export const ComplexMeshParams = {
     ...StructureMeshParams,
-    unitKinds: MultiSelectParam<UnitKind>('Unit Kind', '', [ 'atomic', 'spheres' ], UnitKindOptions),
+    unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', [ 'atomic', 'spheres' ], UnitKindOptions),
 }
-export const DefaultComplexMeshProps = paramDefaultValues(ComplexMeshParams)
+export const DefaultComplexMeshProps = PD.getDefaultValues(ComplexMeshParams)
 export type ComplexMeshProps = typeof DefaultComplexMeshProps
 
 export interface ComplexMeshVisualBuilder<P extends ComplexMeshProps> extends ComplexVisualBuilder<P, Mesh> { }

+ 8 - 8
src/mol-repr/structure/index.ts

@@ -9,7 +9,7 @@ import { Structure } from 'mol-model/structure';
 import { ColorThemeName, ColorThemeOptions } from 'mol-theme/color';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { Representation, RepresentationProps } from '..';
-import { SelectParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Geometry } from 'mol-geo/geometry/geometry';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { Points } from 'mol-geo/geometry/points/points';
@@ -21,38 +21,38 @@ export interface StructureRepresentation<P extends RepresentationProps = {}> ext
 
 export const StructureParams = {
     ...Geometry.Params,
-    colorTheme: SelectParam<ColorThemeName>('Color Theme', '', 'polymer-index', ColorThemeOptions),
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'polymer-index', ColorThemeOptions),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
 }
-export const DefaultStructureProps = paramDefaultValues(StructureParams)
+export const DefaultStructureProps = PD.getDefaultValues(StructureParams)
 export type StructureProps = typeof DefaultStructureProps
 
 export const StructureMeshParams = {
     ...Mesh.Params,
     ...StructureParams,
 }
-export const DefaultStructureMeshProps = paramDefaultValues(StructureMeshParams)
+export const DefaultStructureMeshProps = PD.getDefaultValues(StructureMeshParams)
 export type StructureMeshProps = typeof DefaultStructureMeshProps
 
 export const StructurePointsParams = {
     ...Points.Params,
     ...StructureParams,
 }
-export const DefaultStructurePointsProps = paramDefaultValues(StructurePointsParams)
+export const DefaultStructurePointsProps = PD.getDefaultValues(StructurePointsParams)
 export type StructurePointsProps = typeof DefaultStructurePointsProps
 
 export const StructureLinesParams = {
     ...Lines.Params,
     ...StructureParams,
 }
-export const DefaultStructureLinesProps = paramDefaultValues(StructureLinesParams)
+export const DefaultStructureLinesProps = PD.getDefaultValues(StructureLinesParams)
 export type StructureLinesProps = typeof DefaultStructureLinesProps
 
 export const StructureDirectVolumeParams = {
     ...DirectVolume.Params,
     ...StructureParams,
 }
-export const DefaultStructureDirectVolumeProps = paramDefaultValues(StructureDirectVolumeParams)
+export const DefaultStructureDirectVolumeProps = PD.getDefaultValues(StructureDirectVolumeParams)
 export type StructureDirectVolumeProps = typeof DefaultStructureDirectVolumeProps
 
 export { ComplexRepresentation } from './complex-representation'

+ 2 - 2
src/mol-repr/structure/representation/backbone.ts

@@ -5,7 +5,7 @@
  */
 
 import { PolymerBackboneVisual, PolymerBackboneParams } from '../visual/polymer-backbone-cylinder';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { UnitsRepresentation } from '../units-representation';
 import { StructureRepresentation } from '../index';
 import { Representation } from 'mol-repr';
@@ -13,7 +13,7 @@ import { Representation } from 'mol-repr';
 export const BackboneParams = {
     ...PolymerBackboneParams
 }
-export const DefaultBackboneProps = paramDefaultValues(BackboneParams)
+export const DefaultBackboneProps = PD.getDefaultValues(BackboneParams)
 export type BackboneProps = typeof DefaultBackboneProps
 
 export type BackboneRepresentation = StructureRepresentation<BackboneProps>

+ 6 - 6
src/mol-repr/structure/representation/ball-and-stick.ts

@@ -8,7 +8,7 @@ import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphe
 import { IntraUnitLinkVisual, IntraUnitLinkParams } from '../visual/intra-unit-link-cylinder';
 import { InterUnitLinkVisual, InterUnitLinkParams } from '../visual/inter-unit-link-cylinder';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { paramDefaultValues, SelectParam, NumberParam, MultiSelectParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { UnitKind, UnitKindOptions } from '../visual/util/common';
 import { UnitsRepresentation } from '../units-representation';
 import { ComplexRepresentation } from '../complex-representation';
@@ -19,12 +19,12 @@ export const BallAndStickParams = {
     ...ElementSphereParams,
     ...IntraUnitLinkParams,
     ...InterUnitLinkParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 0.2, 0, 10, 0.1),
-    sizeFactor: NumberParam('Size Factor', '', 1, 0, 10, 0.1),
-    unitKinds: MultiSelectParam<UnitKind>('Unit Kind', '', ['atomic'], UnitKindOptions),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
+    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
+    unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', ['atomic'], UnitKindOptions),
 }
-export const DefaultBallAndStickProps = paramDefaultValues(BallAndStickParams)
+export const DefaultBallAndStickProps = PD.getDefaultValues(BallAndStickParams)
 export type BallAndStickProps = typeof DefaultBallAndStickProps
 
 export type BallAndStickRepresentation = StructureRepresentation<BallAndStickProps>

+ 5 - 5
src/mol-repr/structure/representation/carbohydrate.ts

@@ -7,7 +7,7 @@
 import { CarbohydrateSymbolVisual, CarbohydrateSymbolParams } from '../visual/carbohydrate-symbol-mesh';
 import { CarbohydrateLinkVisual, CarbohydrateLinkParams } from '../visual/carbohydrate-link-cylinder';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { paramDefaultValues, SelectParam, NumberParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { ComplexRepresentation } from '../complex-representation';
 import { StructureRepresentation } from '../index';
 import { Representation } from 'mol-repr';
@@ -15,11 +15,11 @@ import { Representation } from 'mol-repr';
 export const CarbohydrateParams = {
     ...CarbohydrateSymbolParams,
     ...CarbohydrateLinkParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 1, 0, 0.1, 20),
-    sizeFactor: NumberParam('Size Factor', '', 1, 0, 10, 0.1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 1, 0, 0.1, 20),
+    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
 }
-export const DefaultCarbohydrateProps = paramDefaultValues(CarbohydrateParams)
+export const DefaultCarbohydrateProps = PD.getDefaultValues(CarbohydrateParams)
 export type CarbohydrateProps = typeof DefaultCarbohydrateProps
 
 export type CarbohydrateRepresentation = StructureRepresentation<CarbohydrateProps>

+ 4 - 4
src/mol-repr/structure/representation/cartoon.ts

@@ -8,7 +8,7 @@ import { PolymerTraceVisual,  PolymerTraceParams } from '../visual/polymer-trace
 import { PolymerGapVisual, PolymerGapParams } from '../visual/polymer-gap-cylinder';
 import { NucleotideBlockVisual, NucleotideBlockParams } from '../visual/nucleotide-block-mesh';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { paramDefaultValues, SelectParam, NumberParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { UnitsRepresentation } from '../units-representation';
 import { StructureRepresentation } from '../index';
 import { Representation } from 'mol-repr';
@@ -19,10 +19,10 @@ export const CartoonParams = {
     ...PolymerGapParams,
     ...NucleotideBlockParams,
     ...PolymerDirectionParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 0.2, 0, 10, 0.1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
 }
-export const DefaultCartoonProps = { ...paramDefaultValues(CartoonParams), visuals: [ '0', '1', '2' ] }
+export const DefaultCartoonProps = { ...PD.getDefaultValues(CartoonParams), visuals: [ '0', '1', '2' ] }
 export type CartoonProps = typeof DefaultCartoonProps
 
 export type CartoonRepresentation = StructureRepresentation<CartoonProps>

+ 4 - 4
src/mol-repr/structure/representation/distance-restraint.ts

@@ -6,17 +6,17 @@
 
 import { CrossLinkRestraintVisual, CrossLinkRestraintParams } from '../visual/cross-link-restraint-cylinder';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { paramDefaultValues, SelectParam, NumberParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { ComplexRepresentation } from '../complex-representation';
 import { StructureRepresentation } from '../index';
 import { Representation } from 'mol-repr';
 
 export const DistanceRestraintParams = {
     ...CrossLinkRestraintParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 0.25, 0, 0.05, 20),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 0.25, 0, 0.05, 20),
 }
-export const DefaultDistanceRestraintProps = paramDefaultValues(DistanceRestraintParams)
+export const DefaultDistanceRestraintProps = PD.getDefaultValues(DistanceRestraintParams)
 export type DistanceRestraintProps = typeof DefaultDistanceRestraintProps
 
 export type DistanceRestraintRepresentation = StructureRepresentation<DistanceRestraintProps>

+ 3 - 3
src/mol-repr/structure/representation/molecular-surface.ts

@@ -7,7 +7,7 @@
 import { GaussianSurfaceVisual, GaussianSurfaceParams } from '../visual/gaussian-surface-mesh';
 import { UnitsRepresentation } from '../units-representation';
 import { GaussianWireframeVisual, GaussianWireframeParams } from '../visual/gaussian-surface-wireframe';
-import { paramDefaultValues, SelectParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { GaussianDensityVolumeParams, GaussianDensityVolumeVisual } from '../visual/gaussian-density-volume';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { StructureRepresentation } from '../index';
@@ -17,9 +17,9 @@ export const MolecularSurfaceParams = {
     ...GaussianSurfaceParams,
     ...GaussianWireframeParams,
     ...GaussianDensityVolumeParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
 }
-export const DefaultMolecularSurfaceProps = { ...paramDefaultValues(MolecularSurfaceParams), visuals: [ '0' ] }
+export const DefaultMolecularSurfaceProps = { ...PD.getDefaultValues(MolecularSurfaceParams), visuals: [ '0' ] }
 export type MolecularSurfaceProps = typeof DefaultMolecularSurfaceProps
 
 export type MolecularSurfaceRepresentation = StructureRepresentation<MolecularSurfaceProps>

+ 2 - 2
src/mol-repr/structure/representation/point.ts

@@ -6,14 +6,14 @@
 
 import { ElementPointVisual, ElementPointParams } from '../visual/element-point';
 import { UnitsRepresentation } from '../units-representation';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { StructureRepresentation } from '../index';
 import { Representation } from 'mol-repr';
 
 export const PointParams = {
     ...ElementPointParams,
 }
-export const DefaultPointProps = paramDefaultValues(PointParams)
+export const DefaultPointProps = PD.getDefaultValues(PointParams)
 export type PointProps = typeof DefaultPointProps
 
 export type PointRepresentation = StructureRepresentation<PointProps>

+ 2 - 2
src/mol-repr/structure/representation/spacefill.ts

@@ -6,14 +6,14 @@
 
 import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
 import { UnitsRepresentation } from '../units-representation';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { StructureRepresentation } from '../index';
 import { Representation } from 'mol-repr';
 
 export const SpacefillParams = {
     ...ElementSphereParams
 }
-export const DefaultSpacefillProps = paramDefaultValues(SpacefillParams)
+export const DefaultSpacefillProps = PD.getDefaultValues(SpacefillParams)
 export type SpacefillProps = typeof DefaultSpacefillProps
 
 export type SpacefillRepresentation = StructureRepresentation<SpacefillProps>

+ 7 - 7
src/mol-repr/structure/units-visual.ts

@@ -12,7 +12,7 @@ import { MeshRenderObject, PointsRenderObject, LinesRenderObject, DirectVolumeRe
 import { createUnitsMeshRenderObject, createUnitsPointsRenderObject, createUnitsTransform, createUnitsLinesRenderObject, createUnitsDirectVolumeRenderObject, UnitKind, UnitKindOptions, includesUnitKind } from './visual/util/common';
 import { deepEqual, ValueCell, UUID } from 'mol-util';
 import { Interval } from 'mol-data/int';
-import { MultiSelectParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { RenderableValues } from 'mol-gl/renderable/schema';
 import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
@@ -39,9 +39,9 @@ function sameGroupConformation(groupA: Unit.SymmetryGroup, groupB: Unit.Symmetry
 
 const UnitsParams = {
     ...StructureParams,
-    unitKinds: MultiSelectParam<UnitKind>('Unit Kind', '', ['atomic', 'spheres'], UnitKindOptions),
+    unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', ['atomic', 'spheres'], UnitKindOptions),
 }
-const DefaultUnitsProps = paramDefaultValues(UnitsParams)
+const DefaultUnitsProps = PD.getDefaultValues(UnitsParams)
 type UnitsProps = typeof DefaultUnitsProps
 
 type UnitsRenderObject = MeshRenderObject | LinesRenderObject | PointsRenderObject | DirectVolumeRenderObject
@@ -205,7 +205,7 @@ export const UnitsMeshParams = {
     ...StructureMeshParams,
     ...UnitsParams,
 }
-export const DefaultUnitsMeshProps = paramDefaultValues(UnitsMeshParams)
+export const DefaultUnitsMeshProps = PD.getDefaultValues(UnitsMeshParams)
 export type UnitsMeshProps = typeof DefaultUnitsMeshProps
 export interface UnitsMeshVisualBuilder<P extends UnitsMeshProps> extends UnitsVisualBuilder<P, Mesh> { }
 
@@ -228,7 +228,7 @@ export const UnitsPointsParams = {
     ...StructurePointsParams,
     ...UnitsParams,
 }
-export const DefaultUnitsPointsProps = paramDefaultValues(UnitsPointsParams)
+export const DefaultUnitsPointsProps = PD.getDefaultValues(UnitsPointsParams)
 export type UnitsPointsProps = typeof DefaultUnitsPointsProps
 export interface UnitsPointVisualBuilder<P extends UnitsPointsProps> extends UnitsVisualBuilder<P, Points> { }
 
@@ -251,7 +251,7 @@ export const UnitsLinesParams = {
     ...StructureLinesParams,
     ...UnitsParams,
 }
-export const DefaultUnitsLinesProps = paramDefaultValues(UnitsLinesParams)
+export const DefaultUnitsLinesProps = PD.getDefaultValues(UnitsLinesParams)
 export type UnitsLinesProps = typeof DefaultUnitsLinesProps
 export interface UnitsLinesVisualBuilder<P extends UnitsLinesProps> extends UnitsVisualBuilder<P, Lines> { }
 
@@ -274,7 +274,7 @@ export const UnitsDirectVolumeParams = {
     ...StructureDirectVolumeParams,
     ...UnitsParams,
 }
-export const DefaultUnitsDirectVolumeProps = paramDefaultValues(UnitsDirectVolumeParams)
+export const DefaultUnitsDirectVolumeProps = PD.getDefaultValues(UnitsDirectVolumeParams)
 export type UnitsDirectVolumeProps = typeof DefaultUnitsDirectVolumeProps
 export interface UnitsDirectVolumeVisualBuilder<P extends UnitsDirectVolumeProps> extends UnitsVisualBuilder<P, DirectVolume> { }
 

+ 5 - 5
src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts

@@ -14,7 +14,7 @@ import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { LinkType } from 'mol-model/structure/model/types';
 import { BitFlags } from 'mol-util';
 import { UnitsMeshParams } from '../units-visual';
-import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
@@ -64,11 +64,11 @@ async function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure:
 export const CarbohydrateLinkParams = {
     ...UnitsMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 1, 0, 20, 0.1),
-    detail: NumberParam('Sphere Detail', '', 0, 0, 3, 1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1),
 }
-export const DefaultCarbohydrateLinkProps = paramDefaultValues(CarbohydrateLinkParams)
+export const DefaultCarbohydrateLinkProps = PD.getDefaultValues(CarbohydrateLinkParams)
 export type CarbohydrateLinkProps = typeof DefaultCarbohydrateLinkProps
 
 export function CarbohydrateLinkVisual(): ComplexVisual<CarbohydrateLinkProps> {

+ 5 - 5
src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts

@@ -17,7 +17,7 @@ import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants';
 import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
 import { ComplexMeshParams, ComplexMeshVisual } from '../complex-visual';
-import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { ComplexVisual } from '../index';
 import { VisualUpdateState } from '../../util';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
@@ -148,11 +148,11 @@ async function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Struc
 
 export const CarbohydrateSymbolParams = {
     ...ComplexMeshParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 1, 0, 10, 0.1),
-    detail: NumberParam('Sphere Detail', '', 0, 0, 3, 1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1),
+    detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1),
 }
-export const DefaultCarbohydrateSymbolProps = paramDefaultValues(CarbohydrateSymbolParams)
+export const DefaultCarbohydrateSymbolProps = PD.getDefaultValues(CarbohydrateSymbolParams)
 export type CarbohydrateSymbolProps = typeof DefaultCarbohydrateSymbolProps
 
 export function CarbohydrateSymbolVisual(): ComplexVisual<CarbohydrateSymbolProps> {

+ 4 - 4
src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts

@@ -15,7 +15,7 @@ import { Interval } from 'mol-data/int';
 import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
 import { BitFlags } from 'mol-util';
 import { LinkType } from 'mol-model/structure/model/types';
-import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
@@ -54,10 +54,10 @@ async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structur
 export const CrossLinkRestraintParams = {
     ...ComplexMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 1, 0, 20, 0.1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
 }
-export const DefaultCrossLinkRestraintProps = paramDefaultValues(CrossLinkRestraintParams)
+export const DefaultCrossLinkRestraintProps = PD.getDefaultValues(CrossLinkRestraintParams)
 export type CrossLinkRestraintProps = typeof DefaultCrossLinkRestraintProps
 
 export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintProps> {

+ 5 - 5
src/mol-repr/structure/visual/element-point.ts

@@ -11,7 +11,7 @@ import { getElementLoci, StructureElementIterator, markElement } from './util/el
 import { Vec3 } from 'mol-math/linear-algebra';
 import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
 import { UnitsPointsVisual, UnitsPointsParams } from '../units-visual';
-import { SelectParam, NumberParam, BooleanParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Points } from 'mol-geo/geometry/points/points';
 import { PointsBuilder } from 'mol-geo/geometry/points/points-builder';
 import { VisualContext } from 'mol-repr';
@@ -19,11 +19,11 @@ import { Theme } from 'mol-geo/geometry/geometry';
 
 export const ElementPointParams = {
     ...UnitsPointsParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 3, 0, 20, 0.1),
-    pointSizeAttenuation: BooleanParam('Point Size Attenuation', '', false),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 3, 0, 20, 0.1),
+    pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false),
 }
-export const DefaultElementPointProps = paramDefaultValues(ElementPointParams)
+export const DefaultElementPointProps = PD.getDefaultValues(ElementPointParams)
 export type ElementPointProps = typeof DefaultElementPointProps
 
 // TODO size

+ 6 - 6
src/mol-repr/structure/visual/element-sphere.ts

@@ -9,17 +9,17 @@ import { UnitsVisual } from '../index';
 import { VisualUpdateState } from '../../util';
 import { createElementSphereMesh, markElement, getElementLoci, StructureElementIterator } from './util/element';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
-import { NumberParam, paramDefaultValues, SelectParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 
 export const ElementSphereParams = {
     ...UnitsMeshParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 0.2, 0, 10, 0.1),
-    sizeFactor: NumberParam('Size Factor', '', 1, 0, 10, 0.1),
-    detail: NumberParam('Sphere Detail', '', 0, 0, 3, 1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
+    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
+    detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1),
 }
-export const DefaultElementSphereProps = paramDefaultValues(ElementSphereParams)
+export const DefaultElementSphereProps = PD.getDefaultValues(ElementSphereParams)
 export type ElementSphereProps = typeof DefaultElementSphereProps
 
 export function ElementSphereVisual(): UnitsVisual<ElementSphereProps> {

+ 5 - 5
src/mol-repr/structure/visual/gaussian-density-point.ts

@@ -13,7 +13,7 @@ import { Vec3 } from 'mol-math/linear-algebra';
 import { UnitsPointsVisual, UnitsPointsParams } from '../units-visual';
 import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
 import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density';
-import { paramDefaultValues, SelectParam, NumberParam, BooleanParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Points } from 'mol-geo/geometry/points/points';
 import { PointsBuilder } from 'mol-geo/geometry/points/points-builder';
 import { VisualContext } from 'mol-repr';
@@ -22,11 +22,11 @@ import { Theme } from 'mol-geo/geometry/geometry';
 export const GaussianDensityPointParams = {
     ...UnitsPointsParams,
     ...GaussianDensityParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 1, 0, 20, 0.1),
-    pointSizeAttenuation: BooleanParam('Point Size Attenuation', '', false),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false),
 }
-export const DefaultGaussianDensityPointProps = paramDefaultValues(GaussianDensityPointParams)
+export const DefaultGaussianDensityPointProps = PD.getDefaultValues(GaussianDensityPointParams)
 export type GaussianDensityPointProps = typeof DefaultGaussianDensityPointProps
 
 export async function createGaussianDensityPoint(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, points?: Points) {

+ 2 - 2
src/mol-repr/structure/visual/gaussian-density-volume.ts

@@ -10,7 +10,7 @@ import { VisualUpdateState } from '../../util';
 import { UnitsDirectVolumeVisual, UnitsDirectVolumeParams } from '../units-visual';
 import { StructureElementIterator, getElementLoci, markElement } from './util/element';
 import { GaussianDensityProps, GaussianDensityParams, computeUnitGaussianDensityTexture } from 'mol-model/structure/structure/unit/gaussian-density';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
 import { VisualContext } from 'mol-repr';
 import { Theme } from 'mol-geo/geometry/geometry';
@@ -31,7 +31,7 @@ export const GaussianDensityVolumeParams = {
     ...UnitsDirectVolumeParams,
     ...GaussianDensityParams,
 }
-export const DefaultGaussianDensityVolumeProps = paramDefaultValues(GaussianDensityVolumeParams)
+export const DefaultGaussianDensityVolumeProps = PD.getDefaultValues(GaussianDensityVolumeParams)
 export type GaussianDensityVolumeProps = typeof DefaultGaussianDensityVolumeProps
 
 export function GaussianDensityVolumeVisual(): UnitsVisual<GaussianDensityVolumeProps> {

+ 2 - 2
src/mol-repr/structure/visual/gaussian-surface-mesh.ts

@@ -10,7 +10,7 @@ import { VisualUpdateState } from '../../util';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { StructureElementIterator, getElementLoci, markElement } from './util/element';
 import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm';
 import { VisualContext } from 'mol-repr';
@@ -38,7 +38,7 @@ export const GaussianSurfaceParams = {
     ...UnitsMeshParams,
     ...GaussianDensityParams,
 }
-export const DefaultGaussianSurfaceProps = paramDefaultValues(GaussianSurfaceParams)
+export const DefaultGaussianSurfaceProps = PD.getDefaultValues(GaussianSurfaceParams)
 export type GaussianSurfaceProps = typeof DefaultGaussianSurfaceProps
 
 export function GaussianSurfaceVisual(): UnitsVisual<GaussianSurfaceProps> {

+ 5 - 5
src/mol-repr/structure/visual/gaussian-surface-wireframe.ts

@@ -10,7 +10,7 @@ import { VisualUpdateState } from '../../util';
 import { UnitsLinesVisual, UnitsLinesParams } from '../units-visual';
 import { StructureElementIterator, getElementLoci, markElement } from './util/element';
 import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density';
-import { paramDefaultValues, SelectParam, NumberParam, BooleanParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { Lines } from 'mol-geo/geometry/lines/lines';
 import { computeMarchingCubesLines } from 'mol-geo/util/marching-cubes/algorithm';
@@ -36,11 +36,11 @@ async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure
 export const GaussianWireframeParams = {
     ...UnitsLinesParams,
     ...GaussianDensityParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 2, 0, 10, 0.1),
-    lineSizeAttenuation: BooleanParam('Line Size Attenuation', '', false),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 2, 0, 10, 0.1),
+    lineSizeAttenuation: PD.Boolean('Line Size Attenuation', '', false),
 }
-export const DefaultGaussianWireframeProps = paramDefaultValues(GaussianWireframeParams)
+export const DefaultGaussianWireframeProps = PD.getDefaultValues(GaussianWireframeParams)
 export type GaussianWireframeProps = typeof DefaultGaussianWireframeProps
 
 export function GaussianWireframeVisual(): UnitsVisual<GaussianWireframeProps> {

+ 2 - 2
src/mol-repr/structure/visual/inter-unit-link-cylinder.ts

@@ -13,7 +13,7 @@ import { Loci, EmptyLoci } from 'mol-model/loci';
 import { ComplexMeshVisual, ComplexMeshParams } from '../complex-visual';
 import { Interval } from 'mol-data/int';
 import { BitFlags } from 'mol-util';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { VisualContext } from 'mol-repr';
@@ -53,7 +53,7 @@ export const InterUnitLinkParams = {
     ...ComplexMeshParams,
     ...LinkCylinderParams,
 }
-export const DefaultInterUnitLinkProps = paramDefaultValues(InterUnitLinkParams)
+export const DefaultInterUnitLinkProps = PD.getDefaultValues(InterUnitLinkParams)
 export type InterUnitLinkProps = typeof DefaultInterUnitLinkProps
 
 export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkProps> {

+ 5 - 5
src/mol-repr/structure/visual/intra-unit-link-cylinder.ts

@@ -15,7 +15,7 @@ import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { Interval } from 'mol-data/int';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { BitFlags } from 'mol-util';
-import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { VisualContext } from 'mol-repr';
@@ -67,11 +67,11 @@ async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, s
 export const IntraUnitLinkParams = {
     ...UnitsMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 0.2, 0, 10, 0.1),
-    sizeFactor: NumberParam('Size Factor', '', 1, 0, 10, 0.1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
+    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
 }
-export const DefaultIntraUnitLinkProps = paramDefaultValues(IntraUnitLinkParams)
+export const DefaultIntraUnitLinkProps = PD.getDefaultValues(IntraUnitLinkParams)
 export type IntraUnitLinkProps = typeof DefaultIntraUnitLinkProps
 
 export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> {

+ 2 - 2
src/mol-repr/structure/visual/nucleotide-block-mesh.ts

@@ -12,7 +12,7 @@ import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-mode
 import { getElementIndexForAtomRole } from 'mol-model/structure/util';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { NucleotideLocationIterator, markNucleotideElement, getNucleotideElementLoci } from './util/nucleotide';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Box } from 'mol-geo/primitive/box';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
@@ -115,7 +115,7 @@ async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structu
 export const NucleotideBlockParams = {
     ...UnitsMeshParams
 }
-export const DefaultNucleotideBlockProps = paramDefaultValues(NucleotideBlockParams)
+export const DefaultNucleotideBlockProps = PD.getDefaultValues(NucleotideBlockParams)
 export type NucleotideBlockProps = typeof DefaultNucleotideBlockProps
 
 export function NucleotideBlockVisual(): UnitsVisual<NucleotideBlockProps> {

+ 4 - 4
src/mol-repr/structure/visual/polymer-backbone-cylinder.ts

@@ -12,7 +12,7 @@ import { getElementLoci, markElement, StructureElementIterator } from './util/el
 import { Vec3 } from 'mol-math/linear-algebra';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { OrderedSet } from 'mol-data/int';
-import { paramDefaultValues, NumberParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { CylinderProps } from 'mol-geo/primitive/cylinder';
@@ -21,9 +21,9 @@ import { VisualContext } from 'mol-repr';
 import { Theme } from 'mol-geo/geometry/geometry';
 
 export const PolymerBackboneCylinderParams = {
-    radialSegments: NumberParam('Radial Segments', '', 16, 3, 56, 1),
+    radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1),
 }
-export const DefaultPolymerBackboneCylinderProps = paramDefaultValues(PolymerBackboneCylinderParams)
+export const DefaultPolymerBackboneCylinderProps = PD.getDefaultValues(PolymerBackboneCylinderParams)
 export type PolymerBackboneCylinderProps = typeof DefaultPolymerBackboneCylinderProps
 
 async function createPolymerBackboneCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerBackboneCylinderProps, mesh?: Mesh) {
@@ -69,7 +69,7 @@ export const PolymerBackboneParams = {
     ...UnitsMeshParams,
     ...PolymerBackboneCylinderParams,
 }
-export const DefaultPolymerBackboneProps = paramDefaultValues(PolymerBackboneParams)
+export const DefaultPolymerBackboneProps = PD.getDefaultValues(PolymerBackboneParams)
 export type PolymerBackboneProps = typeof DefaultPolymerBackboneProps
 
 export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> {

+ 5 - 5
src/mol-repr/structure/visual/polymer-direction-wedge.ts

@@ -11,7 +11,7 @@ import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Wedge } from 'mol-geo/primitive/wedge';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
@@ -31,10 +31,10 @@ const heightFactor = 6
 const wedge = Wedge()
 
 export const PolymerDirectionWedgeParams = {
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 1, 0, 20, 0.1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
 }
-export const DefaultPolymerDirectionWedgeProps = paramDefaultValues(PolymerDirectionWedgeParams)
+export const DefaultPolymerDirectionWedgeProps = PD.getDefaultValues(PolymerDirectionWedgeParams)
 export type PolymerDirectionWedgeProps = typeof DefaultPolymerDirectionWedgeProps
 
 async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerDirectionWedgeProps, mesh?: Mesh) {
@@ -92,7 +92,7 @@ export const PolymerDirectionParams = {
     ...UnitsMeshParams,
     ...PolymerDirectionWedgeParams
 }
-export const DefaultPolymerDirectionProps = paramDefaultValues(PolymerDirectionParams)
+export const DefaultPolymerDirectionProps = PD.getDefaultValues(PolymerDirectionParams)
 export type PolymerDirectionProps = typeof DefaultPolymerDirectionProps
 
 export function PolymerDirectionVisual(): UnitsVisual<PolymerDirectionProps> {

+ 8 - 8
src/mol-repr/structure/visual/polymer-gap-cylinder.ts

@@ -11,7 +11,7 @@ import { PolymerGapIterator, PolymerGapLocationIterator, markPolymerGapElement,
 import { Vec3 } from 'mol-math/linear-algebra';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
-import { SelectParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { LinkCylinderParams } from './util/link';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
@@ -24,9 +24,9 @@ import { Theme } from 'mol-geo/geometry/geometry';
 const segmentCount = 10
 
 export const PolymerGapCylinderParams = {
-    radialSegments: NumberParam('Radial Segments', '', 16, 3, 56, 1),
+    radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1),
 }
-export const DefaultPolymerGapCylinderProps = paramDefaultValues(PolymerGapCylinderParams)
+export const DefaultPolymerGapCylinderProps = PD.getDefaultValues(PolymerGapCylinderParams)
 export type PolymerGapCylinderProps = typeof DefaultPolymerGapCylinderProps
 
 async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerGapCylinderProps, mesh?: Mesh) {
@@ -78,18 +78,18 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru
 export const InterUnitLinkParams = {
     ...UnitsMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: NumberParam('Size Value', '', 1, 0, 20, 0.1),
-    sizeFactor: NumberParam('Size Factor', '', 0.3, 0, 10, 0.1),
+    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    sizeFactor: PD.Numeric('Size Factor', '', 0.3, 0, 10, 0.1),
 }
-export const DefaultIntraUnitLinkProps = paramDefaultValues(InterUnitLinkParams)
+export const DefaultIntraUnitLinkProps = PD.getDefaultValues(InterUnitLinkParams)
 export type IntraUnitLinkProps = typeof DefaultIntraUnitLinkProps
 
 export const PolymerGapParams = {
     ...UnitsMeshParams,
     ...PolymerGapCylinderParams
 }
-export const DefaultPolymerGapProps = paramDefaultValues(PolymerGapParams)
+export const DefaultPolymerGapProps = PD.getDefaultValues(PolymerGapParams)
 export type PolymerGapProps = typeof DefaultPolymerGapProps
 
 export function PolymerGapVisual(): UnitsVisual<PolymerGapProps> {

+ 7 - 7
src/mol-repr/structure/visual/polymer-trace-mesh.ts

@@ -10,7 +10,7 @@ import { VisualUpdateState } from '../../util';
 import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer';
 import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
-import {  NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { addSheet } from 'mol-geo/geometry/mesh/builder/sheet';
@@ -19,12 +19,12 @@ import { VisualContext } from 'mol-repr';
 import { Theme } from 'mol-geo/geometry/geometry';
 
 export const PolymerTraceMeshParams = {
-    linearSegments: NumberParam('Linear Segments', '', 8, 1, 48, 1),
-    radialSegments: NumberParam('Radial Segments', '', 16, 3, 56, 1),
-    aspectRatio: NumberParam('Aspect Ratio', '', 5, 0.1, 5, 0.1),
-    arrowFactor: NumberParam('Arrow Factor', '', 1.5, 0.1, 5, 0.1),
+    linearSegments: PD.Numeric('Linear Segments', '', 8, 1, 48, 1),
+    radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1),
+    aspectRatio: PD.Numeric('Aspect Ratio', '', 5, 0.1, 5, 0.1),
+    arrowFactor: PD.Numeric('Arrow Factor', '', 1.5, 0.1, 5, 0.1),
 }
-export const DefaultPolymerTraceMeshProps = paramDefaultValues(PolymerTraceMeshParams)
+export const DefaultPolymerTraceMeshProps = PD.getDefaultValues(PolymerTraceMeshParams)
 export type PolymerTraceMeshProps = typeof DefaultPolymerTraceMeshProps
 
 // TODO handle polymer ends properly
@@ -89,7 +89,7 @@ export const PolymerTraceParams = {
     ...UnitsMeshParams,
     ...PolymerTraceMeshParams
 }
-export const DefaultPolymerTraceProps = paramDefaultValues(PolymerTraceParams)
+export const DefaultPolymerTraceProps = PD.getDefaultValues(PolymerTraceParams)
 export type PolymerTraceProps = typeof DefaultPolymerTraceProps
 
 export function PolymerTraceVisual(): UnitsVisual<PolymerTraceProps> {

+ 6 - 6
src/mol-repr/structure/visual/util/link.ts

@@ -7,7 +7,7 @@
 import { Vec3 } from 'mol-math/linear-algebra';
 import { LinkType } from 'mol-model/structure/model/types';
 import { Unit, StructureElement, Structure, Link } from 'mol-model/structure';
-import { RangeParam, NumberParam, paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { CylinderProps } from 'mol-geo/primitive/cylinder';
@@ -16,12 +16,12 @@ import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { VisualContext } from 'mol-repr';
 
 export const LinkCylinderParams = {
-    linkScale: RangeParam('Link Scale', '', 0.4, 0, 1, 0.1),
-    linkSpacing: RangeParam('Link Spacing', '', 1, 0, 2, 0.01),
-    linkRadius: RangeParam('Link Radius', '', 0.25, 0, 10, 0.05),
-    radialSegments: NumberParam('Radial Segments', '', 16, 3, 56, 1),
+    linkScale: PD.Range('Link Scale', '', 0.4, 0, 1, 0.1),
+    linkSpacing: PD.Range('Link Spacing', '', 1, 0, 2, 0.01),
+    linkRadius: PD.Range('Link Radius', '', 0.25, 0, 10, 0.05),
+    radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1),
 }
-export const DefaultLinkCylinderProps = paramDefaultValues(LinkCylinderParams)
+export const DefaultLinkCylinderProps = PD.getDefaultValues(LinkCylinderParams)
 export type LinkCylinderProps = typeof DefaultLinkCylinderProps
 
 const tmpShiftV12 = Vec3.zero()

+ 2 - 2
src/mol-repr/volume/direct-volume.ts

@@ -9,7 +9,7 @@ import { RuntimeContext } from 'mol-task'
 import { VolumeVisual, VolumeRepresentation } from './index';
 import { createDirectVolumeRenderObject } from 'mol-gl/render-object';
 import { Loci, EmptyLoci } from 'mol-model/loci';
-import { paramDefaultValues } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { Box3D } from 'mol-math/geometry';
 import { WebGLContext } from 'mol-gl/webgl/context';
@@ -187,7 +187,7 @@ export const DirectVolumeParams = {
     ...Geometry.Params,
     ...DirectVolume.Params
 }
-export const DefaultDirectVolumeProps = paramDefaultValues(DirectVolumeParams)
+export const DefaultDirectVolumeProps = PD.getDefaultValues(DirectVolumeParams)
 export type DirectVolumeProps = typeof DefaultDirectVolumeProps
 
 export function DirectVolumeVisual(): VolumeVisual<DirectVolumeProps> {

+ 4 - 4
src/mol-repr/volume/index.ts

@@ -8,8 +8,8 @@ import { Task } from 'mol-task'
 import { RepresentationProps, Representation, Visual, RepresentationContext, VisualContext } from '..';
 import { VolumeData, VolumeIsoValue } from 'mol-model/volume';
 import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
-import { paramDefaultValues, RangeParam } from 'mol-util/parameter';
 import { Geometry, updateRenderableState, Theme, createTheme } from 'mol-geo/geometry/geometry';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data';
 import { DirectVolumeRenderObject, PointsRenderObject, LinesRenderObject, MeshRenderObject } from 'mol-gl/render-object';
@@ -136,10 +136,10 @@ export interface VolumeRepresentation<P extends RepresentationProps = {}> extend
 
 export const VolumeParams = {
     ...Geometry.Params,
-    isoValueAbsolute: RangeParam('Iso Value Absolute', '', 0.22, -1, 1, 0.01),
-    isoValueRelative: RangeParam('Iso Value Relative', '', 2, -10, 10, 0.1),
+    isoValueAbsolute: PD.Range('Iso Value Absolute', '', 0.22, -1, 1, 0.01),
+    isoValueRelative: PD.Range('Iso Value Relative', '', 2, -10, 10, 0.1),
 }
-export const DefaultVolumeProps = paramDefaultValues(VolumeParams)
+export const DefaultVolumeProps = PD.getDefaultValues(VolumeParams)
 export type VolumeProps = typeof DefaultVolumeProps
 
 export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeData: VolumeData) => VolumeVisual<P>): VolumeRepresentation<P> {

+ 4 - 4
src/mol-repr/volume/isosurface-mesh.ts

@@ -9,7 +9,7 @@ import { VolumeData } from 'mol-model/volume'
 import { VolumeVisual, VolumeRepresentation } from './index';
 import { createMeshRenderObject } from 'mol-gl/render-object';
 import { Loci, EmptyLoci } from 'mol-model/loci';
-import { paramDefaultValues, RangeParam } from 'mol-util/parameter';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
@@ -42,10 +42,10 @@ export async function createVolumeIsosurface(ctx: VisualContext, volume: VolumeD
 
 export const IsosurfaceParams = {
     ...Mesh.Params,
-    isoValueAbsolute: RangeParam('Iso Value Absolute', '', 0.22, -1, 1, 0.01),
-    isoValueRelative: RangeParam('Iso Value Relative', '', 2, -10, 10, 0.1),
+    isoValueAbsolute: PD.Range('Iso Value Absolute', '', 0.22, -1, 1, 0.01),
+    isoValueRelative: PD.Range('Iso Value Relative', '', 2, -10, 10, 0.1),
 }
-export const DefaultIsosurfaceProps = paramDefaultValues(IsosurfaceParams)
+export const DefaultIsosurfaceProps = PD.getDefaultValues(IsosurfaceParams)
 export type IsosurfaceProps = typeof DefaultIsosurfaceProps
 
 export function IsosurfaceVisual(): VolumeVisual<IsosurfaceProps> {

+ 26 - 34
src/mol-state/context.ts

@@ -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 }
+    constructor(params: { globalContext: unknown, defaultObjectProps: unknown }) {
+        this.globalContext = params.globalContext;
+        this.defaultObjectProps = params.defaultObjectProps;
+    }
+}

+ 1 - 2
src/mol-state/object.ts

@@ -9,7 +9,7 @@ import { Transform } from './transform';
 import { UUID } from 'mol-util';
 
 /** A mutable state object */
-export interface StateObject<P = unknown, D = unknown> {
+export interface StateObject<P = any, D = any> {
     readonly id: UUID,
     readonly type: StateObject.Type,
     readonly props: P,
@@ -45,7 +45,6 @@ export namespace StateObject {
             static is(obj?: StateObject): obj is StateObject<Props, Data> { return !!obj && dataType === obj.type; }
             id = UUID.create();
             type = dataType;
-            ref = 'not set' as Transform.Ref;
             constructor(public props: Props, public data: Data) { }
         }
     }

+ 89 - 57
src/mol-state/state.ts

@@ -13,23 +13,53 @@ 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 }
+
+class State {
+    private _tree: StateTree = StateTree.create();
+    private transformCache = new Map<Transform.Ref, unknown>();
+
+    get tree() { return this._tree; }
+
+    readonly objects: State.Objects = new Map();
+    readonly context: StateContext;
 
-export namespace State {
-    export type Ref = Transform.Ref
-    export type Objects = Map<Ref, StateObject.Node>
+    getSnapshot(): State.Snapshot {
+        throw 'nyi';
+    }
+
+    setSnapshot(snapshot: State.Snapshot): void {
+        throw 'nyi';
+    }
 
-    export function create(rootObject: StateObject, params?: { globalContext?: unknown, defaultObjectProps: unknown }) {
-        const tree = StateTree.create();
-        const objects: Objects = new Map();
+    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,
+                transformCache: this.transformCache
+            };
+            // 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,34 +67,43 @@ 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 }
+    }
+
+    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,
+        transformCache: Map<Ref, unknown>
     }
 
-    async function _update(ctx: UpdateContext): Promise<State> {
+    async function update(ctx: UpdateContext) {
         const roots = findUpdateRoots(ctx.objects, ctx.tree);
         const deletes = findDeletes(ctx);
         for (const d of deletes) {
             ctx.objects.delete(d);
+            ctx.transformCache.delete(d);
             ctx.stateCtx.events.object.removed.next({ ref: d });
         }
 
@@ -73,23 +112,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
@@ -154,6 +179,7 @@ export namespace State {
         const wrap = ctx.objects.get(ref)!;
         if (wrap.obj) {
             ctx.stateCtx.events.object.removed.next({ ref });
+            ctx.transformCache.delete(ref);
             wrap.obj = void 0;
         }
 
@@ -165,7 +191,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)!;
@@ -210,7 +236,7 @@ export namespace State {
         // console.log('parent', transform.transformer.id, transform.transformer.definition.from[0].type, parent ? parent.ref : 'undefined')
         if (!oldTree.nodes.has(currentRef) || !objects.has(currentRef)) {
             // console.log('creating...', transform.transformer.id, oldTree.nodes.has(currentRef), objects.has(currentRef));
-            const obj = await createObject(ctx, transform.transformer, parent, transform.params);
+            const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params);
             objects.set(currentRef, {
                 ref: currentRef,
                 obj,
@@ -223,9 +249,9 @@ export namespace State {
             // console.log('updating...', transform.transformer.id);
             const current = objects.get(currentRef)!;
             const oldParams = oldTree.getValue(currentRef)!.params;
-            switch (await updateObject(ctx, transform.transformer, parent, current.obj!, oldParams, transform.params)) {
+            switch (await updateObject(ctx, currentRef, transform.transformer, parent, current.obj!, oldParams, transform.params)) {
                 case Transformer.UpdateResult.Recreate: {
-                    const obj = await createObject(ctx, transform.transformer, parent, transform.params);
+                    const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params);
                     objects.set(currentRef, {
                         ref: currentRef,
                         obj,
@@ -251,14 +277,20 @@ export namespace State {
         return t as T;
     }
 
-    function createObject(ctx: UpdateContext, transformer: Transformer, a: StateObject, params: any) {
-        return runTask(transformer.definition.apply({ a, params }, ctx.stateCtx.globalContext), ctx.taskCtx);
+    function createObject(ctx: UpdateContext, ref: Ref, transformer: Transformer, a: StateObject, params: any) {
+        const cache = { };
+        ctx.transformCache.set(ref, cache);
+        return runTask(transformer.definition.apply({ a, params, cache }, ctx.stateCtx.globalContext), ctx.taskCtx);
     }
 
-    async function updateObject(ctx: UpdateContext, transformer: Transformer, a: StateObject, b: StateObject, oldParams: any, newParams: any) {
+    async function updateObject(ctx: UpdateContext, ref: Ref, transformer: Transformer, a: StateObject, b: StateObject, oldParams: any, newParams: any) {
         if (!transformer.definition.update) {
             return Transformer.UpdateResult.Recreate;
         }
-        return runTask(transformer.definition.update({ a, oldParams, b, newParams }, ctx.stateCtx.globalContext), ctx.taskCtx);
-    }
-}
+        let cache = ctx.transformCache.get(ref);
+        if (!cache) {
+            cache = { };
+            ctx.transformCache.set(ref, cache);
+        }
+        return runTask(transformer.definition.update({ a, oldParams, b, newParams, cache }, ctx.stateCtx.globalContext), ctx.taskCtx);
+    }

+ 20 - 15
src/mol-state/transformer.ts

@@ -7,6 +7,7 @@
 import { Task } from 'mol-task';
 import { StateObject } from './object';
 import { Transform } from './transform';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export interface Transformer<A extends StateObject = StateObject, B extends StateObject = StateObject, P = unknown> {
     apply(params?: P, props?: Partial<Transform.Options>): Transform<A, B, P>,
@@ -19,18 +20,22 @@ export namespace Transformer {
     export type Id = string & { '@type': 'transformer-id' }
     export type Params<T extends Transformer<any, any, any>> = T extends Transformer<any, any, infer P> ? P : unknown;
     export type To<T extends Transformer<any, any, any>> = T extends Transformer<any, infer B, any> ? B : unknown;
-    export type ControlsFor<Props> = { [P in keyof Props]?: any }
+    export type ControlsFor<A extends StateObject, Props> = { [P in keyof Props]?: PD.Any }
 
     export interface ApplyParams<A extends StateObject = StateObject, P = unknown> {
         a: A,
-        params: P
+        params: P,
+        /** A cache object that is purged each time the corresponding StateObject is removed or recreated. */
+        cache: unknown
     }
 
     export interface UpdateParams<A extends StateObject = StateObject, B extends StateObject = StateObject, P = unknown> {
         a: A,
         b: B,
         oldParams: P,
-        newParams: P
+        newParams: P,
+        /** A cache object that is purged each time the corresponding StateObject is removed or recreated. */
+        cache: unknown
     }
 
     export enum UpdateResult { Unchanged, Updated, Recreate }
@@ -39,6 +44,7 @@ export namespace Transformer {
         readonly name: string,
         readonly from: { type: StateObject.Type }[],
         readonly to: { type: StateObject.Type }[],
+        readonly display?: { readonly name: string, readonly description?: string },
 
         /**
          * Apply the actual transformation. It must be pure (i.e. with no side effects).
@@ -53,17 +59,16 @@ export namespace Transformer {
          */
         update?(params: UpdateParams<A, B, P>, globalCtx: unknown): Task<UpdateResult> | UpdateResult,
 
-        /** Check the parameters and return a list of errors if the are not valid. */
-        defaultParams?(a: A, globalCtx: unknown): P,
-
-        /** Specify default control descriptors for the parameters */
-        defaultControls?(a: A, globalCtx: unknown): Transformer.ControlsFor<P>,
-
-        /** Check the parameters and return a list of errors if the are not valid. */
-        validateParams?(a: A, params: P, globalCtx: unknown): string[] | undefined,
-
-        /** Optional custom parameter equality. Use deep structural equal by default. */
-        areParamsEqual?(oldParams: P, newParams: P): boolean,
+        params?: {
+            /** Check the parameters and return a list of errors if the are not valid. */
+            default?(a: A, globalCtx: unknown): P,
+            /** Specify default control descriptors for the parameters */
+            controls?(a: A, globalCtx: unknown): ControlsFor<A, P>,
+            /** Check the parameters and return a list of errors if the are not valid. */
+            validate?(a: A, params: P, globalCtx: unknown): string[] | undefined,
+            /** Optional custom parameter equality. Use deep structural equal by default. */
+            areEqual?(oldParams: P, newParams: P): boolean
+        }
 
         /** Test if the transform can be applied to a given node */
         isApplicable?(a: A, globalCtx: unknown): boolean,
@@ -75,7 +80,7 @@ export namespace Transformer {
         customSerialization?: { toJSON(params: P, obj?: B): any, fromJSON(data: any): P }
     }
 
-    const registry = new Map<Id, Transformer>();
+    const registry = new Map<Id, Transformer<any, any>>();
 
     export function get(id: string): Transformer {
         const t = registry.get(id as Id);

+ 93 - 0
src/mol-util/param-definition.ts

@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Color as ColorData } from './color';
+
+export namespace ParamDefinition {
+    export interface Base<T> {
+        label: string
+        description: string
+        defaultValue: T
+    }
+
+    export interface GenericValue<T> extends Base<T> {
+        type: 'generic-value'
+    }
+    export function GenericValue<T>(label: string, description: string, defaultValue: T): GenericValue<T> {
+        return { type: 'generic-value', label, description, defaultValue }
+    }
+
+    export interface Select<T extends string> extends Base<T> {
+        type: 'select'
+        /** array of (value, label) tuples */
+        options: [T, string][]
+    }
+    export function Select<T extends string>(label: string, description: string, defaultValue: T, options: [T, string][]): Select<T> {
+        return { type: 'select', label, description, defaultValue, options }
+    }
+
+    export interface MultiSelect<E extends string, T = E[]> extends Base<T> {
+        type: 'multi-select'
+        /** array of (value, label) tuples */
+        options: [E, string][]
+    }
+    export function MultiSelect<E extends string, T = E[]>(label: string, description: string, defaultValue: T, options: [E, string][]): MultiSelect<E, T> {
+        return { type: 'multi-select', label, description, defaultValue, options }
+    }
+
+    export interface Boolean extends Base<boolean> {
+        type: 'boolean'
+    }
+    export function Boolean(label: string, description: string, defaultValue: boolean): Boolean {
+        return { type: 'boolean', label, description, defaultValue }
+    }
+
+    export interface Range extends Base<number> {
+        type: 'range'
+        min: number
+        max: number
+        /** if an `integer` parse value with parseInt, otherwise use parseFloat */
+        step: number
+    }
+    export function Range(label: string, description: string, defaultValue: number, min: number, max: number, step: number): Range {
+        return { type: 'range', label, description, defaultValue, min, max, step }
+    }
+
+    export interface Text extends Base<string> {
+        type: 'text'
+    }
+    export function Text(label: string, description: string, defaultValue: string = ''): Text {
+        return { type: 'text', label, description, defaultValue }
+    }
+
+    export interface Color extends Base<ColorData> {
+        type: 'color'
+    }
+    export function Color(label: string, description: string, defaultValue: ColorData): Color {
+        return { type: 'color', label, description, defaultValue }
+    }
+
+    export interface Numeric extends Base<number> {
+        type: 'number'
+        min: number
+        max: number
+        /** if an `integer` parse value with parseInt, otherwise use parseFloat */
+        step: number
+    }
+    export function Numeric(label: string, description: string, defaultValue: number, min: number, max: number, step: number): Numeric {
+        return { type: 'number', label, description, defaultValue, min, max, step }
+    }
+
+    export type Any = /* ValueParam<any> | */ Select<any> | MultiSelect<any> | Boolean | Range | Text | Color | Numeric
+    export type Params = { [k: string]: Any }
+
+    export function getDefaultValues<T extends Params>(params: T) {
+        const d: { [k: string]: any } = {}
+        Object.keys(params).forEach(k => d[k] = params[k].defaultValue)
+        return d as { [k in keyof T]: T[k]['defaultValue'] }
+    }
+}

+ 0 - 90
src/mol-util/parameter.ts

@@ -1,90 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import { Color } from './color';
-
-export interface BaseParam<T> {
-    label: string
-    description: string
-    defaultValue: T
-}
-
-export interface ValueParam<T> extends BaseParam<T> {
-    type: 'value'
-}
-export function ValueParam<T>(label: string, description: string, defaultValue: T): ValueParam<T> {
-    return { type: 'value', label, description, defaultValue }
-}
-
-export interface SelectParam<T extends string> extends BaseParam<T> {
-    type: 'select'
-    /** array of (value, label) tupels */
-    options: [T, string][]
-}
-export function SelectParam<T extends string>(label: string, description: string, defaultValue: T, options: [T, string][]): SelectParam<T> {
-    return { type: 'select', label, description, defaultValue, options }
-}
-
-export interface MultiSelectParam<E extends string, T = E[]> extends BaseParam<T> {
-    type: 'multi-select'
-    /** array of (value, label) tupels */
-    options: [E, string][]
-}
-export function MultiSelectParam<E extends string, T = E[]>(label: string, description: string, defaultValue: T, options: [E, string][]): MultiSelectParam<E, T> {
-    return { type: 'multi-select', label, description, defaultValue, options }
-}
-
-export interface BooleanParam extends BaseParam<boolean> {
-    type: 'boolean'
-}
-export function BooleanParam(label: string, description: string, defaultValue: boolean): BooleanParam {
-    return { type: 'boolean', label, description, defaultValue }
-}
-
-export interface RangeParam extends BaseParam<number> {
-    type: 'range'
-    min: number
-    max: number
-    /** if an `integer` parse value with parseInt, otherwise use parseFloat */
-    step: number
-}
-export function RangeParam(label: string, description: string, defaultValue: number, min: number, max: number, step: number): RangeParam {
-    return { type: 'range', label, description, defaultValue, min, max, step }
-}
-
-export interface TextParam extends BaseParam<string> {
-    type: 'text'
-}
-export function TextParam(label: string, description: string, defaultValue: string): TextParam {
-    return { type: 'text', label, description, defaultValue }
-}
-
-export interface ColorParam extends BaseParam<Color> {
-    type: 'color'
-}
-export function ColorParam(label: string, description: string, defaultValue: Color): ColorParam {
-    return { type: 'color', label, description, defaultValue }
-}
-
-export interface NumberParam extends BaseParam<number> {
-    type: 'number'
-    min: number
-    max: number
-    /** if an `integer` parse value with parseInt, otherwise use parseFloat */
-    step: number
-}
-export function NumberParam(label: string, description: string, defaultValue: number, min: number, max: number, step: number): NumberParam {
-    return { type: 'number', label, description, defaultValue, min, max, step }
-}
-
-export type Param = ValueParam<any> | SelectParam<any> | MultiSelectParam<any> | BooleanParam | RangeParam | TextParam | ColorParam | NumberParam
-export type Params = { [k: string]: Param }
-
-export function paramDefaultValues<T extends Params>(params: T) {
-    const d: { [k: string]: any } = {}
-    Object.keys(params).forEach(k => d[k] = params[k].defaultValue)
-    return d as { [k in keyof T]: T[k]['defaultValue'] }
-}

+ 39 - 0
src/mol-util/rx-event-helper.ts

@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Subject } from 'rxjs';
+
+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;
+    }
+}

+ 5 - 5
src/perf-tests/state.ts

@@ -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);
 }