Explorar o código

viewer abstraction refactoring

bioinsilico %!s(int64=2) %!d(string=hai) anos
pai
achega
788bb4dd3e
Modificáronse 42 ficheiros con 1536 adicións e 1133 borrados
  1. 16 16
      package-lock.json
  2. 2 2
      package.json
  3. 23 16
      src/RcsbFv3D/RcsbFv3DAbstract.tsx
  4. 67 49
      src/RcsbFv3D/RcsbFv3DAssembly.tsx
  5. 23 28
      src/RcsbFv3D/RcsbFv3DComponent.tsx
  6. 21 17
      src/RcsbFv3D/RcsbFv3DCustom.tsx
  7. 55 25
      src/RcsbFv3D/RcsbFv3DUniprot.tsx
  8. 10 10
      src/RcsbFvContextManager/RcsbFvContextManager.ts
  9. 1 1
      src/RcsbFvSelection/RcsbFvSelectorManager.ts
  10. 12 8
      src/RcsbFvSequence/RcsbFvSequence.tsx
  11. 7 7
      src/RcsbFvSequence/SequenceViews/AbstractView.tsx
  12. 23 23
      src/RcsbFvSequence/SequenceViews/CustomView/CustomView.tsx
  13. 1 1
      src/RcsbFvSequence/SequenceViews/RcsbView/AssemblyModelSate.ts
  14. 14 4
      src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryImplementation/AssemblyCallbackManager.ts
  15. 96 0
      src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryImplementation/UniprotCallbackManager.ts
  16. 19 12
      src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryInterface.ts
  17. 0 61
      src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerImplementation/UniprotCallbackManager.ts
  18. 0 42
      src/RcsbFvSequence/SequenceViews/RcsbView/PfvFactoryImplementation/UniprotPfvFactory.ts
  19. 30 18
      src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/AssemblyPfvManagerFactory.tsx
  20. 7 2
      src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/ChainDisplay.tsx
  21. 53 0
      src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/UniprotPfvFactory.ts
  22. 16 14
      src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryInterface.ts
  23. 22 18
      src/RcsbFvSequence/SequenceViews/RcsbView/RcsbView.tsx
  24. 1 1
      src/RcsbFvSequence/SequenceViews/SequenceViewInterface.ts
  25. 14 11
      src/RcsbFvStructure/RcsbFvStructure.tsx
  26. 0 67
      src/RcsbFvStructure/SaguaroPluginInterface.ts
  27. 0 9
      src/RcsbFvStructure/StructurePlugins/AbstractPlugin.ts
  28. 0 613
      src/RcsbFvStructure/StructurePlugins/MolstarPlugin.ts
  29. 82 0
      src/RcsbFvStructure/StructureViewerInterface.ts
  30. 335 0
      src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarActionManager.ts
  31. 189 0
      src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarCallbackManager.ts
  32. 46 0
      src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarManagerFactory.ts
  33. 157 0
      src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarModelMapManager.ts
  34. 1 1
      src/RcsbFvStructure/StructureViewers/MolstarViewer/StructureRepresentation.ts
  35. 132 0
      src/RcsbFvStructure/StructureViewers/StructureViewer.ts
  36. 4 0
      src/Utils/DataContainer.ts
  37. 9 9
      src/examples/css-config/index.tsx
  38. 11 11
      src/examples/external-mapping/FeatureViewerConfig.ts
  39. 3 3
      src/examples/external-mapping/index.tsx
  40. 15 15
      src/examples/multiple-chain/index.tsx
  41. 10 10
      src/examples/single-chain/index.tsx
  42. 9 9
      src/examples/structural-alignment/index.tsx

+ 16 - 16
package-lock.json

