Browse Source

mol-plugin-ui: added "add representation" to selection mode

David Sehnal 5 years ago
parent
commit
6526090b8b

+ 10 - 3
src/mol-plugin-state/manager/structure/component.ts

@@ -400,11 +400,18 @@ namespace StructureComponentManager {
     };
     export type Options = PD.Values<typeof OptionsParams>
 
-    export function getAddParams(plugin: PluginContext) {
+    export function getAddParams(plugin: PluginContext, params?: { pivot?: StructureRef, allowNone: boolean, hideSelection?: boolean, defaultSelection?: StructureSelectionQuery }) {
         const { options } = plugin.query.structure.registry;
+        params = {
+            pivot: plugin.managers.structure.component.pivotStructure,
+            allowNone: true,
+            hideSelection: false,
+            defaultSelection: StructureSelectionQueries.current,
+            ...params
+        };
         return {
-            selection: PD.Select(options[1][0], options),
-            representation: getRepresentationTypesSelect(plugin, plugin.managers.structure.component.pivotStructure, [['none', '< Create Later >']]),
+            selection: PD.Select(options[1][0], options, { isHidden: params?.hideSelection }),
+            representation: getRepresentationTypesSelect(plugin, params?.pivot, params?.allowNone ? [['none', '< Create Later >']] : []),
             label: PD.Text('')
         };
     }

+ 11 - 0
src/mol-plugin-state/manager/structure/hierarchy.ts

@@ -68,6 +68,17 @@ export class StructureHierarchyManager extends PluginComponent {
         return this.state.selection;
     }
 
+    getStructuresWithSelection() {
+        const xs = this.plugin.managers.structure.hierarchy.current.structures;
+        const ret: StructureRef[] = [];
+        for (const s of xs) {
+            if (this.plugin.managers.structure.selection.structureHasSelection(s)) {
+                ret.push(s);
+            }
+        }
+        return ret;
+    }
+
     private syncCurrent<T extends HierarchyRef>(all: ReadonlyArray<T>, added: Set<StateTransform.Ref>): T[] {
         const current = this.seletionSet;
         const newCurrent: T[] = [];

+ 8 - 0
src/mol-plugin-state/manager/structure/selection.ts

@@ -21,6 +21,7 @@ import { StatefulPluginComponent } from '../../component';
 import { StructureSelectionQuery } from '../../helpers/structure-selection-query';
 import { PluginStateObject } from '../../objects';
 import { UUID } from '../../../mol-util';
+import { StructureRef } from './hierarchy-state';
 
 interface StructureSelectionManagerState {
     entries: Map<string, SelectionEntry>,
@@ -248,6 +249,13 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
         return entry.structure;
     }
 
+    structureHasSelection(structure: StructureRef) {
+        const s = structure.cell?.obj?.data;
+        if (!s) return false;
+        const entry = this.getEntry(s);
+        return !!entry && !StructureElement.Loci.isEmpty(entry.selection);
+    }
+
     has(loci: Loci) {
         if (StructureElement.Loci.is(loci)) {
             const entry = this.getEntry(loci.structure);

+ 20 - 13
src/mol-plugin-ui/structure/components.tsx

@@ -4,19 +4,19 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Add, BookmarksOutlined, Delete, DeleteOutlined, MoreHoriz, Tune, Restore, VisibilityOutlined, VisibilityOffOutlined } from '@material-ui/icons';
+import { Add, BookmarksOutlined, Delete, DeleteOutlined, MoreHoriz, Restore, Tune, VisibilityOffOutlined, VisibilityOutlined } from '@material-ui/icons';
 import * as React from 'react';
 import { getStructureThemeTypes } from '../../mol-plugin-state/helpers/structure-representation-params';
 import { StructureComponentManager } from '../../mol-plugin-state/manager/structure/component';
 import { StructureHierarchyManager } from '../../mol-plugin-state/manager/structure/hierarchy';
-import { StructureComponentRef, StructureRef, StructureRepresentationRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
+import { StructureComponentRef, StructureRepresentationRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
 import { PluginCommands } from '../../mol-plugin/commands';
 import { State } from '../../mol-state';
 import { ParamDefinition } from '../../mol-util/param-definition';
 import { CollapsableControls, CollapsableState, PurePluginUIComponent } from '../base';
 import { ActionMenu } from '../controls/action-menu';
 import { Button, ExpandGroup, IconButton, ToggleButton } from '../controls/common';
-import { Intersect, SetSvg, Subtract, Union, CubeSvg } from '../controls/icons';
+import { CubeSvg, Intersect, SetSvg, Subtract, Union } from '../controls/icons';
 import { ParameterControls } from '../controls/parameters';
 import { UpdateTransformControl } from '../state/update-transform';
 import { GenericEntryListControls } from './generic';
@@ -129,7 +129,7 @@ class ComponentEditorControls extends PurePluginUIComponent<{}, ComponentEditorC
             </div>
             {this.state.action === 'preset' && this.presetControls}
             {this.state.action === 'add' && <div className='msp-control-offset'>
-                <AddComponentControls structures={this.plugin.managers.structure.component.currentStructures} onApply={this.hideAction} />
+                <AddComponentControls onApply={this.hideAction} />
             </div>}
             {this.state.action === 'options' && <div className='msp-control-offset'><ComponentOptionsControls isDisabled={this.isDisabled} /></div>}
         </>;
@@ -142,30 +142,37 @@ interface AddComponentControlsState {
 }
 
 interface AddComponentControlsProps {
-    structures: ReadonlyArray<StructureRef>,
+    forSelection?: boolean,
     onApply: () => void
 }
 
-class AddComponentControls extends PurePluginUIComponent<AddComponentControlsProps, AddComponentControlsState> {
+export class AddComponentControls extends PurePluginUIComponent<AddComponentControlsProps, AddComponentControlsState> {
     createState(): AddComponentControlsState {
-        const params = StructureComponentManager.getAddParams(this.plugin);
+        const params = StructureComponentManager.getAddParams(this.plugin, this.props.forSelection
+            ? { allowNone: false, hideSelection: true }
+            : void 0);
         return { params, values: ParamDefinition.getDefaultValues(params) };
     }
 
     state = this.createState();
 
+    get selectedStructures() {
+        return this.plugin.managers.structure.component.currentStructures;
+    }
+
     apply = () => {
-        this.plugin.managers.structure.component.add(this.state.values, this.props.structures);
+        const target = this.props.forSelection ? this.plugin.managers.structure.hierarchy.getStructuresWithSelection() : this.selectedStructures;
         this.props.onApply();
+        this.plugin.managers.structure.component.add(this.state.values, target);
     }
 
     paramsChanged = (values: any) => this.setState({ values })
 
-    componentDidUpdate(prevProps: AddComponentControlsProps) {
-        if (this.props.structures !== prevProps.structures) {
-            this.setState(this.createState());
-        }
-    }
+    // componentDidUpdate(prevProps: AddComponentControlsProps) {
+    //     if (this.props.structures !== prevProps.structures) {
+    //         this.setState(this.createState());
+    //     }
+    // }
 
     render() {
         return <>

+ 12 - 64
src/mol-plugin-ui/structure/selection.tsx

@@ -19,77 +19,18 @@ import { PluginUIComponent, PurePluginUIComponent } from '../base';
 import { ActionMenu } from '../controls/action-menu';
 import { Button, ControlGroup, IconButton, ToggleButton } from '../controls/common';
 import { ParameterControls, ParamOnChange, PureSelectControl } from '../controls/parameters';
-import { Union, Subtract, Intersect, SetSvg as SetSvg } from '../controls/icons';
+import { Union, Subtract, Intersect, SetSvg as SetSvg, CubeSvg } from '../controls/icons';
+import { AddComponentControls } from './components';
 
 const StructureSelectionParams = {
     granularity: InteractivityManager.Params.granularity,
 };
 
-// interface StructureSelectionControlsState extends CollapsableState {
-//     isEmpty: boolean,
-//     isBusy: boolean,
-// }
-
-// export class StructureSelectionControls<P, S extends StructureSelectionControlsState> extends CollapsableControls<P, S> {
-//     componentDidMount() {
-//         this.subscribe(this.plugin.managers.structure.selection.events.changed, () => {
-//             this.forceUpdate()
-//         });
-
-//         this.subscribe(this.plugin.managers.interactivity.events.propsUpdated, () => {
-//             this.forceUpdate()
-//         });
-
-//         this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, c => {
-//             const isEmpty = c.structures.length === 0;
-//             if (this.state.isEmpty !== isEmpty) {
-//                 this.setState({ isEmpty });
-//             }
-//         });
-//     }
-
-//     get isDisabled() {
-//         return this.state.isBusy || this.state.isEmpty
-//     }
-
-//     setProps = (props: any) => {
-//         this.plugin.managers.interactivity.setProps(props);
-//     }
-
-//     get values () {
-//         return {
-//             granularity: this.plugin.managers.interactivity.props.granularity,
-//         }
-//     }
-
-//     defaultState() {
-//         return {
-//             isCollapsed: false,
-//             header: 'Selection',
-
-//             isEmpty: true,
-//             isBusy: false,
-
-//             brand: { name: 'Sel', accent: 'red' }
-//         } as S
-//     }
-
-//     renderControls() {
-//         return <>
-//             {/* <ParameterControls params={StructureSelectionParams} values={this.values} onChangeValues={this.setProps} />
-//             <StructureSelectionActionsControls /> */}
-//             <StructureSelectionStatsControls />
-//             {/* <div style={{ margin: '6px 0' }}>
-//             </div> */}
-//         </>
-//     }
-// }
-
 interface StructureSelectionActionsControlsState {
     isEmpty: boolean,
     isBusy: boolean,
 
-    action?: StructureSelectionModifier | 'color'
+    action?: StructureSelectionModifier | 'color' | 'add-repr'
 }
 
 const ActionHeader = new Map<StructureSelectionModifier, string>([
@@ -109,7 +50,7 @@ export class StructureSelectionActionsControls extends PluginUIComponent<{}, Str
 
     componentDidMount() {
         this.subscribe(this.plugin.managers.structure.hierarchy.behaviors.selection, c => {
-            const isEmpty = c.structures.length === 0;
+            const isEmpty = c.hierarchy.structures.length === 0;
             if (this.state.isEmpty !== isEmpty) {
                 this.setState({ isEmpty });
             }
@@ -168,6 +109,7 @@ export class StructureSelectionActionsControls extends PluginUIComponent<{}, Str
     toggleIntersect = this.showAction('intersect')
     toggleSet = this.showAction('set')
     toggleColor = this.showAction('color')
+    toggleAddRepr = this.showAction('add-repr')
 
     setGranuality: ParamOnChange = ({ value }) => {
         this.plugin.managers.interactivity.setProps({ granularity: value });
@@ -184,10 +126,11 @@ export class StructureSelectionActionsControls extends PluginUIComponent<{}, Str
                 <ToggleButton icon={Intersect} title={ActionHeader.get('intersect')} toggle={this.toggleIntersect} isSelected={this.state.action === 'intersect'} disabled={this.isDisabled} />
                 <ToggleButton icon={SetSvg} title={ActionHeader.get('set')} toggle={this.toggleSet} isSelected={this.state.action === 'set'} disabled={this.isDisabled} />
                 <ToggleButton icon={Brush} title='Color' toggle={this.toggleColor} isSelected={this.state.action === 'color'} disabled={this.isDisabled} />
+                <ToggleButton icon={CubeSvg} title='Create Representation' toggle={this.toggleAddRepr} isSelected={this.state.action === 'add-repr'} disabled={this.isDisabled} />
                 <PureSelectControl title={`Picking Level`} param={StructureSelectionParams.granularity} name='granularity' value={granularity} onChange={this.setGranuality} isDisabled={this.isDisabled} />
                 <IconButton svg={Close} title='Turn selection mode off' onClick={this.turnOff} />
             </div>
-            {(this.state.action && this.state.action !== 'color') && <div className='msp-selection-viewport-controls-actions'>
+            {(this.state.action && this.state.action !== 'color' && this.state.action !== 'add-repr') && <div className='msp-selection-viewport-controls-actions'>
                 <ActionMenu header={ActionHeader.get(this.state.action as StructureSelectionModifier)} items={this.queries} onSelect={this.selectQuery} noOffset />
             </div>}
             {this.state.action === 'color' && <div className='msp-selection-viewport-controls-actions'>
@@ -195,6 +138,11 @@ export class StructureSelectionActionsControls extends PluginUIComponent<{}, Str
                     <ApplyColorControls />
                 </ControlGroup>
             </div>}
+            {this.state.action === 'add-repr' && <div className='msp-selection-viewport-controls-actions'>
+                <ControlGroup header='Add Representation' initialExpanded={true} hideExpander={true} hideOffset={true} onHeaderClick={this.toggleAddRepr} topRightIcon={Close}>
+                    <AddComponentControls onApply={this.toggleAddRepr} forSelection />
+                </ControlGroup>
+            </div>}
         </>;
     }
 }