Ver código fonte

removed PD.categories, added PD.isEssential & UI support

David Sehnal 5 anos atrás
pai
commit
8436e17af9

+ 2 - 2
src/mol-geo/geometry/base.ts

@@ -35,8 +35,8 @@ export const VisualQualityOptions = PD.arrayToOptions(VisualQualityNames)
 
 export namespace BaseGeometry {
     export const Params = {
-        alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', category: PD.Categories.Simple }),
-        quality: PD.Select<VisualQuality>('auto', VisualQualityOptions, PD.SimpleCategory),
+        alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', isEssential: true }),
+        quality: PD.Select<VisualQuality>('auto', VisualQualityOptions, PD.Essential),
     }
     export type Params = typeof Params
 

+ 6 - 12
src/mol-plugin-state/transforms/representation.ts

@@ -151,16 +151,14 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
                     const p = themeCtx.colorThemeRegistry.get(name)
                     const ct = p.factory({}, params)
                     return { description: ct.description, legend: ct.legend }
-                },
-                category: PD.Categories.Simple
+                }
             }
 
             return {
                 type: PD.Mapped<any>(
                     registry.default.name,
                     registry.types,
-                    name => PD.Group<any>(registry.get(name).getParams(themeCtx, Structure.Empty)),
-                    PD.SimpleCategory),
+                    name => PD.Group<any>(registry.get(name).getParams(themeCtx, Structure.Empty))),
                 colorTheme: PD.Mapped<any>(
                     type.defaultColorTheme.name,
                     themeCtx.colorThemeRegistry.types,
@@ -170,8 +168,7 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
                 sizeTheme: PD.Mapped<any>(
                     type.defaultSizeTheme.name,
                     themeCtx.sizeThemeRegistry.types,
-                    name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams({ structure: Structure.Empty })),
-                    PD.SimpleCategory
+                    name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams({ structure: Structure.Empty }))
                 )
             }
         }
@@ -183,16 +180,14 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
                 const p = themeCtx.colorThemeRegistry.get(name)
                 const ct = p.factory(dataCtx, params)
                 return { description: ct.description, legend: ct.legend }
-            },
-            category: PD.Categories.Simple
+            }
         }
 
         return ({
             type: PD.Mapped<any>(
                 registry.default.name,
                 registry.getApplicableTypes(a.data),
-                name => PD.Group<any>(registry.get(name).getParams(themeCtx, a.data)),
-                PD.SimpleCategory),
+                name => PD.Group<any>(registry.get(name).getParams(themeCtx, a.data))),
             colorTheme: PD.Mapped<any>(
                 type.defaultColorTheme.name,
                 themeCtx.colorThemeRegistry.getApplicableTypes(dataCtx),
@@ -202,8 +197,7 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
             sizeTheme: PD.Mapped<any>(
                 type.defaultSizeTheme.name,
                 themeCtx.sizeThemeRegistry.types,
-                name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams(dataCtx)),
-                PD.SimpleCategory
+                name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams(dataCtx))
             )
         })
     }

+ 60 - 28
src/mol-plugin-ui/controls/parameters.tsx

@@ -31,30 +31,67 @@ export interface ParameterControlsProps<P extends PD.Params = PD.Params> {
     values: any,
     onChange: ParamsOnChange<PD.Values<P>>,
     isDisabled?: boolean,
-    /** null <=> "support" PD.categories === undefined */
-    categoryFilter?: ParameterControlsCategoryFilter
     onEnter?: () => void
 }
 
