Bläddra i källkod

Focus/Selection UI tweaks

David Sehnal 5 år sedan
förälder
incheckning
b76c3613f9

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

@@ -230,9 +230,9 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
             if (!StructureElement.Loci.isEmpty(s.selection)) selections.push(s.selection);
             s.selection = StructureElement.Loci(s.selection.structure, []);
         }
-        this.referenceLoci = undefined
+        this.referenceLoci = undefined;
         this.state.stats = void 0;
-        this.events.changed.next()
+        this.events.changed.next();
         return selections;
     }
 

+ 1 - 4
src/mol-plugin-ui/skin/base/components/controls.scss

@@ -233,10 +233,7 @@
 }
 
 .msp-accent-offset {
-    // border-left-width: $control-spacing / 2;
-    // border-left-style: solid;
-    // border-left-color: color-increase-contrast($default-background, 10%);
-    // padding-left: 1px;
+    padding-left: 1px;
     margin-left: $control-spacing - 2;
     border-left: 2px solid $entity-color-Group;
 }

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

@@ -14,7 +14,7 @@
   text-transform: none;
 
   /* fix buttons height, for twitter bootstrap */
-  line-height: 1em;
+  // line-height: 1em;
 
   /* Animation center compensation - margins should be symmetric */
   /* remove if not needed */
@@ -115,7 +115,7 @@
 .msp-icon-layout:before { content: "\e810"; }
 .msp-icon-menu:before { content: "\e811"; }
 .msp-icon-check:before { content: "\e812"; }
-.msp-icon-cancel:before { content: "\e813"; }
+.msp-icon-cancel:before { content: "\e813"; margin: 0; }
 .msp-icon-cancel-circled:before { content: "\e814"; }
 .msp-icon-cancel-squared:before { content: "\e815"; }
 .msp-icon-plus-circled:before { content: "\e817"; }

+ 29 - 5
src/mol-plugin-ui/structure/focus.tsx

@@ -6,13 +6,16 @@
 
 import * as React from 'react';
 import { PluginUIComponent } from '../base';
-import { ToggleButton } from '../controls/common';
+import { ToggleButton, IconButton } from '../controls/common';
 import { ActionMenu } from '../controls/action-menu';
 import { StructureElement, StructureProperties, Structure } from '../../mol-model/structure';
 import { OrderedSet, SortedArray } from '../../mol-data/int';
 import { UnitIndex } from '../../mol-model/structure/structure/element/element';
 import { FocusEntry } from '../../mol-plugin-state/manager/structure/focus';
 import { lociLabel } from '../../mol-theme/label';
+import { FocusLoci } from '../../mol-plugin/behavior/dynamic/representation';
+import { StateTransform } from '../../mol-state';
+import { Binding } from '../../mol-util/binding';
 
 interface StructureFocusControlsState {
     isBusy: boolean
@@ -146,6 +149,8 @@ export class StructureFocusControls extends PluginUIComponent<{}, StructureFocus
         if (current) this.plugin.managers.camera.focusLoci(current.loci);
     }
 
+    clear = () => this.plugin.managers.structure.focus.clear()
+
     highlightCurrent = () => {
         const { current } = this.plugin.managers.structure.focus
         if (current) this.plugin.managers.interactivity.lociHighlights.highlightOnly({ loci: current.loci }, false);
@@ -155,16 +160,35 @@ export class StructureFocusControls extends PluginUIComponent<{}, StructureFocus
         this.plugin.managers.interactivity.lociHighlights.clearHighlights()
     }
 
