Procházet zdrojové kódy

wip source controls

David Sehnal před 5 roky
rodič
revize
75de544669

+ 21 - 19
src/mol-plugin-state/manager/structure/hierarchy.ts

@@ -8,6 +8,7 @@ import { PluginContext } from '../../../mol-plugin/context';
 import { StructureHierarchy, buildStructureHierarchy, ModelRef, StructureComponentRef, StructureRef, HierarchyRef, TrajectoryRef } from './hierarchy-state';
 import { PluginComponent } from '../../component';
 import { StateTransform } from '../../../mol-state';
+import { SetUtils } from '../../../mol-util/set';
 
 interface StructureHierarchyManagerState {
     hierarchy: StructureHierarchy,
@@ -109,31 +110,32 @@ export class StructureHierarchyManager extends PluginComponent<StructureHierarch
     }
 
     updateCurrent(refs: HierarchyRef[], action: 'add' | 'remove') {
-
-        console.log(refs, action);
-
         const hierarchy = this.state.hierarchy;
-        const map = new Map<StateTransform.Ref, HierarchyRef>();
-        const set = this.currentSeletionSet;
-        if (action === 'add') {
-            set.forEach(r => map.set(r, hierarchy.refs.get(r)!))
-            for (const r of refs) map.set(r.cell.transform.ref, r);
-        } else {
-            set.forEach(r => map.set(r, hierarchy.refs.get(r)!))
-            for (const r of refs) map.delete(r.cell.transform.ref);
+        const set = action === 'add'
+            ? SetUtils.union(this.currentSeletionSet, new Set(refs.map(r => r.cell.transform.ref)))
+            : SetUtils.difference(this.currentSeletionSet, new Set(refs.map(r => r.cell.transform.ref)));
+
+        const trajectories = [];
+        const models = [];
+        const structures = [];
+
+        for (const t of hierarchy.trajectories) {
+            if (set.has(t.cell.transform.ref)) trajectories.push(t);
+            for (const m of t.models) {
+                if (set.has(m.cell.transform.ref)) models.push(m);
+                for (const s of m.structures) {
+                    if (set.has(s.cell.transform.ref)) structures.push(s);
+                }
+            }
         }
-     
-        const trajectories = this.syncCurrentTrajectories(hierarchy, map);
-        const models = this.syncCurrentModels(hierarchy, map, trajectories);
-        const structures = this.syncCurrentStructures(map, models);
 
+        this._currentComponentGroups = void 0;
+        this._currentSelectionSet = void 0;
+     
         this.updateState({ current: { trajectories, models, structures }});
-
-        console.log(this.state.current);
-
         this.behaviors.current.next({ hierarchy, trajectories, models, structures });
     }
-
+    
     remove(refs: HierarchyRef[]) {
         if (refs.length === 0) return;
         const deletes = this.plugin.state.dataState.build();

+ 74 - 9
src/mol-plugin-ui/structure/source.tsx

@@ -8,14 +8,20 @@ import * as React from 'react';
 import { HierarchyRef, ModelRef, TrajectoryRef } from '../../mol-plugin-state/manager/structure/hierarchy-state';
 import { CollapsableControls, CollapsableState } from '../base';
 import { ActionMenu } from '../controls/action-menu';
+import { Icon } from '../controls/icons';
 
 interface StructureSourceControlState extends CollapsableState {
-    isBusy: boolean
+    isBusy: boolean,
+    show?: 'hierarchy' | 'actions'
 }
 
 export class StructureSourceControls extends CollapsableControls<{}, StructureSourceControlState> {
     protected defaultState(): StructureSourceControlState {
-        return { header: 'Source', isCollapsed: false, isBusy: false };
+        return { 
+            header: 'Source',
+            isCollapsed: false,
+            isBusy: false
+        };
     }
 
     componentDidMount() {
@@ -27,18 +33,21 @@ export class StructureSourceControls extends CollapsableControls<{}, StructureSo
 
     private item = (ref: HierarchyRef) => {
         const selected = this.plugin.managers.structure.hierarchy.currentSeletionSet;
-        return { label: ref.cell.obj?.label, selected: selected.has(ref.cell.transform.ref), value: ref } as ActionMenu.Item;
+        return { label: ref.cell.obj?.label, selected: selected.has(ref.cell.transform.ref), value: [ref] } as ActionMenu.Item;
     }
 
     getTrajectoryItems = (t: TrajectoryRef): ActionMenu.Items => {
         if (t.models.length === 0) return this.item(t);
-        // if (t.models.length === 1) return this.getModelItems(t.models[0]);
         return [t.cell.obj?.label!, ...t.models.map(this.getModelItems)];
     }
 
     private getModelItems = (m: ModelRef): ActionMenu.Items => {
         if (m.structures.length === 0) return this.item(m);
-        // if (m.structures.length === 1) return this.item(m.structures[0]);
+        if (m.structures.length === 1) {
+            const selected = this.plugin.managers.structure.hierarchy.currentSeletionSet;
+            const ref = m.structures[0];
+            return { label: `${m.cell.obj?.label} | ${ref.cell.obj?.label}`, selected: selected.has(ref.cell.transform.ref), value: [m, ref] } as ActionMenu.Item;
+        }
         return [m.cell.obj?.label!, ...m.structures.map(this.item)];
     }
 
@@ -46,15 +55,71 @@ export class StructureSourceControls extends CollapsableControls<{}, StructureSo
         return this.plugin.managers.structure.hierarchy.state.current.trajectories.map(this.getTrajectoryItems);
     }
 
-    onSelect: ActionMenu.OnSelectMany = (items) => {
+    get label() {
+        const { structures, models, trajectories } = this.plugin.managers.structure.hierarchy.state.current;
+
+        // TODO: better labels
+        
+        if (structures.length === 1) {
+            const s = structures[0];
+            if (s.model.trajectory.models.length === 1) return s.cell.obj?.data.label;
+            return `${s.model.cell.obj?.label} | ${s.cell.obj?.data.label}`;
+        }
+
+        if (structures.length > 1) {
+            return `${structures.length} structures`;
+        }
+
+        if (models.length > 0) {
+            return `${models.length} model(s)`;
+        }
+
+        if (trajectories.length > 0) {
+            return `${trajectories.length} trajectory(s)`;
+        }
+
+        return 'No structure loaded';
+    }
+
+    selectHierarchy: ActionMenu.OnSelectMany = (items) => {
         if (!items || items.length === 0) return 0;
-        this.plugin.managers.structure.hierarchy.updateCurrent(items.map(i => i.value as HierarchyRef), items[0].selected ? 'remove' : 'add')
+
+        const refs: HierarchyRef[] = [];
+        for (const i of items) {
+            for (const r of (i.value as HierarchyRef[])) refs.push(r);
+        }
+
+        this.plugin.managers.structure.hierarchy.updateCurrent(refs, items[0].selected ? 'remove' : 'add')
+    }
+
+    toggleHierarchy = () => this.setState({ show: this.state.show !== 'hierarchy' ? 'hierarchy' : void 0 });
+    toggleActions = () => this.setState({ show: this.state.show !== 'actions' ? 'actions' : void 0 });
+
+    get actions() {
+        const ret: ActionMenu.Items = [
+            ActionMenu.Item('Show all models', () => this.plugin.managers.structure.hierarchy.createAllModels(this.plugin.managers.structure.hierarchy.state.current.trajectories[0]))
+        ];
+        return ret;
+    }
+
+    selectAction: ActionMenu.OnSelect = item => {
+        if (!item) return;
+        this.setState({ show: void 0 });
+        (item?.value as any)();
     }
 
     renderControls() {
         return <>
-            <ActionMenu items={this.hierarchyItems} onSelect={this.onSelect} multiselect />
-            <button onClick={() => this.plugin.managers.structure.hierarchy.createAllModels(this.plugin.managers.structure.hierarchy.state.current.trajectories[0])}>All Models</button>
+            <div className='msp-flex-row' style={{ marginTop: '1px' }}>
+                <button className='msp-btn msp-form-control msp-flex-item' onClick={this.toggleHierarchy} style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
+                    {this.label}
+                </button>
+                <button className='msp-btn msp-form-control msp-flex-item' onClick={this.toggleActions} style={{ flex: '0 0 40px', }}>
+                    <Icon name='dot-3' />
+                </button>
+            </div>
+            {this.state.show === 'hierarchy' && <ActionMenu items={this.hierarchyItems} onSelect={this.selectHierarchy} multiselect />}
+            {this.state.show === 'actions' && <ActionMenu items={this.actions} onSelect={this.selectAction} />}
         </>;
     }
 }