Browse Source

added PD.merge, always use props from structure.root for custom properties

Alexander Rose 5 years ago
parent
commit
92b988a8d5

+ 1 - 2
src/mol-gl/renderer.ts

@@ -16,7 +16,6 @@ import { ValueCell } from '../mol-util';
 import { RenderableValues, GlobalUniformValues, BaseValues } from './renderable/schema';
 import { GraphicsRenderVariant } from './webgl/render-item';
 import { ParamDefinition as PD } from '../mol-util/param-definition';
-import { deepClone } from '../mol-util/object';
 
 export interface RendererStats {
     programCount: number
@@ -110,7 +109,7 @@ function getStyle(props: RendererProps['style']) {
 namespace Renderer {
     export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer {
         const { gl, state, stats } = ctx
-        const p = deepClone({ ...PD.getDefaultValues(RendererParams), ...props })
+        const p = PD.merge(RendererParams, PD.getDefaultValues(RendererParams), props)
         const style = getStyle(p.style)
 
         const viewport = Viewport()

+ 2 - 2
src/mol-model-props/common/custom-model-property.ts

@@ -54,7 +54,7 @@ namespace CustomModelProperty {
             attach: async (ctx: CustomProperty.Context, data: Model, props: Partial<PD.Values<Params>> = {}, addRef) => {
                 if (addRef) data.customProperties.reference(builder.descriptor, true);
                 const property = get(data)
-                const p = { ...property.props, ...props }
+                const p = PD.merge(builder.defaultParams, property.props, props)
                 if (property.data.value && PD.areEqual(builder.defaultParams, property.props, p)) return
                 const value = await builder.obtain(ctx, data, p)
                 data.customProperties.add(builder.descriptor);
@@ -64,7 +64,7 @@ namespace CustomModelProperty {
             get: (data: Model) => get(data)?.data,
             set: (data: Model, props: Partial<PD.Values<Params>> = {}) => {
                 const property = get(data)
-                const p = { ...property.props, ...props }
+                const p = PD.merge(builder.defaultParams, property.props, props)
                 if (!PD.areEqual(builder.defaultParams, property.props, p)) {
                     // this invalidates property.value
                     set(data, p, undefined)

+ 3 - 2
src/mol-model-props/common/custom-structure-property.ts

@@ -54,8 +54,9 @@ namespace CustomStructureProperty {
             attach: async (ctx: CustomProperty.Context, data: Structure, props: Partial<PD.Values<Params>> = {}, addRef) => {
                 if (addRef) data.customPropertyDescriptors.reference(builder.descriptor, true);
                 if (builder.type === 'root') data = data.root
+                const rootProps = get(data.root).props
                 const property = get(data)
-                const p = { ...property.props, ...props }
+                const p = PD.merge(builder.defaultParams, rootProps, props)
                 if (property.data.value && PD.areEqual(builder.defaultParams, property.props, p)) return
                 const value = await builder.obtain(ctx, data, p)
                 data.customPropertyDescriptors.add(builder.descriptor);
@@ -66,7 +67,7 @@ namespace CustomStructureProperty {
             set: (data: Structure, props: Partial<PD.Values<Params>> = {}, value?: Value) => {
                 if (builder.type === 'root') data = data.root
                 const property = get(data)
-                const p = { ...property.props, ...props }
+                const p = PD.merge(builder.defaultParams, property.props, props)
                 if (!PD.areEqual(builder.defaultParams, property.props, p)) {
                     // this invalidates property.value
                     set(data, p, value)

+ 3 - 3
src/mol-plugin-state/transforms/model.ts

@@ -737,12 +737,12 @@ const CustomStructureProperties = PluginStateTransform.BuiltIn({
     from: SO.Molecule.Structure,
     to: SO.Molecule.Structure,
     params: (a, ctx: PluginContext) => {
-        return ctx.customStructureProperties.getParams(a?.data)
+        return ctx.customStructureProperties.getParams(a?.data.root)
     }
 })({
     apply({ a, params }, ctx: PluginContext) {
         return Task.create('Custom Props', async taskCtx => {
-            await attachStructureProps(a.data, ctx, taskCtx, params);
+            await attachStructureProps(a.data.root, ctx, taskCtx, params);
             return new SO.Molecule.Structure(a.data, { label: a.label, description: a.description });
         });
     },
@@ -756,7 +756,7 @@ const CustomStructureProperties = PluginStateTransform.BuiltIn({
                 if (!property) continue;
                 a.data.customPropertyDescriptors.reference(property.descriptor, false);
             }
-            await attachStructureProps(a.data, ctx, taskCtx, newParams);
+            await attachStructureProps(a.data.root, ctx, taskCtx, newParams);
             return StateTransformer.UpdateResult.Updated;
         });
     }

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

@@ -397,6 +397,38 @@ export namespace ParamDefinition {
         return false;
     }
 
+    export function merge(params: Params, a: any, b: any): any {
+        if (a === undefined) return deepClone(b);
+        if (b === undefined) return deepClone(a);
+
+        const o = Object.create(null)
+        for (const k of Object.keys(params)) {
+            o[k] = mergeParam(params[k], a[k], b[k])
+        }
+        return o;
+    }
+
+    export function mergeParam(p: Any, a: any, b: any): any {
+        if (a === undefined) return deepClone(b);
+        if (b === undefined) return deepClone(a);
+
+        if (p.type === 'group') {
+            return merge(p.params, a, b);
+        } else if (p.type === 'mapped') {
+            const u = a as NamedParams, v = b as NamedParams;
+            if (u.name !== v.name) return deepClone(v);
+            const map = p.map(v.name);
+            return {
+                name: v.name,
+                params: mergeParam(map, u.params, v.params)
+            };
+        } else if (typeof a === 'object' || typeof b === 'object') {
+            return Object.assign({}, deepClone(a), deepClone(b));
+        } else {
+            return b
+        }
+    }
+
     /**
      * Map an object to a list of [K, string][] to be used as options, stringToWords for key used by default (or identity of null).
      *