Browse Source

mol-plugin-ui: ActionMenu fixes

David Sehnal 5 years ago
parent
commit
83698cc52d
2 changed files with 72 additions and 46 deletions
  1. 23 8
      src/mol-plugin-ui/controls/action-menu.tsx
  2. 49 38
      src/mol-plugin-ui/controls/parameters.tsx

+ 23 - 8
src/mol-plugin-ui/controls/action-menu.tsx

@@ -48,14 +48,16 @@ export namespace ActionMenu {
         items: ActionMenu.Spec,
         header?: string,
         label?: string,
-        current?: ActionMenu.Item,
+        current?: Item,
         onSelect: (value: any) => void
     }
 
-    export class Toggle extends React.PureComponent<ToggleProps, { isSelected: boolean }> {
+    type ToggleState = { current?: Item, isSelected: boolean }
+
+    export class Toggle extends React.PureComponent<ToggleProps, ToggleState> {
         private sub: Subscription | undefined = void 0;
 
-        state = { isSelected: false };
+        state = { isSelected: false, current: this.props.current };
 
         componentDidMount() {
             this.sub = this.props.menu.commands.subscribe(command => {
@@ -85,6 +87,11 @@ export namespace ActionMenu {
             this.props.menu.toggle(this.props);
         }
 
+        static getDerivedStateFromProps(props: ToggleProps, state: ToggleState) {
+            if (props.current === state.current) return null;
+            return { isSelected: false, current: props.current };
+        }
+
         render() {
             const props = this.props;
             const label = props.label || props.header;
@@ -95,7 +102,9 @@ export namespace ActionMenu {
         }
     }
 
-    export class Options extends React.PureComponent<{ menu: ActionMenu }, { command: Command, isVisible: boolean }> {
+    type  OptionsProps = { menu: ActionMenu, header?: string, items?: Spec, current?: Item | undefined }
+
+    export class Options extends React.PureComponent<OptionsProps, { command: Command, isVisible: boolean }> {
         private sub: Subscription | undefined = void 0;
 
         state = { isVisible: false, command: HideCmd };
@@ -127,15 +136,21 @@ export namespace ActionMenu {
         }
 
         render() {
-            if (!this.state.isVisible || this.state.command.type !== 'toggle') return null;
+            const cmd = this.state.command;
+            if (!this.state.isVisible || cmd.type !== 'toggle') return null;
+
+            if (this.props.items) {
+                if (cmd.items !== this.props.items || cmd.current !== this.props.current) return null;
+            }
+
             return <div className='msp-action-menu-options' style={{ marginTop: '1px' }}>
-                {this.state.command.header && <div className='msp-control-group-header' style={{ position: 'relative' }}>
+                {cmd.header && <div className='msp-control-group-header' style={{ position: 'relative' }}>
                     <button className='msp-btn msp-btn-block' onClick={this.hide}>
                         <Icon name='off' style={{ position: 'absolute', right: '2px', top: 0 }} />
-                        <b>{this.state.command.header}</b>
+                        <b>{cmd.header}</b>
                     </button>
                 </div>}
-                <Section menu={this.props.menu} items={this.state.command.items} onSelect={this.onSelect} current={this.state.command.current} />
+                <Section menu={this.props.menu} items={cmd.items} onSelect={this.onSelect} current={cmd.current} />
             </div>
         }
     }

+ 49 - 38
src/mol-plugin-ui/controls/parameters.tsx

@@ -71,7 +71,6 @@ export class ParameterMappingControl<S, T> extends PluginUIComponent<{ mapping:
     }
 }
 
-
 function controlFor(param: PD.Any): ParamControl | undefined {
     switch (param.type) {
         case 'value': return void 0;
@@ -128,6 +127,43 @@ export interface ParamProps<P extends PD.Base<any> = PD.Base<any>> {
 }
 export type ParamControl = React.ComponentClass<ParamProps<any>>
 
+function renderSimple(options: { props: ParamProps<any>, state: { isExpanded: boolean }, control: JSX.Element, addOn: JSX.Element | null, toggleHelp: () => void }) {
+    const { props, state, control, toggleHelp, addOn } = options;
+
+    const _className = ['msp-control-row'];
+    if (props.param.shortLabel) _className.push('msp-control-label-short')
+    if (props.param.twoColumns) _className.push('msp-control-col-2')
+    const className = _className.join(' ');
+
+    const label = props.param.label || camelCaseToWords(props.name);
+    const help = props.param.help
+        ? props.param.help(props.value)
+        : { description: props.param.description, legend: props.param.legend }
+    const desc = props.param.description;
+    const hasHelp = help.description || help.legend
+    return <>
+        <div className={className}>
+            <span title={desc}>
+                {label}
+                {hasHelp &&
+                    <button className='msp-help msp-btn-link msp-btn-icon msp-control-group-expander' onClick={toggleHelp}
+                        title={desc || `${state.isExpanded ? 'Hide' : 'Show'} help`}
+                        style={{ background: 'transparent', textAlign: 'left', padding: '0' }}>
+                        <span className={`msp-icon msp-icon-help-circle-${state.isExpanded ? 'collapse' : 'expand'}`} />
+                    </button>
+                }
+            </span>
+            <div>
+                {control}
+            </div>
+        </div>
+        {hasHelp && state.isExpanded && <div className='msp-control-offset'>
+            <ParamHelp legend={help.legend} description={help.description} />
+        </div>}
+        {addOn}
+    </>;
+}
+
 export abstract class SimpleParam<P extends PD.Any> extends React.PureComponent<ParamProps<P>, { isExpanded: boolean }> {
     state = { isExpanded: false };
 
@@ -138,44 +174,16 @@ export abstract class SimpleParam<P extends PD.Any> extends React.PureComponent<
     abstract renderControl(): JSX.Element;
     renderAddOn(): JSX.Element | null { return null; }
     
-    private get className() {
-        const className = ['msp-control-row'];
-        if (this.props.param.shortLabel) className.push('msp-control-label-short')
-        if (this.props.param.twoColumns) className.push('msp-control-col-2')
-        return className.join(' ')
-    }
-
-
-    toggleExpanded = () => this.setState({ isExpanded: !this.state.isExpanded });
+    toggleHelp = () => this.setState({ isExpanded: !this.state.isExpanded });
 
     render() {
-        const label = this.props.param.label || camelCaseToWords(this.props.name);
-        const help = this.props.param.help
-            ? this.props.param.help(this.props.value)
-            : { description: this.props.param.description, legend: this.props.param.legend }
-        const desc = this.props.param.description;
-        const hasHelp = help.description || help.legend
-        return <>
-            <div className={this.className}>
-                <span title={desc}>
-                    {label}
-                    {hasHelp &&
-                        <button className='msp-help msp-btn-link msp-btn-icon msp-control-group-expander' onClick={this.toggleExpanded}
-                            title={desc || `${this.state.isExpanded ? 'Hide' : 'Show'} help`}
-                            style={{ background: 'transparent', textAlign: 'left', padding: '0' }}>
-                            <span className={`msp-icon msp-icon-help-circle-${this.state.isExpanded ? 'collapse' : 'expand'}`} />
-                        </button>
-                    }
-                </span>
-                <div>
-                    {this.renderControl()}
-                </div>
-            </div>
-            {hasHelp && this.state.isExpanded && <div className='msp-control-offset'>
-                <ParamHelp legend={help.legend} description={help.description} />
-            </div>}
-            {this.renderAddOn()}
-        </>;
+        return renderSimple({
+            props: this.props,
+            state: this.state,
+            control: this.renderControl(),
+            toggleHelp: this.toggleHelp,
+            addOn: this.renderAddOn()
+        });
     }
 }
 
@@ -340,7 +348,10 @@ export class SelectControl extends SimpleParam<PD.Select<string | number>> {
     }
 
     renderAddOn() {
-        return <ActionMenu.Options menu={this.menu} />;
+        const items = this.items(this.props.param);
+        const current = ActionMenu.findCurrent(items, this.props.value);
+
+        return <ActionMenu.Options menu={this.menu} items={items} current={current} />;
     }
 }