diff --git a/src/apps/viewer/index.ts b/src/apps/viewer/index.ts index 676ac2ac421b95b686e131a36e4c595b33c75fa7..329610b2b7903f1b5335b3796334fe3a11bf3461 100644 --- a/src/apps/viewer/index.ts +++ b/src/apps/viewer/index.ts @@ -15,6 +15,7 @@ import { PluginSpec } from '../../mol-plugin/spec'; import { LoadCellPackModel } from './extensions/cellpack/model'; import { StructureFromCellpack } from './extensions/cellpack/state'; import { DownloadStructure } from '../../mol-plugin-state/actions/structure'; +import { PluginConfig } from '../../mol-plugin/config'; require('mol-plugin-ui/skin/light.scss') function getParam(name: string, regex: string): string { @@ -46,6 +47,7 @@ function init() { }, config: DefaultPluginSpec.config }; + spec.config?.set(PluginConfig.Viewport.ShowExpand, false); const plugin = createPlugin(document.getElementById('app')!, spec); trySetSnapshot(plugin); tryLoadFromUrl(plugin); diff --git a/src/mol-math/linear-algebra/matrix/principal-axes.ts b/src/mol-math/linear-algebra/matrix/principal-axes.ts index 21a9d4d122fc4ca3a9b617deaa11aefc66eb7af3..e8fd57230e72cfb314b2ee3dafdde571fc379f5b 100644 --- a/src/mol-math/linear-algebra/matrix/principal-axes.ts +++ b/src/mol-math/linear-algebra/matrix/principal-axes.ts @@ -26,7 +26,7 @@ namespace PrincipalAxes { export function calculateMomentsAxes(positions: NumberArray): Axes3D { if (positions.length === 3) { - return Axes3D.create(Vec3.fromArray(Vec3(), positions, 0), Vec3(), Vec3(), Vec3()) + return Axes3D.create(Vec3.fromArray(Vec3(), positions, 0), Vec3.create(1, 0, 0), Vec3.create(0, 1, 0), Vec3.create(0, 1, 0)) } const points = Matrix.fromArray(positions, 3, positions.length / 3) diff --git a/src/mol-model/loci.ts b/src/mol-model/loci.ts index 1a793cfcec5fc34de04c114f3e833a86d6a8e160..09e9f621033a855a1485c28dad6d6783aa26f7c7 100644 --- a/src/mol-model/loci.ts +++ b/src/mol-model/loci.ts @@ -192,21 +192,6 @@ namespace Loci { ? StructureElement.Loci.extendToWholeChains(loci) : loci }, - 'elementInstances': (loci: Loci) => { - return StructureElement.Loci.is(loci) - ? StructureElement.Loci.extendToAllInstances(loci) - : loci - }, - 'residueInstances': (loci: Loci) => { - return StructureElement.Loci.is(loci) - ? StructureElement.Loci.extendToAllInstances(StructureElement.Loci.extendToWholeResidues(loci, true)) - : loci - }, - 'chainInstances': (loci: Loci) => { - return StructureElement.Loci.is(loci) - ? StructureElement.Loci.extendToAllInstances(StructureElement.Loci.extendToWholeChains(loci)) - : loci - }, 'entity': (loci: Loci) => { return StructureElement.Loci.is(loci) ? StructureElement.Loci.extendToWholeEntities(loci) @@ -224,9 +209,25 @@ namespace Loci { ? Shape.Loci(loci.shape) : loci }, + 'elementInstances': (loci: Loci) => { + return StructureElement.Loci.is(loci) + ? StructureElement.Loci.extendToAllInstances(loci) + : loci + }, + 'residueInstances': (loci: Loci) => { + return StructureElement.Loci.is(loci) + ? StructureElement.Loci.extendToAllInstances(StructureElement.Loci.extendToWholeResidues(loci, true)) + : loci + }, + 'chainInstances': (loci: Loci) => { + return StructureElement.Loci.is(loci) + ? StructureElement.Loci.extendToAllInstances(StructureElement.Loci.extendToWholeChains(loci)) + : loci + }, } export type Granularity = keyof typeof Granularity export const GranularityOptions = ParamDefinition.objectToOptions(Granularity, k => { + if (k.indexOf('Instances') > 0) return [stringToWords(k), 'With Symmetry']; switch (k) { case 'element': return'Atom/Coarse Element' case 'structure': return'Structure/Shape' diff --git a/src/mol-plugin-state/manager/structure/component.ts b/src/mol-plugin-state/manager/structure/component.ts index d3dbb43ce2f5c650270b29acc2f16a83adc71a02..762ae2dcdaa9c64efc5598e8c625d64f1b8178a1 100644 --- a/src/mol-plugin-state/manager/structure/component.ts +++ b/src/mol-plugin-state/manager/structure/component.ts @@ -147,6 +147,12 @@ class StructureComponentManager extends StatefulPluginComponent<StructureCompone } } + if (root.genericRepresentations) { + for (const r of root.genericRepresentations) { + sync(r); + } + } + if (changed) return this.plugin.updateDataState(update); } diff --git a/src/mol-plugin-ui/plugin.tsx b/src/mol-plugin-ui/plugin.tsx index dda09d98eb763b86c16a6813283d93ea176201ea..2b4a5b52062846c0dce38a1bd8f85adb601498c7 100644 --- a/src/mol-plugin-ui/plugin.tsx +++ b/src/mol-plugin-ui/plugin.tsx @@ -101,7 +101,7 @@ class Layout extends PluginUIComponent { render() { const layout = this.plugin.layout.state; const controls = this.plugin.spec.layout?.controls || { }; - const viewport = this.plugin.spec.components?.viewport || DefaultViewport; + const viewport = this.plugin.spec.components?.viewport?.view || DefaultViewport; return <div className='msp-plugin'> <div className={this.layoutClassName}> @@ -129,7 +129,7 @@ export class ControlsWrapper extends PluginUIComponent { export class DefaultViewport extends PluginUIComponent { render() { - const VPControls = this.plugin.spec.components?.viewportControls || ViewportControls; + const VPControls = this.plugin.spec.components?.viewport?.controls || ViewportControls; return <> <Viewport /> diff --git a/src/mol-plugin-ui/skin/base/icons.scss b/src/mol-plugin-ui/skin/base/icons.scss index 5608f029b61116a4883e74e2199732b0f1c2db45..4bf993f12a25f6a3347a2500ce4524be3561a695 100644 --- a/src/mol-plugin-ui/skin/base/icons.scss +++ b/src/mol-plugin-ui/skin/base/icons.scss @@ -115,7 +115,7 @@ .msp-icon-layout:before { content: "\e810"; } .msp-icon-menu:before { content: "\e811"; } .msp-icon-check:before { content: "\e812"; } -.msp-icon-cancel:before { content: "\e813"; margin: 0; } +.msp-icon-cancel:before { content: "\e813"; } .msp-icon-cancel-circled:before { content: "\e814"; } .msp-icon-cancel-squared:before { content: "\e815"; } .msp-icon-plus-circled:before { content: "\e817"; } diff --git a/src/mol-plugin-ui/state/common.tsx b/src/mol-plugin-ui/state/common.tsx index 81df06671a0a3433b88a516060f2bb5e40ada8e4..4508bfbc8db49d48ca94b756fc4a9160bf14fcc6 100644 --- a/src/mol-plugin-ui/state/common.tsx +++ b/src/mol-plugin-ui/state/common.tsx @@ -249,7 +249,7 @@ abstract class TransformControlBase<P, S extends TransformControlBase.ComponentS <Icon name={this.props.simpleApply?.icon} /> {this.props.simpleApply?.header} </button> - {!info.isEmpty && <ToggleButton icon='cog' label='' title='Options' toggle={this.toggleExpanded} isSelected={!this.state.isCollapsed} disabled={this.state.busy} style={{ flex: '0 0 40px' }} />} + {!info.isEmpty && <ToggleButton icon='cog' label='' title='Options' toggle={this.toggleExpanded} isSelected={!this.state.isCollapsed} disabled={this.state.busy} style={{ flex: '0 0 40px', padding: 0 }} />} </div> if (this.state.isCollapsed) return apply; diff --git a/src/mol-plugin-ui/structure/components.tsx b/src/mol-plugin-ui/structure/components.tsx index a9d3ca5e243cb78471cb7db71c228c43e28ae26d..fd6b643c35b63d108f53d6399662da9709eefeea 100644 --- a/src/mol-plugin-ui/structure/components.tsx +++ b/src/mol-plugin-ui/structure/components.tsx @@ -119,8 +119,8 @@ class ComponentEditorControls extends PurePluginUIComponent<{}, ComponentEditorC <div className='msp-control-row msp-select-row'> <ToggleButton icon='bookmarks' label='Preset' toggle={this.togglePreset} isSelected={this.state.action === 'preset'} disabled={this.isDisabled} /> <ToggleButton icon='plus' label='Add' toggle={this.toggleAdd} isSelected={this.state.action === 'add'} disabled={this.isDisabled} /> - <ToggleButton icon='cog' label='' title='Options' style={{ flex: '0 0 40px' }} toggle={this.toggleOptions} isSelected={this.state.action === 'options'} disabled={this.isDisabled} /> - <IconButton customClass='msp-flex-item' style={{ flex: '0 0 40px' }} onClick={this.undo} disabled={!this.state.canUndo || this.isDisabled} icon='back' title={undoTitle} /> + <ToggleButton icon='cog' label='' title='Options' style={{ flex: '0 0 40px', padding: 0 }} toggle={this.toggleOptions} isSelected={this.state.action === 'options'} disabled={this.isDisabled} /> + <IconButton customClass='msp-flex-item' style={{ flex: '0 0 40px', padding: 0 }} onClick={this.undo} disabled={!this.state.canUndo || this.isDisabled} icon='back' title={undoTitle} /> </div> {this.state.action === 'preset' && this.presetControls} {this.state.action === 'add' && <div className='msp-control-offset'> @@ -347,9 +347,9 @@ class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureCo {label} {/* <small className='msp-25-lower-contrast-text' style={{ float: 'right' }}>{reprLabel}</small> */} </button> - <IconButton onClick={this.toggleVisible} icon='visual-visibility' toggleState={!cell.state.isHidden} title={`${cell.state.isHidden ? 'Show' : 'Hide'} component`} small customClass='msp-form-control' style={{ flex: '0 0 32px' }} /> - <IconButton onClick={this.toggleRemove} icon='remove' title='Remove' small toggleState={this.state.action === 'remove'} customClass='msp-form-control' style={{ flex: '0 0 32px' }} /> - <IconButton onClick={this.toggleAction} icon='dot-3' title='Actions' toggleState={this.state.action === 'action'} customClass='msp-form-control' style={{ flex: '0 0 32px', padding: '0px' }} /> + <IconButton onClick={this.toggleVisible} icon='visual-visibility' toggleState={!cell.state.isHidden} title={`${cell.state.isHidden ? 'Show' : 'Hide'} component`} small customClass='msp-form-control' style={{ flex: '0 0 32px', padding: 0 }} /> + <IconButton onClick={this.toggleRemove} icon='remove' title='Remove' small toggleState={this.state.action === 'remove'} customClass='msp-form-control' style={{ flex: '0 0 32px', padding: 0 }} /> + <IconButton onClick={this.toggleAction} icon='dot-3' title='Actions' toggleState={this.state.action === 'action'} customClass='msp-form-control' style={{ flex: '0 0 32px', padding: 0 }} /> </div> {this.state.action === 'remove' && <div style={{ marginBottom: '6px' }}> <ActionMenu items={this.removeActions} onSelect={this.selectRemoveAction} /> diff --git a/src/mol-plugin-ui/structure/focus.tsx b/src/mol-plugin-ui/structure/focus.tsx index c755da80311f47aac80116ba91344a66b7991740..998ba8272152873f9ad289f3eb9d572293902500 100644 --- a/src/mol-plugin-ui/structure/focus.tsx +++ b/src/mol-plugin-ui/structure/focus.tsx @@ -149,7 +149,10 @@ export class StructureFocusControls extends PluginUIComponent<{}, StructureFocus if (current) this.plugin.managers.camera.focusLoci(current.loci); } - clear = () => this.plugin.managers.structure.focus.clear() + clear = () => { + this.plugin.managers.structure.focus.clear(); + this.plugin.managers.camera.reset(); + } highlightCurrent = () => { const { current } = this.plugin.managers.structure.focus @@ -187,8 +190,8 @@ export class StructureFocusControls extends PluginUIComponent<{}, StructureFocus style={{ textAlignLast: current ? 'left' : void 0 }}> {label} </button> - {current && <IconButton onClick={this.clear} icon='cancel' title='Clear' customClass='msp-form-control' style={{ flex: '0 0 32px' }} disabled={this.isDisabled} />} - <ToggleButton icon='book-open' title='Select Target' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px' }} /> + {current && <IconButton onClick={this.clear} icon='cancel' title='Clear' customClass='msp-form-control' style={{ flex: '0 0 32px', padding: 0 }} disabled={this.isDisabled} />} + <ToggleButton icon='book-open' title='Select Target' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px', padding: 0 }} /> </div> {this.state.showAction && <ActionMenu items={this.actionItems} onSelect={this.selectAction} />} </>; diff --git a/src/mol-plugin-ui/structure/generic.tsx b/src/mol-plugin-ui/structure/generic.tsx index 860056d46e6636ac5a195b8ebb6978ca8e9d537b..0069ec32cf8d560a063f6080265d8f8a7b474875 100644 --- a/src/mol-plugin-ui/structure/generic.tsx +++ b/src/mol-plugin-ui/structure/generic.tsx @@ -139,8 +139,8 @@ export class GenericEntry<T extends HierarchyRef> extends PurePluginUIComponent< <button className='msp-form-control msp-control-button-label' title={`${label}. Click to focus.`} onClick={this.focus} onMouseEnter={this.highlight} onMouseLeave={this.clearHighlight} style={{ textAlign: 'left' }}> {label} <small>{description}</small> </button> - <IconButton customClass='msp-form-control' onClick={this.toggleVisibility} icon='visual-visibility' toggleState={!pivot.cell.state.isHidden} title={`${pivot.cell.state.isHidden ? 'Show' : 'Hide'}`} small style={{ flex: '0 0 32px' }} /> - {refs.length === 1 && <IconButton customClass='msp-form-control' onClick={this.toggleOptions} icon='dot-3' title='Options' toggleState={this.state.showOptions} style={{ flex: '0 0 32px', padding: '0px' }} />} + <IconButton customClass='msp-form-control' onClick={this.toggleVisibility} icon='visual-visibility' toggleState={!pivot.cell.state.isHidden} title={`${pivot.cell.state.isHidden ? 'Show' : 'Hide'}`} small style={{ flex: '0 0 32px', padding: 0 }} /> + {refs.length === 1 && <IconButton customClass='msp-form-control' onClick={this.toggleOptions} icon='dot-3' title='Options' toggleState={this.state.showOptions} style={{ flex: '0 0 32px', padding: 0 }} />} </div> {(refs.length === 1 && this.state.showOptions) && <> <div className='msp-control-offset'> diff --git a/src/mol-plugin-ui/structure/measurements.tsx b/src/mol-plugin-ui/structure/measurements.tsx index e18cd5e7b210ed829073793b2aead941f36f2e9e..32a04d9e5f3c0aabb488743073ed4099f0540bbd 100644 --- a/src/mol-plugin-ui/structure/measurements.tsx +++ b/src/mol-plugin-ui/structure/measurements.tsx @@ -143,7 +143,7 @@ export class MeasurementControls extends PurePluginUIComponent<{}, { isBusy: boo </button> {history.length > 1 && <IconButton small={true} customClass='msp-form-control' onClick={() => this.moveHistory(e, 'up')} icon='up-thin' style={{ flex: '0 0 20px', maxWidth: '20px', padding: 0 }} title={'Move up'} />} {history.length > 1 && <IconButton small={true} customClass='msp-form-control' onClick={() => this.moveHistory(e, 'down')} icon='down-thin' style={{ flex: '0 0 20px', maxWidth: '20px', padding: 0 }} title={'Move down'} />} - <IconButton small={true} customClass='msp-form-control' onClick={() => this.plugin.managers.structure.selection.modifyHistory(e, 'remove')} icon='remove' style={{ flex: '0 0 32px' }} title={'Remove'} /> + <IconButton small={true} customClass='msp-form-control' onClick={() => this.plugin.managers.structure.selection.modifyHistory(e, 'remove')} icon='remove' style={{ flex: '0 0 32px', padding: 0 }} title={'Remove'} /> </div>; } @@ -170,7 +170,7 @@ export class MeasurementControls extends PurePluginUIComponent<{}, { isBusy: boo return <> <div className='msp-control-row msp-select-row'> <ToggleButton icon='plus' label='Add' toggle={this.toggleAdd} isSelected={this.state.action === 'add'} disabled={this.state.isBusy} /> - <ToggleButton icon='cog' label='' title='Options' toggle={this.toggleOptions} isSelected={this.state.action === 'options'} disabled={this.state.isBusy} style={{ flex: '0 0 40px' }} /> + <ToggleButton icon='cog' label='' title='Options' toggle={this.toggleOptions} isSelected={this.state.action === 'options'} disabled={this.state.isBusy} style={{ flex: '0 0 40px', padding: 0 }} /> </div> {this.state.action === 'add' && this.add()} {this.state.action === 'options' && <MeasurementsOptions />} @@ -286,9 +286,9 @@ class MeasurementEntry extends PurePluginUIComponent<{ cell: StructureMeasuremen <button className='msp-form-control msp-control-button-label msp-no-overflow' title='Click to focus. Hover to highlight.' onClick={this.focus} style={{ width: 'auto', textAlign: 'left' }}> <span dangerouslySetInnerHTML={{ __html: this.label }} /> </button> - <IconButton small customClass='msp-form-control' onClick={this.toggleVisibility} icon='eye' style={{ flex: '0 0 32px' }} title={cell.state.isHidden ? 'Show' : 'Hide'} toggleState={!cell.state.isHidden} /> - <IconButton small customClass='msp-form-control' onClick={this.delete} icon='remove' style={{ flex: '0 0 32px' }} title='Delete' /> - <IconButton customClass='msp-form-control' onClick={this.toggleUpdate} icon='dot-3' style={{ flex: '0 0 32px', padding: '0px' }} title='Actions' toggleState={this.state.showUpdate} /> + <IconButton small customClass='msp-form-control' onClick={this.toggleVisibility} icon='eye' style={{ flex: '0 0 32px', padding: 0 }} title={cell.state.isHidden ? 'Show' : 'Hide'} toggleState={!cell.state.isHidden} /> + <IconButton small customClass='msp-form-control' onClick={this.delete} icon='remove' style={{ flex: '0 0 32px', padding: 0 }} title='Delete' /> + <IconButton customClass='msp-form-control' onClick={this.toggleUpdate} icon='dot-3' style={{ flex: '0 0 32px', padding: 0 }} title='Actions' toggleState={this.state.showUpdate} /> </div> {this.state.showUpdate && <> <ActionMenu items={this.actions} onSelect={this.selectAction} /> diff --git a/src/mol-plugin-ui/structure/selection.tsx b/src/mol-plugin-ui/structure/selection.tsx index 13459c29ed069557f4850a2dd97d8f13136bef0f..87dd5bbed3aacb253f1d0fbb1c77953756ac66b0 100644 --- a/src/mol-plugin-ui/structure/selection.tsx +++ b/src/mol-plugin-ui/structure/selection.tsx @@ -79,7 +79,7 @@ export class StructureSelectionControls<P, S extends StructureSelectionControlsS focus = () => { if (this.plugin.managers.structure.selection.stats.elementCount === 0) return; const principalAxes = this.plugin.managers.structure.selection.getPrincipalAxes(); - const { sphere } = this.plugin.managers.structure.selection.getBoundary() + const { sphere } = this.plugin.managers.structure.selection.getBoundary(); this.plugin.managers.camera.focusSphere(sphere, { principalAxes }); } @@ -173,7 +173,7 @@ export class StructureSelectionControls<P, S extends StructureSelectionControlsS style={{ textAlignLast: !empty ? 'left' : void 0 }}> {this.stats} </button> - {!empty && <IconButton onClick={this.clear} icon='cancel' title='Clear' customClass='msp-form-control' style={{ flex: '0 0 32px' }} />} + {!empty && <IconButton onClick={this.clear} icon='cancel' title='Clear' customClass='msp-form-control' style={{ flex: '0 0 32px', padding: 0 }} />} </div> <StructureMeasurementsControls /> </> diff --git a/src/mol-plugin-ui/structure/source.tsx b/src/mol-plugin-ui/structure/source.tsx index 1e823830d150391da23652e7d0b2909c7a7a1de8..82f6f44af004416bb227106a913b32f5c713624b 100644 --- a/src/mol-plugin-ui/structure/source.tsx +++ b/src/mol-plugin-ui/structure/source.tsx @@ -253,7 +253,7 @@ export class StructureSourceControls extends CollapsableControls<{}, StructureSo <button className='msp-btn msp-form-control msp-flex-item msp-no-overflow' onClick={this.toggleHierarchy} style={{ overflow: 'hidden', textOverflow: 'ellipsis' }} disabled={disabled} title={label}> {label} </button> - {presets.length > 0 && <IconButton customClass='msp-form-control' style={{ flex: '0 0 32px' }} onClick={this.togglePreset} icon='bookmarks' title='Presets' toggleState={this.state.show === 'presets'} disabled={disabled} />} + {presets.length > 0 && <IconButton customClass='msp-form-control' style={{ flex: '0 0 32px', padding: 0 }} onClick={this.togglePreset} icon='bookmarks' title='Presets' toggleState={this.state.show === 'presets'} disabled={disabled} />} </div> {this.state.show === 'hierarchy' && <ActionMenu items={this.hierarchyItems} onSelect={this.selectHierarchy} multiselect />} {this.state.show === 'presets' && <ActionMenu items={presets} onSelect={this.applyPreset} />} diff --git a/src/mol-plugin-ui/viewport.tsx b/src/mol-plugin-ui/viewport.tsx index b3dba83715a9ebbad33a5a9676cf93f8d1833cf4..07de365d43ec52128eb282ac8ae9f461451a6974 100644 --- a/src/mol-plugin-ui/viewport.tsx +++ b/src/mol-plugin-ui/viewport.tsx @@ -14,6 +14,7 @@ import { ControlGroup, IconButton } from './controls/common'; import { SimpleSettingsControl } from './viewport/simple-settings'; import { DownloadScreenshotControls } from './viewport/screenshot'; import { IconName } from './controls/icons'; +import { PluginConfig } from '../mol-plugin/config'; interface ViewportControlsState { isSettingsExpanded: boolean, @@ -93,7 +94,7 @@ export class ViewportControls extends PluginUIComponent<ViewportControlsProps, V <div> <div className='msp-semi-transparent-background' /> {this.icon('tools', this.toggleControls, 'Toggle Controls', this.plugin.layout.state.showControls)} - {this.icon('expand-layout', this.toggleExpanded, 'Toggle Expanded', this.plugin.layout.state.isExpanded)} + {this.plugin.config.get(PluginConfig.Viewport.ShowExpand) && this.icon('expand-layout', this.toggleExpanded, 'Toggle Expanded', this.plugin.layout.state.isExpanded)} {this.icon('settings', this.toggleSettingsExpanded, 'Settings / Controls Info', this.state.isSettingsExpanded)} </div> </div> diff --git a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts index 69290fb603eeb285f209b150385d1f83373f5bbd..09cc2b2dbe816047972842cbc1687d8796629880 100644 --- a/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts +++ b/src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts @@ -154,9 +154,9 @@ const assemblySymmetryPreset = StructureRepresentationPresetProvider({ if (!structureCell || !model) return {}; const assemblySymmetry = await tryCreateAssemblySymmetry(plugin, structureCell); - const repr = await PresetStructureRepresentations.auto.apply(ref, { ...params, globalThemeName: Tag.Cluster as any }, plugin); + const preset = await PresetStructureRepresentations.auto.apply(ref, { ...params, globalThemeName: Tag.Cluster as any }, plugin); - return { components: repr.components, representations: { ...repr.components, assemblySymmetry } }; + return { components: preset.components, representations: { ...preset.representations, assemblySymmetry } }; } }); diff --git a/src/mol-plugin/config.ts b/src/mol-plugin/config.ts index fb922a90a5fa9e43b607b301fe96301e4cd7ab52..9fb8adb7892f3047428db3efc48bf59cc1163602 100644 --- a/src/mol-plugin/config.ts +++ b/src/mol-plugin/config.ts @@ -29,6 +29,9 @@ export const PluginConfig = { // the following test is to include e.g. 'updated' files from PDBe || (!Model.isFromPdbArchive(s.models[0]) && s.models[0].entryId.length === 4)) }) + }, + Viewport: { + ShowExpand: item('viewer.show-expand-button', true) } } diff --git a/src/mol-plugin/spec.ts b/src/mol-plugin/spec.ts index c2310e3e42a5b4eec45ccac010e4832de4a98299..a900a6f85a8f15eb2d3425d3631238daec40e6cf 100644 --- a/src/mol-plugin/spec.ts +++ b/src/mol-plugin/spec.ts @@ -25,8 +25,10 @@ interface PluginSpec { components?: { remoteState?: 'none' | 'default', structureTools?: React.ComponentClass, - viewport?: React.ComponentClass, - viewportControls?: React.ComponentClass + viewport?: { + view?: React.ComponentClass, + controls?: React.ComponentClass + } }, config?: Map<PluginConfigItem, unknown> } diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 67151e7128b3dec2204ccd30f8d75dd32eb87b52..699e84444755defd906dfd050458da64e90b330f 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -441,17 +441,18 @@ export namespace ParamDefinition { * * if options is { [string]: string } and mapping is not provided, use the Value. */ - export function objectToOptions<K extends string, V>(options: { [k in K]: V }, f?: null | ((k: K, v: V) => string)): [K, string][] { - const ret: [K, string][] = []; + export function objectToOptions<K extends string, V>(options: { [k in K]: V }, f?: null | ((k: K, v: V) => string | [string, string])): [K, string][] { + const ret: ([K, string] | [K, string, string])[] = []; for (const k of Object.keys(options) as K[]) { if (!f) { if (typeof options[k as K] === 'string') ret.push([k as K, options[k as K] as any]); else ret.push([k as K, f === null ? k : stringToWords(k)]); } else { - ret.push([k, f(k as K, options[k as K])]) + const o = f(k as K, options[k as K]); + ret.push(typeof o === 'string' ? [k, o] : [k, o[0], o[1]]); } } - return ret; + return ret as [K, string][]; } /**