-export class ParameterControls<P extends PD.Params> extends React.PureComponent<ParameterControlsProps<P>, {}> {
+export class ParameterControls<P extends PD.Params> extends React.PureComponent<ParameterControlsProps<P>, { isExpanded: boolean }> {
+    state = { isExpanded: false };
+
     onChange: ParamOnChange = (params) => this.props.onChange(params, this.props.values);
 
-    render() {
+    renderControls(keys: string[], essentials: boolean) {
         const params = this.props.params;
         const values = this.props.values;
-        const filter = this.props.categoryFilter;
-        const keys = filterParamKeys(params, filter);
-        if (keys.length === 0 || values === undefined) return null;
+
         return <>
-            {keys.map(key => {
+            {keys.map(key => {                
                 const param = params[key];
                 if (param.isHidden) return null;
+                if ((essentials && !param.isEssential) || (!essentials && param.isEssential)) return null;
                 const Control = controlFor(param);
                 if (!Control) return null;
-                return <Control param={param} key={key} onChange={this.onChange} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} name={key} value={values[key]} categoryFilter={filter} />
+                return <Control param={param} key={key} onChange={this.onChange} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} name={key} value={values[key]} />
             })}
         </>;
     }
+
+    toggleExpanded = () => this.setState({ isExpanded: !this.state.isExpanded });
+
+    renderCategories(keys: string[]) {
+        return <>
+            {this.renderControls(keys, true)}
+            <div className='msp-control-group-header' style={{ marginTop: '1px' }}>
+                <button className='msp-btn msp-btn-block' onClick={this.toggleExpanded}>
+                    <span className={`msp-icon msp-icon-${this.state.isExpanded ? 'collapse' : 'expand'}`} />
+                    {'Advanced Parameters'}
+                </button>
+            </div>
+            {this.state.isExpanded && <div className='msp-control-offset'>
+                {this.renderControls(keys, false)}
+            </div>}
+        </>;
+    }
+
+    render() {
+        const params = this.props.params;
+        const values = this.props.values;
+        const keys = Object.keys(params);
+        if (keys.length === 0 || values === undefined) return null;
+
+        let essentialCount = 0, nonEssentialCount = 0;
+        for (const k of keys) {
+            const p = params[k];
+            if (p.isEssential) essentialCount += p.isHidden ? 0 : 1;
+            else nonEssentialCount += p.isHidden ? 0 : 1;
+        }
+
+        if (essentialCount === 0 && nonEssentialCount === 0) return null;
+
+        if (essentialCount === 0) return this.renderControls(keys, false);
+        if (nonEssentialCount === 0) return this.renderControls(keys, true);
+
+        return this.renderCategories(keys);
+    }
 }
 
 export class ParameterMappingControl<S, T> extends PluginUIComponent<{ mapping: ParamMapping<S, T, PluginContext> }> {
@@ -76,10 +113,6 @@ export class ParameterMappingControl<S, T> extends PluginUIComponent<{ mapping:
     }
 }
 
-function filterParamKeys(params: PD.Params, filter: ParameterControlsCategoryFilter | undefined) {
-    return filter === void 0 ? Object.keys(params) : Object.keys(params).filter(key => PD.hasCategory(params[key], filter));
-}
-
 function controlFor(param: PD.Any): ParamControl | undefined {
     switch (param.type) {
         case 'value': return void 0;
@@ -131,7 +164,6 @@ export interface ParamProps<P extends PD.Base<any> = PD.Base<any>> {
     value: P['defaultValue'],
     param: P,
     isDisabled?: boolean,
-    categoryFilter?: ParameterControlsCategoryFilter
     onChange: ParamOnChange,
     onEnter?: () => void
 }
@@ -428,7 +460,7 @@ export class IntervalControl extends React.PureComponent<ParamProps<PD.Interval>
                 </div>
             </div>
             <div className='msp-control-offset' style={{ display: this.state.isExpanded ? 'block' : 'none' }}>
-                <ParameterControls params={this.components} values={v} onChange={this.componentChange} onEnter={this.props.onEnter} categoryFilter={this.props.categoryFilter} />
+                <ParameterControls params={this.components} values={v} onChange={this.componentChange} onEnter={this.props.onEnter} />
             </div>
         </>;
     }
@@ -553,7 +585,7 @@ export class Vec3Control extends React.PureComponent<ParamProps<PD.Vec3>, { isEx
                 </div>
             </div>
             <div className='msp-control-offset' style={{ display: this.state.isExpanded ? 'block' : 'none' }}>
-                <ParameterControls params={this.components} values={v} onChange={this.componentChange} onEnter={this.props.onEnter} categoryFilter={this.props.categoryFilter} />
+                <ParameterControls params={this.components} values={v} onChange={this.componentChange} onEnter={this.props.onEnter} />
             </div>
         </>;
     }
@@ -668,11 +700,11 @@ export class GroupControl extends React.PureComponent<ParamProps<PD.Group<any>>
         const params = this.props.param.params;
 
         // Do not show if there are no params.
-        if (filterParamKeys(params, this.props.categoryFilter).length === 0) return null;
+        if (Object.keys(params).length === 0) return null;
 
         const label = this.props.param.label || camelCaseToWords(this.props.name);
 
-        const controls = <ParameterControls params={params} onChange={this.onChangeParam} values={this.props.value} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} categoryFilter={this.props.categoryFilter} />;
+        const controls = <ParameterControls params={params} onChange={this.onChangeParam} values={this.props.value} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} />;
 
         if (this.props.inMapped) {
             return <div className='msp-control-offset'>{controls}</div>;
@@ -689,7 +721,7 @@ export class GroupControl extends React.PureComponent<ParamProps<PD.Group<any>>
                     {label}
                 </button>
             </div>
-            {this.state.isExpanded && <div className='msp-control-offset' style={{ display: this.state.isExpanded ? 'block' : 'none' }}>
+            {this.state.isExpanded && <div className='msp-control-offset'>
                 {controls}
             </div>}
         </div>
@@ -749,11 +781,11 @@ export class MappedControl extends React.PureComponent<ParamProps<PD.Mapped<any>
         }
 
         if (param.type === 'group' && !param.isFlat) {
-            if (filterParamKeys(param.params, this.props.categoryFilter).length > 0) {
+            if (Object.keys(param.params).length > 0) {
                 return <div className='msp-mapped-parameter-group'>
                     {Select}
                     <IconButton icon='log' onClick={this.toggleExpanded} toggleState={this.state.isExpanded} title={`${label} Properties`} />
-                    {this.state.isExpanded && <GroupControl inMapped param={param} value={value.params} name={`${label} Properties`} onChange={this.onChangeParam} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} categoryFilter={this.props.categoryFilter} />}
+                    {this.state.isExpanded && <GroupControl inMapped param={param} value={value.params} name={`${label} Properties`} onChange={this.onChangeParam} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} />}
                 </div>
             }
 
@@ -762,12 +794,12 @@ export class MappedControl extends React.PureComponent<ParamProps<PD.Mapped<any>
 
         return <>
             {Select}
-            <Mapped param={param} value={value.params} name={`${label} Properties`} onChange={this.onChangeParam} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} categoryFilter={this.props.categoryFilter} />
+            <Mapped param={param} value={value.params} name={`${label} Properties`} onChange={this.onChangeParam} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} />
         </>
     }
 }
 
