/** * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose */ import { CustomPropertyDescriptor, Model } from '../../mol-model/structure'; import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ValueBox } from '../../mol-util'; import { CustomProperty } from './custom-property'; export { CustomModelProperty } namespace CustomModelProperty { export interface Provider extends CustomProperty.Provider { } export interface ProviderBuilder { readonly label: string readonly descriptor: CustomPropertyDescriptor readonly defaultParams: Params readonly getParams: (data: Model) => Params readonly isApplicable: (data: Model) => boolean readonly obtain: (ctx: CustomProperty.Context, data: Model, props: PD.Values) => Promise readonly type: 'static' | 'dynamic' } export function createProvider(builder: ProviderBuilder): CustomProperty.Provider { const descriptorName = builder.descriptor.name const propertyDataName = builder.type === 'static' ? '_staticPropertyData' : '_dynamicPropertyData' const get = (data: Model) => { if (!(descriptorName in data[propertyDataName])) { (data[propertyDataName][descriptorName] as CustomProperty.Container, Value>) = { props: { ...PD.getDefaultValues(builder.getParams(data)) }, data: ValueBox.create(undefined) } } return data[propertyDataName][descriptorName] as CustomProperty.Container, Value>; } const set = (data: Model, props: PD.Values, value: Value | undefined) => { const property = get(data); (data[propertyDataName][descriptorName] as CustomProperty.Container, Value>) = { props, data: ValueBox.withValue(property.data, value) }; } return { label: builder.label, descriptor: builder.descriptor, getParams: builder.getParams, defaultParams: builder.defaultParams, isApplicable: builder.isApplicable, attach: async (ctx: CustomProperty.Context, data: Model, props: Partial> = {}, addRef) => { if (addRef) data.customProperties.reference(builder.descriptor, true); const property = get(data) 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); set(data, p, value); }, ref: (data: Model, add: boolean) => data.customProperties.reference(builder.descriptor, add), get: (data: Model) => get(data)?.data, set: (data: Model, props: Partial> = {}) => { const property = get(data) 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) } } } } }