/** * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal * @author Alexander Rose */ import * as React from 'react'; import { throttleTime } from 'rxjs'; import { Canvas3DParams } from '../mol-canvas3d/canvas3d'; import { PluginCommands } from '../mol-plugin/commands'; import { LeftPanelTabName } from '../mol-plugin/layout'; import { StateTransform } from '../mol-state'; import { ParamDefinition as PD } from '../mol-util/param-definition'; import { PluginUIComponent } from './base'; import { IconButton, SectionHeader } from './controls/common'; import { AccountTreeOutlinedSvg, DeleteOutlinedSvg, HelpOutlineSvg, HomeOutlinedSvg, SaveOutlinedSvg, TuneSvg } from './controls/icons'; import { ParameterControls } from './controls/parameters'; import { StateObjectActions } from './state/actions'; import { RemoteStateSnapshots, StateSnapshots } from './state/snapshots'; import { StateTree } from './state/tree'; import { HelpContent } from './viewport/help'; export class CustomImportControls extends PluginUIComponent<{ initiallyCollapsed?: boolean }> { componentDidMount() { this.subscribe(this.plugin.state.behaviors.events.changed, () => this.forceUpdate()); } render() { const controls: JSX.Element[] = []; this.plugin.customImportControls.forEach((Controls, key) => { controls.push(); }); return controls.length > 0 ? <>{controls} : null; } } export class LeftPanelControls extends PluginUIComponent<{}, { tab: LeftPanelTabName }> { state = { tab: this.plugin.behaviors.layout.leftPanelTabName.value }; componentDidMount() { this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, tab => { if (this.state.tab !== tab) this.setState({ tab }); if (tab === 'none' && this.plugin.layout.state.regionState.left !== 'collapsed') { PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'collapsed' } } }); } }); this.subscribe(this.plugin.state.data.events.changed, ({ state }) => { if (this.state.tab !== 'data') return; if (state.cells.size === 1) this.set('root'); }); } set = (tab: LeftPanelTabName) => { if (this.state.tab === tab) { this.setState({ tab: 'none' }, () => this.plugin.behaviors.layout.leftPanelTabName.next('none')); PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'collapsed' } } }); return; } this.setState({ tab }, () => this.plugin.behaviors.layout.leftPanelTabName.next(tab)); if (this.plugin.layout.state.regionState.left !== 'full') { PluginCommands.Layout.Update(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'full' } } }); } }; tabs: { [K in LeftPanelTabName]: JSX.Element } = { 'none': <>, 'root': <> {this.plugin.spec.components?.remoteState !== 'none' && } , 'data': <> State Tree} /> , 'states': , 'settings': <> , 'help': <> }; render() { const tab = this.state.tab; return
this.set('root')} title='Home' /> this.set('states')} title='Plugin State' /> this.set('help')} title='Help' />
this.set('settings')} title='Settings' />
{this.tabs[tab]}
; } } class DataIcon extends PluginUIComponent<{ set: (tab: LeftPanelTabName) => void }, { changed: boolean }> { state = { changed: false }; get tab() { return this.plugin.behaviors.layout.leftPanelTabName.value; } componentDidMount() { this.subscribe(this.plugin.behaviors.layout.leftPanelTabName, tab => { if (this.tab === 'data') this.setState({ changed: false }); else this.forceUpdate(); }); this.subscribe(this.plugin.state.data.events.changed, state => { if (this.tab !== 'data') this.setState({ changed: true }); }); } render() { return this.props.set('data')} title='State Tree' style={{ position: 'relative' }} extraContent={this.state.changed ?
: void 0} />; } } class FullSettings extends PluginUIComponent { private setSettings = (p: { param: PD.Base, name: string, value: any }) => { PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { [p.name]: p.value } }); }; componentDidMount() { this.subscribe(this.plugin.events.canvas3d.settingsUpdated, () => this.forceUpdate()); this.subscribe(this.plugin.layout.events.updated, () => this.forceUpdate()); if (this.plugin.canvas3d) { this.subscribe(this.plugin.canvas3d.camera.stateChanged.pipe(throttleTime(500, undefined, { leading: true, trailing: true })), state => { if (state.radiusMax !== undefined || state.radius !== undefined) { this.forceUpdate(); } }); } } render() { return <> {this.plugin.canvas3d && <> } ; } } class RemoveAllButton extends PluginUIComponent<{ }> { componentDidMount() { this.subscribe(this.plugin.state.events.cell.created, e => { if (e.cell.transform.parent === StateTransform.RootRef) this.forceUpdate(); }); this.subscribe(this.plugin.state.events.cell.removed, e => { if (e.parent === StateTransform.RootRef) this.forceUpdate(); }); } remove = (e: React.MouseEvent) => { e.preventDefault(); PluginCommands.State.RemoveObject(this.plugin, { state: this.plugin.state.data, ref: StateTransform.RootRef }); }; render() { const count = this.plugin.state.data.tree.children.get(StateTransform.RootRef).size; if (count === 0) return null; return ; } }