@@ -11,8 +11,8 @@
       "dependencies": {
         "@rcsb/rcsb-api-tools": "^4.1.0-models.1",
         "@rcsb/rcsb-molstar": "^2.5.5",
-        "@rcsb/rcsb-saguaro": "^2.1.6",
-        "@rcsb/rcsb-saguaro-app": "^4.4.0-models.32",
+        "@rcsb/rcsb-saguaro": "^2.1.7",
+        "@rcsb/rcsb-saguaro-app": "^4.4.0-models.33",
         "molstar": "^3.13.0"
       },
       "devDependencies": {
@@ -2499,9 +2499,9 @@
       }
     },
     "node_modules/@rcsb/rcsb-saguaro": {
-      "version": "2.1.6",
-      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro/-/rcsb-saguaro-2.1.6.tgz",
-      "integrity": "sha512-35KPxAY1tOrZTd/8EDESlUfcJGeAER05OzzkHh9ihgjHqrkXdZAL+ubY42OXtkIVVd4E7urbedmFhwTAzcTXnA==",
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro/-/rcsb-saguaro-2.1.7.tgz",
+      "integrity": "sha512-O6hKDJ7xsWYCJeZURazeF/XOYIyqPohVvN7QTz5IjJgPcXfL162Cx1y05bNhcyLThOmDSSAZgWFfKhpfBYfNTA==",
       "dependencies": {
         "@d3fc/d3fc-sample": "^5.0.1",
         "@popperjs/core": "^2.11.5",
@@ -2515,12 +2515,12 @@
       }
     },
     "node_modules/@rcsb/rcsb-saguaro-app": {
-      "version": "4.4.0-models.32",
-      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro-app/-/rcsb-saguaro-app-4.4.0-models.32.tgz",
-      "integrity": "sha512-TmMkbVYQG3+oh/to6j8Fnk7ZFdQDGiAqka4zbls7uqollGXCBwfUx6+uh7YwNFH+1cZ/pxo+P7KZS87mRaDODA==",
+      "version": "4.4.0-models.33",
+      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro-app/-/rcsb-saguaro-app-4.4.0-models.33.tgz",
+      "integrity": "sha512-CNy8cOmWSQ8khrss7bsmykCIfPS6xzpdMpSdEt5GRXCB3+9hp7VhRUCZpWea6oUyRZ8ycKTMP+SrWCEldgObTQ==",
       "dependencies": {
         "@rcsb/rcsb-api-tools": "^4.1.0-models.1",
-        "@rcsb/rcsb-saguaro": "^2.1.6",
+        "@rcsb/rcsb-saguaro": "^2.1.7",
         "react-select": "^5.4.0",
         "rxjs": "^7.5.5",
         "victory": "^36.5.0"
@@ -14226,9 +14226,9 @@
       }
     },
     "@rcsb/rcsb-saguaro": {
-      "version": "2.1.6",
-      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro/-/rcsb-saguaro-2.1.6.tgz",
-      "integrity": "sha512-35KPxAY1tOrZTd/8EDESlUfcJGeAER05OzzkHh9ihgjHqrkXdZAL+ubY42OXtkIVVd4E7urbedmFhwTAzcTXnA==",
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro/-/rcsb-saguaro-2.1.7.tgz",
+      "integrity": "sha512-O6hKDJ7xsWYCJeZURazeF/XOYIyqPohVvN7QTz5IjJgPcXfL162Cx1y05bNhcyLThOmDSSAZgWFfKhpfBYfNTA==",
       "requires": {
         "@d3fc/d3fc-sample": "^5.0.1",
         "@popperjs/core": "^2.11.5",
@@ -14242,12 +14242,12 @@
       }
     },
     "@rcsb/rcsb-saguaro-app": {
-      "version": "4.4.0-models.32",
-      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro-app/-/rcsb-saguaro-app-4.4.0-models.32.tgz",
-      "integrity": "sha512-TmMkbVYQG3+oh/to6j8Fnk7ZFdQDGiAqka4zbls7uqollGXCBwfUx6+uh7YwNFH+1cZ/pxo+P7KZS87mRaDODA==",
+      "version": "4.4.0-models.33",
+      "resolved": "https://registry.npmjs.org/@rcsb/rcsb-saguaro-app/-/rcsb-saguaro-app-4.4.0-models.33.tgz",
+      "integrity": "sha512-CNy8cOmWSQ8khrss7bsmykCIfPS6xzpdMpSdEt5GRXCB3+9hp7VhRUCZpWea6oUyRZ8ycKTMP+SrWCEldgObTQ==",
       "requires": {
         "@rcsb/rcsb-api-tools": "^4.1.0-models.1",
-        "@rcsb/rcsb-saguaro": "^2.1.6",
+        "@rcsb/rcsb-saguaro": "^2.1.7",
         "react-select": "^5.4.0",
         "rxjs": "^7.5.5",
         "victory": "^36.5.0"

+ 2 - 2
package.json

@@ -79,8 +79,8 @@
   "dependencies": {
     "@rcsb/rcsb-api-tools": "^4.1.0-models.1",
     "@rcsb/rcsb-molstar": "^2.5.5",
-    "@rcsb/rcsb-saguaro": "^2.1.6",
-    "@rcsb/rcsb-saguaro-app": "^4.4.0-models.32",
+    "@rcsb/rcsb-saguaro": "^2.1.7",
+    "@rcsb/rcsb-saguaro-app": "^4.4.0-models.33",
     "molstar": "^3.13.0"
   },
   "bugs": {

+ 23 - 16
src/RcsbFv3D/RcsbFv3DAbstract.tsx

@@ -1,39 +1,45 @@
 import * as React from "react";
 import {createRoot, Root} from "react-dom/client";
 import {RcsbFv3DComponent, RcsbFv3DCssConfig} from './RcsbFv3DComponent';
-import {RcsbFvStructureInterface} from "../RcsbFvStructure/RcsbFvStructure";
+import {RcsbFvStructureConfigInterface} from "../RcsbFvStructure/RcsbFvStructure";
 import {RcsbFvSequenceInterface} from "../RcsbFvSequence/RcsbFvSequence";
 import {EventType, RcsbFvContextManager} from "../RcsbFvContextManager/RcsbFvContextManager";
 import {PluginContext} from "molstar/lib/mol-plugin/context";
 import {CSSProperties} from "react";
+import {StructureViewerInterface} from "../RcsbFvStructure/StructureViewerInterface";
 
-export interface RcsbFv3DAbstractInterface {
+export interface RcsbFv3DAbstractInterface<T,R,S,U> {
     elementId: string;
     cssConfig?: RcsbFv3DCssConfig;
+    sequenceConfig: RcsbFvSequenceInterface<T,R,U>;
+    structureConfig: RcsbFvStructureConfigInterface<R,S>;
+    structureViewer: StructureViewerInterface<R,S>;
 }
 
-export abstract class RcsbFv3DAbstract<T extends {}> {
+export abstract class RcsbFv3DAbstract<T,R,S,U> {
 
-    protected elementId: string;
+    private readonly elementId: string;
     private reactRoot: Root;
-    protected structureConfig: RcsbFvStructureInterface;
-    protected sequenceConfig: RcsbFvSequenceInterface<T>;
-    protected ctxManager: RcsbFvContextManager<T> = new RcsbFvContextManager<T>();
+    private readonly structureConfig: RcsbFvStructureConfigInterface<R,S>;
+    private readonly structureViewer: StructureViewerInterface<R,S>;
+    private readonly sequenceConfig: RcsbFvSequenceInterface<T,R,U>;
+    private readonly ctxManager: RcsbFvContextManager<T,R,S,U> = new RcsbFvContextManager<T,R,S,U>();
     private fullScreenFlag: boolean = false;
     private overflowStyle: string = "";
-    protected cssConfig:{
+    private readonly cssConfig:{
         rootPanel?: CSSProperties,
         structurePanel?: CSSProperties,
         sequencePanel?: CSSProperties
     } | undefined;
 
-    protected constructor(config?: any) {
-        if(config != null)
-            this.init(config);
+    protected constructor(config: RcsbFv3DAbstractInterface<T,R,S,U>) {
+       this.elementId = config.elementId;
+       if(config.cssConfig) this.cssConfig = config.cssConfig;
+       this.sequenceConfig = config.sequenceConfig;
+       this.structureConfig = config.structureConfig;
+       this.structureViewer = config.structureViewer;
     }
 
-    protected abstract init(config: any): void;
-
     public render(): void{
         if(this.elementId == null )
             throw "HTML element not found";
@@ -45,14 +51,15 @@ export abstract class RcsbFv3DAbstract<T extends {}> {
         }
         this.reactRoot = createRoot(element);
         this.reactRoot.render(
-            <RcsbFv3DComponent
+            <RcsbFv3DComponent<T,R,S,U>
                 structurePanelConfig={this.structureConfig}
                 sequencePanelConfig={this.sequenceConfig}
-                id={"RcsbFv3D_innerDiv_"+Math.random().toString(36).substr(2)}
+                id={this.elementId}
                 ctxManager={this.ctxManager}
                 cssConfig={this.cssConfig}
                 unmount={this.unmount.bind(this)}
                 fullScreen={this.fullScreenFlag}
+                structureViewer={this.structureViewer}
             />);
     }
 
@@ -69,7 +76,7 @@ export abstract class RcsbFv3DAbstract<T extends {}> {
         }
     }
 
-    public updateConfig(config: {structurePanelConfig?: Partial<RcsbFvStructureInterface>; sequencePanelConfig?: Partial<RcsbFvSequenceInterface<T>>;}){
+    public updateConfig(config: {structurePanelConfig?: Partial<RcsbFvStructureConfigInterface<R,S>>; sequencePanelConfig?: Partial<RcsbFvSequenceInterface<T,R,U>>;}){
         this.ctxManager.next({eventType: EventType.UPDATE_CONFIG, eventData:config});
     }
 

+ 67 - 49
src/RcsbFv3D/RcsbFv3DAssembly.tsx

@@ -1,63 +1,81 @@
-import {LoadMethod} from "../RcsbFvStructure/StructurePlugins/MolstarPlugin";
-import {RcsbFv3DAbstract, RcsbFv3DAbstractInterface} from "./RcsbFv3DAbstract";
-import {RcsbRepresentationPreset} from "../RcsbFvStructure/StructurePlugins/StructureRepresentation";
+import {RcsbFv3DAbstract} from "./RcsbFv3DAbstract";
+import {RcsbRepresentationPreset} from "../RcsbFvStructure/StructureViewers/MolstarViewer/StructureRepresentation";
 import {RcsbFvAdditionalConfig} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
 import {InstanceSequenceConfig} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvInstanceBuilder";
-import {OperatorInfo} from "../RcsbFvStructure/SaguaroPluginInterface";
-import {AssemblyPfvFactory} from "../RcsbFvSequence/SequenceViews/RcsbView/PfvFactoryImplementation/AssemblyPfvFactory";
+import {OperatorInfo} from "../RcsbFvStructure/StructureViewerInterface";
+import {LoadMethod, LoadMolstarInterface} from "../RcsbFvStructure/StructureViewers/MolstarViewer/MolstarActionManager";
+import {ViewerProps} from "@rcsb/rcsb-molstar/build/src/viewer";
+import {StructureViewer} from "../RcsbFvStructure/StructureViewers/StructureViewer";
+import {MolstarManagerFactory} from "../RcsbFvStructure/StructureViewers/MolstarViewer/MolstarManagerFactory";
+import {RcsbFv3DCssConfig} from "./RcsbFv3DComponent";
 import uniqid from "uniqid";
-import {AssemblyCallbackManager} from "../RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerImplementation/AssemblyCallbackManager";
+import {RcsbFvStructure} from "../RcsbFvStructure/RcsbFvStructure";
+import {
+    AssemblyPfvManagerFactory
+} from "../RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/AssemblyPfvManagerFactory";
+import {
+    AssemblyCallbackManagerFactory
+} from "../RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryImplementation/AssemblyCallbackManager";
 
 type RcsbFv3DAssemblyAdditionalConfig = RcsbFvAdditionalConfig & {operatorChangeCallback?:(operatorInfo: OperatorInfo)=>void};
-export interface RcsbFv3DAssemblyInterface extends RcsbFv3DAbstractInterface {
-   config: {
-       entryId: string;
-       assemblyId?: string;
-       title?: string;
-       subtitle?: string;
-   };
-   additionalConfig?: RcsbFv3DAssemblyAdditionalConfig;
-   instanceSequenceConfig?: InstanceSequenceConfig;
-   useOperatorsFlag?:boolean;
-}
 
-export class RcsbFv3DAssembly extends RcsbFv3DAbstract<{instanceSequenceConfig?: InstanceSequenceConfig}>{
+export interface RcsbFv3DAssemblyInterface {
+    elementId?: string;
+    config: {
+        entryId: string;
+        assemblyId?: string;
+        title?: string;
+        subtitle?: string;
+    };
+    additionalConfig?: RcsbFv3DAssemblyAdditionalConfig;
+    instanceSequenceConfig?: InstanceSequenceConfig;
+    useOperatorsFlag?:boolean;
+    molstarProps?: Partial<ViewerProps>;
+    cssConfig?: RcsbFv3DCssConfig;
+}
 
-    constructor(config?: RcsbFv3DAssemblyInterface) {
-            super(config);
-    }
+export class RcsbFv3DAssembly extends RcsbFv3DAbstract<{instanceSequenceConfig?:InstanceSequenceConfig},LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>},undefined>{
 
-    init(assemblyData: RcsbFv3DAssemblyInterface) {
-        this.elementId = assemblyData.elementId ?? "RcsbFv3D_mainDiv_"+uniqid();
-        this.structureConfig = {
-            loadConfig: {
-                loadMethod: LoadMethod.loadPdbId,
-                loadParams: {
-                    pdbId:assemblyData.config.entryId,
-                    id:assemblyData.config.entryId,
-                    reprProvider: RcsbRepresentationPreset,
-                    params:{
-                        preset:{
-                            assemblyId: typeof (assemblyData.config.assemblyId) === "string" &&  assemblyData.config.assemblyId?.length > 0 ? assemblyData.config.assemblyId : '1'
+    constructor(params: RcsbFv3DAssemblyInterface) {
+        const elementId: string = params.elementId ?? uniqid("RcsbFv3D_");
+        super({
+            elementId: params.elementId ?? elementId,
+            sequenceConfig:{
+                type:"rcsb",
+                title: params.config.title,
+                subtitle: params.config.subtitle,
+                config:{
+                    rcsbId:params.config.entryId,
+                    additionalConfig:params.additionalConfig,
+                    useOperatorsFlag:params.useOperatorsFlag,
+                    pfvParams:{
+                        instanceSequenceConfig:params.instanceSequenceConfig
+                    },
+                    pfvManagerFactory: new AssemblyPfvManagerFactory(),
+                    callbackManagerFactory: new AssemblyCallbackManagerFactory<LoadMolstarInterface>()
+                }
+            },
+            structureViewer: new StructureViewer<LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>}>(new MolstarManagerFactory()),
+            structureConfig: {
+                loadConfig: {
+                    loadMethod: LoadMethod.loadPdbId,
+                    loadParams: {
+                        pdbId: params.config.entryId,
+                        id: params.config.entryId,
+                        reprProvider: RcsbRepresentationPreset,
+                        params: {
+                            preset: {
+                                assemblyId: typeof (params.config.assemblyId) === "string" && params.config.assemblyId?.length > 0 ? params.config.assemblyId : '1'
+                            }
                         }
                     }
+                },
+                pluginConfig: {
+                    viewerElement: RcsbFvStructure.componentId(elementId),
+                    viewerProps:params.molstarProps ?? {}
                 }
-            }
-        };
-        this.sequenceConfig = {
-            type:"rcsb",
-            config: {
-                rcsbId:assemblyData.config.entryId,
-                additionalConfig: assemblyData.additionalConfig,
-                pfvFactory:AssemblyPfvFactory,
-                pfvParams:{instanceSequenceConfig: assemblyData.instanceSequenceConfig},
-                useOperatorsFlag: assemblyData.useOperatorsFlag,
-                callbackManager: AssemblyCallbackManager
             },
-            title: assemblyData.config.title,
-            subtitle: assemblyData.config.subtitle
-        };
-        this.cssConfig = assemblyData.cssConfig;
+            cssConfig: params.cssConfig
+        });
     }
-
 }

+ 23 - 28
src/RcsbFv3D/RcsbFv3DComponent.tsx

@@ -1,12 +1,12 @@
 import * as React from "react";
 import classes from '../styles/RcsbFvStyle.module.scss';
 
-import {MolstarPlugin} from '../RcsbFvStructure/StructurePlugins/MolstarPlugin';
-import {SaguaroPluginInterface} from '../RcsbFvStructure/SaguaroPluginInterface';
+import {StructureViewer} from '../RcsbFvStructure/StructureViewers/StructureViewer';
+import {StructureViewerInterface} from '../RcsbFvStructure/StructureViewerInterface';
 
 import '../styles/RcsbFvMolstarStyle.module.scss';
 import {RcsbFvSequence, RcsbFvSequenceInterface} from "../RcsbFvSequence/RcsbFvSequence";
-import {RcsbFvStructure, RcsbFvStructureInterface} from "../RcsbFvStructure/RcsbFvStructure";
+import {RcsbFvStructure, RcsbFvStructureConfigInterface} from "../RcsbFvStructure/RcsbFvStructure";
 import {
     EventType,
     RcsbFvContextManager,
@@ -25,40 +25,35 @@ export interface RcsbFv3DCssConfig {
     sequencePanel?: CSSProperties;
 }
 
-export interface RcsbFv3DComponentInterface<T extends {}> {
-    structurePanelConfig:RcsbFvStructureInterface;
-    sequencePanelConfig: RcsbFvSequenceInterface<T>;
+export interface RcsbFv3DComponentInterface<T,R,S,U> {
+    structurePanelConfig:RcsbFvStructureConfigInterface<R,S>;
+    sequencePanelConfig: RcsbFvSequenceInterface<T,R,U>;
     id: string;
-    ctxManager: RcsbFvContextManager<T>;
+    ctxManager: RcsbFvContextManager<T,R,S,U>;
     cssConfig?:RcsbFv3DCssConfig;
     unmount:(flag:boolean)=>void;
     fullScreen: boolean;
+    structureViewer: StructureViewerInterface<R,S>;
 }
 
-interface RcsbFv3DComponentState<T extends {}> {
-    structurePanelConfig:RcsbFvStructureInterface;
-    sequencePanelConfig:RcsbFvSequenceInterface<T>;
+interface RcsbFv3DComponentState<T,R,S,U> {
+    structurePanelConfig:RcsbFvStructureConfigInterface<R,S>;
+    sequencePanelConfig:RcsbFvSequenceInterface<T,R,U>;
     pfvScreenFraction: number;
 }
 
-export class RcsbFv3DComponent<T extends {}> extends React.Component <RcsbFv3DComponentInterface<T>, RcsbFv3DComponentState<T>> {
+export class RcsbFv3DComponent<T,R,S,U> extends React.Component <RcsbFv3DComponentInterface<T,R,S,U>, RcsbFv3DComponentState<T,R,S,U>> {
 
-    private readonly plugin: SaguaroPluginInterface;
     private readonly selectorManager: RcsbFvSelectorManager = new RcsbFvSelectorManager();
     private subscription: Subscription;
     private readonly ROOT_DIV_ID: string = "rootPanelDiv";
 
-    readonly state: RcsbFv3DComponentState<T> = {
+    readonly state: RcsbFv3DComponentState<T,R,S,U> = {
         structurePanelConfig: this.props.structurePanelConfig,
         sequencePanelConfig: this.props.sequencePanelConfig,
         pfvScreenFraction: 0.55
     }
 
-    constructor(props: RcsbFv3DComponentInterface<T>) {
-        super(props);
-        this.plugin = new MolstarPlugin(this.selectorManager);
-    }
-
     render(): JSX.Element {
         return (
             <div className={this.props.fullScreen ? classes.fullScreen : classes.fullHeight} >
@@ -70,19 +65,19 @@ export class RcsbFv3DComponent<T extends {}> extends React.Component <RcsbFv3DCo
                     onMouseUp={ (e)=>{this.splitPanelMouseUp()} }
                 >
                     <div style={this.structureCssConfig(this.props.cssConfig?.structurePanel)} >
-                        <RcsbFvStructure
+                        <RcsbFvStructure<R,S>
                             {...this.state.structurePanelConfig}
                             componentId={this.props.id}
-                            plugin={this.plugin}
+                            plugin={this.props.structureViewer}
                             selectorManager={this.selectorManager}
                         />
                     </div>
                     <div style={this.sequenceCssConfig(this.props.cssConfig?.sequencePanel)}  >
-                        <RcsbFvSequence<T>
+                        <RcsbFvSequence<T,R,U>
                             type={this.state.sequencePanelConfig.type}
                             config={this.state.sequencePanelConfig.config}
                             componentId={this.props.id}
-                            plugin={this.plugin}
+                            plugin={this.props.structureViewer}
                             selectorManager={this.selectorManager}
                             title={this.state.sequencePanelConfig.title}
                             subtitle={this.state.sequencePanelConfig.subtitle}
@@ -140,11 +135,11 @@ export class RcsbFv3DComponent<T extends {}> extends React.Component <RcsbFv3DCo
     }
 
     private subscribe(): Subscription{
-        return this.props.ctxManager.subscribe((obj:RcsbFvContextManagerInterface<T>)=>{
+        return this.props.ctxManager.subscribe((obj:RcsbFvContextManagerInterface<T,R,S,U>)=>{
             if(obj.eventType == EventType.UPDATE_CONFIG){
-                this.updateConfig(obj.eventData as UpdateConfigInterface<T>)
+                this.updateConfig(obj.eventData as UpdateConfigInterface<T,R,S,U>)
             }else if(obj.eventType == EventType.PLUGIN_CALL){
-                this.plugin.pluginCall(obj.eventData as ((f:PluginContext)=>void));
+                this.props.structureViewer.pluginCall(obj.eventData as ((f:PluginContext)=>void));
             }
         });
     }
@@ -154,9 +149,9 @@ export class RcsbFv3DComponent<T extends {}> extends React.Component <RcsbFv3DCo
         this.subscription.unsubscribe();
     }
 
-    private updateConfig(config:UpdateConfigInterface<T>){
-        const structureConfig: Partial<RcsbFvStructureInterface> | undefined = config.structurePanelConfig;
-        const sequenceConfig: Partial<RcsbFvSequenceInterface<T>> | undefined = config.sequencePanelConfig;
+    private updateConfig(config:UpdateConfigInterface<T,R,S,U>){
+        const structureConfig: Partial<RcsbFvStructureConfigInterface<R,S>> | undefined = config.structurePanelConfig;
+        const sequenceConfig: Partial<RcsbFvSequenceInterface<T,R,U>> | undefined = config.sequencePanelConfig;
         if(structureConfig != null && sequenceConfig != null){
             this.setState({structurePanelConfig:{...this.state.structurePanelConfig, ...structureConfig}, sequencePanelConfig:{...this.state.sequencePanelConfig, ...sequenceConfig}});
         }else if(structureConfig != null){

+ 21 - 17
src/RcsbFv3D/RcsbFv3DCustom.tsx

@@ -1,32 +1,36 @@
 
-import {RcsbFvStructureInterface} from "../RcsbFvStructure/RcsbFvStructure";
+import {RcsbFvStructureConfigInterface} from "../RcsbFvStructure/RcsbFvStructure";
 import {CustomViewInterface} from "../RcsbFvSequence/SequenceViews/CustomView/CustomView";
 import {RcsbFv3DAbstract, RcsbFv3DAbstractInterface} from "./RcsbFv3DAbstract";
 import uniqid from "uniqid";
+import {InstanceSequenceConfig} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvInstanceBuilder";
+import {LoadMolstarInterface} from "../RcsbFvStructure/StructureViewers/MolstarViewer/MolstarActionManager";
+import {ViewerProps} from "@rcsb/rcsb-molstar/build/src/viewer";
+import {StructureViewer} from "../RcsbFvStructure/StructureViewers/StructureViewer";
+import {MolstarManagerFactory} from "../RcsbFvStructure/StructureViewers/MolstarViewer/MolstarManagerFactory";
 
-export interface RcsbFv3DCustomInterface extends RcsbFv3DAbstractInterface {
-    structurePanelConfig: RcsbFvStructureInterface;
+export interface RcsbFv3DCustomInterface extends RcsbFv3DAbstractInterface<{},LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>},undefined> {
+    structurePanelConfig: RcsbFvStructureConfigInterface<LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>}>;
     sequencePanelConfig: {
-        config: CustomViewInterface;
+        config: CustomViewInterface<LoadMolstarInterface>;
         title?: string;
         subtitle?: string;
     };
 }
 
-export class RcsbFv3DCustom extends RcsbFv3DAbstract<{}> {
+export class RcsbFv3DCustom extends RcsbFv3DAbstract<{},LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>},undefined> {
 
-    constructor(config?: RcsbFv3DCustomInterface) {
-        super(config);
-    }
-
-    init(config: RcsbFv3DCustomInterface) {
-        this.elementId = config.elementId ?? "RcsbFv3D_mainDiv_"+uniqid();
-        this.structureConfig = config.structurePanelConfig;
-        this.sequenceConfig = {
-            ...config.sequencePanelConfig,
-            type:"custom"
-        };
-        this.cssConfig = config.cssConfig;
+    constructor(config: RcsbFv3DCustomInterface) {
+        super({
+            elementId: config.elementId ?? "RcsbFv3D_mainDiv_" + uniqid(),
+            structureConfig: config.structurePanelConfig,
+            sequenceConfig:{
+                ...config.sequencePanelConfig,
+                type:"custom"
+            },
+            structureViewer:new StructureViewer<LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>}>( new MolstarManagerFactory() ),
+            cssConfig: config.cssConfig
+        });
     }
 
 }

+ 55 - 25
src/RcsbFv3D/RcsbFv3DUniprot.tsx

@@ -1,41 +1,71 @@
 import {RcsbFv3DAbstract, RcsbFv3DAbstractInterface} from "./RcsbFv3DAbstract";
-import {RcsbFvAdditionalConfig} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
+import {
+    RcsbFvAdditionalConfig,
+    RcsbFvModulePublicInterface
+} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
 import uniqid from "uniqid";
-import {UniprotPfvFactory} from "../RcsbFvSequence/SequenceViews/RcsbView/PfvFactoryImplementation/UniprotPfvFactory";
+
+import {LoadMethod, LoadMolstarInterface} from "../RcsbFvStructure/StructureViewers/MolstarViewer/MolstarActionManager";
+import {ViewerProps} from "@rcsb/rcsb-molstar/build/src/viewer";
+
+import {
+    UniprotSequenceOnchangeInterface
+} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvUniprotBuilder";
+import {StructureViewer} from "../RcsbFvStructure/StructureViewers/StructureViewer";
+import {MolstarManagerFactory} from "../RcsbFvStructure/StructureViewers/MolstarViewer/MolstarManagerFactory";
 import {
-    UniprotCallbackManager
-} from "../RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerImplementation/UniprotCallbackManager";
+    UniprotPfvManagerFactory
+} from "../RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/UniprotPfvFactory";
+import {
+    UniprotCallbackManagerFactory
+} from "../RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryImplementation/UniprotCallbackManager";
 
-export interface RcsbFv3DUniprotInterface extends RcsbFv3DAbstractInterface {
+export interface RcsbFv3DUniprotInterface extends RcsbFv3DAbstractInterface<{upAcc:string},LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>},{context:UniprotSequenceOnchangeInterface,module:RcsbFvModulePublicInterface}> {
     config: {
         upAcc: string;
         title?: string;
         subtitle?: string;
     };
     additionalConfig?:RcsbFvAdditionalConfig;
+    molstarProps?: Partial<ViewerProps>;
 }
 
-export class RcsbFv3DUniprot extends RcsbFv3DAbstract<{upAcc:string}> {
-    constructor(config?:RcsbFv3DUniprotInterface){
-        super(config);
-    }
-
-    protected init(upData: RcsbFv3DUniprotInterface): void {
-        this.elementId = upData.elementId ?? "RcsbFv3D_mainDiv_"+uniqid();
-        this.structureConfig = {};
-        this.sequenceConfig = {
-            type: "rcsb",
-            config:{
-                rcsbId: upData.config.upAcc,
-                additionalConfig: upData.additionalConfig,
-                pfvFactory:UniprotPfvFactory,
-                pfvParams:{
-                    upAcc:upData.config.upAcc
+export class RcsbFv3DUniprot extends RcsbFv3DAbstract<{upAcc:string},LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>},{context:UniprotSequenceOnchangeInterface,module:RcsbFvModulePublicInterface}> {
+    constructor(params:RcsbFv3DUniprotInterface){
+        super({
+            elementId:params.elementId ?? "RcsbFv3D_mainDiv_"+uniqid(),
+            structureConfig: {
+                loadConfig: {
+                    loadMethod: LoadMethod.loadPdbId,
+                    loadParams: []
                 },
-                callbackManager: UniprotCallbackManager,
-                buildPfvOnMount: true
-            }
-        }
+                pluginConfig: {
+                    viewerElement: params.elementId,
+                    viewerProps: params.molstarProps ?? {}
+                }
+            },
+            sequenceConfig:{
+                type: "rcsb",
+                config:{
+                    rcsbId: params.config.upAcc,
+                    additionalConfig: params.additionalConfig,
+                    pfvParams:{
+                        upAcc:params.config.upAcc
+                    },
+                    buildPfvOnMount: true,
+                    pfvManagerFactory: new UniprotPfvManagerFactory<LoadMolstarInterface>(),
+                    callbackManagerFactory: new UniprotCallbackManagerFactory<LoadMolstarInterface>({
+                        pluginLoadParamsCollector:(pdbId:string)=>({
+                            loadMethod: LoadMethod.loadPdbId,
+                            loadParams:{
+                                pdbId
+                            }
+                        })
+                    })
+                }
+            },
+            structureViewer: new StructureViewer<LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>}>( new MolstarManagerFactory() ),
+        });
     }
 
 }

+ 10 - 10
src/RcsbFvContextManager/RcsbFvContextManager.ts

@@ -1,12 +1,12 @@
 import {Subject, Subscription} from 'rxjs';
-import {RcsbFvStructureInterface} from "../RcsbFvStructure/RcsbFvStructure";
+import {RcsbFvStructureConfigInterface} from "../RcsbFvStructure/RcsbFvStructure";
 import {RcsbFvSequenceInterface} from "../RcsbFvSequence/RcsbFvSequence";
 import {PluginContext} from "molstar/lib/mol-plugin/context";
 
 /**Main Event Data Object Interface*/
-export interface RcsbFvContextManagerInterface<T extends {}> {
+export interface RcsbFvContextManagerInterface<T,R,S,U> {
     eventType: EventType;
-    eventData: string | UpdateConfigInterface<T> | ((plugin: PluginContext) => void);
+    eventData: string | UpdateConfigInterface<T,R,S,U> | ((plugin: PluginContext) => void);
 }
 
 /**Event types*/
@@ -15,24 +15,24 @@ export enum EventType {
     PLUGIN_CALL = "pluginCall"
 }
 
-export interface UpdateConfigInterface<T extends {}> {
-    structurePanelConfig?:Partial<RcsbFvStructureInterface>;
-    sequencePanelConfig?:Partial<RcsbFvSequenceInterface<T>>;
+export interface UpdateConfigInterface<T,R,S,U> {
+    structurePanelConfig?:Partial<RcsbFvStructureConfigInterface<R,S>>;
+    sequencePanelConfig?:Partial<RcsbFvSequenceInterface<T,R,U>>;
 }
 
 /**rxjs Event Handler Object. It allows objects to subscribe methods and then, get(send) events to(from) other objects*/
-export class RcsbFvContextManager<T extends {}> {
-    private readonly subject: Subject<RcsbFvContextManagerInterface<T>> = new Subject<RcsbFvContextManagerInterface<T>>();
+export class RcsbFvContextManager<T,R,S,U> {
+    private readonly subject: Subject<RcsbFvContextManagerInterface<T,R,S,U>> = new Subject<RcsbFvContextManagerInterface<T,R,S,U>>();
     /**Call other subscribed methods
      * @param obj Event Data Structure Interface
      * */
-    public next( obj: RcsbFvContextManagerInterface<T> ):void {
+    public next( obj: RcsbFvContextManagerInterface<T,R,S,U> ):void {
         this.subject.next(obj);
     }
     /**Subscribe loadMethod
      * @return Subscription
      * */
-    public subscribe(f:(x:RcsbFvContextManagerInterface<T>)=>void):Subscription {
+    public subscribe(f:(x:RcsbFvContextManagerInterface<T,R,S,U>)=>void):Subscription {
         return this.subject.asObservable().subscribe(f);
     }
     /**Unsubscribe all methods*/

+ 1 - 1
src/RcsbFvSelection/RcsbFvSelectorManager.ts

@@ -1,4 +1,4 @@
-import {SaguaroChain, SaguaroRange, SaguaroRegionList, SaguaroSet} from "../RcsbFvStructure/SaguaroPluginInterface";
+import {SaguaroChain, SaguaroRange, SaguaroRegionList, SaguaroSet} from "../RcsbFvStructure/StructureViewerInterface";
 
 export interface RegionSelectionInterface{
     begin:number;

+ 12 - 8
src/RcsbFvSequence/RcsbFvSequence.tsx

@@ -1,14 +1,17 @@
 import * as React from "react";
 import {CustomView, CustomViewInterface} from "./SequenceViews/CustomView/CustomView";
-import {SaguaroPluginInterface} from "../RcsbFvStructure/SaguaroPluginInterface";
+import {
+    ViewerActionManagerInterface,
+    ViewerCallbackManagerInterface
+} from "../RcsbFvStructure/StructureViewerInterface";
 import {PluginContext} from "molstar/lib/mol-plugin/context";
 import {RcsbFv, RcsbFvTrackDataElementInterface} from "@rcsb/rcsb-saguaro";
 import {RcsbFvSelectorManager} from "../RcsbFvSelection/RcsbFvSelectorManager";
 import {RcsbView, RcsbViewInterface} from "./SequenceViews/RcsbView/RcsbView";
 
-export interface RcsbFvSequenceInterface<T extends {}>{
+export interface RcsbFvSequenceInterface<T,R,U>{
     type: "custom" | "rcsb";
-    config: RcsbViewInterface<T> | CustomViewInterface;
+    config: RcsbViewInterface<T,R,U> | CustomViewInterface<R>;
     title?: string;
     subtitle?: string;
 }
@@ -18,12 +21,13 @@ interface CallbackConfig {
     sequenceCallback?: (rcsbFv: RcsbFv)=>void;
 }
 
-export class RcsbFvSequence<T extends {}> extends React.Component <RcsbFvSequenceInterface<T> & CallbackConfig & {unmount:(flag:boolean)=>void, plugin: SaguaroPluginInterface, selectorManager:RcsbFvSelectorManager, componentId:string}, RcsbFvSequenceInterface<T> > {
+type PluginType<R> = ViewerCallbackManagerInterface & ViewerActionManagerInterface<R>;
+export class RcsbFvSequence<T,R,U> extends React.Component <RcsbFvSequenceInterface<T,R,U> & CallbackConfig & {unmount:(flag:boolean)=>void, plugin: PluginType<R>, selectorManager:RcsbFvSelectorManager, componentId:string}, RcsbFvSequenceInterface<T,R,U> > {
 
     render() {
         if(this.props.type == "custom"){
-            const config: CustomViewInterface = this.props.config as CustomViewInterface;
-            return (<CustomView
+            const config: CustomViewInterface<R> = this.props.config as CustomViewInterface<R>;
+            return (<CustomView<R>
                 {...config}
                 componentId={this.props.componentId}
                 plugin={this.props.plugin}
@@ -33,8 +37,8 @@ export class RcsbFvSequence<T extends {}> extends React.Component <RcsbFvSequenc
                 unmount={this.props.unmount}
             />)
         }else if(this.props.type == "rcsb"){
-            const config: RcsbViewInterface<T> = this.props.config as RcsbViewInterface<T>;
-            return (<RcsbView<T>
+            const config: RcsbViewInterface<T,R,U> = this.props.config as unknown as RcsbViewInterface<T,R,U>;
+            return (<RcsbView<T,R,U>
                 {...config}
                 componentId={this.props.componentId}
                 plugin={this.props.plugin}

+ 7 - 7
src/RcsbFvSequence/SequenceViews/AbstractView.tsx

@@ -4,28 +4,28 @@ import {asyncScheduler, Subscription} from "rxjs";
 
 import {RcsbFvDOMConstants} from "../../RcsbFvConstants/RcsbFvConstants";
 import {
-    SaguaroPluginInterface,
-    SaguaroPluginModelMapType
-} from "../../RcsbFvStructure/SaguaroPluginInterface";
+    StructureViewerInterface,
+    SaguaroPluginModelMapType, ViewerCallbackManagerInterface, ViewerActionManagerInterface
+} from "../../RcsbFvStructure/StructureViewerInterface";
 import {RcsbFvSelectorManager} from "../../RcsbFvSelection/RcsbFvSelectorManager";
 import {SequenceViewInterface} from "./SequenceViewInterface";
 
-export interface AbstractViewInterface {
+export interface AbstractViewInterface<R> {
     componentId: string;
     title?: string;
     subtitle?: string;
-    plugin: SaguaroPluginInterface;
+    plugin: ViewerCallbackManagerInterface & ViewerActionManagerInterface<R>;
     selectorManager: RcsbFvSelectorManager;
     unmount:(flag:boolean,callback:()=>void)=>void;
 }
 
-export abstract class AbstractView<P,S> extends React.Component <P & AbstractViewInterface, S> implements SequenceViewInterface {
+export abstract class AbstractView<P,S,R> extends React.Component <P & AbstractViewInterface<R>, S> implements SequenceViewInterface {
 
     protected readonly componentDivId: string;
     protected readonly rcsbFvDivId: string;
     private updateDimTask: Subscription | null = null;
 
-    constructor(props:P & AbstractViewInterface) {
+    constructor(props:P & AbstractViewInterface<R>) {
         super(props);
         this.componentDivId = props.componentId+"_"+RcsbFvDOMConstants.PFV_DIV;
         this.rcsbFvDivId = props.componentId+"_"+RcsbFvDOMConstants.PFV_APP_ID;

+ 23 - 23
src/RcsbFvSequence/SequenceViews/CustomView/CustomView.tsx

@@ -11,34 +11,34 @@ import * as React from "react";
 import {RcsbFvSelectorManager} from "../../../RcsbFvSelection/RcsbFvSelectorManager";
 import {
     SaguaroPluginModelMapType,
-    SaguaroPluginPublicInterface
-} from "../../../RcsbFvStructure/SaguaroPluginInterface";
+    StructureViewerPublicInterface
+} from "../../../RcsbFvStructure/StructureViewerInterface";
 
-export type CustomViewStateInterface = Omit<CustomViewInterface, "modelChangeCallback">;
+export type CustomViewStateInterface<R> = Omit<CustomViewInterface<R>, "modelChangeCallback">;
 
-export interface CustomViewInterface {
-    blockConfig: FeatureBlockInterface | Array<FeatureBlockInterface>;
+export interface CustomViewInterface<R> {
+    blockConfig: FeatureBlockInterface<R> | Array<FeatureBlockInterface<R>>;
     blockSelectorElement?: (blockSelector: BlockSelectorManager) => JSX.Element;
-    modelChangeCallback?: (modelMap: SaguaroPluginModelMapType) => CustomViewStateInterface;
-    blockChangeCallback?: (plugin: SaguaroPluginPublicInterface, pfvList: Array<RcsbFv>, selection: RcsbFvSelectorManager) => void;
+    modelChangeCallback?: (modelMap: SaguaroPluginModelMapType) => CustomViewStateInterface<R>;
+    blockChangeCallback?: (plugin: StructureViewerPublicInterface<R>, pfvList: Array<RcsbFv>, selection: RcsbFvSelectorManager) => void;
 }
 
-export interface FeatureBlockInterface {
+export interface FeatureBlockInterface<R> {
     blockId:string;
     blockTitle?: string;
     blockShortName?: string;
-    featureViewConfig: Array<FeatureViewInterface> | FeatureViewInterface;
+    featureViewConfig: Array<FeatureViewInterface<R>> | FeatureViewInterface<R>;
 }
 
-export interface FeatureViewInterface {
+export interface FeatureViewInterface<R> {
     boardId?:string;
     boardConfig: RcsbFvBoardConfigInterface;
     rowConfig: Array<RcsbFvRowConfigInterface>;
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => void;
-    sequenceElementClickCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => void;
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, hoverRegion: Array<RcsbFvTrackDataElementInterface>) => void;
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selectorManager: RcsbFvSelectorManager) => void;
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selectorManager: RcsbFvSelectorManager) => void;
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface<R>, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => void;
+    sequenceElementClickCallback: (plugin: StructureViewerPublicInterface<R>, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => void;
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface<R>, selectorManager: RcsbFvSelectorManager, hoverRegion: Array<RcsbFvTrackDataElementInterface>) => void;
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface<R>, pfv: RcsbFv, selectorManager: RcsbFvSelectorManager) => void;
+    structureHoverCallback: (plugin: StructureViewerPublicInterface<R>, pfv: RcsbFv, selectorManager: RcsbFvSelectorManager) => void;
 }
 
 export class BlockSelectorManager {
@@ -61,23 +61,23 @@ export class BlockSelectorManager {
     }
 }
 
-export class CustomView extends AbstractView<CustomViewInterface & AbstractViewInterface, CustomViewStateInterface> {
+export class CustomView<R> extends AbstractView<CustomViewInterface<R>, CustomViewStateInterface<R>,R> {
 
     private blockViewSelector: BlockSelectorManager = new BlockSelectorManager( this.blockChange.bind(this) );
-    private boardMap: Map<string, FeatureViewInterface> = new Map<string, FeatureViewInterface>();
+    private boardMap: Map<string, FeatureViewInterface<R>> = new Map<string, FeatureViewInterface<R>>();
     private blockMap: Map<string, Array<string>> = new Map<string, Array<string>>();
     private rcsbFvMap: Map<string, RcsbFv> = new Map<string, RcsbFv>();
     private firstModelLoad: boolean = true;
     private innerSelectionFlag: boolean = false;
     private updateContext:"state-change"|null = null;
 
-    readonly state: CustomViewStateInterface = {
+    readonly state: CustomViewStateInterface<R> = {
         blockConfig: this.props.blockConfig,
         blockSelectorElement: this.props.blockSelectorElement,
         blockChangeCallback: this.props.blockChangeCallback
     };
 
-    constructor(props: CustomViewInterface & AbstractViewInterface) {
+    constructor(props: CustomViewInterface<R> & AbstractViewInterface<R>) {
         super(props);
         this.mapBlocks(props.blockConfig);
     }
@@ -94,7 +94,7 @@ export class CustomView extends AbstractView<CustomViewInterface & AbstractViewI
         });
     }
 
-    componentDidUpdate(prevProps: Readonly<CustomViewInterface & AbstractViewInterface>, prevState: Readonly<CustomViewStateInterface>, snapshot?: any) {
+    componentDidUpdate(prevProps: Readonly<CustomViewInterface<R> & AbstractViewInterface<R>>, prevState: Readonly<CustomViewStateInterface<R>>, snapshot?: any) {
         if(this.updateContext != "state-change") {
             this.updateContext = "state-change";
             this.mapBlocks(this.props.blockConfig);
@@ -106,7 +106,7 @@ export class CustomView extends AbstractView<CustomViewInterface & AbstractViewI
         }
     }
 
-    private mapBlocks(config: FeatureBlockInterface | Array<FeatureBlockInterface>){
+    private mapBlocks(config: FeatureBlockInterface<R> | Array<FeatureBlockInterface<R>>){
         this.rcsbFvMap.forEach((pfv, id) => {
             pfv.unmount();
         });
@@ -218,7 +218,7 @@ export class CustomView extends AbstractView<CustomViewInterface & AbstractViewI
             return;
         }
         if(typeof this.props.modelChangeCallback === "function") {
-            let newConfig: CustomViewStateInterface = this.props.modelChangeCallback(modelMap);
+            let newConfig: CustomViewStateInterface<R> = this.props.modelChangeCallback(modelMap);
             if(newConfig != null ){
                 this.updateContext = "state-change";
                 if(newConfig.blockConfig != null && newConfig.blockSelectorElement != null){
@@ -234,7 +234,7 @@ export class CustomView extends AbstractView<CustomViewInterface & AbstractViewI
         }
     }
 
-    setState<K extends keyof CustomViewStateInterface>(state: ((prevState: Readonly<CustomViewStateInterface>, props: Readonly<CustomViewInterface & AbstractViewInterface>) => (Pick<CustomViewStateInterface, K> | CustomViewStateInterface | null)) | Pick<CustomViewStateInterface, K> | CustomViewStateInterface | null, callback?: () => void) {
+    setState<K extends keyof CustomViewStateInterface<R>>(state: ((prevState: Readonly<CustomViewStateInterface<R>>, props: Readonly<CustomViewInterface<R> & AbstractViewInterface<R>>) => (Pick<CustomViewStateInterface<R>, K> | CustomViewStateInterface<R> | null)) | Pick<CustomViewStateInterface<R>, K> | CustomViewStateInterface<R> | null, callback?: () => void) {
         super.setState(state, ()=>{
             this.blockViewSelector.setActiveBlock( (this.state.blockConfig instanceof Array ? this.state.blockConfig : [this.state.blockConfig])[0].blockId! )
             if(typeof callback === "function") callback();

+ 1 - 1
src/RcsbFvSequence/SequenceViews/RcsbView/AssemblyModelSate.ts

@@ -1,4 +1,4 @@
-import {ChainInfo, OperatorInfo, SaguaroPluginModelMapType} from "../../../RcsbFvStructure/SaguaroPluginInterface";
+import {ChainInfo, OperatorInfo, SaguaroPluginModelMapType} from "../../../RcsbFvStructure/StructureViewerInterface";
 
 interface AssemblyModelStateInterface {
     modelId: string;

+ 14 - 4
src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerImplementation/AssemblyCallbackManager.ts → src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryImplementation/AssemblyCallbackManager.ts

@@ -1,12 +1,22 @@
 import {
     SaguaroPluginModelMapType, SaguaroRange,
     SaguaroRegionList
-} from "../../../../RcsbFvStructure/SaguaroPluginInterface";
+} from "../../../../RcsbFvStructure/StructureViewerInterface";
 import {RcsbFvTrackDataElementInterface} from "@rcsb/rcsb-saguaro";
 import {asyncScheduler} from "rxjs";
-import {AbstractCallbackManager} from "../CallbackManagerInterface";
+import {
+    AbstractCallbackManager, CallbackConfigInterface,
+    CallbackManagerFactoryInterface,
+    CallbackManagerInterface
+} from "../CallbackManagerFactoryInterface";
+
+export class AssemblyCallbackManagerFactory<R> implements CallbackManagerFactoryInterface<R,undefined> {
+    getCallbackManager(config: CallbackConfigInterface<R>): CallbackManagerInterface<undefined> {
+        return new AssemblyCallbackManager<R>(config);
+    }
+}
 
-export class AssemblyCallbackManager extends AbstractCallbackManager {
+class AssemblyCallbackManager<R> extends AbstractCallbackManager<R,undefined> {
 
     private readonly CREATE_COMPONENT_THR: number = 3;
 
@@ -97,7 +107,7 @@ export class AssemblyCallbackManager extends AbstractCallbackManager {
     }
 
     public async modelChangeCallback(modelMap:SaguaroPluginModelMapType, defaultAuthId?: string, defaultOperatorName?:string): Promise<void> {
-        this.rcsbFvContainer.set(await this.pfvFactory.getPfv({modelMap, defaultAuthId, defaultOperatorName}));
+        this.rcsbFvContainer.set(await this.pfvFactory.create({modelMap, defaultAuthId, defaultOperatorName}));
     }
 
     public async pfvChangeCallback(): Promise<void>{

+ 96 - 0
src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryImplementation/UniprotCallbackManager.ts

@@ -0,0 +1,96 @@
+import {
+    AbstractCallbackManager,
+    CallbackConfigInterface,
+    CallbackManagerFactoryInterface, CallbackManagerInterface
+} from "../CallbackManagerFactoryInterface";
+import {RcsbFvTrackDataElementInterface} from "@rcsb/rcsb-saguaro";
+import {SaguaroPluginModelMapType} from "../../../../RcsbFvStructure/StructureViewerInterface";
+import {
+    RcsbFvModulePublicInterface
+} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
+import {AlignmentResponse} from "@rcsb/rcsb-api-tools/build/RcsbGraphQL/Types/Borrego/GqlTypes";
+import {
+    UniprotSequenceOnchangeInterface
+} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvUniprotBuilder";
+
+export class UniprotCallbackManagerFactory<R> implements CallbackManagerFactoryInterface<R,{context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface}> {
+
+    private readonly pluginLoadParamsCollector:(id: string)=>R;
+    constructor(config: {pluginLoadParamsCollector:(id: string)=>R}) {
+        this.pluginLoadParamsCollector = config.pluginLoadParamsCollector;
+    }
+
+    getCallbackManager(config: CallbackConfigInterface<R>): CallbackManagerInterface<{ context: UniprotSequenceOnchangeInterface; module: RcsbFvModulePublicInterface }> {
+        return new UniprotCallbackManager( {...config, loadParamRequest:this.pluginLoadParamsCollector});
+    }
+}
+
+class UniprotCallbackManager<R>  extends AbstractCallbackManager<R,{context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface}>{
+
+    private readonly loadParamRequest:(id: string)=>R;
+
+    constructor(config: CallbackConfigInterface<R> & {loadParamRequest:(id: string)=>R}) {
+        super(config);
+        this.loadParamRequest = config.loadParamRequest;
+    }
+
+    elementClickCallback(e: RcsbFvTrackDataElementInterface): void {
+    }
+
+    highlightHoverCallback(selection: RcsbFvTrackDataElementInterface[]): void {
+    }
+
+    modelChangeCallback(modelMap: SaguaroPluginModelMapType, defaultAuthId?: string, defaultOperatorName?: string): Promise<void> {
+        return Promise.resolve(undefined);
+    }
+
+    pluginSelectCallback(mode: "select" | "hover"): Promise<void> {
+        return Promise.resolve(undefined);
+    }
+
+    selectionChangeCallback(selection: Array<RcsbFvTrackDataElementInterface>): void {
+    }
+
+    async pfvChangeCallback(params:{context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface}): Promise<void> {
+        if(params.context.entryId) {
+            await this.plugin.load(this.loadParamRequest(params.context.entryId));
+        }else{
+            const alignments: AlignmentResponse = await params.module.getAlignmentResponse();
+            if(alignments.target_alignment && alignments.target_alignment.length > 0){
+                const entryId: string|undefined = alignments.target_alignment[0]!.target_id?.split("_")[0];
+                if(entryId)
+                    await this.plugin.load(this.loadParamRequest(entryId));
+            }
+        }
+    }
+
+    /*async pfvChangeCallback(context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface): Promise<void> {
+        if(context.entryId) {
+            await this.plugin.load({
+                loadMethod: LoadMethod.loadPdbId,
+                loadParams: {
+                    pdbId: context.entryId
+                }
+            });
+        }else{
+            const alignments: AlignmentResponse = await module.getAlignmentResponse();
+            if(alignments.target_alignment && alignments.target_alignment.length > 0){
+                const entryId: string|undefined = alignments.target_alignment[0]!.target_id?.split("_")[0];
+                await this.plugin.load({
+                    loadMethod: LoadMethod.loadPdbId,
+                    loadParams: {
+                        pdbId: entryId
+                    }
+                });
+            }
+        }
+    }*/
+
+    protected innerPluginSelect(mode: "select" | "hover"): Promise<void> {
+        return Promise.resolve(undefined);
+    }
+
+    protected innerSelectionChange(selection: Array<RcsbFvTrackDataElementInterface>): void {
+    }
+
+}

+ 19 - 12
src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerInterface.ts → src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerFactoryInterface.ts

@@ -1,40 +1,47 @@
 import {RcsbFvTrackDataElementInterface} from "@rcsb/rcsb-saguaro";
-import {SaguaroPluginInterface, SaguaroPluginModelMapType} from "../../../RcsbFvStructure/SaguaroPluginInterface";
+import {
+    SaguaroPluginModelMapType,
+    ViewerCallbackManagerInterface, ViewerActionManagerInterface
+} from "../../../RcsbFvStructure/StructureViewerInterface";
 import {DataContainer} from "../../../Utils/DataContainer";
 import {
     RcsbFvModulePublicInterface
 } from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
 import {RcsbFvSelectorManager} from "../../../RcsbFvSelection/RcsbFvSelectorManager";
 import {AssemblyModelSate} from "./AssemblyModelSate";
-import {PfvFactoryInterface} from "./PfvFactoryInterface";
+import {PfvManagerInterface} from "./PfvManagerFactoryInterface";
 
-export interface CallbackManagerInterface {
+export interface CallbackManagerInterface<U> {
     pluginSelectCallback(mode:'select'|'hover'): Promise<void>;
     elementClickCallback(e:RcsbFvTrackDataElementInterface): void;
     highlightHoverCallback(selection: RcsbFvTrackDataElementInterface[]): void;
     selectionChangeCallback(selection: Array<RcsbFvTrackDataElementInterface>): void;
     modelChangeCallback(modelMap:SaguaroPluginModelMapType, defaultAuthId?: string, defaultOperatorName?:string): Promise<void>;
-    pfvChangeCallback(...context: unknown[]): Promise<void>;
+    pfvChangeCallback(args:U): Promise<void>;
+}
+
+export interface CallbackManagerFactoryInterface<R,U> {
+    getCallbackManager(config: CallbackConfigInterface<R>): CallbackManagerInterface<U>;
 }
 
-export interface CallbackConfigInterface {
+export interface CallbackConfigInterface<R> {
     rcsbFvContainer: DataContainer<RcsbFvModulePublicInterface>;
     selectorManager: RcsbFvSelectorManager;
     assemblyModelSate: AssemblyModelSate;
-    plugin: SaguaroPluginInterface;
-    pfvFactory: PfvFactoryInterface;
+    plugin: ViewerCallbackManagerInterface & ViewerActionManagerInterface<R>;
+    pfvFactory: PfvManagerInterface;
 }
 
-export abstract class AbstractCallbackManager implements CallbackManagerInterface {
+export abstract class AbstractCallbackManager<R,U> implements CallbackManagerInterface<U> {
     protected readonly rcsbFvContainer: DataContainer<RcsbFvModulePublicInterface>;
     protected readonly selectorManager: RcsbFvSelectorManager;
     protected readonly assemblyModelSate: AssemblyModelSate;
     protected selectedComponentId: string|undefined;
-    protected readonly plugin: SaguaroPluginInterface;
-    protected pfvFactory: PfvFactoryInterface;
+    protected readonly plugin: ViewerCallbackManagerInterface & ViewerActionManagerInterface<R>;
+    protected pfvFactory: PfvManagerInterface;
     protected readonly isInnerSelection: DataContainer<boolean> = new DataContainer<boolean>();
 
-    constructor(config: CallbackConfigInterface) {
+    constructor(config: CallbackConfigInterface<R>) {
         this.rcsbFvContainer = config.rcsbFvContainer;
         this.selectorManager = config.selectorManager;
         this.assemblyModelSate = config.assemblyModelSate;
@@ -59,7 +66,7 @@ export abstract class AbstractCallbackManager implements CallbackManagerInterfac
     abstract elementClickCallback(e:RcsbFvTrackDataElementInterface): void;
     abstract highlightHoverCallback(selection: RcsbFvTrackDataElementInterface[]): void;
     abstract modelChangeCallback(modelMap:SaguaroPluginModelMapType, defaultAuthId?: string, defaultOperatorName?:string): Promise<void>;
-    abstract pfvChangeCallback(...context: unknown[]): Promise<void>;
+    abstract pfvChangeCallback(args: U): Promise<void>;
     protected abstract innerPluginSelect(mode: "select" | "hover"): Promise<void> ;
     protected abstract innerSelectionChange(selection: Array<RcsbFvTrackDataElementInterface>): void;
 

+ 0 - 61
src/RcsbFvSequence/SequenceViews/RcsbView/CallbackManagerImplementation/UniprotCallbackManager.ts

@@ -1,61 +0,0 @@
-import {AbstractCallbackManager} from "../CallbackManagerInterface";
-import {RcsbFvTrackDataElementInterface} from "@rcsb/rcsb-saguaro";
-import {SaguaroPluginModelMapType} from "../../../../RcsbFvStructure/SaguaroPluginInterface";
-import {LoadMethod} from "../../../../RcsbFvStructure/StructurePlugins/MolstarPlugin";
-import {
-    RcsbFvModulePublicInterface
-} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
-import {AlignmentResponse} from "@rcsb/rcsb-api-tools/build/RcsbGraphQL/Types/Borrego/GqlTypes";
-import {
-    UniprotSequenceOnchangeInterface
-} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvUniprotBuilder";
-
-export class UniprotCallbackManager  extends AbstractCallbackManager{
-
-    elementClickCallback(e: RcsbFvTrackDataElementInterface): void {
-    }
-
-    highlightHoverCallback(selection: RcsbFvTrackDataElementInterface[]): void {
-    }
-
-    modelChangeCallback(modelMap: SaguaroPluginModelMapType, defaultAuthId?: string, defaultOperatorName?: string): Promise<void> {
-        return Promise.resolve(undefined);
-    }
-
-    pluginSelectCallback(mode: "select" | "hover"): Promise<void> {
-        return Promise.resolve(undefined);
-    }
-
-    selectionChangeCallback(selection: Array<RcsbFvTrackDataElementInterface>): void {
-    }
-
-    async pfvChangeCallback(context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface): Promise<void> {
-        if(context.entryId) {
-            this.plugin.load({
-                loadMethod: LoadMethod.loadPdbId,
-                loadParams: {
-                    pdbId: context.entryId
-                }
-            });
-        }else{
-            const alignments: AlignmentResponse = await module.getAlignmentResponse();
-            if(alignments.target_alignment && alignments.target_alignment.length > 0){
-                const entryId: string|undefined = alignments.target_alignment[0]!.target_id?.split("_")[0];
-                this.plugin.load({
-                    loadMethod: LoadMethod.loadPdbId,
-                    loadParams: {
-                        pdbId: entryId
-                    }
-                });
-            }
-        }
-    }
-
-    protected innerPluginSelect(mode: "select" | "hover"): Promise<void> {
-        return Promise.resolve(undefined);
-    }
-
-    protected innerSelectionChange(selection: Array<RcsbFvTrackDataElementInterface>): void {
-    }
-
-}

+ 0 - 42
src/RcsbFvSequence/SequenceViews/RcsbView/PfvFactoryImplementation/UniprotPfvFactory.ts

@@ -1,42 +0,0 @@
-import {PfvAbstractFactory, PfvFactoryConfigInterface} from "../PfvFactoryInterface";
-import {
-    RcsbFvModulePublicInterface
-} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
-import {buildMultipleAlignmentSequenceFv, FeatureType, RcsbFvUI, RcsbRequestContextManager} from "@rcsb/rcsb-saguaro-app";
-import {RcsbFvDOMConstants} from "../../../../RcsbFvConstants/RcsbFvConstants";
-import {
-    UniprotSequenceOnchangeInterface
-} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvUniprotBuilder";
-
-interface UniprotPfvFactoryInterface extends PfvFactoryConfigInterface {
-    upAcc:string;
-}
-
-export class UniprotPfvFactory extends PfvAbstractFactory<{upAcc:string}>{
-
-    private readonly upAcc:string;
-    private module: Promise<RcsbFvModulePublicInterface>;
-
-    constructor(config:UniprotPfvFactoryInterface) {
-        super(config);
-        this.upAcc = config.upAcc;
-    }
-
-    async getPfv(): Promise<RcsbFvModulePublicInterface | undefined> {
-        this.module = buildMultipleAlignmentSequenceFv(
-            this.rcsbFvDivId,
-            RcsbFvDOMConstants.SELECT_BUTTON_PFV_ID,
-            this.upAcc,
-            {
-                onChangeCallback:(context,module)=>{
-                    this.pfvChangeCallback(context, module);
-                }
-            },
-            this.additionalConfig
-        );
-        const module: RcsbFvModulePublicInterface = await this.module;
-        this.rcsbFvContainer.set(module);
-        return module;
-    }
-
-}

+ 30 - 18
src/RcsbFvSequence/SequenceViews/RcsbView/PfvFactoryImplementation/AssemblyPfvFactory.tsx → src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/AssemblyPfvManagerFactory.tsx

@@ -3,9 +3,8 @@ import {
 } from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
 import {
     ChainInfo, OperatorInfo,
-    SaguaroPluginInterface,
-    SaguaroPluginModelMapType
-} from "../../../../RcsbFvStructure/SaguaroPluginInterface";
+    SaguaroPluginModelMapType, ViewerActionManagerInterface
+} from "../../../../RcsbFvStructure/StructureViewerInterface";
 import {
     InstanceSequenceConfig
 } from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvInstanceBuilder";
@@ -23,28 +22,41 @@ import {
     InterfaceInstanceTranslate
 } from "@rcsb/rcsb-saguaro-app/build/dist/RcsbUtils/Translators/InterfaceInstanceTranslate";
 import {DataContainer} from "../../../../Utils/DataContainer";
-import {BuildPfvInterface, PfvAbstractFactory, PfvFactoryConfigInterface} from "../PfvFactoryInterface";
+import {
+    BuildPfvInterface,
+    AbstractPfvManager,
+    PfvManagerFactoryConfigInterface,
+    PfvManagerInterface,
+    PfvManagerFactoryInterface
+} from "../PfvManagerFactoryInterface";
 import {ColorTheme} from "molstar/lib/mol-theme/color";
 import {PLDDTConfidenceColorThemeProvider} from "molstar/lib/extensions/model-archive/quality-assessment/color/plddt";
 
-interface AssemblyPfvFactoryInterface extends PfvFactoryConfigInterface{
-    useOperatorsFlag:boolean | undefined;
+interface AssemblyPfvManagerInterface<R> extends PfvManagerFactoryConfigInterface<R,undefined>{
+    useOperatorsFlag: boolean | undefined;
     instanceSequenceConfig: InstanceSequenceConfig | undefined;
 }
 
-export class AssemblyPfvFactory extends PfvAbstractFactory<{instanceSequenceConfig: InstanceSequenceConfig|undefined}> {
+export class AssemblyPfvManagerFactory<R> implements PfvManagerFactoryInterface<{instanceSequenceConfig: InstanceSequenceConfig|undefined;useOperatorsFlag: boolean | undefined;},R,undefined> {
+    public getPfvManager(config:  AssemblyPfvManagerInterface<R>): PfvManagerInterface {
+        return new AssemblyPfvManager<R>(config);
+    }
+}
+
+class AssemblyPfvManager<R> extends AbstractPfvManager<{instanceSequenceConfig: InstanceSequenceConfig|undefined;useOperatorsFlag: boolean | undefined;},R,undefined> {
 
     private readonly instanceSequenceConfig: InstanceSequenceConfig|undefined;
     private readonly useOperatorsFlag:boolean | undefined;
     private readonly OPERATOR_DROPDOWN_TITLE: string = "Symmetry Partner";
+    private module: RcsbFvModulePublicInterface | undefined = undefined;
 
-    constructor(config: AssemblyPfvFactoryInterface) {
+    constructor(config: AssemblyPfvManagerInterface<R>) {
         super(config);
         this.instanceSequenceConfig = config.instanceSequenceConfig;
         this.useOperatorsFlag = config.useOperatorsFlag;
     }
 
-    async getPfv(config: BuildPfvInterface): Promise<RcsbFvModulePublicInterface | undefined> {
+    public async create(config: BuildPfvInterface): Promise<RcsbFvModulePublicInterface | undefined> {
         this.assemblyModelSate.setMap(config.modelMap);
         this.plugin.clearFocus();
         const onChangeCallback: Map<string, (x: PolymerEntityInstanceInterface)=>void> = new Map<string, (x: PolymerEntityInstanceInterface) => {}>();
@@ -55,14 +67,13 @@ export class AssemblyPfvFactory extends PfvAbstractFactory<{instanceSequenceConf
                 this.assemblyModelSate.set({entryId: v.entryId, labelAsymId: x.asymId, modelId: k});
                 asyncScheduler.schedule(()=>{
                     this.selectorManager.setLastSelection('select', null);
-                    this.pfvChangeCallback();
-                },1000);
+                    this.pfvChangeCallback(undefined);
+                },100);
             });
         });
         const operatorNameContainer: DataContainer<string> = new DataContainer<string>(config.defaultOperatorName);
-        let module: RcsbFvModulePublicInterface | undefined = undefined;
         if(this.assemblyModelSate.get("entryId") != null) {
-            module = await buildInstanceSequenceFv(
+            this.module = await buildInstanceSequenceFv(
                 this.rcsbFvDivId,
                 RcsbFvDOMConstants.SELECT_BUTTON_PFV_ID,
                 this.assemblyModelSate.getString("entryId"),
@@ -105,8 +116,8 @@ export class AssemblyPfvFactory extends PfvAbstractFactory<{instanceSequenceConf
             );
         }
         if(!config.defaultAuthId)
-            await createComponents(this.plugin, this.assemblyModelSate.getMap());
-        return module;
+            await createComponents<R>(this.plugin, this.assemblyModelSate.getMap());
+        return this.module;
     }
 
     private addOperatorButton(operatorName?: string): void{
@@ -120,8 +131,9 @@ export class AssemblyPfvFactory extends PfvAbstractFactory<{instanceSequenceConf
                     label:`${op.ids.join("-")} (${op.name})`,
                     optId:op.name,
                     onChange: async ()=>{
+                        this.module?.getFv()?.reset();
                         this.assemblyModelSate.set({operator:op});
-                        await this.getPfv({
+                        await this.create({
                             modelMap: this.assemblyModelSate.getMap(),
                             defaultAuthId: this.assemblyModelSate.getChainInfo()?.auth,
                             defaultOperatorName: op.name
@@ -166,7 +178,7 @@ export class AssemblyPfvFactory extends PfvAbstractFactory<{instanceSequenceConf
 
 }
 
-async function createComponents(plugin: SaguaroPluginInterface, modelMap:SaguaroPluginModelMapType): Promise<void> {
+async function createComponents<R>(plugin: ViewerActionManagerInterface<R>, modelMap:SaguaroPluginModelMapType): Promise<void> {
     plugin.displayComponent("Water", false);
     await plugin.colorComponent("Polymer", 'chain-id');
     const chains: Array<{modelId: string; auth: string; label: string;}> = new Array<{modelId: string; auth: string; label: string;}>();
@@ -177,7 +189,7 @@ async function createComponents(plugin: SaguaroPluginInterface, modelMap:Saguaro
             }
         });
     });
-    plugin.removeComponent();
+    await plugin.removeComponent();
     plugin.clearFocus();
     //TODO improve colorTheme condition (PLDDTConfidenceColorThemeProvider.isApplicable)
     const colorTheme: ColorTheme.BuiltIn = (chains.length === 1 && chains[0].modelId.includes("AF_AF")) ? PLDDTConfidenceColorThemeProvider.name as ColorTheme.BuiltIn : "chain-id";

+ 7 - 2
src/RcsbFvSequence/SequenceViews/RcsbView/PfvFactoryImplementation/ChainDisplay.tsx → src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/ChainDisplay.tsx

@@ -1,8 +1,13 @@
 import * as React from "react";
-import {SaguaroPluginInterface} from "../../../../RcsbFvStructure/SaguaroPluginInterface";
+import {
+    StructureViewerInterface
+} from "../../../../RcsbFvStructure/StructureViewerInterface";
 
+type DisplayComponentMethod = (StructureViewerInterface<undefined,[]>)["displayComponent"]
 interface ChainDisplayInterface {
-    plugin: SaguaroPluginInterface;
+    plugin: {
+        displayComponent:DisplayComponentMethod
+    };
     label: string;
 }
 

+ 53 - 0
src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryImplementation/UniprotPfvFactory.ts

@@ -0,0 +1,53 @@
+import {
+    AbstractPfvManager,
+    PfvManagerFactoryConfigInterface,
+    PfvManagerInterface,
+    PfvManagerFactoryInterface
+} from "../PfvManagerFactoryInterface";
+import {
+    RcsbFvModulePublicInterface
+} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
+import {buildMultipleAlignmentSequenceFv} from "@rcsb/rcsb-saguaro-app";
+import {RcsbFvDOMConstants} from "../../../../RcsbFvConstants/RcsbFvConstants";
+import {
+    UniprotSequenceOnchangeInterface
+} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvUniprotBuilder";
+
+interface UniprotPfvManagerInterface<R> extends PfvManagerFactoryConfigInterface<R,{context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface}> {
+    upAcc:string;
+}
+
+export class UniprotPfvManagerFactory<R> implements PfvManagerFactoryInterface<{upAcc:string},R,{context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface}> {
+    getPfvManager(config: UniprotPfvManagerInterface<R>): PfvManagerInterface {
+        return new UniprotPfvManager(config);
+    }
+}
+
+class UniprotPfvManager<R> extends AbstractPfvManager<{upAcc:string},R,{context: UniprotSequenceOnchangeInterface, module: RcsbFvModulePublicInterface}>{
+
+    private readonly upAcc:string;
+    private module: Promise<RcsbFvModulePublicInterface>;
+
+    constructor(config:UniprotPfvManagerInterface<R>) {
+        super(config);
+        this.upAcc = config.upAcc;
+    }
+
+    async create(): Promise<RcsbFvModulePublicInterface | undefined> {
+        this.module = buildMultipleAlignmentSequenceFv(
+            this.rcsbFvDivId,
+            RcsbFvDOMConstants.SELECT_BUTTON_PFV_ID,
+            this.upAcc,
+            {
+                onChangeCallback:(context,module)=>{
+                    this.pfvChangeCallback({context, module});
+                }
+            },
+            this.additionalConfig
+        );
+        const module: RcsbFvModulePublicInterface = await this.module;
+        this.rcsbFvContainer.set(module);
+        return module;
+    }
+
+}

+ 16 - 14
src/RcsbFvSequence/SequenceViews/RcsbView/PfvFactoryInterface.ts → src/RcsbFvSequence/SequenceViews/RcsbView/PfvManagerFactoryInterface.ts

@@ -7,45 +7,47 @@ import {RcsbFvSelectorManager} from "../../../RcsbFvSelection/RcsbFvSelectorMana
 import {AssemblyModelSate} from "./AssemblyModelSate";
 import {
     OperatorInfo,
-    SaguaroPluginInterface,
-    SaguaroPluginModelMapType
-} from "../../../RcsbFvStructure/SaguaroPluginInterface";
+    SaguaroPluginModelMapType, ViewerCallbackManagerInterface, ViewerActionManagerInterface
+} from "../../../RcsbFvStructure/StructureViewerInterface";
 import {RcsbFvBoardConfigInterface} from "@rcsb/rcsb-saguaro";
 
-
-export interface PfvFactoryConfigInterface {
+export interface PfvManagerFactoryConfigInterface<R,U> {
     rcsbFvDivId: string;
     rcsbFvContainer: DataContainer<RcsbFvModulePublicInterface>;
     selectorManager: RcsbFvSelectorManager;
     assemblyModelSate: AssemblyModelSate;
-    plugin: SaguaroPluginInterface;
+    plugin: ViewerCallbackManagerInterface & ViewerActionManagerInterface <R>;
     boardConfigContainer: DataContainer<Partial<RcsbFvBoardConfigInterface>>;
-    pfvChangeCallback(...context: unknown[]): Promise<void>;
+    pfvChangeCallback(context: U): Promise<void>;
     additionalConfig: RcsbFvAdditionalConfig & {operatorChangeCallback?:(operatorInfo: OperatorInfo)=>void} | undefined;
 }
 
+export interface PfvManagerFactoryInterface<T,R,U> {
+    getPfvManager(config:T & PfvManagerFactoryConfigInterface<R,U>): PfvManagerInterface;
+}
+
 export interface BuildPfvInterface {
     modelMap:SaguaroPluginModelMapType;
     defaultAuthId?: string;
     defaultOperatorName?:string;
 }
 
-export interface PfvFactoryInterface {
-    getPfv(config?: BuildPfvInterface): Promise<RcsbFvModulePublicInterface | undefined>;
+export interface PfvManagerInterface {
+    create(config?: BuildPfvInterface): Promise<RcsbFvModulePublicInterface | undefined>;
 }
 
-export abstract class PfvAbstractFactory<T={}> implements PfvFactoryInterface {
+export abstract class AbstractPfvManager<T,R,U> implements PfvManagerInterface {
 
     protected readonly rcsbFvDivId: string;
     protected readonly rcsbFvContainer: DataContainer<RcsbFvModulePublicInterface>;
     protected readonly selectorManager: RcsbFvSelectorManager;
     protected readonly assemblyModelSate: AssemblyModelSate;
-    protected readonly plugin: SaguaroPluginInterface;
+    protected readonly plugin: ViewerCallbackManagerInterface & ViewerActionManagerInterface <R>;
     protected readonly boardConfigContainer: DataContainer<Partial<RcsbFvBoardConfigInterface>>;
-    protected readonly pfvChangeCallback: (...context: unknown[])=>Promise<void>;
+    protected readonly pfvChangeCallback: (context: U)=>Promise<void>;
     protected readonly additionalConfig: RcsbFvAdditionalConfig & {operatorChangeCallback?:(operatorInfo: OperatorInfo)=>void} | undefined;
 
-    protected constructor(config:PfvFactoryConfigInterface & T){
+    protected constructor(config:T & PfvManagerFactoryConfigInterface<R,U>){
         this.rcsbFvDivId = config.rcsbFvDivId;
         this.rcsbFvContainer = config.rcsbFvContainer;
         this.selectorManager = config.selectorManager;
@@ -56,5 +58,5 @@ export abstract class PfvAbstractFactory<T={}> implements PfvFactoryInterface {
         this.pfvChangeCallback = config.pfvChangeCallback;
     }
 
-    abstract getPfv(config?: BuildPfvInterface): Promise<RcsbFvModulePublicInterface | undefined>;
+    public abstract create(config?: BuildPfvInterface): Promise<RcsbFvModulePublicInterface | undefined>;
 }

+ 22 - 18
src/RcsbFvSequence/SequenceViews/RcsbView/RcsbView.tsx

@@ -5,36 +5,40 @@ import {unmount} from "@rcsb/rcsb-saguaro-app";
 import {AbstractView, AbstractViewInterface} from "../AbstractView";
 import {InstanceSequenceConfig} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvBuilder/RcsbFvInstanceBuilder";
 import {RcsbFvBoardConfigInterface, RcsbFvTrackDataElementInterface} from "@rcsb/rcsb-saguaro";
-import {OperatorInfo, SaguaroPluginModelMapType} from "../../../RcsbFvStructure/SaguaroPluginInterface";
+import {OperatorInfo, SaguaroPluginModelMapType} from "../../../RcsbFvStructure/StructureViewerInterface";
 import {RcsbFvAdditionalConfig, RcsbFvModulePublicInterface} from "@rcsb/rcsb-saguaro-app/build/dist/RcsbFvWeb/RcsbFvModule/RcsbFvModuleInterface";
 import {AssemblyModelSate} from "./AssemblyModelSate";
-import {AssemblyCallbackManager} from "./CallbackManagerImplementation/AssemblyCallbackManager";
-import {AssemblyPfvFactory} from "./PfvFactoryImplementation/AssemblyPfvFactory";
 import {DataContainer} from "../../../Utils/DataContainer";
-import {PfvAbstractFactory, PfvFactoryConfigInterface, PfvFactoryInterface} from "./PfvFactoryInterface";
-import {AbstractCallbackManager, CallbackConfigInterface, CallbackManagerInterface} from "./CallbackManagerInterface";
-
-export interface RcsbViewInterface<T extends {}> {
+import {
+    PfvManagerInterface,
+    PfvManagerFactoryInterface
+} from "./PfvManagerFactoryInterface";
+import {
+    CallbackManagerFactoryInterface,
+    CallbackManagerInterface
+} from "./CallbackManagerFactoryInterface";
+
+export interface RcsbViewInterface<T,R,U> {
     rcsbId: string;
     additionalConfig?: RcsbFvAdditionalConfig & {operatorChangeCallback?:(operatorInfo: OperatorInfo)=>void};
     useOperatorsFlag?:boolean;
     pfvParams:T;
-    pfvFactory: new(config:PfvFactoryConfigInterface & T) => PfvFactoryInterface;
-    callbackManager: new(config: CallbackConfigInterface) => CallbackManagerInterface;
+    pfvManagerFactory: PfvManagerFactoryInterface<T,R,U>;
+    callbackManagerFactory: CallbackManagerFactoryInterface<R,U>;
     buildPfvOnMount?: boolean;
 }
 
-export class RcsbView<T extends {}> extends AbstractView<RcsbViewInterface<T> & AbstractViewInterface, {}>{
+export class RcsbView<T,R,U> extends AbstractView<RcsbViewInterface<T,R,U>, {}, R>{
 
     private readonly assemblyModelSate: AssemblyModelSate = new AssemblyModelSate();
     private boardConfigContainer: DataContainer<Partial<RcsbFvBoardConfigInterface>> = new DataContainer();
     private rcsbFvContainer: DataContainer<RcsbFvModulePublicInterface> = new DataContainer<RcsbFvModulePublicInterface>();
-    private readonly callbackManager: CallbackManagerInterface;
-    private readonly pfvFactory: PfvFactoryInterface;
+    private readonly callbackManager: CallbackManagerInterface<U>;
+    private readonly pfvFactory: PfvManagerInterface;
 
-    constructor(props:RcsbViewInterface<T> & AbstractViewInterface) {
+    constructor(props:RcsbViewInterface<T,R,U> & AbstractViewInterface<R>) {
         super(props);
-        this.pfvFactory = new (this.props.pfvFactory)({
+        this.pfvFactory = this.props.pfvManagerFactory.getPfvManager({
             ...this.props.pfvParams,
             rcsbFvContainer: this.rcsbFvContainer,
             selectorManager: this.props.selectorManager,
@@ -46,7 +50,7 @@ export class RcsbView<T extends {}> extends AbstractView<RcsbViewInterface<T> &
             additionalConfig: this.props.additionalConfig,
             useOperatorsFlag: this.props.useOperatorsFlag
         });
-        this.callbackManager = new (this.props.callbackManager)({
+        this.callbackManager = this.props.callbackManagerFactory.getCallbackManager({
             rcsbFvContainer: this.rcsbFvContainer,
             selectorManager: this.props.selectorManager,
             plugin: this.props.plugin,
@@ -106,7 +110,7 @@ export class RcsbView<T extends {}> extends AbstractView<RcsbViewInterface<T> &
             },
         });
         if(this.props.buildPfvOnMount)
-            this.rcsbFvContainer.set(await this.pfvFactory.getPfv());
+            this.rcsbFvContainer.set(await this.pfvFactory.create());
     }
 
     componentWillUnmount() {
@@ -143,8 +147,8 @@ export class RcsbView<T extends {}> extends AbstractView<RcsbViewInterface<T> &
         await this.callbackManager.pluginSelectCallback(mode);
     }
 
-    private async pfvChangeCallback(...context: unknown[]): Promise<void>{
-        await this.callbackManager.pfvChangeCallback(...context);
+    private async pfvChangeCallback(context: U): Promise<void>{
+        await this.callbackManager.pfvChangeCallback(context);
     }
 
     private highlightHoverCallback(selection: RcsbFvTrackDataElementInterface[]): void {

+ 1 - 1
src/RcsbFvSequence/SequenceViews/SequenceViewInterface.ts

@@ -1,4 +1,4 @@
-import {SaguaroPluginModelMapType} from "../../RcsbFvStructure/SaguaroPluginInterface";
+import {SaguaroPluginModelMapType} from "../../RcsbFvStructure/StructureViewerInterface";
 
 export interface SequenceViewInterface {
     structureSelectionCallback(): void;

+ 14 - 11
src/RcsbFvStructure/RcsbFvStructure.tsx

@@ -1,29 +1,28 @@
 import * as React from "react";
-import {SaguaroPluginInterface} from "./SaguaroPluginInterface";
+import {StructureViewerInterface} from "./StructureViewerInterface";
 import {RcsbFvDOMConstants} from "../RcsbFvConstants/RcsbFvConstants";
-import {ViewerProps} from "@rcsb/rcsb-molstar/build/src/viewer";
-import {LoadMolstarInterface} from "./StructurePlugins/MolstarPlugin";
 import {RcsbFvSelectorManager} from "../RcsbFvSelection/RcsbFvSelectorManager";
 
-export interface RcsbFvStructureInterface {
-    loadConfig?: LoadMolstarInterface | Array<LoadMolstarInterface>;
-    pluginConfig?: Partial<ViewerProps>;
+export interface RcsbFvStructureConfigInterface<R,S> {
+    loadConfig: R | Array<R>;
+    pluginConfig: S;
 }
 
-export class RcsbFvStructure extends React.Component <RcsbFvStructureInterface & {plugin: SaguaroPluginInterface, componentId: string, selectorManager: RcsbFvSelectorManager}, RcsbFvStructureInterface > {
+export class RcsbFvStructure<R,S> extends React.Component <RcsbFvStructureConfigInterface<R,S> & {plugin: StructureViewerInterface<R,S>, componentId: string, selectorManager: RcsbFvSelectorManager}, RcsbFvStructureConfigInterface<R,S> > {
 
     render():JSX.Element {
         return (
             <div id={this.props.componentId+"_"+RcsbFvDOMConstants.MOLSTAR_DIV} >
-                <div id={this.props.componentId+"_"+RcsbFvDOMConstants.MOLSTAR_APP_ID} style={{position:"absolute"}}/>
+                <div id={RcsbFvStructure.componentId(this.props.componentId)} style={{position:"absolute"}}/>
             </div>
         );
     }
 
-    componentDidMount() {
+    async componentDidMount() {
         this.updateDimensions();
-        this.props.plugin.init(this.props.componentId+"_"+RcsbFvDOMConstants.MOLSTAR_APP_ID, this.props.pluginConfig);
-        if(this.props.loadConfig) this.props.plugin.load(this.props.loadConfig);
+        this.props.plugin.init(this.props.selectorManager, this.props.pluginConfig);
+        if(this.props.loadConfig)
+            await this.props.plugin.load(this.props.loadConfig);
         window.addEventListener('resize', this.updateDimensions.bind(this));
     }
 
@@ -45,4 +44,8 @@ export class RcsbFvStructure extends React.Component <RcsbFvStructureInterface &
         element.style.height = rect.height+"px";
     }
 
+    public static componentId(id:string): string {
+        return `${id}_${RcsbFvDOMConstants.MOLSTAR_APP_ID}`;
+    }
+
 }

+ 0 - 67
src/RcsbFvStructure/SaguaroPluginInterface.ts

@@ -1,67 +0,0 @@
-import {LoadMolstarInterface} from "./StructurePlugins/MolstarPlugin";
-import {PluginContext} from "molstar/lib/mol-plugin/context";
-import {StructureRepresentationRegistry} from "molstar/lib/mol-repr/structure/registry";
-import {ColorTheme} from "molstar/lib/mol-theme/color";
-import {RegionSelectionInterface} from "../RcsbFvSelection/RcsbFvSelectorManager";
-
-export type ChainType = "polymer"|"water"|"branched"|"non-polymer"|"macrolide";
-export type OperatorInfo = {ids:string[], name: string};
-export type ChainInfo = {auth:string;label:string;entityId:string;title:string;type:ChainType;operators:OperatorInfo[]};
-export type SaguaroPluginModelMapType = Map<string,{entryId: string; assemblyId: string, chains:Array<ChainInfo>;}>;
-
-export interface SaguaroChain {
-    modelId: string;
-    labelAsymId: string;
-    operatorName?: string;
-}
-
-export interface SaguaroPosition extends SaguaroChain{
-    position: number;
-}
-
-export interface SaguaroRange extends SaguaroChain {
-    begin: number;
-    end: number;
-}
-
-export interface SaguaroSet extends SaguaroChain{
-    seqIds: Set<number>;
-}
-
-export interface SaguaroRegionList extends SaguaroChain{
-    regions: Array<RegionSelectionInterface>;
-}
-
-export interface SaguaroPluginInterface extends SaguaroPluginPublicInterface{
-    init: (elementId: string, props?: any) => void;
-    load: (args: LoadMolstarInterface|Array<LoadMolstarInterface>) => void;
-    pluginCall: (f:(plugin: PluginContext)=>void) => void;
-    clear: () => void;
-    setSelectCallback: (g:(flag?:boolean)=>void)=>void;
-    setModelChangeCallback: (f:(modelMap:SaguaroPluginModelMapType)=>void)=>void;
-    setHoverCallback:(g:(flag?:boolean)=>void)=>void;
-    setRepresentationChangeCallback:(g:(flag?:boolean)=>void)=>void;
-    unsetCallbacks:()=>void;
-}
-
-export interface SaguaroPluginPublicInterface {
-    select(modelId:string, labelAsymId: string, x: number, y: number, mode: 'select'|'hover', operation:'set'|'add', operatorName?:string): void;
-    select(selection: Array<SaguaroPosition>, mode: 'select'|'hover', operation:'add'|'set'): void;
-    select(selection: Array<SaguaroRange>, mode: 'select'|'hover', operation:'add'|'set'): void;
-    clearSelection(mode:'select'|'hover', option?:SaguaroChain): void;
-    createComponent(componentId: string, modelId:string, labelAsymId: string, begin: number, end : number, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
-    createComponent(componentId: string, modelId:string, labelAsymId: string, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
-    createComponent(componentId: string, residues: Array<SaguaroPosition>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
-    createComponent(componentId: string, residues: Array<SaguaroRange>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
-    colorComponent(componentId: string, color: ColorTheme.BuiltIn): Promise<void>;
-    removeComponent(componentId?: string): void;
-    isComponent(componentId: string): boolean;
-    displayComponent(componentLabel: string, visibilityFlag: boolean): void;
-    displayComponent(componentLabel: string): boolean;
-    getComponentSet(): Set<string>;
-    setFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void;
-    clearFocus(): void;
-    cameraFocus(modelId: string, labelAsymId: string, positions:Array<number>, operatorName?:string): void;
-    cameraFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void;
-    resetCamera(): void;
-}

+ 0 - 9
src/RcsbFvStructure/StructurePlugins/AbstractPlugin.ts

@@ -1,9 +0,0 @@
-import {RcsbFvSelectorManager} from "../../RcsbFvSelection/RcsbFvSelectorManager";
-
-export class AbstractPlugin {
-    protected readonly selection: RcsbFvSelectorManager;
-
-    constructor(selection: RcsbFvSelectorManager) {
-        this.selection = selection;
-    }
-}

+ 0 - 613
src/RcsbFvStructure/StructurePlugins/MolstarPlugin.ts

@@ -1,613 +0,0 @@
-import {Viewer, ViewerProps} from '@rcsb/rcsb-molstar/build/src/viewer';
-import {PresetProps} from '@rcsb/rcsb-molstar/build/src/viewer/helpers/preset';
-import {
-    ChainInfo, OperatorInfo, SaguaroChain,
-    SaguaroPluginInterface,
-    SaguaroPluginModelMapType, SaguaroPosition, SaguaroRange, SaguaroSet
-} from "../SaguaroPluginInterface";
-
-import {PluginContext} from "molstar/lib/mol-plugin/context";
-import {Loci} from "molstar/lib/mol-model/loci";
-import {Mat4} from "molstar/lib/mol-math/linear-algebra";
-import {BuiltInTrajectoryFormat} from "molstar/lib/mol-plugin-state/formats/trajectory";
-import {PluginState} from "molstar/lib/mol-plugin/state";
-import {
-    Structure,
-    StructureElement,
-    StructureProperties as SP,
-    StructureSelection,
-    Queries as Q,
-    StructureQuery
-} from "molstar/lib/mol-model/structure";
-import {OrderedSet} from "molstar/lib/mol-data/int";
-import { PluginStateObject as PSO } from 'molstar/lib/mol-plugin-state/objects';
-import {State, StateObject} from "molstar/lib/mol-state";
-import {StructureComponentRef, StructureRef} from "molstar/lib/mol-plugin-state/manager/structure/hierarchy-state";
-import {
-    RcsbFvSelectorManager
-} from "../../RcsbFvSelection/RcsbFvSelectorManager";
-import {AbstractPlugin} from "./AbstractPlugin";
-import {Subscription} from "rxjs";
-import {Script} from "molstar/lib/mol-script/script";
-import {MolScriptBuilder as MS} from "molstar/lib/mol-script/language/builder";
-import {SetUtils} from "molstar/lib/mol-util/set";
-import {StructureRepresentationRegistry} from "molstar/lib/mol-repr/structure/registry";
-import {ColorTheme} from "molstar/lib/mol-theme/color";
-import {TrajectoryHierarchyPresetProvider} from "molstar/lib/mol-plugin-state/builder/structure/hierarchy-preset";
-import {Expression} from "molstar/lib/commonjs/mol-script/language/expression";
-
-export enum LoadMethod {
-    loadPdbId = "loadPdbId",
-    loadPdbIds = "loadPdbIds",
-    loadStructureFromUrl = "loadStructureFromUrl",
-    loadSnapshotFromUrl = "loadSnapshotFromUrl",
-    loadStructureFromData = "loadStructureFromData"
-}
-
-export interface LoadMolstarInterface {
-    loadMethod: LoadMethod;
-    loadParams: LoadParams | Array<LoadParams>;
-}
-
-interface LoadParams<P=any,S={}> {
-    pdbId?: string;
-    props?: PresetProps;
-    matrix?: Mat4;
-    url?: string,
-    format?: BuiltInTrajectoryFormat,
-    isBinary?: boolean,
-    type?: PluginState.SnapshotType,
-    data?: string | number[]
-    id?:string;
-    reprProvider?: TrajectoryHierarchyPresetProvider<P,S>;
-    params?:P;
-}
-
-export class MolstarPlugin extends AbstractPlugin implements SaguaroPluginInterface {
-    private viewer: Viewer;
-    private innerSelectionFlag: boolean = false;
-    private loadingFlag: boolean = false;
-    private selectCallbackSubs: Subscription;
-    private modelChangeCallback: (chainMap:SaguaroPluginModelMapType)=>void;
-    private modelChangeCallbackSubs: Subscription;
-    private modelMap: Map<string,string|undefined> = new Map<string, string>();
-    private readonly componentMap: Map<string, StructureComponentRef> = new Map<string, StructureComponentRef>();
-
-    constructor(props: RcsbFvSelectorManager) {
-        super(props);
-    }
-
-    public init(target: string | HTMLElement, props?: Partial<ViewerProps>) {
-        this.viewer = new Viewer(target, {
-            ...props,
-            layoutShowControls:false,
-            layoutShowSequence: true,
-            canvas3d: {
-                multiSample: {
-                    mode: 'off'
-                }
-            }
-        });
-    }
-
-    public clear(): void{
-        this.viewer.clear();
-    }
-
-    async load(loadConfig: LoadMolstarInterface|Array<LoadMolstarInterface>): Promise<void>{
-        this.loadingFlag = true;
-        for (const lC of (Array.isArray(loadConfig) ? loadConfig : [loadConfig])) {
-            if(MolstarPlugin.checkLoadData(lC)) {
-                if (lC.loadMethod == LoadMethod.loadPdbId) {
-                    const config: LoadParams = lC.loadParams as LoadParams;
-                    await this.viewer.loadPdbId(config.pdbId!, {props: config.props, matrix: config.matrix, reprProvider: config.reprProvider, params: config.params});
-                } else if (lC.loadMethod == LoadMethod.loadPdbIds) {
-                    const config: Array<LoadParams> = lC.loadParams as Array<LoadParams>;
-                    await this.viewer.loadPdbIds(config.map((d) => {
-                        return {pdbId: d.pdbId!, config:{props: d.props, matrix: d.matrix, reprProvider: d.reprProvider, params: d.params}}
-                    }));
-                } else if (lC.loadMethod == LoadMethod.loadStructureFromUrl) {
-                    const config: LoadParams = lC.loadParams as LoadParams;
-                    await this.viewer.loadStructureFromUrl(config.url!, config.format!, config.isBinary!,{props: config.props, matrix: config.matrix, reprProvider: config.reprProvider, params: config.params});
-                } else if (lC.loadMethod == LoadMethod.loadSnapshotFromUrl) {
-                    const config: LoadParams = lC.loadParams as LoadParams;
-                    await this.viewer.loadSnapshotFromUrl(config.url!, config.type!);
-                } else if (lC.loadMethod == LoadMethod.loadStructureFromData) {
-                    const config: LoadParams = lC.loadParams as LoadParams;
-                    await this.viewer.loadStructureFromData(config.data!, config.format!, config.isBinary!, {props: config.props, matrix: config.matrix, reprProvider: config.reprProvider, params: config.params});
-                }
-            }
-            this.viewer.plugin.selectionMode = true;
-            (Array.isArray(lC.loadParams) ? lC.loadParams : [lC.loadParams]).forEach(lP=>{
-                if(typeof lP.params?.getMap === "function") {
-                    const map: Map<string,string> = lP.params.getMap();
-                    if(typeof map?.forEach === "function")
-                        map.forEach((modelId: string, key: string) => {
-                            if (typeof modelId === "string" && typeof key === "string") {
-                                this.modelMap.set(key, modelId);
-                                this.modelMap.set(modelId, key);
-                            }
-                        })
-                }
-            });
-            this.mapModels(lC.loadParams);
-        }
-        this.loadingFlag = false;
-        this.modelChangeCallback(this.getChains());
-    }
-
-    private static checkLoadData(loadConfig: LoadMolstarInterface): boolean{
-        const method: LoadMethod = loadConfig.loadMethod;
-        const params: LoadParams | Array<LoadParams> = loadConfig.loadParams;
-        if( method == LoadMethod.loadPdbId ){
-            if(params instanceof Array || params.pdbId == null)
-                throw loadConfig.loadMethod+": missing pdbId";
-        }else if( method == LoadMethod.loadPdbIds ){
-            if(!(params instanceof Array))
-                throw loadConfig.loadMethod+": Array object spected";
-            for(const d of params){
-                if(d.pdbId == null)
-                    throw loadConfig.loadMethod+": missing pdbId"
-            }
-        }else if( method == LoadMethod.loadStructureFromUrl ){
-            if(params instanceof Array || params.url == null || params.isBinary == null || params.format == null)
-                throw loadConfig.loadMethod+": arguments needed url, format, isBinary"
-        }else if( method == LoadMethod.loadSnapshotFromUrl ){
-            if(params instanceof Array || params.url == null || params.type == null)
-                throw loadConfig.loadMethod+": arguments needed url, type"
-        }else if( method == LoadMethod.loadStructureFromData ){
-            if(params instanceof Array || params.data == null || params.format == null || params.isBinary == null)
-                throw loadConfig.loadMethod+": arguments needed data, format, isBinary"
-        }
-        return true;
-    }
-
-    public setBackground(color: number) {
-    }
-
-    public select(modelId:string, labelAsymId: string, begin: number, end: number, mode: 'select'|'hover', operation:'add'|'set', operatorName?:string): void;
-    public select(selection: Array<SaguaroPosition>, mode: 'select'|'hover', operation:'add'|'set'): void;
-    public select(selection: Array<SaguaroRange>, mode: 'select'|'hover', operation:'add'|'set'): void;
-    public select(...args: any[]): void{
-        if(args.length >= 6){
-            this.selectRange(args[0],args[1],args[2],args[3],args[4],args[5]);
-        }else if(args.length === 3 && (args[0] as Array<any>).length > 0 && typeof (args[0] as Array<any>)[0].position === 'number'){
-            this.selectSet(args[0],args[1],args[2]);
-        }else if(args.length === 3 && (args[0] as Array<any>).length > 0 && typeof (args[0] as Array<any>)[0].begin === 'number'){
-            this.selectMultipleRanges(args[0],args[1],args[2]);
-        }
-    }
-    private selectRange(modelId:string, labelAsymId: string, begin: number, end: number, mode: 'select'|'hover', operation:'add'|'set', operatorName?:string): void {
-        if(mode == null || mode === 'select') {
-            this.innerSelectionFlag = true;
-        }
-        this.viewer.select({modelId:this.getModelId(modelId), labelAsymId: labelAsymId, labelSeqRange:{beg: begin, end:end}, operatorName: operatorName}, mode,operation);
-        this.innerSelectionFlag = false;
-    }
-    private selectSet(selection: Array<SaguaroPosition>, mode: 'select'|'hover', operation:'add'|'set'): void {
-        if(mode == null || mode === 'select') {
-            this.innerSelectionFlag = true;
-        }
-        this.viewer.select(selection.map(r=>({modelId: this.getModelId(r.modelId), labelSeqId:r.position, labelAsymId: r.labelAsymId, operatorName: r.operatorName})), mode, operation);
-        this.innerSelectionFlag = false;
-    }
-    private selectMultipleRanges(selection: Array<SaguaroRange>, mode: 'select'|'hover', operation:'add'|'set'): void {
-        if(mode == null || mode === 'select') {
-            this.innerSelectionFlag = true;
-        }
-        this.viewer.select(selection.map(r=>({modelId: this.getModelId(r.modelId), labelAsymId: r.labelAsymId, labelSeqRange:{beg:r.begin, end: r.end}, operatorName: r.operatorName})), mode, operation);
-        this.innerSelectionFlag = false;
-    }
-
-    public clearSelection(mode:'select'|'hover', option?:SaguaroChain): void {
-        if(mode === 'select') {
-            this.viewer.clearFocus();
-            this.innerSelectionFlag = true;
-        }
-        if(option != null)
-            this.viewer.clearSelection(mode, {...option, modelId: this.getModelId(option.modelId)});
-        else
-            this.viewer.clearSelection(mode);
-        this.innerSelectionFlag = false;
-    }
-
-    public setFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void{
-        this.viewer.setFocus({modelId: this.getModelId(modelId), labelAsymId: labelAsymId, labelSeqRange:{beg:begin, end: end}, operatorName: operatorName});
-    }
-    public clearFocus(): void {
-        this.viewer.clearFocus();
-    }
-
-    public cameraFocus(modelId: string, labelAsymId: string, positions:Array<number>, operatorName?:string): void;
-    public cameraFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void;
-    public cameraFocus(...args: any[]): void{
-        if(typeof args[3] === "number"){
-            this.focusRange(args[0],args[1],args[2],args[3],args[4]);
-        }else{
-            this.focusPositions(args[0],args[1],args[2],args[3]);
-        }
-    }
-    private focusPositions(modelId: string, labelAsymId: string, positions:Array<number>, operatorName?:string): void{
-        const structure: Structure | undefined = getStructureWithModelId(this.viewer.plugin.managers.structure.hierarchy.current.structures, this.getModelId(modelId));
-        if (structure == null) return;
-        const chainTests: Expression[] = [MS.core.rel.eq([MS.ammp('label_asym_id'), labelAsymId])];
-        if(operatorName)
-            chainTests.push(MS.core.rel.eq([operatorName, MS.acp('operatorName')]));
-        const sel: StructureSelection = Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
-            'chain-test': Q.core.logic.and(chainTests),
-            'residue-test': Q.core.set.has([MS.set(...SetUtils.toArray(new Set(positions))), MS.ammp('label_seq_id')])
-        }), structure);
-        const loci: Loci = StructureSelection.toLociWithSourceUnits(sel);
-        if(!StructureElement.Loci.isEmpty(loci))
-            this.viewer.plugin.managers.camera.focusLoci(loci);
-        else
-            this.viewer.plugin.managers.camera.reset();
-    }
-    private focusRange(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void{
-        const seqIds: Array<number> = new Array<number>();
-        for(let n = begin; n <= end; n++){
-            seqIds.push(n);
-        }
-        this.focusPositions(modelId, labelAsymId, seqIds, operatorName);
-    }
-
-    public async createComponent(componentLabel: string, modelId:string, labelAsymId: string, begin: number, end : number, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
-    public async createComponent(componentLabel: string, modelId:string, labelAsymId: string, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
-    public async createComponent(componentLabel: string, residues: Array<SaguaroPosition>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
-    public async createComponent(componentLabel: string, residues: Array<SaguaroRange>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
-    public async createComponent(...args: any[]): Promise<void> {
-        this.removeComponent(args[0]);
-        if(args.length === 3){
-            if( args[1] instanceof Array && args[1].length > 0 ) {
-                if(typeof args[1][0].position === "number"){
-                    await this.viewer.createComponent(args[0], args[1].map(r=>({modelId: this.getModelId(r.modelId), labelAsymId: r.labelAsymId, labelSeqId: r.position, operatorName: r.operatorName})), args[2]);
-                }else{
-                    await this.viewer.createComponent(args[0], args[1].map(r=>({modelId: this.getModelId(r.modelId), labelAsymId: r.labelAsymId, labelSeqRange:{beg:r.begin, end: r.end}, operatorName: r.operatorName})), args[2]);
-                }
-            }
-        }else if(args.length >= 6){
-            await this.viewer.createComponent(args[0], {modelId: this.getModelId(args[1]), labelAsymId: args[2], labelSeqRange:{beg:args[3], end:args[4]}, operatorName: args[6]}, args[5]);
-        }else{
-            await this.viewer.createComponent(args[0], {modelId: this.getModelId(args[1]), labelAsymId:args[2], operatorName: args[4]}, args[3]);
-        }
-        this.componentMap.set(args[0], this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups[this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups.length-1][0]);
-    }
-
-    public isComponent(componentLabel: string): boolean{
-        for(const c of this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups){
-            for(const comp of c){
-                if(comp.cell.obj?.label === componentLabel) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    public async colorComponent(componentLabel: string, color: ColorTheme.BuiltIn): Promise<void>{
-        for(const c of this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups){
-            for(const comp of c){
-                if(comp.cell.obj?.label === componentLabel) {
-                    await this.viewer.plugin.managers.structure.component.updateRepresentationsTheme([comp], { color: color });
-                    return;
-                }
-            }
-        }
-    }
-
-    public getComponentSet(): Set<string>{
-        const out: Set<string> = new Set<string>();
-        this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups.forEach((c)=>{
-            for(const comp of c){
-                if(comp.cell.obj?.label != null && out.has(comp.cell.obj?.label)) {
-                    break;
-                }else if(comp.cell.obj?.label != null){
-                    out.add(comp.cell.obj?.label);
-                }
-            }
-        });
-        return out;
-    }
-
-    public removeComponent(componentLabel?: string): void{
-        if(componentLabel == null){
-            this.componentMap.forEach((comp, id)=>{
-                this.viewer.removeComponent(id);
-                this.componentMap.delete(id);
-            })
-        }else{
-            this.viewer.removeComponent(componentLabel);
-            this.componentMap.delete(componentLabel);
-        }
-    }
-
-    public displayComponent(componentLabel: string): boolean;
-    public displayComponent(componentLabel: string, visibilityFlag: boolean): void;
-    public displayComponent(componentLabel: string, visibilityFlag?: boolean): void|boolean {
-        if(typeof visibilityFlag === 'boolean')
-            return this.changeComponentDisplay(componentLabel, visibilityFlag);
-        else
-            return this.getComponentDisplay(componentLabel);
-    }
-    private changeComponentDisplay(componentLabel: string, visibilityFlag: boolean): void{
-        if(this.componentMap.has(componentLabel) && this.getComponentDisplay(componentLabel) != visibilityFlag) {
-            this.viewer.plugin.managers.structure.component.toggleVisibility([this.componentMap.get(componentLabel)!]);
-        }else if(!this.componentMap.has(componentLabel)){
-            for (const c of this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups) {
-                for (const comp of c) {
-                    if(comp.cell.obj?.label === componentLabel) {
-                        if(!comp.cell.state.isHidden != visibilityFlag) {
-                            this.viewer.plugin.managers.structure.component.toggleVisibility(c);
-                            return void 0;
-                        }
-                    }
-                }
-            }
-        }
-    }
-    private getComponentDisplay(componentLabel: string): boolean | undefined{
-        if(this.componentMap.has(componentLabel)) {
-            return !this.componentMap.get(componentLabel)!.cell.state.isHidden!;
-        }
-    }
-
-    public setRepresentationChangeCallback(g:()=>void){
-    }
-
-    public setHoverCallback(g:()=>void){
-        this.viewer.plugin.behaviors.interaction.hover.subscribe((r)=>{
-            const sequenceData: Array<SaguaroSet> = new Array<SaguaroSet>();
-            const loci:Loci = r.current.loci;
-            if(StructureElement.Loci.is(loci)){
-                const loc = StructureElement.Location.create(loci.structure);
-                for (const e of loci.elements) {
-                    const modelId: string = e.unit?.model?.id;
-                    const seqIds = new Set<number>();
-                    loc.unit = e.unit;
-                    for (let i = 0, il = OrderedSet.size(e.indices); i < il; ++i) {
-                        loc.element = e.unit.elements[OrderedSet.getAt(e.indices, i)];
-                        seqIds.add(SP.residue.label_seq_id(loc));
-                    }
-                    sequenceData.push({
-                        modelId: this.getModelId(modelId),
-                        labelAsymId: SP.chain.label_asym_id(loc),
-                        operatorName: SP.unit.operator_name(loc),
-                        seqIds
-                    });
-                }
-            }
-            this.selection.setSelectionFromResidueSelection(sequenceData, 'hover', 'structure');
-            g();
-        });
-    }
-
-    public setSelectCallback(g:(flag?:boolean)=>void){
-        this.selectCallbackSubs = this.viewer.plugin.managers.structure.selection.events.changed.subscribe(()=>{
-            if(this.innerSelectionFlag) {
-                return;
-            }
-            if(this.viewer.plugin.managers.structure.selection.additionsHistory.length > 0) {
-                const currentLoci: Loci = this.viewer.plugin.managers.structure.selection.additionsHistory[0].loci;
-                const loc: StructureElement.Location = StructureElement.Location.create(currentLoci.structure);
-                StructureElement.Location.set(
-                    loc,
-                    currentLoci.structure,
-                    currentLoci.elements[0].unit,
-                    currentLoci.elements[0].unit.elements[OrderedSet.getAt(currentLoci.elements[0].indices,0)]
-                );
-                const currentModelId: string = this.getModelId(currentLoci.structure.model.id);
-                if(currentLoci.elements.length > 0)
-                    if(SP.entity.type(loc) === 'non-polymer') {
-                        const resAuthId: number = SP.residue.auth_seq_id(loc);
-                        const chainLabelId: string = SP.chain.label_asym_id(loc);
-                        const query: StructureQuery = Q.modifiers.includeSurroundings(
-                            Q.generators.residues({
-                                residueTest:l=>SP.residue.auth_seq_id(l.element) === resAuthId,
-                                chainTest:l=>SP.chain.label_asym_id(l.element) === chainLabelId
-                            }),
-                            {
-                                radius: 5,
-                                wholeResidues: true
-                            });
-                        this.innerSelectionFlag = true;
-                        const sel: StructureSelection = StructureQuery.run(query, currentLoci.structure);
-                        const surroundingsLoci: Loci = StructureSelection.toLociWithSourceUnits(sel);
-                        this.viewer.plugin.managers.structure.selection.fromLoci('add', surroundingsLoci);
-                        const surroundingsLoc = StructureElement.Location.create(surroundingsLoci.structure);
-                        for (const e of surroundingsLoci.elements) {
-                            StructureElement.Location.set(surroundingsLoc, surroundingsLoci.structure, e.unit, e.unit.elements[0]);
-                            if(SP.entity.type(surroundingsLoc) === 'polymer'){
-                                this.selection.setLastSelection('select', {
-                                    modelId: currentModelId,
-                                    labelAsymId: SP.chain.label_asym_id(surroundingsLoc),
-                                    regions: []
-                                });
-                            }
-                        }
-                        this.innerSelectionFlag = false;
-                    }else if( SP.entity.type(loc) === 'polymer' ) {
-                        this.selection.setLastSelection('select', {
-                            modelId: currentModelId,
-                            labelAsymId: SP.chain.label_asym_id(loc),
-                            operatorName: SP.unit.operator_name(loc),
-                            regions: []
-                        });
-                    }else{
-                        this.selection.setLastSelection('select', null);
-                    }
-            }else{
-                this.selection.setLastSelection('select', null);
-            }
-            const sequenceData: Array<SaguaroSet> = new Array<SaguaroSet>();
-            for(const structure of this.viewer.plugin.managers.structure.hierarchy.current.structures){
-                const data: Structure | undefined = structure.cell.obj?.data;
-                if(data == null) return;
-                const loci: Loci = this.viewer.plugin.managers.structure.selection.getLoci(data);
-                if(StructureElement.Loci.is(loci)){
-                    const loc = StructureElement.Location.create(loci.structure);
-                    for (const e of loci.elements) {
-                        StructureElement.Location.set(loc, loci.structure, e.unit, e.unit.elements[0]);
-                        const seqIds = new Set<number>();
-                        for (let i = 0, il = OrderedSet.size(e.indices); i < il; ++i) {
-                            loc.element = e.unit.elements[OrderedSet.getAt(e.indices, i)];
-                            seqIds.add(SP.residue.label_seq_id(loc));
-                        }
-                        sequenceData.push({
-                            modelId: this.getModelId(data.model.id),
-                            labelAsymId: SP.chain.label_asym_id(loc),
-                            operatorName: SP.unit.operator_name(loc),
-                            seqIds
-                        });
-                    }
-
-                }
-            }
-            this.selection.setSelectionFromResidueSelection(sequenceData, 'select', 'structure');
-            g();
-        });
-    }
-
-    public pluginCall(f: (plugin: PluginContext) => void){
-        this.viewer.pluginCall(f);
-    }
-
-    public setModelChangeCallback(f:(modelMap:SaguaroPluginModelMapType)=>void){
-        this.modelChangeCallback = f;
-        this.modelChangeCallbackSubs = this.viewer.plugin.state.events.object.updated.subscribe((o:{obj: StateObject, action: "in-place" | "recreate"})=>{
-            if(this.loadingFlag)
-                return;
-            if(o.obj.type.name === "Behavior" && o.action === "in-place") {
-                f(this.getChains());
-            }else if(o.obj.type.name === "Model" && o.action === "in-place"){
-                f(this.getChains());
-            }
-        });
-    }
-
-    private getChains(): SaguaroPluginModelMapType{
-        const structureRefList = getStructureOptions(this.viewer.plugin);
-        const out: SaguaroPluginModelMapType = new Map<string, {entryId: string; chains: Array<ChainInfo>; assemblyId:string;}>();
-        structureRefList.forEach((structureRef,i)=>{
-            const structure: Structure = getStructure(structureRef[0], this.viewer.plugin.state.data);
-            let modelEntityId = getModelEntityOptions(structure)[0][0];
-            const chains: [{modelId:string;entryId:string;assemblyId:string;},ChainInfo[]] = getChainValues(structure, modelEntityId);
-            out.set(this.getModelId(chains[0].modelId),{entryId:chains[0].entryId, assemblyId:chains[0].assemblyId, chains: chains[1]});
-        });
-        return out;
-    }
-
-    private mapModels(loadParams: LoadParams | Array<LoadParams>): void{
-        const loadParamList: Array<LoadParams> = loadParams instanceof Array ? loadParams : [loadParams];
-        const structureRefList = getStructureOptions(this.viewer.plugin);
-        if(loadParamList.length == structureRefList.length )
-            structureRefList.forEach((structureRef,i)=>{
-                const structure = getStructure(structureRef[0], this.viewer.plugin.state.data);
-                let modelEntityId = getModelEntityOptions(structure)[0][0];
-                const chains: [{modelId:string, entryId:string},ChainInfo[]] = getChainValues(structure, modelEntityId);
-                if(!this.modelMap.has(chains[0].modelId)) {
-                    this.modelMap.set(chains[0].modelId, loadParamList[i].id);
-                    if (loadParamList[i].id != null)
-                        this.modelMap.set(loadParamList[i].id!, chains[0].modelId);
-                }
-            });
-    }
-
-    private getModelId(id: string): string{
-        return this.modelMap.get(id) ?? id;
-    }
-
-    public unsetCallbacks(): void {
-        this.selectCallbackSubs?.unsubscribe();
-        this.modelChangeCallbackSubs?.unsubscribe();
-    }
-
-    public resetCamera(): void {
-        this.viewer.plugin.managers.camera.reset();
-    }
-
-}
-
-function getStructureOptions(plugin: PluginContext): [string,string][] {
-    const options: [string, string][] = [];
-    plugin.managers.structure.hierarchy.current.structures.forEach(s=>{
-        options.push([s.cell.transform.ref, s.cell.obj!.data.label]);
-    })
-    return options;
-}
-
-function getChainValues(structure: Structure, modelEntityId: string): [{modelId:string; entryId:string; assemblyId:string;},ChainInfo[]] {
-    const chains: Map<number, ChainInfo> = new Map<number, ChainInfo>();
-    const l = StructureElement.Location.create(structure);
-    let assemblyId:string = "-";
-    const [modelIdx, entityId] = splitModelEntityId(modelEntityId);
-    for (const unit of structure.units) {
-        StructureElement.Location.set(l, structure, unit, unit.elements[0]);
-        assemblyId = SP.unit.pdbx_struct_assembly_id(l);
-        if (structure.getModelIndex(unit.model) !== modelIdx) continue;
-        const chId: number = unit.chainGroupId;
-        if(chains.has(chId)){
-           chains.get(chId)!.operators.push(opKey(l))
-        }else{
-            chains.set(chId, {label:SP.chain.label_asym_id(l), auth:SP.chain.auth_asym_id(l), entityId: SP.entity.id(l), title: SP.entity.pdbx_description(l).join("|"), type: SP.entity.type(l), operators:[opKey(l)]});
-        }
-    }
-    const id: {modelId:string; entryId:string; assemblyId:string;} = {modelId:l.unit?.model?.id, entryId: l.unit?.model?.entryId, assemblyId: assemblyId};
-    return [id,Array.from(chains.values())];
-}
-
-function getStructureWithModelId(structures: StructureRef[], modelId: string): Structure|undefined{
-    for(const structure of structures){
-        if(!structure.cell?.obj?.data?.units)
-            continue;
-        const unit =  structure.cell.obj.data.units[0];
-        const id:string = unit.model.id;
-        if(id === modelId)
-            return structure.cell.obj.data
-    }
-}
-
-function getStructure(ref: string, state: State) {
-    const cell = state.select(ref)[0];
-    if (!ref || !cell || !cell.obj) return Structure.Empty;
-    return (cell.obj as PSO.Molecule.Structure).data;
-}
-
-function getModelEntityOptions(structure: Structure):[string, string][] {
-    const options: [string, string][] = [];
-    const l = StructureElement.Location.create(structure);
-    const seen = new Set<string>();
-    for (const unit of structure.units) {
-        StructureElement.Location.set(l, structure, unit, unit.elements[0]);
-        const id = SP.entity.id(l);
-        const modelIdx = structure.getModelIndex(unit.model);
-        const key = `${modelIdx}|${id}`;
-        if (seen.has(key)) continue;
-        let description = SP.entity.pdbx_description(l).join(', ');
-        if (structure.models.length) {
-            if (structure.representativeModel) { // indicates model trajectory
-                description += ` (Model ${structure.models[modelIdx].modelNum})`;
-            } else  if (description.startsWith('Polymer ')) { // indicates generic entity name
-                description += ` (${structure.models[modelIdx].entry})`;
-            }
-        }
-        const label = `${id}: ${description}`;
-        options.push([ key, label ]);
-        seen.add(key);
-    }
-    if (options.length === 0) options.push(['', 'No entities']);
-    return options;
-}
-
-function splitModelEntityId(modelEntityId: string) {
-    const [ modelIdx, entityId ] = modelEntityId.split('|');
-    return [ parseInt(modelIdx), entityId ];
-}
-
-function opKey(l: StructureElement.Location): OperatorInfo {
-    const ids = SP.unit.pdbx_struct_oper_list_ids(l);
-    const ncs = SP.unit.struct_ncs_oper_id(l);
-    const hkl = SP.unit.hkl(l);
-    const spgrOp = SP.unit.spgrOp(l);
-    const name = SP.unit.operator_name(l);
-    return {ids:ids,name:name};
-}

+ 82 - 0
src/RcsbFvStructure/StructureViewerInterface.ts

@@ -0,0 +1,82 @@
+import {PluginContext} from "molstar/lib/mol-plugin/context";
+import {StructureRepresentationRegistry} from "molstar/lib/mol-repr/structure/registry";
+import {ColorTheme} from "molstar/lib/mol-theme/color";
+import {RcsbFvSelectorManager, RegionSelectionInterface} from "../RcsbFvSelection/RcsbFvSelectorManager";
+
+export type ChainType = "polymer"|"water"|"branched"|"non-polymer"|"macrolide";
+export type OperatorInfo = {ids:string[], name: string};
+export type ChainInfo = {auth:string;label:string;entityId:string;title:string;type:ChainType;operators:OperatorInfo[]};
+export type SaguaroPluginModelMapType = Map<string,{entryId: string; assemblyId: string, chains:Array<ChainInfo>;}>;
+
+export interface SaguaroChain {
+    modelId: string;
+    labelAsymId: string;
+    operatorName?: string;
+}
+
+export interface SaguaroPosition extends SaguaroChain{
+    position: number;
+}
+
+export interface SaguaroRange extends SaguaroChain {
+    begin: number;
+    end: number;
+}
+
+export interface SaguaroSet extends SaguaroChain{
+    seqIds: Set<number>;
+}
+
+export interface SaguaroRegionList extends SaguaroChain{
+    regions: Array<RegionSelectionInterface>;
+}
+
+export interface StructureViewerInterface<R,S> extends StructureViewerPublicInterface<R>,ViewerCallbackManagerInterface {
+    init: (selection: RcsbFvSelectorManager, args:S) => void;
+}
+
+export interface StructureViewerPublicInterface<T> extends ViewerActionManagerInterface<T>{}
+
+export interface ViewerManagerFactoryInterface<R,S extends {}> {
+    getViewerManagerFactory(selection: RcsbFvSelectorManager, args: S): {callbackManager:ViewerCallbackManagerInterface;actionManager:ViewerActionManagerInterface<R>};
+}
+
+export interface ViewerCallbackManagerInterface {
+    setRepresentationChangeCallback(g:()=>void): void;
+    setHoverCallback(g:()=>void): void;
+    setSelectCallback(g:(flag?:boolean)=>void): void;
+    pluginCall(f: (plugin: PluginContext) => void): void;
+    setModelChangeCallback(f:(modelMap:SaguaroPluginModelMapType)=>void): void;
+    getModelChangeCallback():(modelMap:SaguaroPluginModelMapType)=>void;
+    unsetCallbacks(): void;
+}
+
+export interface ViewerActionManagerInterface<R> {
+    load(loadConfig: R|Array<R>): Promise<void>;
+    select(modelId:string, labelAsymId: string, begin: number, end: number, mode: 'select'|'hover', operation:'add'|'set', operatorName?:string): void;
+    select(selection: Array<SaguaroPosition>, mode: 'select'|'hover', operation:'add'|'set'): void;
+    select(selection: Array<SaguaroRange>, mode: 'select'|'hover', operation:'add'|'set'): void;
+    clear(): Promise<void>;
+    clearSelection(mode:'select'|'hover', option?:SaguaroChain): void;
+    setFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void;
+    clearFocus(): void;
+    cameraFocus(modelId: string, labelAsymId: string, positions:Array<number>, operatorName?:string): void;
+    cameraFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void;
+    createComponent(componentLabel: string, modelId:string, labelAsymId: string, begin: number, end : number, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
+    createComponent(componentLabel: string, modelId:string, labelAsymId: string, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
+    createComponent(componentLabel: string, residues: Array<SaguaroPosition>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
+    createComponent(componentLabel: string, residues: Array<SaguaroRange>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
+    isComponent(componentLabel: string): boolean;
+    colorComponent(componentLabel: string, color: ColorTheme.BuiltIn): Promise<void>;
+    getComponentSet(): Set<string>;
+    removeComponent(componentLabel?: string): Promise<void>;
+    displayComponent(componentLabel: string): boolean;
+    displayComponent(componentLabel: string, visibilityFlag: boolean): void;
+    resetCamera(): void;
+}
+
+export interface ViewerModelMapManagerInterface<R> {
+    add(lC: R): void;
+    getChains(): SaguaroPluginModelMapType;
+    getModelId(id: string): string;
+}

+ 335 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarActionManager.ts

@@ -0,0 +1,335 @@
+import {
+    SaguaroChain,
+    SaguaroPosition,
+    SaguaroRange,
+    ViewerActionManagerInterface, ViewerCallbackManagerInterface,
+    ViewerModelMapManagerInterface
+} from "../../StructureViewerInterface";
+import {Viewer} from "@rcsb/rcsb-molstar/build/src/viewer";
+import {RcsbFvSelectorManager} from "../../../RcsbFvSelection/RcsbFvSelectorManager";
+import {DataContainer, DataContainerReader} from "../../../Utils/DataContainer";
+import {MolstarModelMapManager} from "./MolstarModelMapManager";
+import {Structure, StructureElement, StructureSelection} from "molstar/lib/mol-model/structure";
+import {Expression} from "molstar/lib/commonjs/mol-script/language/expression";
+import {MolScriptBuilder as MS} from "molstar/lib/mol-script/language/builder";
+import {Script} from "molstar/lib/mol-script/script";
+import {SetUtils} from "molstar/lib/mol-util/set";
+import {Loci} from "molstar/lib/mol-model/loci";
+import {StructureComponentRef, StructureRef} from "molstar/lib/mol-plugin-state/manager/structure/hierarchy-state";
+import {ColorTheme} from "molstar/lib/mol-theme/color";
+import {StructureRepresentationRegistry} from "molstar/lib/mol-repr/structure/registry";
+import {PresetProps} from "@rcsb/rcsb-molstar/build/src/viewer/helpers/preset";
+import {Mat4} from "molstar/lib/mol-math/linear-algebra";
+import {BuiltInTrajectoryFormat} from "molstar/lib/mol-plugin-state/formats/trajectory";
+import {PluginState} from "molstar/lib/mol-plugin/state";
+import {TrajectoryHierarchyPresetProvider} from "molstar/lib/mol-plugin-state/builder/structure/hierarchy-preset";
+
+export enum LoadMethod {
+    loadPdbId = "loadPdbId",
+    loadPdbIds = "loadPdbIds",
+    loadStructureFromUrl = "loadStructureFromUrl",
+    loadSnapshotFromUrl = "loadSnapshotFromUrl",
+    loadStructureFromData = "loadStructureFromData"
+}
+
+export interface LoadMolstarInterface {
+    loadMethod: LoadMethod;
+    loadParams: LoadParams | Array<LoadParams>;
+}
+
+interface LoadParams<P=any,S={}> {
+    pdbId?: string;
+    props?: PresetProps;
+    matrix?: Mat4;
+    url?: string,
+    format?: BuiltInTrajectoryFormat,
+    isBinary?: boolean,
+    type?: PluginState.SnapshotType,
+    data?: string | number[]
+    id?:string;
+    reprProvider?: TrajectoryHierarchyPresetProvider<P,S>;
+    params?:P;
+}
+
+export class MolstarActionManager implements ViewerActionManagerInterface<LoadMolstarInterface>{
+
+    private readonly viewer: Viewer;
+
+    private readonly innerSelectionFlag: DataContainer<boolean>;
+    private readonly modelMapManager: ViewerModelMapManagerInterface<LoadMolstarInterface>;
+    private readonly callbackManager: ViewerCallbackManagerInterface;
+    private readonly componentMap: Map<string, StructureComponentRef> = new Map<string, StructureComponentRef>();
+    private readonly loadingFlag: DataContainer<boolean>;
+
+    constructor(config:{viewer: Viewer;modelMapManager: ViewerModelMapManagerInterface<LoadMolstarInterface>;innerSelectionFlag: DataContainer<boolean>; loadingFlag: DataContainer<boolean>; callbackManager: ViewerCallbackManagerInterface;}) {
+        this.viewer = config.viewer;
+        this.modelMapManager = config.modelMapManager;
+        this.innerSelectionFlag = config.innerSelectionFlag;
+        this.loadingFlag = config.loadingFlag;
+        this.callbackManager = config.callbackManager;
+    }
+
+    async load(loadConfig: LoadMolstarInterface|Array<LoadMolstarInterface>): Promise<void>{
+        this.loadingFlag.set(true);
+        for (const lC of (Array.isArray(loadConfig) ? loadConfig : [loadConfig])) {
+            if(checkLoadData(lC)) {
+                if (lC.loadMethod == LoadMethod.loadPdbId) {
+                    const config: LoadParams = lC.loadParams as LoadParams;
+                    await this.viewer.loadPdbId(config.pdbId!, {props: config.props, matrix: config.matrix, reprProvider: config.reprProvider, params: config.params});
+                } else if (lC.loadMethod == LoadMethod.loadPdbIds) {
+                    const config: Array<LoadParams> = lC.loadParams as Array<LoadParams>;
+                    await this.viewer.loadPdbIds(config.map((d) => {
+                        return {pdbId: d.pdbId!, config:{props: d.props, matrix: d.matrix, reprProvider: d.reprProvider, params: d.params}}
+                    }));
+                } else if (lC.loadMethod == LoadMethod.loadStructureFromUrl) {
+                    const config: LoadParams = lC.loadParams as LoadParams;
+                    await this.viewer.loadStructureFromUrl(config.url!, config.format!, config.isBinary!,{props: config.props, matrix: config.matrix, reprProvider: config.reprProvider, params: config.params});
+                } else if (lC.loadMethod == LoadMethod.loadSnapshotFromUrl) {
+                    const config: LoadParams = lC.loadParams as LoadParams;
+                    await this.viewer.loadSnapshotFromUrl(config.url!, config.type!);
+                } else if (lC.loadMethod == LoadMethod.loadStructureFromData) {
+                    const config: LoadParams = lC.loadParams as LoadParams;
+                    await this.viewer.loadStructureFromData(config.data!, config.format!, config.isBinary!, {props: config.props, matrix: config.matrix, reprProvider: config.reprProvider, params: config.params});
+                }
+                this.modelMapManager.add(lC);
+            }
+        }
+        this.loadingFlag.set(false);
+        this.callbackManager.getModelChangeCallback()(this.modelMapManager.getChains());
+    }
+
+    public select(modelId:string, labelAsymId: string, begin: number, end: number, mode: 'select'|'hover', operation:'add'|'set', operatorName?:string): void;
+    public select(selection: Array<SaguaroPosition>, mode: 'select'|'hover', operation:'add'|'set'): void;
+    public select(selection: Array<SaguaroRange>, mode: 'select'|'hover', operation:'add'|'set'): void;
+    public select(...args: any[]): void{
+        if(args[5] != undefined){
+            this.selectRange(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
+        }else if(Array.isArray(args[0]) && args[0].length > 0 && typeof args[0][0].position === 'number'){
+            this.selectSet(args[0],args[1],args[2]);
+        }else if(Array.isArray(args[0]) && args[0].length > 0 && typeof args[0][0].begin === 'number'){
+            this.selectMultipleRanges(args[0],args[1],args[2]);
+        }
+    }
+    private selectRange(modelId:string, labelAsymId: string, begin: number, end: number, mode: 'select'|'hover', operation:'add'|'set', operatorName?:string): void {
+        if(mode == null || mode === 'select') {
+            this.innerSelectionFlag.set(true);
+        }
+        this.viewer.select({modelId:this.modelMapManager.getModelId(modelId), labelAsymId: labelAsymId, labelSeqRange:{beg: begin, end:end}, operatorName: operatorName}, mode,operation);
+        this.innerSelectionFlag.set(false);
+    }
+    private selectSet(selection: Array<SaguaroPosition>, mode: 'select'|'hover', operation:'add'|'set'): void {
+        if(mode == null || mode === 'select') {
+            this.innerSelectionFlag.set(true);
+        }
+        this.viewer.select(selection.map(r=>({modelId: this.modelMapManager.getModelId(r.modelId), labelSeqId:r.position, labelAsymId: r.labelAsymId, operatorName: r.operatorName})), mode, operation);
+        this.innerSelectionFlag.set(false);
+    }
+    private selectMultipleRanges(selection: Array<SaguaroRange>, mode: 'select'|'hover', operation:'add'|'set'): void {
+        if(mode == null || mode === 'select') {
+            this.innerSelectionFlag.set(true);
+        }
+        this.viewer.select(selection.map(r=>({modelId: this.modelMapManager.getModelId(r.modelId), labelAsymId: r.labelAsymId, labelSeqRange:{beg:r.begin, end: r.end}, operatorName: r.operatorName})), mode, operation);
+        this.innerSelectionFlag.set(false);
+    }
+
+    public async clear(): Promise<void>{
+        await this.viewer.clear();
+    }
+
+    public clearSelection(mode:'select'|'hover', option?:SaguaroChain): void {
+        if(mode === 'select') {
+            this.viewer.clearFocus();
+            this.innerSelectionFlag.set(true);
+        }
+        if(option != null)
+            this.viewer.clearSelection(mode, {...option, modelId: this.modelMapManager.getModelId(option.modelId)});
+        else
+            this.viewer.clearSelection(mode);
+        this.innerSelectionFlag.set(false);
+    }
+
+    public setFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void{
+        this.viewer.setFocus({modelId: this.modelMapManager.getModelId(modelId), labelAsymId: labelAsymId, labelSeqRange:{beg:begin, end: end}, operatorName: operatorName});
+    }
+
+    public clearFocus(): void {
+        this.viewer.clearFocus();
+    }
+
+    public cameraFocus(modelId: string, labelAsymId: string, positions:Array<number>, operatorName?:string): void;
+    public cameraFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void;
+    public cameraFocus(...args: any[]): void{
+        if(Array.isArray(args[2])){
+            this.focusPositions(args[0],args[1],args[2],args[3]);
+        }else{
+            this.focusRange(args[0],args[1],args[2],args[3],args[4]);
+        }
+    }
+    private focusRange(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void{
+        const seqIds: Array<number> = new Array<number>();
+        for(let n = begin; n <= end; n++){
+            seqIds.push(n);
+        }
+        this.focusPositions(modelId, labelAsymId, seqIds, operatorName);
+    }
+    private focusPositions(modelId: string, labelAsymId: string, positions:Array<number>, operatorName?:string): void{
+        const structure: Structure | undefined = getStructureWithModelId(this.viewer.plugin.managers.structure.hierarchy.current.structures, this.modelMapManager.getModelId(modelId));
+        if (structure == null) return;
+        const chainTests: Expression[] = [MS.core.rel.eq([MS.ammp('label_asym_id'), labelAsymId])];
+        if(operatorName)
+            chainTests.push(MS.core.rel.eq([operatorName, MS.acp('operatorName')]));
+        const sel: StructureSelection = Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
+            'chain-test': Q.core.logic.and(chainTests),
+            'residue-test': Q.core.set.has([MS.set(...SetUtils.toArray(new Set(positions))), MS.ammp('label_seq_id')])
+        }), structure);
+        const loci: Loci = StructureSelection.toLociWithSourceUnits(sel);
+        if(!StructureElement.Loci.isEmpty(loci)) {
+            this.viewer.plugin.managers.camera.focusLoci(loci);
+        }else{
+            this.resetCamera();
+        }
+    }
+
+    public async createComponent(componentLabel: string, modelId:string, labelAsymId: string, begin: number, end : number, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
+    public async createComponent(componentLabel: string, modelId:string, labelAsymId: string, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
+    public async createComponent(componentLabel: string, residues: Array<SaguaroPosition>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
+    public async createComponent(componentLabel: string, residues: Array<SaguaroRange>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
+    public async createComponent(...args: any[]): Promise<void> {
+        await this.removeComponent(args[0]);
+        if(Array.isArray(args[1])){
+            if( args[1].length > 0 ) {
+                if(typeof args[1][0].position === "number"){
+                    await this.viewer.createComponent(args[0], args[1].map(r=>({modelId: this.modelMapManager.getModelId(r.modelId), labelAsymId: r.labelAsymId, labelSeqId: r.position, operatorName: r.operatorName})), args[2]);
+                }else{
+                    await this.viewer.createComponent(args[0], args[1].map(r=>({modelId: this.modelMapManager.getModelId(r.modelId), labelAsymId: r.labelAsymId, labelSeqRange:{beg:r.begin, end: r.end}, operatorName: r.operatorName})), args[2]);
+                }
+            }
+        }else if(args[5] != undefined){
+            await this.viewer.createComponent(args[0], {modelId: this.modelMapManager.getModelId(args[1]), labelAsymId: args[2], labelSeqRange:{beg:args[3], end:args[4]}, operatorName: args[6]}, args[5]);
+        }else{
+            await this.viewer.createComponent(args[0], {modelId: this.modelMapManager.getModelId(args[1]), labelAsymId:args[2], operatorName: args[4]}, args[3]);
+        }
+        this.componentMap.set(args[0], this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups[this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups.length-1][0]);
+    }
+
+    public isComponent(componentLabel: string): boolean{
+        for(const c of this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups){
+            for(const comp of c){
+                if(comp.cell.obj?.label === componentLabel) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public async colorComponent(componentLabel: string, color: ColorTheme.BuiltIn): Promise<void>{
+        for(const c of this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups){
+            for(const comp of c){
+                if(comp.cell.obj?.label === componentLabel) {
+                    await this.viewer.plugin.managers.structure.component.updateRepresentationsTheme([comp], { color: color });
+                    return;
+                }
+            }
+        }
+    }
+
+    public getComponentSet(): Set<string>{
+        const out: Set<string> = new Set<string>();
+        this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups.forEach((c)=>{
+            for(const comp of c){
+                if(comp.cell.obj?.label != null && out.has(comp.cell.obj?.label)) {
+                    break;
+                }else if(comp.cell.obj?.label != null){
+                    out.add(comp.cell.obj?.label);
+                }
+            }
+        });
+        return out;
+    }
+
+    public async removeComponent(componentLabel?: string): Promise<void>{
+        if(componentLabel == null){
+            await Promise.all(Array.from(this.componentMap.entries()).map(async ([id,comp], n)=>{
+                await this.viewer.removeComponent(id);
+                this.componentMap.delete(id);
+            }))
+        }else{
+            await this.viewer.removeComponent(componentLabel);
+            this.componentMap.delete(componentLabel);
+        }
+    }
+
+    public displayComponent(componentLabel: string): boolean;
+    public displayComponent(componentLabel: string, visibilityFlag: boolean): void;
+    public displayComponent(componentLabel: string, visibilityFlag?: boolean): void|boolean {
+        if(typeof visibilityFlag === 'boolean')
+            return this.changeComponentDisplay(componentLabel, visibilityFlag);
+        else
+            return this.getComponentDisplay(componentLabel);
+    }
+    private changeComponentDisplay(componentLabel: string, visibilityFlag: boolean): void{
+        if(this.componentMap.has(componentLabel) && this.getComponentDisplay(componentLabel) != visibilityFlag) {
+            this.viewer.plugin.managers.structure.component.toggleVisibility([this.componentMap.get(componentLabel)!]);
+        }else if(!this.componentMap.has(componentLabel)){
+            for (const c of this.viewer.plugin.managers.structure.hierarchy.currentComponentGroups) {
+                for (const comp of c) {
+                    if(comp.cell.obj?.label === componentLabel) {
+                        if(!comp.cell.state.isHidden != visibilityFlag) {
+                            this.viewer.plugin.managers.structure.component.toggleVisibility(c);
+                            return void 0;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    private getComponentDisplay(componentLabel: string): boolean | undefined{
+        if(this.componentMap.has(componentLabel)) {
+            return !this.componentMap.get(componentLabel)!.cell.state.isHidden!;
+        }
+    }
+
+    public resetCamera(): void {
+        this.viewer.plugin.managers.camera.reset();
+    }
+
+}
+
+function getStructureWithModelId(structures: StructureRef[], modelId: string): Structure|undefined{
+    for(const structure of structures){
+        if(!structure.cell?.obj?.data?.units)
+            continue;
+        const unit =  structure.cell.obj.data.units[0];
+        const id:string = unit.model.id;
+        if(id === modelId)
+            return structure.cell.obj.data
+    }
+}
+
+
+function checkLoadData(loadConfig: LoadMolstarInterface): boolean{
+    const method: LoadMethod = loadConfig.loadMethod;
+    const params: LoadParams | Array<LoadParams> = loadConfig.loadParams;
+    if( method == LoadMethod.loadPdbId ){
+        if(params instanceof Array || params.pdbId == null)
+            throw loadConfig.loadMethod+": missing pdbId";
+    }else if( method == LoadMethod.loadPdbIds ){
+        if(!(params instanceof Array))
+            throw loadConfig.loadMethod+": Array object spected";
+        for(const d of params){
+            if(d.pdbId == null)
+                throw loadConfig.loadMethod+": missing pdbId"
+        }
+    }else if( method == LoadMethod.loadStructureFromUrl ){
+        if(params instanceof Array || params.url == null || params.isBinary == null || params.format == null)
+            throw loadConfig.loadMethod+": arguments needed url, format, isBinary"
+    }else if( method == LoadMethod.loadSnapshotFromUrl ){
+        if(params instanceof Array || params.url == null || params.type == null)
+            throw loadConfig.loadMethod+": arguments needed url, type"
+    }else if( method == LoadMethod.loadStructureFromData ){
+        if(params instanceof Array || params.data == null || params.format == null || params.isBinary == null)
+            throw loadConfig.loadMethod+": arguments needed data, format, isBinary"
+    }
+    return true;
+}

+ 189 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarCallbackManager.ts

@@ -0,0 +1,189 @@
+import {
+    SaguaroPluginModelMapType,
+    SaguaroSet,
+    ViewerCallbackManagerInterface,
+    ViewerModelMapManagerInterface
+} from "../../StructureViewerInterface";
+import {Loci} from "molstar/lib/mol-model/loci";
+import {
+    Structure,
+    StructureElement,
+    StructureProperties as SP,
+    StructureQuery,
+    StructureSelection
+} from "molstar/lib/mol-model/structure";
+import {OrderedSet} from "molstar/lib/mol-data/int";
+import {Queries as Q} from "molstar/lib/mol-model/structure/query";
+import {PluginContext} from "molstar/lib/mol-plugin/context";
+import {StateObject} from "molstar/lib/mol-state";
+import {Viewer} from "@rcsb/rcsb-molstar/build/src/viewer";
+import {Subscription} from "rxjs";
+import {RcsbFvSelectorManager} from "../../../RcsbFvSelection/RcsbFvSelectorManager";
+import {DataContainer, DataContainerReader} from "../../../Utils/DataContainer";
+import {MolstarModelMapManager} from "./MolstarModelMapManager";
+
+
+export class MolstarCallbackManager implements ViewerCallbackManagerInterface{
+
+    private readonly viewer: Viewer;
+    private readonly selection: RcsbFvSelectorManager;
+    private readonly loadingFlag: DataContainerReader<boolean>;
+    private readonly modelMapManager: Omit<ViewerModelMapManagerInterface<null>,'add'>;
+    private readonly innerSelectionFlag: DataContainer<boolean>;
+
+    private selectCallbackSubs: Subscription;
+    private modelChangeCallbackSubs: Subscription;
+    private modelChangeCallback: (chainMap:SaguaroPluginModelMapType)=>void;
+
+    constructor(config:{viewer: Viewer;selection: RcsbFvSelectorManager;loadingFlag: DataContainerReader<boolean>;modelMapManager: Omit<ViewerModelMapManagerInterface<null>,'add'>;innerSelectionFlag: DataContainer<boolean>;}) {
+        this.viewer = config.viewer;
+        this.selection = config.selection;
+        this.loadingFlag = config.loadingFlag;
+        this.modelMapManager = config.modelMapManager;
+        this.innerSelectionFlag = config.innerSelectionFlag;
+    }
+
+    public setRepresentationChangeCallback(g:()=>void){
+    }
+
+    public setHoverCallback(g:()=>void){
+        this.viewer.plugin.behaviors.interaction.hover.subscribe((r)=>{
+            const sequenceData: Array<SaguaroSet> = new Array<SaguaroSet>();
+            const loci:Loci = r.current.loci;
+            if(StructureElement.Loci.is(loci)){
+                const loc = StructureElement.Location.create(loci.structure);
+                for (const e of loci.elements) {
+                    const modelId: string = e.unit?.model?.id;
+                    const seqIds = new Set<number>();
+                    loc.unit = e.unit;
+                    for (let i = 0, il = OrderedSet.size(e.indices); i < il; ++i) {
+                        loc.element = e.unit.elements[OrderedSet.getAt(e.indices, i)];
+                        seqIds.add(SP.residue.label_seq_id(loc));
+                    }
+                    sequenceData.push({
+                        modelId: this.modelMapManager.getModelId(modelId),
+                        labelAsymId: SP.chain.label_asym_id(loc),
+                        operatorName: SP.unit.operator_name(loc),
+                        seqIds
+                    });
+                }
+            }
+            this.selection.setSelectionFromResidueSelection(sequenceData, 'hover', 'structure');
+            g();
+        });
+    }
+
+    public setSelectCallback(g:(flag?:boolean)=>void){
+        this.selectCallbackSubs = this.viewer.plugin.managers.structure.selection.events.changed.subscribe(()=>{
+            if(this.innerSelectionFlag.get()) {
+                return;
+            }
+            if(this.viewer.plugin.managers.structure.selection.additionsHistory.length > 0) {
+                const currentLoci: Loci = this.viewer.plugin.managers.structure.selection.additionsHistory[0].loci;
+                const loc: StructureElement.Location = StructureElement.Location.create(currentLoci.structure);
+                StructureElement.Location.set(
+                    loc,
+                    currentLoci.structure,
+                    currentLoci.elements[0].unit,
+                    currentLoci.elements[0].unit.elements[OrderedSet.getAt(currentLoci.elements[0].indices,0)]
+                );
+                const currentModelId: string = this.modelMapManager.getModelId(currentLoci.structure.model.id);
+                if(currentLoci.elements.length > 0)
+                    if(SP.entity.type(loc) === 'non-polymer') {
+                        const resAuthId: number = SP.residue.auth_seq_id(loc);
+                        const chainLabelId: string = SP.chain.label_asym_id(loc);
+                        const query: StructureQuery = Q.modifiers.includeSurroundings(
+                            Q.generators.residues({
+                                residueTest:l=>SP.residue.auth_seq_id(l.element) === resAuthId,
+                                chainTest:l=>SP.chain.label_asym_id(l.element) === chainLabelId
+                            }),
+                            {
+                                radius: 5,
+                                wholeResidues: true
+                            });
+                        this.innerSelectionFlag.set(true);
+                        const sel: StructureSelection = StructureQuery.run(query, currentLoci.structure);
+                        const surroundingsLoci: Loci = StructureSelection.toLociWithSourceUnits(sel);
+                        this.viewer.plugin.managers.structure.selection.fromLoci('add', surroundingsLoci);
+                        const surroundingsLoc = StructureElement.Location.create(surroundingsLoci.structure);
+                        for (const e of surroundingsLoci.elements) {
+                            StructureElement.Location.set(surroundingsLoc, surroundingsLoci.structure, e.unit, e.unit.elements[0]);
+                            if(SP.entity.type(surroundingsLoc) === 'polymer'){
+                                this.selection.setLastSelection('select', {
+                                    modelId: currentModelId,
+                                    labelAsymId: SP.chain.label_asym_id(surroundingsLoc),
+                                    regions: []
+                                });
+                            }
+                        }
+                        this.innerSelectionFlag.set(false);
+                    }else if( SP.entity.type(loc) === 'polymer' ) {
+                        this.selection.setLastSelection('select', {
+                            modelId: currentModelId,
+                            labelAsymId: SP.chain.label_asym_id(loc),
+                            operatorName: SP.unit.operator_name(loc),
+                            regions: []
+                        });
+                    }else{
+                        this.selection.setLastSelection('select', null);
+                    }
+            }else{
+                this.selection.setLastSelection('select', null);
+            }
+            const sequenceData: Array<SaguaroSet> = new Array<SaguaroSet>();
+            for(const structure of this.viewer.plugin.managers.structure.hierarchy.current.structures){
+                const data: Structure | undefined = structure.cell.obj?.data;
+                if(data == null) return;
+                const loci: Loci = this.viewer.plugin.managers.structure.selection.getLoci(data);
+                if(StructureElement.Loci.is(loci)){
+                    const loc = StructureElement.Location.create(loci.structure);
+                    for (const e of loci.elements) {
+                        StructureElement.Location.set(loc, loci.structure, e.unit, e.unit.elements[0]);
+                        const seqIds = new Set<number>();
+                        for (let i = 0, il = OrderedSet.size(e.indices); i < il; ++i) {
+                            loc.element = e.unit.elements[OrderedSet.getAt(e.indices, i)];
+                            seqIds.add(SP.residue.label_seq_id(loc));
+                        }
+                        sequenceData.push({
+                            modelId: this.modelMapManager.getModelId(data.model.id),
+                            labelAsymId: SP.chain.label_asym_id(loc),
+                            operatorName: SP.unit.operator_name(loc),
+                            seqIds
+                        });
+                    }
+
+                }
+            }
+            this.selection.setSelectionFromResidueSelection(sequenceData, 'select', 'structure');
+            g();
+        });
+    }
+
+    public pluginCall(f: (plugin: PluginContext) => void){
+        this.viewer.pluginCall(f);
+    }
+
+    public setModelChangeCallback(f:(modelMap:SaguaroPluginModelMapType)=>void){
+        this.modelChangeCallback = f;
+        this.modelChangeCallbackSubs = this.viewer.plugin.state.events.object.updated.subscribe((o:{obj: StateObject, action: "in-place" | "recreate"})=>{
+            if(this.loadingFlag.get())
+                return;
+            if(o.obj.type.name === "Behavior" && o.action === "in-place") {
+                f(this.modelMapManager.getChains());
+            }else if(o.obj.type.name === "Model" && o.action === "in-place"){
+                f(this.modelMapManager.getChains());
+            }
+        });
+    }
+
+    public getModelChangeCallback():(modelMap:SaguaroPluginModelMapType)=>void {
+        return this.modelChangeCallback;
+    }
+
+    public unsetCallbacks(): void {
+        this.selectCallbackSubs?.unsubscribe();
+        this.modelChangeCallbackSubs?.unsubscribe();
+    }
+
+
+}

+ 46 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarManagerFactory.ts

@@ -0,0 +1,46 @@
+import {ViewerManagerFactoryInterface} from "../../StructureViewerInterface";
+import {LoadMolstarInterface, MolstarActionManager} from "./MolstarActionManager";
+import {Viewer, ViewerProps} from "@rcsb/rcsb-molstar/build/src/viewer";
+import {MolstarModelMapManager} from "./MolstarModelMapManager";
+import {MolstarCallbackManager} from "./MolstarCallbackManager";
+import {DataContainer} from "../../../Utils/DataContainer";
+import {RcsbFvSelectorManager} from "../../../RcsbFvSelection/RcsbFvSelectorManager";
+
+export class MolstarManagerFactory implements ViewerManagerFactoryInterface<LoadMolstarInterface,{viewerElement:string|HTMLElement,viewerProps:Partial<ViewerProps>}> {
+
+    public getViewerManagerFactory(selection: RcsbFvSelectorManager, viewerParams: {viewerElement: string | HTMLElement, viewerProps: Partial<ViewerProps>}) {
+        const loadingFlag: DataContainer<boolean> = new DataContainer(false);
+        const innerSelectionFlag: DataContainer<boolean> = new DataContainer(false);
+        const viewer = new Viewer(viewerParams.viewerElement, {
+            ...viewerParams,
+            layoutShowControls:false,
+            layoutShowSequence: true,
+            canvas3d: {
+                multiSample: {
+                    mode: 'off'
+                }
+            }
+        });
+        viewer.plugin.selectionMode = true;
+        const modelMapManager:MolstarModelMapManager = new MolstarModelMapManager(viewer);
+        const callbackManager: MolstarCallbackManager =  new MolstarCallbackManager({
+            viewer: viewer,
+            selection: selection,
+            loadingFlag: loadingFlag,
+            modelMapManager: modelMapManager,
+            innerSelectionFlag: innerSelectionFlag
+        });
+        const actionManager = new MolstarActionManager({
+            viewer: viewer,
+            modelMapManager: modelMapManager,
+            innerSelectionFlag: innerSelectionFlag,
+            loadingFlag: loadingFlag,
+            callbackManager: callbackManager
+        });
+        return {
+            actionManager,
+            callbackManager
+        }
+    }
+
+}

+ 157 - 0
src/RcsbFvStructure/StructureViewers/MolstarViewer/MolstarModelMapManager.ts

@@ -0,0 +1,157 @@
+import {ChainInfo, OperatorInfo, SaguaroPluginModelMapType} from "../../StructureViewerInterface";
+import {PluginContext} from "molstar/lib/mol-plugin/context";
+import {Structure, StructureElement, StructureProperties as SP} from "molstar/lib/mol-model/structure";
+import {StructureRef} from "molstar/lib/mol-plugin-state/manager/structure/hierarchy-state";
+import {State} from "molstar/lib/mol-state";
+import {PluginStateObject as PSO} from "molstar/lib/mol-plugin-state/objects";
+import {Viewer} from "@rcsb/rcsb-molstar/build/src/viewer";
+import {LoadMolstarInterface} from "./MolstarActionManager";
+
+interface LoadParams<P=any,S={}> {
+    id?:string;
+    params?:P;
+}
+
+export class MolstarModelMapManager {
+
+    private readonly viewer: Viewer;
+    private readonly modelMap: Map<string,string|undefined> = new Map<string, string>();
+
+    constructor(viewer: Viewer) {
+        this.viewer = viewer;
+    }
+
+    public add(lC: LoadMolstarInterface){
+        (Array.isArray(lC.loadParams) ? lC.loadParams : [lC.loadParams]).forEach((lP: LoadParams)=>{
+            if(typeof lP.params?.getMap === "function") {
+                const map: Map<string,string> = lP.params.getMap();
+                if(typeof map?.forEach === "function")
+                    map.forEach((modelId: string, key: string) => {
+                        if (typeof modelId === "string" && typeof key === "string") {
+                            this.modelMap.set(key, modelId);
+                            this.modelMap.set(modelId, key);
+                        }
+                    })
+            }
+        });
+        this.map(lC.loadParams);
+    }
+
+    public getChains(): SaguaroPluginModelMapType{
+        const structureRefList = getStructureOptions(this.viewer.plugin);
+        const out: SaguaroPluginModelMapType = new Map<string, {entryId: string; chains: Array<ChainInfo>; assemblyId:string;}>();
+        structureRefList.forEach((structureRef,i)=>{
+            const structure: Structure = getStructure(structureRef[0], this.viewer.plugin.state.data);
+            let modelEntityId = getModelEntityOptions(structure)[0][0];
+            const chains: [{modelId:string;entryId:string;assemblyId:string;},ChainInfo[]] = getChainValues(structure, modelEntityId);
+            out.set(this.getModelId(chains[0].modelId),{entryId:chains[0].entryId, assemblyId:chains[0].assemblyId, chains: chains[1]});
+        });
+        return out;
+    }
+
+    public getModelId(id: string): string{
+        return this.modelMap.get(id) ?? id;
+    }
+
+    private map(loadParams: LoadParams | Array<LoadParams>): void{
+        const loadParamList: Array<LoadParams> = loadParams instanceof Array ? loadParams : [loadParams];
+        const structureRefList = getStructureOptions(this.viewer.plugin);
+        if(loadParamList.length == structureRefList.length )
+            structureRefList.forEach((structureRef,i)=>{
+                const structure = getStructure(structureRef[0], this.viewer.plugin.state.data);
+                let modelEntityId = getModelEntityOptions(structure)[0][0];
+                const chains: [{modelId:string, entryId:string},ChainInfo[]] = getChainValues(structure, modelEntityId);
+                if(!this.modelMap.has(chains[0].modelId)) {
+                    this.modelMap.set(chains[0].modelId, loadParamList[i].id);
+                    if (loadParamList[i].id != null)
+                        this.modelMap.set(loadParamList[i].id!, chains[0].modelId);
+                }
+            });
+    }
+}
+
+
+function getStructureOptions(plugin: PluginContext): [string,string][] {
+    const options: [string, string][] = [];
+    plugin.managers.structure.hierarchy.current.structures.forEach(s=>{
+        options.push([s.cell.transform.ref, s.cell.obj!.data.label]);
+    })
+    return options;
+}
+
+function getChainValues(structure: Structure, modelEntityId: string): [{modelId:string; entryId:string; assemblyId:string;},ChainInfo[]] {
+    const chains: Map<number, ChainInfo> = new Map<number, ChainInfo>();
+    const l = StructureElement.Location.create(structure);
+    let assemblyId:string = "-";
+    const [modelIdx, entityId] = splitModelEntityId(modelEntityId);
+    for (const unit of structure.units) {
+        StructureElement.Location.set(l, structure, unit, unit.elements[0]);
+        assemblyId = SP.unit.pdbx_struct_assembly_id(l);
+        if (structure.getModelIndex(unit.model) !== modelIdx) continue;
+        const chId: number = unit.chainGroupId;
+        if(chains.has(chId)){
+            chains.get(chId)!.operators.push(opKey(l))
+        }else{
+            chains.set(chId, {label:SP.chain.label_asym_id(l), auth:SP.chain.auth_asym_id(l), entityId: SP.entity.id(l), title: SP.entity.pdbx_description(l).join("|"), type: SP.entity.type(l), operators:[opKey(l)]});
+        }
+    }
+    const id: {modelId:string; entryId:string; assemblyId:string;} = {modelId:l.unit?.model?.id, entryId: l.unit?.model?.entryId, assemblyId: assemblyId};
+    return [id,Array.from(chains.values())];
+}
+
+function getStructureWithModelId(structures: StructureRef[], modelId: string): Structure|undefined{
+    for(const structure of structures){
+        if(!structure.cell?.obj?.data?.units)
+            continue;
+        const unit =  structure.cell.obj.data.units[0];
+        const id:string = unit.model.id;
+        if(id === modelId)
+            return structure.cell.obj.data
+    }
+}
+
+function getStructure(ref: string, state: State) {
+    const cell = state.select(ref)[0];
+    if (!ref || !cell || !cell.obj) return Structure.Empty;
+    return (cell.obj as PSO.Molecule.Structure).data;
+}
+
+function getModelEntityOptions(structure: Structure):[string, string][] {
+    const options: [string, string][] = [];
+    const l = StructureElement.Location.create(structure);
+    const seen = new Set<string>();
+    for (const unit of structure.units) {
+        StructureElement.Location.set(l, structure, unit, unit.elements[0]);
+        const id = SP.entity.id(l);
+        const modelIdx = structure.getModelIndex(unit.model);
+        const key = `${modelIdx}|${id}`;
+        if (seen.has(key)) continue;
+        let description = SP.entity.pdbx_description(l).join(', ');
+        if (structure.models.length) {
+            if (structure.representativeModel) { // indicates model trajectory
+                description += ` (Model ${structure.models[modelIdx].modelNum})`;
+            } else  if (description.startsWith('Polymer ')) { // indicates generic entity name
+                description += ` (${structure.models[modelIdx].entry})`;
+            }
+        }
+        const label = `${id}: ${description}`;
+        options.push([ key, label ]);
+        seen.add(key);
+    }
+    if (options.length === 0) options.push(['', 'No entities']);
+    return options;
+}
+
+function splitModelEntityId(modelEntityId: string) {
+    const [ modelIdx, entityId ] = modelEntityId.split('|');
+    return [ parseInt(modelIdx), entityId ];
+}
+
+function opKey(l: StructureElement.Location): OperatorInfo {
+    const ids = SP.unit.pdbx_struct_oper_list_ids(l);
+    const ncs = SP.unit.struct_ncs_oper_id(l);
+    const hkl = SP.unit.hkl(l);
+    const spgrOp = SP.unit.spgrOp(l);
+    const name = SP.unit.operator_name(l);
+    return {ids:ids,name:name};
+}

+ 1 - 1
src/RcsbFvStructure/StructurePlugins/StructureRepresentation.ts → src/RcsbFvStructure/StructureViewers/MolstarViewer/StructureRepresentation.ts

@@ -9,7 +9,7 @@ import {PluginStateObject} from "molstar/lib/mol-plugin-state/objects";
 import {StateObject} from "molstar/lib/mol-state/object";
 import {StateTransformer} from "molstar/lib/mol-state/transformer";
 import {Structure, StructureElement, StructureProperties as SP} from "molstar/lib/mol-model/structure";
-import {ChainInfo} from "../SaguaroPluginInterface";
+import {ChainInfo} from "../../StructureViewerInterface";
 
 type StructureObject = StateObjectSelector<PluginStateObject.Molecule.Structure, StateTransformer<StateObject<any, StateObject.Type<any>>, StateObject<any, StateObject.Type<any>>, any>>
 

+ 132 - 0
src/RcsbFvStructure/StructureViewers/StructureViewer.ts

@@ -0,0 +1,132 @@
+import {
+    SaguaroChain,
+    StructureViewerInterface,
+    SaguaroPluginModelMapType,
+    SaguaroPosition,
+    SaguaroRange,
+    ViewerCallbackManagerInterface,
+    ViewerActionManagerInterface, ViewerManagerFactoryInterface
+} from "../StructureViewerInterface";
+
+import {PluginContext} from "molstar/lib/mol-plugin/context";
+import {
+    RcsbFvSelectorManager
+} from "../../RcsbFvSelection/RcsbFvSelectorManager";
+import {StructureRepresentationRegistry} from "molstar/lib/mol-repr/structure/registry";
+import {ColorTheme} from "molstar/lib/mol-theme/color";
+
+
+
+export class StructureViewer<R,S> implements StructureViewerInterface<R,S> {
+    private readonly structureViewerManagerFactory:  ViewerManagerFactoryInterface<R,S>;
+    private callbackManager: ViewerCallbackManagerInterface;
+    private actionManager: ViewerActionManagerInterface<R>;
+
+    constructor(structureViewerManagerFactory:  ViewerManagerFactoryInterface<R,S>) {
+        this.structureViewerManagerFactory = structureViewerManagerFactory;
+    }
+
+    public init(selection: RcsbFvSelectorManager, args:S): void {
+        const {actionManager,callbackManager} = this.structureViewerManagerFactory.getViewerManagerFactory(selection, args);
+        this.actionManager = actionManager;
+        this.callbackManager = callbackManager;
+    }
+
+    public async clear(): Promise<void>{
+        await this.actionManager.clear();
+    }
+
+    async load(loadConfig: R|Array<R>): Promise<void>{
+      await this.actionManager.load(loadConfig);
+    }
+
+    public setBackground(color: number) {
+    }
+
+    public select(modelId:string, labelAsymId: string, begin: number, end: number, mode: 'select'|'hover', operation:'add'|'set', operatorName?:string): void;
+    public select(selection: Array<SaguaroPosition>, mode: 'select'|'hover', operation:'add'|'set'): void;
+    public select(selection: Array<SaguaroRange>, mode: 'select'|'hover', operation:'add'|'set'): void;
+    public select(...args: any[]): void{
+        this.actionManager.select(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
+    }
+
+    public clearSelection(mode:'select'|'hover', option?:SaguaroChain): void {
+        this.actionManager.clearSelection(mode,option);
+    }
+
+    public setFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void{
+        this.actionManager.setFocus(modelId,labelAsymId,begin,end,operatorName);
+    }
+    public clearFocus(): void {
+        this.actionManager.clearFocus();
+    }
+
+    public cameraFocus(modelId: string, labelAsymId: string, positions:Array<number>, operatorName?:string): void;
+    public cameraFocus(modelId: string, labelAsymId: string, begin: number, end: number, operatorName?:string): void;
+    public cameraFocus(...args: any[]): void{
+        this.actionManager.cameraFocus(args[0],args[1],args[2],args[3],args[4]);
+    }
+
+    public async createComponent(componentLabel: string, modelId:string, labelAsymId: string, begin: number, end : number, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
+    public async createComponent(componentLabel: string, modelId:string, labelAsymId: string, representationType: StructureRepresentationRegistry.BuiltIn, operatorName?:string): Promise<void>;
+    public async createComponent(componentLabel: string, residues: Array<SaguaroPosition>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
+    public async createComponent(componentLabel: string, residues: Array<SaguaroRange>, representationType: StructureRepresentationRegistry.BuiltIn): Promise<void>;
+    public async createComponent(...args: any[]): Promise<void> {
+        await this.actionManager.createComponent(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
+    }
+
+    public isComponent(componentLabel: string): boolean{
+        return this.actionManager.isComponent(componentLabel);
+    }
+
+    public async colorComponent(componentLabel: string, color: ColorTheme.BuiltIn): Promise<void>{
+        await this.actionManager.colorComponent(componentLabel,color);
+    }
+
+    public getComponentSet(): Set<string>{
+        return this.actionManager.getComponentSet();
+    }
+
+    public async removeComponent(componentLabel?: string): Promise<void>{
+       await this.actionManager.removeComponent(componentLabel);
+    }
+
+    public displayComponent(componentLabel: string): boolean;
+    public displayComponent(componentLabel: string, visibilityFlag: boolean): void;
+    public displayComponent(componentLabel: string, visibilityFlag?: boolean): void|boolean {
+        return this.actionManager.displayComponent(componentLabel as any,visibilityFlag as any);
+    }
+
+    public setRepresentationChangeCallback(g:()=>void){
+        this.callbackManager.setRepresentationChangeCallback(g);
+    }
+
+    public setHoverCallback(g:()=>void){
+        this.callbackManager.setHoverCallback(g);
+    }
+
+    public setSelectCallback(g:(flag?:boolean)=>void){
+        this.callbackManager.setSelectCallback(g);
+    }
+
+    public pluginCall(f: (plugin: PluginContext) => void){
+        this.callbackManager.pluginCall(f);
+    }
+
+    public setModelChangeCallback(f:(modelMap:SaguaroPluginModelMapType)=>void){
+        this.callbackManager.setModelChangeCallback(f);
+    }
+
+    public getModelChangeCallback(): (modelMap: SaguaroPluginModelMapType) => void {
+        return this.callbackManager.getModelChangeCallback();
+    }
+
+    public unsetCallbacks(): void {
+        this.callbackManager.unsetCallbacks();
+    }
+
+    public resetCamera(): void {
+        this.actionManager.resetCamera();
+    }
+
+}

+ 4 - 0
src/Utils/DataContainer.ts

@@ -12,4 +12,8 @@ export class DataContainer<T> {
     public set(data: T | undefined): void{
         this.data = data;
     }
+}
+
+export interface DataContainerReader<T> {
+    get(): T | undefined;
 }

+ 9 - 9
src/examples/css-config/index.tsx

@@ -1,6 +1,6 @@
 import {RcsbFv3DCustom, RcsbFv3DCustomInterface} from "../../RcsbFv3D/RcsbFv3DCustom";
-import {RcsbFvStructureInterface} from "../../RcsbFvStructure/RcsbFvStructure";
-import {LoadMethod} from "../../RcsbFvStructure/StructurePlugins/MolstarPlugin";
+import {RcsbFvStructureConfigInterface} from "../../RcsbFvStructure/RcsbFvStructure";
+import {LoadMethod} from "../../RcsbFvStructure/StructureViewers/StructureViewer";
 import {
     CustomViewInterface,
     FeatureBlockInterface,
@@ -17,7 +17,7 @@ import {
     RcsbFvSelectorManager,
     RegionSelectionInterface
 } from "../../RcsbFvSelection/RcsbFvSelectorManager";
-import {SaguaroPluginPublicInterface, SaguaroRegionList} from "../../RcsbFvStructure/SaguaroPluginInterface";
+import {StructureViewerPublicInterface, SaguaroRegionList} from "../../RcsbFvStructure/StructureViewerInterface";
 import {AlignmentManager} from "./AlignmentManager";
 import {Mat4} from "molstar/lib/mol-math/linear-algebra";
 
@@ -109,7 +109,7 @@ const fvConfig: FeatureViewInterface = {
         includeAxis: true
     },
     rowConfig: rowConfig,
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
         selectorManager.clearSelection("select", {modelId:"1ash_model", labelAsymId:"A"});
         selectorManager.clearSelection("select", {modelId:"101m_model", labelAsymId:"A"});
         if(sequenceRegion.length > 0) {
@@ -136,7 +136,7 @@ const fvConfig: FeatureViewInterface = {
             plugin.resetCamera();
         }
     },
-    sequenceElementClickCallback: async (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
+    sequenceElementClickCallback: async (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
         plugin.removeComponent("1ash_component");
         plugin.removeComponent("101m_component");
         if(d.begin === d.end || !d.end){
@@ -144,7 +144,7 @@ const fvConfig: FeatureViewInterface = {
             await plugin.createComponent("101m_component", "101m_model", "A", alignmentManager.getTargetPosition(d.begin)!, alignmentManager.getTargetPosition(d.begin)!, "ball-and-stick");
         }
     },
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
         if (elements == null || elements.length == 0){
             plugin.clearSelection("hover");
         }else {
@@ -164,7 +164,7 @@ const fvConfig: FeatureViewInterface = {
                 ), "hover", "set");
         }
     },
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel_1ash: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1ash_model", "A", "select");
         const sel_101m: SaguaroRegionList | undefined = selection.getSelectionWithCondition("101m_model", "A", "select");
         pfv.clearSelection("select");
@@ -181,7 +181,7 @@ const fvConfig: FeatureViewInterface = {
                     })), mode: "select"});
         }
     },
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureHoverCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel_1ash: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1ash_model", "A", "hover");
         const sel_101m: SaguaroRegionList | undefined = selection.getSelectionWithCondition("101m_model", "A", "hover");
         if(sel_1ash == null && sel_101m == null)
@@ -212,7 +212,7 @@ const sequenceConfig = {
     config: customConfig
 };
 
-const molstarConfig: RcsbFvStructureInterface = {
+const molstarConfig: RcsbFvStructureConfigInterface = {
     loadConfig: {
         loadMethod: LoadMethod.loadPdbIds,
         loadParams: [{

+ 11 - 11
src/examples/external-mapping/FeatureViewerConfig.ts

@@ -1,5 +1,5 @@
 import {FeatureViewInterface} from "../../RcsbFvSequence/SequenceViews/CustomView/CustomView";
-import {SaguaroPluginPublicInterface, SaguaroRegionList} from "../../RcsbFvStructure/SaguaroPluginInterface";
+import {StructureViewerPublicInterface, SaguaroRegionList} from "../../RcsbFvStructure/StructureViewerInterface";
 import {RcsbFvSelectorManager, RegionSelectionInterface} from "../../RcsbFvSelection/RcsbFvSelectorManager";
 import {
     RcsbFv,
@@ -43,7 +43,7 @@ export const fvConfig1: FeatureViewInterface = {
         includeAxis: true
     },
     rowConfig: rowConfig,
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
         selectorManager.clearSelection("select", {modelId:"structure_1", labelAsymId:"A"});
         if(sequenceRegion.length > 0) {
             const regions = sequenceRegion.map(r => ({
@@ -62,11 +62,11 @@ export const fvConfig1: FeatureViewInterface = {
             plugin.resetCamera();
         }
     },
-    sequenceElementClickCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
+    sequenceElementClickCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
         if(d!=null)
             plugin.cameraFocus("structure_1", "A", d.begin, d.end ?? d.begin);
     },
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
         if(elements == null || elements.length == 0)
             plugin.clearSelection("hover");
         else
@@ -77,7 +77,7 @@ export const fvConfig1: FeatureViewInterface = {
                 end: e.end ?? e.begin
             })), "hover", "set");
     },
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("structure_1", "A", "select");
         if(sel == null) {
             pfv.clearSelection("select");
@@ -86,7 +86,7 @@ export const fvConfig1: FeatureViewInterface = {
             pfv.setSelection({elements: sel.regions, mode: "select"});
         }
     },
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureHoverCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("structure_1", "A", "hover");
         if(sel == null)
             pfv.clearSelection("hover");
@@ -106,7 +106,7 @@ export const fvConfig2: FeatureViewInterface = {
         includeAxis: true
     },
     rowConfig: rowConfig,
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
         selectorManager.clearSelection("select", {modelId:"structure_2", labelAsymId:"A"});
         if(sequenceRegion.length > 0) {
             const regions = sequenceRegion.map(r => ({
@@ -125,11 +125,11 @@ export const fvConfig2: FeatureViewInterface = {
             plugin.resetCamera();
         }
     },
-    sequenceElementClickCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
+    sequenceElementClickCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
         if(d!=null)
             plugin.cameraFocus("structure_2", "A", d.begin, d.end ?? d.begin);
     },
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
         if(elements == null || elements.length == 0)
             plugin.clearSelection("hover");
         else
@@ -140,7 +140,7 @@ export const fvConfig2: FeatureViewInterface = {
                 end: e.end ?? e.begin
             })), "hover", "set");
     },
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("structure_2", "A", "select");
         if(sel == null) {
             pfv.clearSelection("select");
@@ -149,7 +149,7 @@ export const fvConfig2: FeatureViewInterface = {
             pfv.setSelection({elements: sel.regions, mode: "select"});
         }
     },
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureHoverCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("structure_2", "A", "hover");
         if(sel == null)
             pfv.clearSelection("hover");

+ 3 - 3
src/examples/external-mapping/index.tsx

@@ -1,6 +1,6 @@
 import {RcsbFv3DCustom} from "../../RcsbFv3D/RcsbFv3DCustom";
-import {RcsbFvStructureInterface} from "../../RcsbFvStructure/RcsbFvStructure";
-import {LoadMethod} from "../../RcsbFvStructure/StructurePlugins/MolstarPlugin";
+import {RcsbFvStructureConfigInterface} from "../../RcsbFvStructure/RcsbFvStructure";
+import {LoadMethod} from "../../RcsbFvStructure/StructureViewers/StructureViewer";
 import {
     CustomViewInterface,
     FeatureBlockInterface
@@ -25,7 +25,7 @@ const sequenceConfig = {
     config: customConfig
 };
 
-const molstarConfig: RcsbFvStructureInterface = {
+const molstarConfig: RcsbFvStructureConfigInterface = {
     loadConfig: [{
         loadMethod: LoadMethod.loadPdbId,
         loadParams: {

+ 15 - 15
src/examples/multiple-chain/index.tsx

@@ -1,6 +1,6 @@
 import {RcsbFv3DCustom} from "../../RcsbFv3D/RcsbFv3DCustom";
-import {RcsbFvStructureInterface} from "../../RcsbFvStructure/RcsbFvStructure";
-import {LoadMethod} from "../../RcsbFvStructure/StructurePlugins/MolstarPlugin";
+import {RcsbFvStructureConfigInterface} from "../../RcsbFvStructure/RcsbFvStructure";
+import {LoadMethod} from "../../RcsbFvStructure/StructureViewers/StructureViewer";
 import {
     BlockSelectorManager,
     CustomViewInterface,
@@ -18,8 +18,8 @@ import {
     RegionSelectionInterface
 } from "../../RcsbFvSelection/RcsbFvSelectorManager";
 import {
-    SaguaroPluginPublicInterface, SaguaroRegionList
-} from "../../RcsbFvStructure/SaguaroPluginInterface";
+    StructureViewerPublicInterface, SaguaroRegionList
+} from "../../RcsbFvStructure/StructureViewerInterface";
 
 const rowConfigChainA: Array<RcsbFvRowConfigInterface> = [
     {
@@ -91,7 +91,7 @@ const fvConfigChainA: FeatureViewInterface = {
         includeAxis: true
     },
     rowConfig: rowConfigChainA,
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
         selectorManager.clearSelection("select", {modelId:"1acb_board", labelAsymId:"A"});
         plugin.clearSelection("select", {modelId: "1acb_board", labelAsymId: "A"})
         if(sequenceRegion.length > 0) {
@@ -110,11 +110,11 @@ const fvConfigChainA: FeatureViewInterface = {
             plugin.resetCamera();
         }
     },
-    sequenceElementClickCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
+    sequenceElementClickCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
         if(d!=null)
             plugin.cameraFocus("1acb_board", "A", d.begin, d.end ?? d.begin);
     },
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
         if(elements == null || elements.length == 0)
             plugin.clearSelection("hover");
         else
@@ -125,7 +125,7 @@ const fvConfigChainA: FeatureViewInterface = {
                 end: e.end ?? e.begin
             })), "hover", "set");
     },
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1acb_board", "A", "select");
         if(sel == null) {
             pfv.clearSelection("select");
@@ -134,7 +134,7 @@ const fvConfigChainA: FeatureViewInterface = {
             pfv.setSelection({elements: sel.regions, mode: "select"});
         }
     },
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureHoverCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1acb_board", "A", "hover");
         if(sel == null)
             pfv.clearSelection("hover");
@@ -154,7 +154,7 @@ const fvConfigChainB: FeatureViewInterface = {
         includeAxis: true
     },
     rowConfig: rowConfigChainB,
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
         selectorManager.clearSelection("select", {modelId:"1acb_board", labelAsymId:"B"});
         plugin.clearSelection("select", {modelId: "1acb_board", labelAsymId: "B"})
         if(sequenceRegion.length > 0) {
@@ -173,11 +173,11 @@ const fvConfigChainB: FeatureViewInterface = {
             plugin.resetCamera();
         }
     },
-    sequenceElementClickCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
+    sequenceElementClickCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
         if(d!=null)
             plugin.cameraFocus("1acb_board", "B", d.begin, d.end ?? d.begin);
     },
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
         if(elements == null || elements.length == 0)
             plugin.clearSelection("hover");
         else
@@ -188,7 +188,7 @@ const fvConfigChainB: FeatureViewInterface = {
                 end: e.end ?? e.begin
             })), "hover", "set");
     },
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1acb_board", "B", "select");
         if(sel == null) {
             pfv.clearSelection("select");
@@ -197,7 +197,7 @@ const fvConfigChainB: FeatureViewInterface = {
             pfv.setSelection({elements: sel.regions, mode: "select"});
         }
     },
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureHoverCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1acb_board", "B", "hover");
         if(sel == null)
             pfv.clearSelection("hover");
@@ -240,7 +240,7 @@ const sequenceConfig = {
     config: customConfig
 };
 
-const molstarConfig: RcsbFvStructureInterface = {
+const molstarConfig: RcsbFvStructureConfigInterface = {
     loadConfig: {
         loadMethod: LoadMethod.loadPdbIds,
         loadParams: [{

+ 10 - 10
src/examples/single-chain/index.tsx

@@ -1,6 +1,6 @@
 import {RcsbFv3DCustom} from "../../RcsbFv3D/RcsbFv3DCustom";
-import {RcsbFvStructureInterface} from "../../RcsbFvStructure/RcsbFvStructure";
-import {LoadMethod} from "../../RcsbFvStructure/StructurePlugins/MolstarPlugin";
+import {RcsbFvStructureConfigInterface} from "../../RcsbFvStructure/RcsbFvStructure";
+import {LoadMethod} from "../../RcsbFvStructure/StructureViewers/StructureViewer";
 import {
     CustomViewInterface,
     FeatureBlockInterface, FeatureViewInterface
@@ -17,8 +17,8 @@ import {
     RegionSelectionInterface
 } from "../../RcsbFvSelection/RcsbFvSelectorManager";
 import {
-    SaguaroPluginPublicInterface, SaguaroRegionList
-} from "../../RcsbFvStructure/SaguaroPluginInterface";
+    StructureViewerPublicInterface, SaguaroRegionList
+} from "../../RcsbFvStructure/StructureViewerInterface";
 
 const rowConfig: Array<RcsbFvRowConfigInterface> = [
     {
@@ -59,7 +59,7 @@ const fvConfig: FeatureViewInterface = {
         includeAxis: true
     },
     rowConfig: rowConfig,
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
         selectorManager.clearSelection("select", {modelId:"1ash_model", labelAsymId:"A"});
         if(sequenceRegion.length > 0) {
             const regions = sequenceRegion.map(r => ({
@@ -78,11 +78,11 @@ const fvConfig: FeatureViewInterface = {
             plugin.resetCamera();
         }
     },
-    sequenceElementClickCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
+    sequenceElementClickCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
         if(d!=null)
             plugin.cameraFocus("1ash_model", "A", d.begin, d.end ?? d.begin);
     },
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
         if(elements == null || elements.length == 0)
             plugin.clearSelection("hover");
         else
@@ -93,7 +93,7 @@ const fvConfig: FeatureViewInterface = {
                 end: e.end ?? e.begin
             })), "hover", "set");
     },
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1ash_model", "A", "select");
         if(sel == null) {
             pfv.clearSelection("select");
@@ -102,7 +102,7 @@ const fvConfig: FeatureViewInterface = {
             pfv.setSelection({elements: sel.regions, mode: "select"});
         }
     },
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureHoverCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1ash_model", "A", "hover");
         if(sel == null)
             pfv.clearSelection("hover");
@@ -126,7 +126,7 @@ const sequenceConfig = {
     config: customConfig
 };
 
-const molstarConfig: RcsbFvStructureInterface = {
+const molstarConfig: RcsbFvStructureConfigInterface = {
     loadConfig: {
         loadMethod: LoadMethod.loadPdbIds,
         loadParams: [{

+ 9 - 9
src/examples/structural-alignment/index.tsx

@@ -1,6 +1,6 @@
 import {RcsbFv3DCustom, RcsbFv3DCustomInterface} from "../../RcsbFv3D/RcsbFv3DCustom";
-import {RcsbFvStructureInterface} from "../../RcsbFvStructure/RcsbFvStructure";
-import {LoadMethod} from "../../RcsbFvStructure/StructurePlugins/MolstarPlugin";
+import {RcsbFvStructureConfigInterface} from "../../RcsbFvStructure/RcsbFvStructure";
+import {LoadMethod} from "../../RcsbFvStructure/StructureViewers/StructureViewer";
 import {
     CustomViewInterface,
     FeatureBlockInterface,
@@ -17,7 +17,7 @@ import {
     RcsbFvSelectorManager,
     RegionSelectionInterface
 } from "../../RcsbFvSelection/RcsbFvSelectorManager";
-import {SaguaroPluginPublicInterface, SaguaroRegionList} from "../../RcsbFvStructure/SaguaroPluginInterface";
+import {StructureViewerPublicInterface, SaguaroRegionList} from "../../RcsbFvStructure/StructureViewerInterface";
 import {AlignmentManager} from "./AlignmentManager";
 import {Mat4} from "molstar/lib/mol-math/linear-algebra";
 
@@ -107,7 +107,7 @@ const fvConfig: FeatureViewInterface = {
         includeAxis: true
     },
     rowConfig: rowConfig,
-    sequenceSelectionChangeCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceSelectionChangeCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, sequenceRegion: Array<RcsbFvTrackDataElementInterface>) => {
         selectorManager.clearSelection("select", {modelId:"1ash_model", labelAsymId:"A"});
         selectorManager.clearSelection("select", {modelId:"101m_model", labelAsymId:"A"});
         if(sequenceRegion.length > 0) {
@@ -134,7 +134,7 @@ const fvConfig: FeatureViewInterface = {
             plugin.resetCamera();
         }
     },
-    sequenceElementClickCallback: async (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
+    sequenceElementClickCallback: async (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, d: RcsbFvTrackDataElementInterface) => {
         plugin.removeComponent("1ash_component");
         plugin.removeComponent("101m_component");
         if(d.begin === d.end || !d.end){
@@ -142,7 +142,7 @@ const fvConfig: FeatureViewInterface = {
             await plugin.createComponent("101m_component", "101m_model", "A", alignmentManager.getTargetPosition(d.begin)!, alignmentManager.getTargetPosition(d.begin)!, "ball-and-stick");
         }
     },
-    sequenceHoverCallback: (plugin: SaguaroPluginPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
+    sequenceHoverCallback: (plugin: StructureViewerPublicInterface, selectorManager: RcsbFvSelectorManager, elements: Array<RcsbFvTrackDataElementInterface>) => {
         if (elements == null || elements.length == 0){
             plugin.clearSelection("hover");
         }else {
@@ -162,7 +162,7 @@ const fvConfig: FeatureViewInterface = {
                 ), "hover", "set");
         }
     },
-    structureSelectionCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureSelectionCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel_1ash: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1ash_model", "A", "select");
         const sel_101m: SaguaroRegionList | undefined = selection.getSelectionWithCondition("101m_model", "A", "select");
         pfv.clearSelection("select");
@@ -179,7 +179,7 @@ const fvConfig: FeatureViewInterface = {
                     })), mode: "select"});
         }
     },
-    structureHoverCallback: (plugin: SaguaroPluginPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
+    structureHoverCallback: (plugin: StructureViewerPublicInterface, pfv: RcsbFv, selection: RcsbFvSelectorManager) => {
         const sel_1ash: SaguaroRegionList | undefined = selection.getSelectionWithCondition("1ash_model", "A", "hover");
         const sel_101m: SaguaroRegionList | undefined = selection.getSelectionWithCondition("101m_model", "A", "hover");
         if(sel_1ash == null && sel_101m == null)
@@ -210,7 +210,7 @@ const sequenceConfig = {
     config: customConfig
 };
 
-const molstarConfig: RcsbFvStructureInterface = {
+const molstarConfig: RcsbFvStructureConfigInterface = {
     loadConfig: {
         loadMethod: LoadMethod.loadPdbIds,
         loadParams: [{