+    getToggleBindingLabel() {
+        const t = this.plugin.state.behaviors.transforms.get(FocusLoci.id) as StateTransform<typeof FocusLoci>;
+        if (!t) return '';
+        const binding = t.params?.bindings.clickFocus;
+        if (!binding || Binding.isEmpty(binding)) return '';
+        return Binding.formatTriggers(binding);
+    }
+
     render() {
-        const { current } = this.plugin.managers.structure.focus
-        const label = current?.label || 'Nothing Focused'
+        const { current } = this.plugin.managers.structure.focus;
+        const label = current?.label || 'Nothing Focused';
+
+        let title = 'Click to Center Camera';
+        if (!current) {
+            title = 'Select focus using the menu';
+            const binding = this.getToggleBindingLabel();
+            if (binding) {
+                title += `\nor use '${binding}' on element`;
+            }
+        }
 
         return <>
             <div className='msp-control-row msp-select-row'>
-                <button className='msp-btn msp-btn-block msp-no-overflow' onClick={this.focus} title='Click to Center Focused' onMouseEnter={this.highlightCurrent} onMouseLeave={this.clearHighlights} disabled={this.isDisabled || !current}>
+                <button className='msp-btn msp-btn-block msp-no-overflow' onClick={this.focus} title={title} onMouseEnter={this.highlightCurrent} onMouseLeave={this.clearHighlights} disabled={this.isDisabled || !current}
+                    style={{ textAlignLast: current ? 'left' : void 0 }}>
                     {label}
                 </button>
-                <ToggleButton icon='target' title='Focus Target' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px' }} />
+                {current && <IconButton onClick={this.clear} icon='cancel' title='Clear' customClass='msp-form-control' style={{ flex: '0 0 32px' }} disabled={this.isDisabled} />}
+                <ToggleButton icon='book-open' title='Select Target' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px' }} />
             </div>
             {this.state.showAction && <ActionMenu items={this.actionItems} onSelect={this.selectAction} />}
         </>;

+ 7 - 3
src/mol-plugin-ui/structure/selection.tsx

@@ -16,7 +16,7 @@ import { ParamDefinition } from '../../mol-util/param-definition';
 import { stripTags } from '../../mol-util/string';
 import { CollapsableControls, CollapsableState, PurePluginUIComponent } from '../base';
 import { ActionMenu } from '../controls/action-menu';
-import { ControlGroup, ToggleButton } from '../controls/common';
+import { ControlGroup, ToggleButton, IconButton } from '../controls/common';
 import { Icon } from '../controls/icons';
 import { ParameterControls } from '../controls/parameters';
 import { StructureMeasurementsControls } from './measurements';
@@ -74,6 +74,8 @@ export class StructureSelectionControls<P, S extends StructureSelectionControlsS
         }
     }
 
+    clear = () => this.plugin.managers.interactivity.lociSelects.deselectAll();
+
     focus = () => {
         if (this.plugin.managers.structure.selection.stats.elementCount === 0) return;
         const principalAxes = this.plugin.managers.structure.selection.getPrincipalAxes();
@@ -166,10 +168,12 @@ export class StructureSelectionControls<P, S extends StructureSelectionControlsS
         return <>
             <ParameterControls params={StructureSelectionParams} values={this.values} onChangeValues={this.setProps} />
             {this.controls}
-            <div className='msp-control-row msp-row-text' style={{ margin: '6px 0' }}>
-                <button className='msp-btn msp-btn-block msp-no-overflow' onClick={this.focus} title='Click to Focus Selection' disabled={empty}>
+            <div className='msp-control-row msp-select-row' style={{ margin: '6px 0' }}>
+                <button className='msp-btn msp-btn-block msp-no-overflow' onClick={this.focus} title='Click to Focus Selection' disabled={empty}
+                    style={{ textAlignLast: !empty ? 'left' : void 0 }}>
                     {this.stats}
                 </button>
+                {!empty && <IconButton onClick={this.clear} icon='cancel' title='Clear' customClass='msp-form-control' style={{ flex: '0 0 32px' }} />}
             </div>
             <StructureMeasurementsControls />
         </>

+ 2 - 2
src/mol-plugin-ui/viewport.tsx

@@ -98,12 +98,12 @@ export class ViewportControls extends PluginUIComponent<ViewportControlsProps, V
                 </div>
             </div>
             {this.state.isScreenshotExpanded && <div className='msp-viewport-controls-panel'>
-                <ControlGroup header='Screenshot' initialExpanded={true} hideExpander={true} hideOffset={true} onHeaderClick={this.toggleScreenshotExpanded} topRightIcon='off'>
+                <ControlGroup header='Screenshot' initialExpanded={true} hideExpander={true} hideOffset={true} onHeaderClick={this.toggleScreenshotExpanded} topRightIcon='off' noTopMargin>
                     <DownloadScreenshotControls close={this.toggleScreenshotExpanded} />
                 </ControlGroup>
             </div>}
             {this.state.isSettingsExpanded && <div className='msp-viewport-controls-panel'>
-                <ControlGroup header='Settings / Controls Info' initialExpanded={true} hideExpander={true} hideOffset={true} onHeaderClick={this.toggleSettingsExpanded} topRightIcon='off'>
+                <ControlGroup header='Settings / Controls Info' initialExpanded={true} hideExpander={true} hideOffset={true} onHeaderClick={this.toggleSettingsExpanded} topRightIcon='off' noTopMargin>
                     <SimpleSettingsControl />
                 </ControlGroup>
             </div>}

+ 5 - 1
src/mol-util/binding.ts

@@ -34,9 +34,13 @@ namespace Binding {
         return binding.triggers.some(t => Trigger.match(t, buttons, modifiers))
     }
 
+    export function formatTriggers(binding: Binding) {
+        return binding.triggers.map(Trigger.format).join(' or ');
+    }
+
     export function format(binding: Binding, name = '') {
         const help = binding.description || stringToWords(name)
-        return interpolate(help, { triggers: '<i>' + binding.triggers.map(t => Trigger.format(t)).join(' or ') + '</i>' })
+        return interpolate(help, { triggers: '<i>' + formatTriggers(binding) + '</i>' })
     }
 
     export interface Trigger {