Explorar el Código

StructureSelectionManager improvements

- remap/clear referenceLoci onUpdate
- remap/clear history onUpdate
- removed unused prevHighlight
- support group-by-structure in modifyHistory
Alexander Rose hace 4 años
padre
commit
b1308de0b9

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

@@ -46,7 +46,7 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
         }
     }
 
-    private referenceLoci: Loci | undefined
+    private referenceLoci: StructureElement.Loci | undefined
 
     get entries() { return this.state.entries; }
     get additionsHistory() { return this.state.additionsHistory; }
@@ -144,26 +144,34 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
         return !StructureElement.Loci.areEqual(sel, entry.selection);
     }
 
-    modifyHistory(entry: StructureSelectionHistoryEntry, action: 'remove' | 'up' | 'down', modulus?: number) {
-        const idx = this.additionsHistory.indexOf(entry);
+    modifyHistory(entry: StructureSelectionHistoryEntry, action: 'remove' | 'up' | 'down', modulus?: number, groupByStructure = false) {
+        const history = this.additionsHistory;
+        const idx = history.indexOf(entry);
         if (idx < 0) return;
 
         let swapWith: number | undefined = void 0;
 
         switch (action) {
-            case 'remove': arrayRemoveAtInPlace(this.additionsHistory, idx); break;
+            case 'remove': arrayRemoveAtInPlace(history, idx); break;
             case 'up': swapWith = idx - 1; break;
             case 'down': swapWith = idx + 1; break;
         }
 
         if (swapWith !== void 0) {
-            const mod = modulus ? Math.min(this.additionsHistory.length, modulus) : this.additionsHistory.length;
-            swapWith = swapWith % mod;
-            if (swapWith < 0) swapWith += mod;
-
-            const t = this.additionsHistory[idx];
-            this.additionsHistory[idx] = this.additionsHistory[swapWith];
-            this.additionsHistory[swapWith] = t;
+            const mod = modulus ? Math.min(history.length, modulus) : history.length;
+            while (true) {
+                swapWith = swapWith % mod;
+                if (swapWith < 0) swapWith += mod;
+
+                if (!groupByStructure || history[idx].loci.structure === history[swapWith].loci.structure) {
+                    const t = history[idx];
+                    history[idx] = history[swapWith];
+                    history[swapWith] = t;
+                    break;
+                } else {
+                    swapWith += action === 'up' ? -1 : +1;
+                }
+            }
         }
 
         this.events.additionsHistoryUpdated.next();
@@ -205,11 +213,32 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
         }
     }
 
