diff --git a/src/mol-plugin/state/transforms/visuals.ts b/src/mol-plugin/state/transforms/visuals.ts index 81760fc7e4bf58b3836a28a4aaf0daa1af46d987..b0238b0173f174ecfe3a044b3bf6d9ec24cbafe7 100644 --- a/src/mol-plugin/state/transforms/visuals.ts +++ b/src/mol-plugin/state/transforms/visuals.ts @@ -38,8 +38,9 @@ const CreateStructureRepresentation = PluginStateTransform.Create<SO.Molecule.St ctx.structureReprensentation.registry.types, name => PD.Group( ctx.structureReprensentation.registry.get(name).getParams(ctx.structureReprensentation.themeCtx, a.data), - { label: 'Params' } - ) + { label: 'Type Parameters' } + ), + { label: 'Type' } ) }) }, diff --git a/src/mol-plugin/ui/controls/parameters.tsx b/src/mol-plugin/ui/controls/parameters.tsx index 354bbf449dfbef3b25005d58aaaf3d5c48f0b577..d5c129e4440a4b08d2300214fceb23391ebef560 100644 --- a/src/mol-plugin/ui/controls/parameters.tsx +++ b/src/mol-plugin/ui/controls/parameters.tsx @@ -8,6 +8,8 @@ import * as React from 'react' import { ParamDefinition as PD } from 'mol-util/param-definition'; import { camelCaseToWords } from 'mol-util/string'; +import { ColorNames } from 'mol-util/color/tables'; +import { Color } from 'mol-util/color'; export interface ParameterControlsProps<P extends PD.Params = PD.Params> { params: P, @@ -37,6 +39,7 @@ function controlFor(param: PD.Any): ParamControl | undefined { case 'value': return void 0; case 'boolean': return BoolControl; case 'number': return NumberControl; + case 'converted': return ConvertedControl; case 'multi-select': return MultiSelectControl; case 'color': return ColorControl; case 'select': return SelectControl; @@ -122,37 +125,56 @@ export class SelectControl extends SimpleParam<PD.Select<any>> { } } - -export class MultiSelectControl extends SimpleParam<PD.MultiSelect<any>> { +export class IntervalControl extends SimpleParam<PD.Interval> { // onChange = (e: React.ChangeEvent<HTMLSelectElement>) => { // this.setState({ value: e.target.value }); // this.props.onChange(e.target.value); // } renderControl() { - return <span>multiselect TODO</span>; + return <span>interval TODO</span>; } } -export class IntervalControl extends SimpleParam<PD.Interval> { - // onChange = (e: React.ChangeEvent<HTMLSelectElement>) => { - // this.setState({ value: e.target.value }); - // this.props.onChange(e.target.value); - // } +export class ColorControl extends SimpleParam<PD.Color> { + onChange = (e: React.ChangeEvent<HTMLSelectElement>) => { + this.update(Color(parseInt(e.target.value))); + } renderControl() { - return <span>interval TODO</span>; + return <select value={this.props.value} onChange={this.onChange}> + {Object.keys(ColorNames).map(name => { + return <option key={name} value={(ColorNames as { [k: string]: Color})[name]}>{name}</option> + })} + </select>; } } -export class ColorControl extends SimpleParam<PD.Color> { - // onChange = (e: React.ChangeEvent<HTMLSelectElement>) => { - // this.setState({ value: e.target.value }); - // this.props.onChange(e.target.value); - // } +export class MultiSelectControl extends React.PureComponent<ParamProps<PD.MultiSelect<any>>> { + change(value: PD.MultiSelect<any>['defaultValue'] ) { + console.log(this.props.name, value); + this.props.onChange({ name: this.props.name, param: this.props.param, value }); + } - renderControl() { - return <span>color TODO</span>; + toggle(key: string) { + return () => { + if (this.props.value.indexOf(key) < 0) this.change(this.props.value.concat(key)); + else this.change(this.props.value.filter(v => v !== key)) + } + } + + render() { + const current = this.props.value; + const label = this.props.param.label || camelCaseToWords(this.props.name); + return <div> + <div>{label} <small>{`${current.length} of ${this.props.param.options.length}`}</small></div> + <div style={{ paddingLeft: '7px' }}> + {this.props.param.options.map(([value, label]) => + <button key={value} onClick={this.toggle(value)} disabled={this.props.isDisabled}> + {current.indexOf(value) >= 0 ? `âś“ ${label}` : `âś— ${label}`} + </button>)} + </div> + </div>; } } @@ -169,8 +191,11 @@ export class GroupControl extends React.PureComponent<ParamProps<PD.Group<any>>> render() { const value: PD.Mapped<any>['defaultValue'] = this.props.value; const params = this.props.param.params; + const label = this.props.param.label || camelCaseToWords(this.props.name); + // TODO toggle panel return <div> + <div>{label}</div> <ParameterControls params={params} onChange={this.onChangeParam} values={value.params} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} /> </div> } @@ -182,6 +207,7 @@ export class MappedControl extends React.PureComponent<ParamProps<PD.Mapped<any> } onChangeName: ParamOnChange = e => { + // TODO: Cache values when changing types? this.change({ name: e.value, params: this.props.param.map(e.value).defaultValue }); } @@ -210,4 +236,22 @@ export class MappedControl extends React.PureComponent<ParamProps<PD.Mapped<any> </div> </div> } -} \ No newline at end of file +} + +export class ConvertedControl extends React.PureComponent<ParamProps<PD.Converted<any, any>>> { + onChange: ParamOnChange = e => { + this.props.onChange({ + name: this.props.name, + param: this.props.param, + value: { name: e.value, params: this.props.param.toValue(e.value) } + }); + } + + render() { + const value = this.props.param.fromValue(this.props.value); + const Converted = controlFor(this.props.param.converted); + + if (!Converted) return null; + return <Converted param={this.props.param.converted} value={value} name={this.props.name} onChange={this.onChange} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} /> + } +} diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts index 6dbba30bc03067e313c7eb2b6644a3d37d41d66b..955906abca4e24c7fe9dbabccd88785038ebbdf3 100644 --- a/src/mol-util/param-definition.ts +++ b/src/mol-util/param-definition.ts @@ -134,12 +134,12 @@ export namespace ParamDefinition { export interface Converted<T, C> extends Base<T> { type: 'converted', - convertedControl: Any, + converted: Any, fromValue(v: T): C, toValue(v: C): T } - export function Converted<T, C extends Any>(defaultValue: T, convertedControl: C, fromValue: (v: T) => C, toValue: (v: C) => T, info?: Info): Converted<T, C> { - return setInfo<Converted<T, C>>({ type: 'converted', defaultValue, convertedControl, fromValue, toValue }, info); + export function Converted<T, C extends Any>(defaultValue: T, converted: C, fromValue: (v: T) => C, toValue: (v: C) => T): Converted<T, C> { + return { type: 'converted', defaultValue, converted, fromValue, toValue }; } export type Any = Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Numeric | Interval | LineGraph | Group<any> | Mapped<any> | Converted<any, any>