Переглянути джерело

PluginStateAnimation.canApply

David Sehnal 5 роки тому
батько
коміт
46113bf3d4

+ 23 - 1
src/mol-plugin-state/animation/built-in.ts

@@ -23,6 +23,15 @@ export const AnimateModelIndex = PluginStateAnimation.create({
         }, { options: [['palindrome', 'Palindrome'], ['loop', 'Loop'], ['once', 'Once']] }),
         maxFPS: PD.Numeric(15, { min: 1, max: 30, step: 1 })
     }),
+    canApply(ctx) {
+        const state = ctx.state.data;
+        const models = state.select(StateSelection.Generators.ofTransformer(StateTransforms.Model.ModelFromTrajectory));
+        for (const m of models) {
+            const parent = StateSelection.findAncestorOfType(state.tree, state.cells, m.transform.ref, [PluginStateObject.Molecule.Trajectory]);
+            if (parent && parent.obj && parent.obj.data.length > 1) return { canApply: true };
+        }
+        return { canApply: false, reason: 'No trajectory to animate' };
+    },
     initialState: () => ({} as { palindromeDirections?: { [id: string]: -1 | 1 | undefined } }),
     async apply(animState, t, ctx) {
         // limit fps
@@ -48,6 +57,8 @@ export const AnimateModelIndex = PluginStateAnimation.create({
             const parent = StateSelection.findAncestorOfType(state.tree, state.cells, m.transform.ref, [PluginStateObject.Molecule.Trajectory]);
             if (!parent || !parent.obj) continue;
             const traj = parent.obj;
+            if (traj.data.length <= 1) continue;
+
             update.to(m).update(old => {
                 const len = traj.data.length;
                 if (len !== 1) {
@@ -79,7 +90,9 @@ export const AnimateModelIndex = PluginStateAnimation.create({
             });
         }
 
-        await PluginCommands.State.Update(ctx.plugin, { state, tree: update, options: { doNotLogTiming: true } });
+        if (!allSingles) {
+            await PluginCommands.State.Update(ctx.plugin, { state, tree: update, options: { doNotLogTiming: true } });
+        }
 
         if (allSingles || (params.mode.name === 'once' && isEnd)) return { kind: 'finished' };
         if (params.mode.name === 'palindrome') return { kind: 'next', state: { palindromeDirections } };
@@ -104,6 +117,12 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
             target: PD.Select(targets[0][0], targets)
         };
     },
+    canApply(plugin) {
+        const state = plugin.state.data;
+        const root = StateTransform.RootRef;
+        const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D, root));
+        return { canApply: reprs.length > 0 };
+    },
     initialState: () => ({ t: 0 }),
     setup(params, plugin) {
         const state = plugin.state.data;
@@ -231,6 +250,9 @@ export const AnimateStateInterpolation = PluginStateAnimation.create({
     params: () => ({
         transtionDurationInMs: PD.Numeric(2000, { min: 100, max: 30000, step: 10 })
     }),
+    canApply(plugin) {
+        return { canApply: plugin.managers.snapshot.state.entries.size > 1 };
+    },
     initialState: () => ({ }),
     async apply(animState, t, ctx) {
 

+ 2 - 0
src/mol-plugin-state/animation/model.ts

@@ -15,7 +15,9 @@ export { PluginStateAnimation };
 interface PluginStateAnimation<P = any, S = any> {
     name: string,
     readonly display: { readonly name: string, readonly description?: string },
+
     params(ctx: PluginContext): PD.For<P>,
+    canApply?(ctx: PluginContext): { canApply: true } | { canApply: false, reason?: string },
     initialState(params: P, ctx: PluginContext): S,
 
     // TODO: support state in setup/teardown?

+ 3 - 2
src/mol-plugin-ui/state/animation.tsx

@@ -37,14 +37,15 @@ export class AnimationControls extends PluginUIComponent<{ onStart?: () => void
         if (anim.isEmpty) return null;
 
         const isDisabled = anim.state.animationState === 'playing';
+        const canApply = anim.current.anim.canApply?.(this.plugin);
 
         return <>
             <ParameterControls params={anim.getParams()} values={anim.state.params} onChange={this.updateParams} isDisabled={isDisabled} />
             <ParameterControls params={anim.current.params} values={anim.current.paramValues} onChange={this.updateCurrentParams} isDisabled={isDisabled} />
 
             <div className='msp-flex-row'>
-                <Button icon={anim.state.animationState !== 'playing' ? void 0 : PlayArrow} onClick={this.startOrStop}>
-                    {anim.state.animationState === 'playing' ? 'Stop' : 'Start'}
+                <Button icon={anim.state.animationState !== 'playing' ? void 0 : PlayArrow} onClick={this.startOrStop} disabled={canApply !== void 0 && canApply.canApply === false}>
+                    {anim.state.animationState === 'playing' ? 'Stop' : canApply === void 0 || canApply.canApply ? 'Start' : canApply.reason || 'Start'}
                 </Button>
             </div>
         </>;