Browse Source

focus improvements- support shift to add in focus menu- keep section in focus menu open- always include loci label

Alexander Rose 5 years ago
parent
commit
440474d53b

+ 7 - 0
src/mol-plugin-state/manager/structure/focus.ts

@@ -82,6 +82,13 @@ export class StructureFocusManager extends StatefulPluginComponent<StructureFocu
         this.set({ loci, label: lociLabel(loci, { reverse: true, hidePrefix: true, htmlStyling: false }) })
     }
 
+    addFromLoci(anyLoci: Loci) {
+        const union = this.state.current && StructureElement.Loci.is(anyLoci)
+            ? StructureElement.Loci.union(anyLoci, this.state.current.loci)
+            : anyLoci
+        this.setFromLoci(union)
+    }
+
     clear() {
         if (this.state.current) {
             this.state.current = undefined

+ 9 - 7
src/mol-plugin-ui/structure/focus.tsx

@@ -80,7 +80,7 @@ function getFocusEntries(structure: Structure) {
     const entries: FocusEntry[] = []
     entityEntries.forEach((e, name) => {
         if (e.length === 1) {
-            entries.push({ label: name, loci: e[0].loci })
+            entries.push({ label: `${name}: ${e[0].label}`, loci: e[0].loci })
         } else {
             entries.push(...e)
         }
@@ -152,21 +152,23 @@ export class StructureFocusControls extends PluginUIComponent<{}, StructureFocus
         }
 
         const items: ActionMenu.Items[] = []
-        if (historyItems.length > 0) items.push(...historyItems)
         if (presetItems.length > 0) items.push(...presetItems)
+        if (historyItems.length > 0) items.push(...historyItems)
 
         return items
     }
 
-    selectAction: ActionMenu.OnSelect = item => {
+    selectAction: ActionMenu.OnSelect = (item, e) => {
         if (!item || !this.state.showAction) {
             this.setState({ showAction: false });
             return;
         }
-        this.setState({ showAction: false }, () => {
-            const f = item.value as FocusEntry
+        const f = item.value as FocusEntry
+        if (e?.shiftKey) {
+            this.plugin.managers.structure.focus.addFromLoci(f.loci)
+        } else {
             this.plugin.managers.structure.focus.set(f)
-        })
+        }
     }
 
     toggleAction = () => this.setState({ showAction: !this.state.showAction })
@@ -218,7 +220,7 @@ export class StructureFocusControls extends PluginUIComponent<{}, StructureFocus
                     {label}
                 </Button>
                 {current && <IconButton onClick={this.clear} icon='cancel' title='Clear' className='msp-form-control' flex disabled={this.isDisabled} />}
-                <ToggleButton icon='book-open' title='Select a focus target to center on an show its surroundings.' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px', padding: 0 }} />
+                <ToggleButton icon='book-open' title='Select a focus target to center on an show its surroundings. Hold shift to focus on multiple targets.' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px', padding: 0 }} />
             </div>
             {this.state.showAction && <ActionMenu items={this.actionItems} onSelect={this.selectAction} />}
         </>;

+ 11 - 28
src/mol-plugin/behavior/dynamic/representation.ts

@@ -226,46 +226,29 @@ export const FocusLoci = PluginBehavior.create<FocusLociProps>({
             this.subscribeObservable(this.ctx.behaviors.interaction.click, ({ current, button, modifiers }) => {
                 const { clickFocus, clickFocusAdd, clickFocusSelectMode, clickFocusAddSelectMode } = this.params.bindings;
 
-                const binding = this.ctx.selectionMode
-                    ? clickFocusSelectMode
-                    : clickFocus;
+                const binding = this.ctx.selectionMode ? clickFocusSelectMode : clickFocus;
+                const matched = Binding.match(binding, button, modifiers)
 
-                if (Binding.match(binding, button, modifiers)) {
+                const bindingAdd = this.ctx.selectionMode ? clickFocusAddSelectMode : clickFocusAdd;
+                const matchedAdd = Binding.match(bindingAdd, button, modifiers)
+
+                if (matched || matchedAdd) {
                     const loci = Loci.normalize(current.loci, 'residue')
                     const entry = this.ctx.managers.structure.focus.current
                     if (entry && Loci.areEqual(entry.loci, loci)) {
                         this.ctx.managers.structure.focus.clear()
                     } else {
-                        this.ctx.managers.structure.focus.setFromLoci(loci)
+                        if (matched) {
+                            this.ctx.managers.structure.focus.setFromLoci(loci)
+                        } else {
+                            this.ctx.managers.structure.focus.addFromLoci(loci)
+                        }
                         if (isEmptyLoci(loci)) {
                             this.ctx.managers.camera.reset()
                         }
                     }
                     return
                 }
-
-                const bindingAdd = this.ctx.selectionMode
-                    ? clickFocusAddSelectMode
-                    : clickFocusAdd;
-
-                if (Binding.match(bindingAdd, button, modifiers)) {
-                    const loci = Loci.normalize(current.loci, 'residue')
-                    if (StructureElement.Loci.is(loci)) {
-                        const entry = this.ctx.managers.structure.focus.current
-                        if (entry && Loci.areEqual(entry.loci, loci)) {
-                            this.ctx.managers.structure.focus.clear()
-                        } else {
-                            const union = entry
-                                ? StructureElement.Loci.union(entry.loci, loci)
-                                : loci
-                            this.ctx.managers.structure.focus.setFromLoci(union)
-                            if (isEmptyLoci(union)) {
-                                this.ctx.managers.camera.reset()
-                            }
-                        }
-                    }
-                    return
-                }
             });
         }
     },

+ 2 - 2
src/mol-theme/label.ts

@@ -61,8 +61,8 @@ function getResidueCount(unit: Unit.Atomic) {
     const { elements, model } = unit
     const { chainAtomSegments, residueAtomSegments } = model.atomicHierarchy
     const elementStart = chainAtomSegments.offsets[chainAtomSegments.index[elements[0]]]
-    const elementEnd = chainAtomSegments.offsets[chainAtomSegments.index[elements[elements.length - 1]] + 1]
-    return residueAtomSegments.index[elementEnd] - residueAtomSegments.index[elementStart]
+    const elementEnd = chainAtomSegments.offsets[chainAtomSegments.index[elements[elements.length - 1]] + 1] - 1
+    return residueAtomSegments.index[elementEnd] - residueAtomSegments.index[elementStart] + 1
 }
 
 export function structureElementStatsLabel(stats: StructureElement.Stats, options: Partial<LabelOptions> = {}): string {