-    private onRemove(ref: string) {
+    private clearHistoryForStructure(structure: Structure) {
+        const historyEntryToRemove: StructureSelectionHistoryEntry[] = [];
+        for (const e of this.state.additionsHistory) {
+            if (e.loci.structure === structure) {
+                historyEntryToRemove.push(e);
+            }
+        }
+        for (const e of historyEntryToRemove) {
+            this.modifyHistory(e, 'remove');
+        }
+        if (historyEntryToRemove.length !== 0) {
+            this.events.additionsHistoryUpdated.next();
+        }
+    }
+
+    private onRemove(ref: string, obj: StateObject | undefined) {
         if (this.entries.has(ref)) {
             this.entries.delete(ref);
-            this.clearHistory();
-            this.referenceLoci = undefined;
+            if (obj?.data) {
+                this.clearHistoryForStructure(obj.data);
+            }
+            if (this.referenceLoci?.structure === obj?.data) {
+                this.referenceLoci = undefined;
+            }
+            this.state.stats = void 0;
+            this.events.changed.next();
         }
     }
 
@@ -219,18 +248,37 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
         if (this.entries.has(ref)) {
             if (!PluginStateObject.Molecule.Structure.is(oldObj) || oldObj === obj || oldObj.data === obj.data) return;
 
-            // TODO: property update the latest loci & reference loci
-            this.state.additionsHistory = [];
-            this.referenceLoci = undefined;
-
             // remap the old selection to be related to the new object if possible.
             if (Structure.areUnitAndIndicesEqual(oldObj.data, obj.data)) {
                 this.entries.set(ref, remapSelectionEntry(this.entries.get(ref)!, obj.data));
-                return;
-            }
 
-            // clear the selection
-            this.entries.set(ref, new SelectionEntry(StructureElement.Loci(obj.data, [])));
+                // remap referenceLoci & prevHighlight if needed and possible
+                if (this.referenceLoci?.structure === oldObj.data) {
+                    this.referenceLoci = StructureElement.Loci.remap(this.referenceLoci, obj.data);
+                }
+
+                // remap history locis if needed and possible
+                let changedHistory = false;
+                for (const e of this.state.additionsHistory) {
+                    if (e.loci.structure === oldObj.data) {
+                        e.loci = StructureElement.Loci.remap(e.loci, obj.data);
+                        changedHistory = true;
+                    }
+                }
+                if (changedHistory) this.events.additionsHistoryUpdated.next();
+            } else {
+                // clear the selection for ref
+                this.entries.set(ref, new SelectionEntry(StructureElement.Loci(obj.data, [])));
+
+                if (this.referenceLoci?.structure === oldObj.data) {
+                    this.referenceLoci = undefined;
+                }
+
+                this.clearHistoryForStructure(oldObj.data);
+
+                this.state.stats = void 0;
+                this.events.changed.next();
+            }
         }
     }
 
@@ -292,7 +340,7 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
         if (!xs) return;
 
         const ref = this.referenceLoci;
-        if (!ref || !StructureElement.Loci.is(ref) || ref.structure.root !== loci.structure.root) return;
+        if (!ref || !StructureElement.Loci.is(ref) || ref.structure !== loci.structure) return;
 
         let e: StructureElement.Loci['elements'][0] | undefined;
         for (const _e of ref.elements) {
@@ -305,26 +353,7 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
 
         if (xs.unit !== e.unit) return;
 
-        return getElementRange(loci.structure.root, e, xs);
-    }
-
-    private prevHighlight: StructureElement.Loci | undefined = void 0;
-
-    accumulateInteractiveHighlight(loci: Loci) {
-        if (StructureElement.Loci.is(loci)) {
-            if (this.prevHighlight) {
-                this.prevHighlight = StructureElement.Loci.union(this.prevHighlight, loci);
-            } else {
-                this.prevHighlight = loci;
-            }
-        }
-        return this.prevHighlight;
-    }
-
-    clearInteractiveHighlight() {
-        const ret = this.prevHighlight;
-        this.prevHighlight = void 0;
-        return ret || EmptyLoci;
+        return getElementRange(loci.structure, e, xs);
     }
 
     /** Count of all selected elements */
@@ -445,7 +474,7 @@ export class StructureSelectionManager extends StatefulPluginComponent<Structure
     constructor(private plugin: PluginContext) {
         super({ entries: new Map(), additionsHistory: [], stats: SelectionStats() });
 
-        plugin.state.data.events.object.removed.subscribe(e => this.onRemove(e.ref));
+        plugin.state.data.events.object.removed.subscribe(e => this.onRemove(e.ref, e.obj));
         plugin.state.data.events.object.updated.subscribe(e => this.onUpdate(e.ref, e.oldObj, e.obj));
     }
 }

+ 1 - 2
src/mol-plugin-ui/structure/superposition.tsx

@@ -182,8 +182,7 @@ export class SuperpositionControls extends PurePluginUIComponent<{}, Superpositi
     }
 
     moveHistory(e: StructureSelectionHistoryEntry, direction: 'up' | 'down') {
-        // TODO take structure grouping into account
-        this.plugin.managers.structure.selection.modifyHistory(e, direction);
+        this.plugin.managers.structure.selection.modifyHistory(e, direction, void 0, true);
     }
 
     focusLoci(loci: StructureElement.Loci) {