diff --git a/src/mol-plugin/behavior/built-in/state.ts b/src/mol-plugin/behavior/built-in/state.ts index 195eb380cceb17c43ec978a7eaca05c010c93624..80853b667ae3fd3eb20da47a9961b31633da21d5 100644 --- a/src/mol-plugin/behavior/built-in/state.ts +++ b/src/mol-plugin/behavior/built-in/state.ts @@ -22,6 +22,7 @@ export function ApplyAction(ctx: PluginContext) { export function RemoveObject(ctx: PluginContext) { PluginCommands.State.RemoveObject.subscribe(ctx, ({ state, ref }) => { const tree = state.tree.build().delete(ref).getTree(); + console.log('tree', tree); return ctx.runTask(state.update(tree)); }); } diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts index 86c38c7fb36e95ec2063e44db12fdce2a6250172..7a210b8143ed0b4f698820eee62be485bf7fe360 100644 --- a/src/mol-plugin/context.ts +++ b/src/mol-plugin/context.ts @@ -101,7 +101,10 @@ export class PluginContext { _test_initDataActions() { this.state.data.actions .add(CreateStructureFromPDBe) - .add(StateTransforms.Data.Download.toAction()); + .add(StateTransforms.Data.Download) + .add(StateTransforms.Model.CreateStructureAssembly) + .add(StateTransforms.Model.CreateStructure) + .add(StateTransforms.Visuals.CreateStructureRepresentation); } applyTransform(state: State, a: Transform.Ref, transformer: Transformer, params: any) { diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 6d4633670302a7fba8eb4c9310d80f5422b0fd81..ca75fa2cbacd8fb64be0f2ce1558ef70e0c4b020 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -42,7 +42,6 @@ export const CreateStructureFromPDBe = StateAction.create<PluginStateObject.Root .apply(StateTransforms.Data.ParseCif) .apply(StateTransforms.Model.ParseTrajectoryFromMmCif, {}) .apply(StateTransforms.Model.CreateModelFromTrajectory, { modelIndex: 0 }) - .apply(StateTransforms.Model.CreateStructureFromModel, { }) .apply(StateTransforms.Model.CreateStructureAssembly) // .apply(StateTransforms.Model.CreateStructureSelection, { query, label: 'ALA residues' }) .apply(StateTransforms.Visuals.CreateStructureRepresentation) @@ -55,8 +54,7 @@ export const CreateStructureFromPDBe = StateAction.create<PluginStateObject.Root export const UpdateTrajectory = StateAction.create<PluginStateObject.Root, void, { action: 'advance' | 'reset', by?: number }>({ from: [], display: { - name: 'Entry from PDBe', - description: 'Download a structure from PDBe and create its default Assembly and visual' + name: 'Update Trajectory' }, params: { default: () => ({ action: 'reset', by: 1 }) diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 58af7db25378e42d4efcc6503b35af7653d4e837..93b5907132aa1f2a9675901878dca5a59ddf7479 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -69,9 +69,9 @@ const CreateModelFromTrajectory = PluginStateTransform.Create<SO.Molecule.Trajec } }); -export { CreateStructureFromModel } -namespace CreateStructureFromModel { export interface Params { transform3d?: Mat4 } } -const CreateStructureFromModel = PluginStateTransform.Create<SO.Molecule.Model, SO.Molecule.Structure, CreateStructureFromModel.Params>({ +export { CreateStructure } +namespace CreateStructure { export interface Params { transform3d?: Mat4 } } +const CreateStructure = PluginStateTransform.Create<SO.Molecule.Model, SO.Molecule.Structure, CreateStructure.Params>({ name: 'create-structure-from-model', display: { name: 'Structure from Model', @@ -93,32 +93,32 @@ function structureDesc(s: Structure) { export { CreateStructureAssembly } namespace CreateStructureAssembly { export interface Params { /** if not specified, use the 1st */ id?: string } } -const CreateStructureAssembly = PluginStateTransform.Create<SO.Molecule.Structure, SO.Molecule.Structure, CreateStructureAssembly.Params>({ +const CreateStructureAssembly = PluginStateTransform.Create<SO.Molecule.Model, SO.Molecule.Structure, CreateStructureAssembly.Params>({ name: 'create-structure-assembly', display: { name: 'Structure Assembly', description: 'Create a molecular structure assembly.' }, - from: [SO.Molecule.Structure], + from: [SO.Molecule.Model], to: [SO.Molecule.Structure], params: { default: () => ({ id: void 0 }), controls(a) { - const { model } = a.data; + 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; + const model = a.data; if (!id && model.symmetry.assemblies.length) id = model.symmetry.assemblies[0].id; - const asm = ModelSymmetry.findAssembly(a.data.model, id || ''); + const asm = ModelSymmetry.findAssembly(model, id || ''); if (!asm) throw new Error(`Assembly '${id}' not found`); - const s = await StructureSymmetry.buildAssembly(a.data, id!).runInContext(ctx); + const base = Structure.ofModel(model); + const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx); const label = { label: `Assembly ${id}`, description: structureDesc(s) }; return new SO.Molecule.Structure(s, label); }) diff --git a/src/mol-plugin/ui/controls.tsx b/src/mol-plugin/ui/controls.tsx index b1a813abe967939d1a6571a12ad8034840caa174..044a418d7ced3a674c1e9d220357aa55d0201a4a 100644 --- a/src/mol-plugin/ui/controls.tsx +++ b/src/mol-plugin/ui/controls.tsx @@ -100,11 +100,13 @@ export class _test_ApplyAction extends React.Component<{ plugin: PluginContext, const action = this.props.action; return <div key={`${this.props.nodeRef} ${this.props.action.id}`}> - <div style={{ borderBottom: '1px solid #999' }}><h3>{(action.definition.display && action.definition.display.name) || action.id}</h3></div> + <div style={{ borderBottom: '1px solid #999', marginBottom: '5px' }}><h3>{(action.definition.display && action.definition.display.name) || action.id}</h3></div> <ParametersComponent params={this.getParamDef()} values={this.state.params as any} onChange={(k, v) => { this.setState({ params: { ...this.state.params, [k]: v } }); }} /> - <button onClick={() => this.create()} style={{ width: '100%' }}>Create</button> + <div style={{ textAlign: 'right' }}> + <button onClick={() => this.create()}>Create</button> + </div> </div> } } diff --git a/src/mol-state/action/manager.ts b/src/mol-state/action/manager.ts index 373e68d0c95f6fe782e03d85edebb7feb551bd54..4e489df48ccf19d884881f97fd7152a730062276 100644 --- a/src/mol-state/action/manager.ts +++ b/src/mol-state/action/manager.ts @@ -6,6 +6,7 @@ import { StateAction } from 'mol-state/action'; import { StateObject } from '../object'; +import { Transformer } from 'mol-state/transformer'; export { StateActionManager } @@ -13,7 +14,9 @@ class StateActionManager { private actions: Map<StateAction['id'], StateAction> = new Map(); private fromTypeIndex = new Map<StateObject.Type, StateAction[]>(); - add(action: StateAction) { + add(actionOrTransformer: StateAction | Transformer) { + const action = Transformer.is(actionOrTransformer) ? actionOrTransformer.toAction() : actionOrTransformer; + if (this.actions.has(action.id)) return this; this.actions.set(action.id, action); diff --git a/src/mol-state/transformer.ts b/src/mol-state/transformer.ts index c38b03e9c0513a9a498e3042d41038b4f4587e53..b8aa03809bfce3ae0d0dc48647ffb3577c359256 100644 --- a/src/mol-state/transformer.ts +++ b/src/mol-state/transformer.ts @@ -25,6 +25,10 @@ export namespace Transformer { 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]?: PD.Any } + export function is(obj: any): obj is Transformer { + return !!obj && typeof (obj as Transformer).toAction === 'function' && typeof (obj as Transformer).apply === 'function'; + } + export interface ApplyParams<A extends StateObject = StateObject, P = unknown> { a: A, params: P, diff --git a/src/mol-state/tree/transient.ts b/src/mol-state/tree/transient.ts index 6fa34fe35f2b13b75b05585554860f433d44a23a..be807e77c5afccf39a5bbea5348a808ee488b71d 100644 --- a/src/mol-state/tree/transient.ts +++ b/src/mol-state/tree/transient.ts @@ -71,6 +71,10 @@ class TransientTree implements StateTree { const parent = Transform.RootRef; if (this.children.get(parent).size === 0) return; const set = OrderedSet<Transform.Ref>(); + if (!this.changedChildren) { + this.changedChildren = true; + this.children = this.children.asMutable(); + } this.children.set(parent, set); this.mutations.set(parent, set); }