Browse Source

mol-plugin-ui: improved selection controls

David Sehnal 5 years ago
parent
commit
7e5cdd8e06

+ 2 - 2
src/mol-plugin-ui/skin/base/components/misc.scss

@@ -427,7 +427,7 @@
     position: relative;
     // display: inline-block;
     margin: $control-spacing auto 0 auto;
-    width: 332px;
+    width: 400px;
     line-height: $row-height;
 
     &-actions {
@@ -444,7 +444,7 @@
     select.msp-form-control {
         padding: 0 5px;
         text-align: center;
-        background: none;
+        background: $msp-form-control-background;
         flex: 0 0 80px;
         text-overflow: ellipsis;
     }

+ 39 - 10
src/mol-plugin-ui/structure/selection.tsx

@@ -8,11 +8,13 @@
 import Close from '@material-ui/icons/Close';
 import Clear from '@material-ui/icons/Clear';
 import Brush from '@material-ui/icons/Brush';
+import Restore from '@material-ui/icons/Restore';
+import Remove from '@material-ui/icons/Remove';
 import * as React from 'react';
 import { StructureSelectionQueries, StructureSelectionQuery } from '../../mol-plugin-state/helpers/structure-selection-query';
 import { InteractivityManager } from '../../mol-plugin-state/manager/interactivity';
 import { StructureComponentManager } from '../../mol-plugin-state/manager/structure/component';
-import { StructureRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
+import { StructureRef, StructureComponentRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
 import { StructureSelectionModifier } from '../../mol-plugin-state/manager/structure/selection';
 import { memoizeLatest } from '../../mol-util/memoize';
 import { ParamDefinition } from '../../mol-util/param-definition';
@@ -31,15 +33,16 @@ const StructureSelectionParams = {
 interface StructureSelectionActionsControlsState {
     isEmpty: boolean,
     isBusy: boolean,
+    canUndo: boolean,
 
     action?: StructureSelectionModifier | 'color' | 'add-repr'
 }
 
 const ActionHeader = new Map<StructureSelectionModifier, string>([
-    ['add', 'Add/Union'],
-    ['remove', 'Remove/Subtract'],
-    ['intersect', 'Intersect'],
-    ['set', 'Set']
+    ['add', 'Add/Union Selection'],
+    ['remove', 'Remove/Subtract Selection'],
+    ['intersect', 'Intersect Selection'],
+    ['set', 'Set Selection']
 ] as const);
 
 export class StructureSelectionActionsControls extends PluginUIComponent<{}, StructureSelectionActionsControlsState> {
@@ -48,6 +51,7 @@ export class StructureSelectionActionsControls extends PluginUIComponent<{}, Str
 
         isEmpty: true,
         isBusy: false,
+        canUndo: false,
     }
 
     componentDidMount() {
@@ -65,6 +69,10 @@ export class StructureSelectionActionsControls extends PluginUIComponent<{}, Str
         this.subscribe(this.plugin.managers.interactivity.events.propsUpdated, () => {
             this.forceUpdate();
         });
+
+        this.subscribe(this.plugin.state.data.events.historyUpdated, ({ state }) => {
+            this.setState({ canUndo: state.canUndo });
+        });
     }
 
     get isDisabled() {
@@ -119,25 +127,46 @@ export class StructureSelectionActionsControls extends PluginUIComponent<{}, Str
 
     turnOff = () => this.plugin.selectionMode = false;
 
+    undo = () => {
+        const task = this.plugin.state.data.undo();
+        if (task) this.plugin.runTask(task);
+    }
+
+    subtract = () => {
+        const sel = this.plugin.managers.structure.hierarchy.getStructuresWithSelection();
+        const components: StructureComponentRef[] = [];
+        for (const s of sel) components.push(...s.components);
+        if (components.length === 0) return;
+        this.plugin.managers.structure.component.modifyByCurrentSelection(components, 'subtract');
+    }
+
     render() {
         const granularity = this.plugin.managers.interactivity.props.granularity;
+        const undoTitle = this.state.canUndo
+            ? `Undo ${this.plugin.state.data.latestUndoLabel}`
+            : 'Some mistakes of the past can be undone.';
+
         return <>
-            <div className='msp-flex-row'>
+            <div className='msp-flex-row' style={{ background: 'none' }}>
+                <PureSelectControl title={`Picking Level`} param={StructureSelectionParams.granularity} name='granularity' value={granularity} onChange={this.setGranuality} isDisabled={this.isDisabled} />
                 <ToggleButton icon={Union} title={ActionHeader.get('add')} toggle={this.toggleAdd} isSelected={this.state.action === 'add'} disabled={this.isDisabled} />
                 <ToggleButton icon={Subtract} title={ActionHeader.get('remove')} toggle={this.toggleRemove} isSelected={this.state.action === 'remove'} disabled={this.isDisabled} />
                 <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={Brush} title='Color' toggle={this.toggleColor} isSelected={this.state.action === 'color'} disabled={this.isDisabled} style={{ marginLeft: '10px' }}  />
                 <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} />
+                <IconButton svg={Remove} title='Subtract from Representations' onClick={this.subtract} disabled={this.isDisabled} />
+                <IconButton svg={Restore} onClick={this.undo} disabled={!this.state.canUndo || this.isDisabled} title={undoTitle} />
+
+                <IconButton svg={Close} title='Turn selection mode off' onClick={this.turnOff} style={{ marginLeft: '10px' }} />
             </div>
             {(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'>
                 <ControlGroup header='Color' initialExpanded={true} hideExpander={true} hideOffset={true} onHeaderClick={this.toggleColor} topRightIcon={Close}>
-                    <ApplyColorControls />
+                    <ApplyColorControls onApply={this.toggleColor} />
                 </ControlGroup>
             </div>}
             {this.state.action === 'add-repr' && <div className='msp-selection-viewport-controls-actions'>