-class ObjectListEditor extends React.PureComponent<{ params: PD.Params, value: object, isUpdate?: boolean, apply: (value: any) => void, isDisabled?: boolean, categoryFilter?: ParameterControlsCategoryFilter }, { params: PD.Params, value: object, current: object }> {
+class ObjectListEditor extends React.PureComponent<{ params: PD.Params, value: object, isUpdate?: boolean, apply: (value: any) => void, isDisabled?: boolean }, { params: PD.Params, value: object, current: object }> {
     state = { params: {}, value: void 0 as any, current: void 0 as any };
 
     onChangeParam: ParamOnChange = e => {
@@ -789,7 +821,7 @@ class ObjectListEditor extends React.PureComponent<{ params: PD.Params, value: o
 
     render() {
         return <>
-            <ParameterControls params={this.props.params} onChange={this.onChangeParam} values={this.state.current} onEnter={this.apply} isDisabled={this.props.isDisabled} categoryFilter={this.props.categoryFilter} />
+            <ParameterControls params={this.props.params} onChange={this.onChangeParam} values={this.state.current} onEnter={this.apply} isDisabled={this.props.isDisabled} />
             <button className={`msp-btn msp-btn-block msp-form-control msp-control-top-offset`} onClick={this.apply} disabled={this.props.isDisabled}>
                 {this.props.isUpdate ? 'Update' : 'Add'}
             </button>
@@ -797,7 +829,7 @@ class ObjectListEditor extends React.PureComponent<{ params: PD.Params, value: o
     }
 }
 
-class ObjectListItem extends React.PureComponent<{ param: PD.ObjectList, value: object, index: number, actions: ObjectListControl['actions'], isDisabled?: boolean, categoryFilter?: ParameterControlsCategoryFilter }, { isExpanded: boolean }> {
+class ObjectListItem extends React.PureComponent<{ param: PD.ObjectList, value: object, index: number, actions: ObjectListControl['actions'], isDisabled?: boolean }, { isExpanded: boolean }> {
     state = { isExpanded: false };
 
     update = (v: object) => {
@@ -846,7 +878,7 @@ class ObjectListItem extends React.PureComponent<{ param: PD.ObjectList, value:
                 </div>
             </div>
             {this.state.isExpanded && <div className='msp-control-offset'>
-                <ObjectListEditor params={this.props.param.element} apply={this.update} value={this.props.value} isUpdate isDisabled={this.props.isDisabled} categoryFilter={this.props.categoryFilter} />
+                <ObjectListEditor params={this.props.param.element} apply={this.update} value={this.props.value} isUpdate isDisabled={this.props.isDisabled} />
             </div>}
         </>;
     }
@@ -910,9 +942,9 @@ export class ObjectListControl extends React.PureComponent<ParamProps<PD.ObjectL
             </div>
 
             {this.state.isExpanded && <div className='msp-control-offset'>
-                {this.props.value.map((v, i) => <ObjectListItem key={i} param={this.props.param} value={v} index={i} actions={this.actions} categoryFilter={this.props.categoryFilter} />)}
+                {this.props.value.map((v, i) => <ObjectListItem key={i} param={this.props.param} value={v} index={i} actions={this.actions} />)}
                 <ControlGroup header='New Item'>
-                    <ObjectListEditor params={this.props.param.element} apply={this.add} value={this.props.param.ctor()} isDisabled={this.props.isDisabled} categoryFilter={this.props.categoryFilter} />
+                    <ObjectListEditor params={this.props.param.element} apply={this.add} value={this.props.param.ctor()} isDisabled={this.props.isDisabled} />
                 </ControlGroup>
             </div>}
         </>;

+ 3 - 9
src/mol-plugin-ui/state/common.tsx

@@ -31,7 +31,7 @@ class StateTransformParameters extends PurePluginUIComponent<StateTransformParam
     };
 
     render() {
-        return <ParameterControls params={this.props.info.params} values={this.props.params} onChange={this.onChange} onEnter={this.props.events.onEnter} isDisabled={this.props.isDisabled} categoryFilter={this.props.simpleOnly ? PD.Categories.Simple : void 0} />;
+        return <ParameterControls params={this.props.info.params} values={this.props.params} onChange={this.onChange} onEnter={this.props.events.onEnter} isDisabled={this.props.isDisabled} />;
     }
 }
 
@@ -50,8 +50,7 @@ namespace StateTransformParameters {
         params: any,
         isDisabled?: boolean,
         a?: StateObject,
-        b?: StateObject,
-        simpleOnly?: boolean
+        b?: StateObject
     }
 
     export type Class = React.ComponentClass<Props>
@@ -172,10 +171,6 @@ abstract class TransformControlBase<P, S extends TransformControlBase.ComponentS
         this.setState({ isCollapsed: !this.state.isCollapsed });
     }
 
-    toggleSimple = () => {
-        this.setState({ simpleOnly: !this.state.simpleOnly });
-    }
-
     render() {
         const info = this.getInfo();
         const isEmpty = info.isEmpty && this.isUpdate();
@@ -203,7 +198,7 @@ abstract class TransformControlBase<P, S extends TransformControlBase.ComponentS
                 </button>
             </div>}
             {!isEmpty && !this.state.isCollapsed && <>
-                <ParamEditor info={info} a={a} b={b} events={this.events} params={this.state.params} isDisabled={this.state.busy} simpleOnly={this.state.simpleOnly} />
+                <ParamEditor info={info} a={a} b={b} events={this.events} params={this.state.params} isDisabled={this.state.busy} />
 
                 <div className='msp-transform-apply-wrap'>
                     <button className='msp-btn msp-btn-block msp-transform-default-params' onClick={this.setDefault} disabled={this.state.busy} title='Set default params'><Icon name='cw' /></button>
@@ -216,7 +211,6 @@ abstract class TransformControlBase<P, S extends TransformControlBase.ComponentS
                             {this.applyText()}
                         </button>
                     </div>
-                    {this.isUpdate() && <button className='msp-btn msp-btn-block msp-transform-default-params' style={{ left: '33px' }}  onClick={this.toggleSimple} disabled={this.state.busy} title='Show/hide simple params'><Icon name='log' /></button>}
                 </div>
             </>}
         </div>

+ 6 - 31
src/mol-util/param-definition.ts

@@ -14,27 +14,20 @@ import { Legend } from './legend';
 import { stringToWords } from './string';
 
 export namespace ParamDefinition {
-    interface InfoBase {
+    export interface Info {
         label?: string,
         description?: string,
         legend?: Legend,
         fieldLabels?: { [name: string]: string },
         isHidden?: boolean,
         shortLabel?: boolean,
-        twoColumns?: boolean
+        twoColumns?: boolean,
+        isEssential?: boolean
 
         help?: (value: any) => { description?: string, legend?: Legend }
     }
 
-    export enum Categories {
-        Simple = 'Simple'
-    }
-
-    export const SimpleCategory = { category: [Categories.Simple] };
-
-    export interface Info extends InfoBase {
-        category?: string | string[]
-    }
+    export const Essential = { isEssential: true };
 
     function setInfo<T extends Base<any>>(param: T, info?: Info): T {
         if (!info) return param;
@@ -45,16 +38,13 @@ export namespace ParamDefinition {
         if (info.isHidden) param.isHidden = info.isHidden;
         if (info.shortLabel) param.shortLabel = info.shortLabel;
         if (info.twoColumns) param.twoColumns = info.twoColumns;
-        if (info.category) {
-            param.categories = typeof info.category === 'string' ? [info.category] : info.category.length > 0 ? info.category : void 0;
-        }
+        if (info.isEssential) param.isEssential = info.isEssential;
 
         if (info.help) param.help = info.help;
         return param;
     }
 
-    export interface Base<T> extends InfoBase {
-        categories?: ReadonlyArray<string>
+    export interface Base<T> extends Info {
         isOptional?: boolean,
         defaultValue: T
     }
@@ -387,21 +377,6 @@ export namespace ParamDefinition {
         return false;
     }
 
-    const _isNullish = (x: any) => !x;
-    export function hasCategory(param: Any, filter?: string | null | (string | null)[]) {
-        if (!filter || filter.length === 0) return filter === null || filter?.length === 0 ? !param.categories : false;
-        if (!param.categories) return !filter || (typeof filter !== 'string' && filter.some(_isNullish));
-        if (typeof filter === 'string') return param.categories.indexOf(filter) >= 0;
-        if (filter.length === 1 && filter[0]) return param.categories.indexOf(filter[0]) >= 0;
-
-        for (const c of param.categories) {
-            for (const d of filter) {
-                if (c === d) return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Map an object to a list of [K, string][] to be used as options, stringToWords for key used by default (or identity of null).
      *