Browse Source

show number of selected elements and structures

Alexander Rose 5 years ago
parent
commit
0c79aa1709

+ 1 - 0
src/mol-data/int/ordered-set.ts

@@ -28,6 +28,7 @@ namespace OrderedSet {
     export const max: <T extends number = number>(set: OrderedSet<T>) => T = Base.max as any;
     export const start: <T extends number = number>(set: OrderedSet<T>) => T = Base.start as any;
     export const end: <T extends number = number>(set: OrderedSet<T>) => T = Base.end as any;
+    /** Number of elements in the OrderedSet */
     export const size: <T extends number = number>(set: OrderedSet<T>) => number = Base.size as any;
     export const hashCode: <T extends number = number>(set: OrderedSet<T>) => number = Base.hashCode as any;
 

+ 2 - 1
src/mol-plugin/context.ts

@@ -77,7 +77,8 @@ export class PluginContext {
             settingsUpdated: this.ev()
         },
         interactivity: {
-            propsUpdated: this.ev()
+            propsUpdated: this.ev(),
+            selectionUpdated: this.ev()
         }
     } as const
 

+ 14 - 0
src/mol-plugin/ui/structure/selection.tsx

@@ -13,6 +13,7 @@ import { QueryContext, StructureSelection, QueryFn, Queries as _Queries } from '
 import { compile } from '../../../mol-script/runtime/query/compiler';
 import { ButtonsType } from '../../../mol-util/input/input-observer';
 import { EmptyLoci } from '../../../mol-model/loci';
+import { formatStructureSelectionStats } from '../../util/structure-element-selection';
 
 const Queries = {
     all: () => compile<StructureSelection>(MS.struct.generator.all()),
@@ -25,6 +26,16 @@ const Queries = {
 export class StructureSelectionControls extends PluginUIComponent<{}, {}> {
     state = {}
 
+    componentDidMount() {
+        this.subscribe(this.plugin.events.interactivity.selectionUpdated, () => {
+            this.forceUpdate()
+        });
+    }
+
+    get stats() {
+        return formatStructureSelectionStats(this.plugin.helpers.structureSelection.stats)
+    }
+
     select = (query: QueryFn<StructureSelection>) => {
         const state = this.plugin.state.dataState
         const structures = state.select(StateSelection.Generators.rootsOfType(PluginStateObject.Molecule.Structure))
@@ -60,6 +71,9 @@ export class StructureSelectionControls extends PluginUIComponent<{}, {}> {
                 <button className='msp-btn msp-btn-block'>Current Selection</button>
             </div>
             <div>
+                <div className='msp-control-row msp-row-text'>
+                    <div>{this.stats}</div>
+                </div>
                 <div className='msp-btn-row-group'>
                     <button className='msp-btn msp-btn-block msp-form-control' onClick={() => this.select(Queries.all())}>All</button>
                     <button className='msp-btn msp-btn-block msp-form-control' onClick={() => this.clear()}>None</button>

+ 33 - 1
src/mol-plugin/util/structure-element-selection.ts

@@ -12,8 +12,19 @@ import { StateObject } from '../../mol-state';
 import { PluginContext } from '../context';
 import { PluginStateObject } from '../state/objects';
 
-export { StructureElementSelectionManager };
+export type StructureSelectionStats = { structureCount: number, elementCount: number }
+
+export function formatStructureSelectionStats(stats: StructureSelectionStats) {
+    if (stats.structureCount === 0 || stats.elementCount === 0) {
+        return 'Selected nothing'
+    } else if (stats.structureCount === 1) {
+        return `Selected ${stats.elementCount} elements`
+    }
+    return `Selected ${stats.elementCount} elements in ${stats.structureCount} structures`
+}
+
 
+export { StructureElementSelectionManager };
 class StructureElementSelectionManager {
     private entries = new Map<string, SelectionEntry>();
 
@@ -30,11 +41,29 @@ class StructureElementSelectionManager {
         return this.entries.get(ref)!;
     }
 
+    get stats() {
+        let structureCount = 0
+        let elementCount = 0
+
+        this.entries.forEach(v => {
+            const { elements } = v.selection
+            if (elements.length) {
+                structureCount += 1
+                for (let i = 0, il = elements.length; i < il; ++i) {
+                    elementCount += OrderedSet.size(elements[i].indices)
+                }
+            }
+        })
+
+        return { structureCount, elementCount }
+    }
+
     add(loci: Loci): Loci {
         if (StructureElement.isLoci(loci)) {
             const entry = this.getEntry(loci.structure);
             if (entry) {
                 entry.selection = StructureElement.Loci.union(entry.selection, loci);
+                this.plugin.events.interactivity.selectionUpdated.next()
                 return entry.selection;
             }
         }
@@ -46,6 +75,7 @@ class StructureElementSelectionManager {
             const entry = this.getEntry(loci.structure);
             if (entry) {
                 entry.selection = StructureElement.Loci.subtract(entry.selection, loci);
+                this.plugin.events.interactivity.selectionUpdated.next()
                 return entry.selection.elements.length === 0 ? EmptyLoci : entry.selection;
             }
         }
@@ -57,6 +87,7 @@ class StructureElementSelectionManager {
             const entry = this.getEntry(loci.structure);
             if (entry) {
                 entry.selection = loci;
+                this.plugin.events.interactivity.selectionUpdated.next()
                 return entry.selection.elements.length === 0 ? EmptyLoci : entry.selection;
             }
         }
@@ -73,6 +104,7 @@ class StructureElementSelectionManager {
             if (s.selection.elements.length > 0) selections.push(s.selection);
             s.selection = StructureElement.Loci(s.selection.structure, []);
         }
+        this.plugin.events.interactivity.selectionUpdated.next()
         return selections;
     }