Forráskód Böngészése

added IntervalControl, use 'step' for precision, allow 'range' in Vec3

Alexander Rose 5 éve
szülő
commit
0e91aa521e

+ 50 - 10
src/mol-plugin-ui/controls/parameters.tsx

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -19,6 +19,7 @@ import { _Props, _State } from '../base';
 import { legendFor } from './legend';
 import { Legend as LegendData } from '../../mol-util/legend';
 import { CombinedColorControl, ColorValueOption, ColorOptions } from './color';
+import { getPrecision } from '../../mol-util/number';
 
 export interface ParameterControlsProps<P extends PD.Params = PD.Params> {
     params: P,
@@ -214,17 +215,20 @@ export class NumberInputControl extends React.PureComponent<ParamProps<PD.Numeri
     state = { value: '0' };
 
     update = (value: number) => {
+        const p = getPrecision(this.props.param.step || 0.01)
+        value = parseFloat(value.toFixed(p))
         this.props.onChange({ param: this.props.param, name: this.props.name, value });
     }
 
     render() {
         const placeholder = this.props.param.label || camelCaseToWords(this.props.name);
         const label = this.props.param.label || camelCaseToWords(this.props.name);
+        const p = getPrecision(this.props.param.step || 0.01)
         return <div className='msp-control-row'>
             <span title={this.props.param.description}>{label}</span>
             <div>
                 <NumericInput
-                    value={this.props.value} onEnter={this.props.onEnter} placeholder={placeholder}
+                    value={parseFloat(this.props.value.toFixed(p))} onEnter={this.props.onEnter} placeholder={placeholder}
                     isDisabled={this.props.isDisabled} onChange={this.update} />
             </div>
         </div>;
@@ -306,10 +310,45 @@ export class SelectControl extends SimpleParam<PD.Select<string | number>> {
     }
 }
 
-export class IntervalControl extends SimpleParam<PD.Interval> {
-    onChange = (v: [number, number]) => { this.update(v); }
-    renderControl() {
-        return <span>interval TODO</span>;
+export class IntervalControl extends React.PureComponent<ParamProps<PD.Interval>, { isExpanded: boolean }> {
+    state = { isExpanded: false }
+
+    components = {
+        0: PD.Numeric(0, { step: this.props.param.step }, { label: 'Min' }),
+        1: PD.Numeric(0, { step: this.props.param.step }, { label: 'Max' })
+    }
+
+    change(value: PD.MultiSelect<any>['defaultValue']) {
+        this.props.onChange({ name: this.props.name, param: this.props.param, value });
+    }
+
+    componentChange: ParamOnChange = ({ name, value }) => {
+        const v = [...this.props.value];
+        v[+name] = value;
+        this.change(v);
+    }
+
+    toggleExpanded = (e: React.MouseEvent<HTMLButtonElement>) => {
+        this.setState({ isExpanded: !this.state.isExpanded });
+        e.currentTarget.blur();
+    }
+
+    render() {
+        const v = this.props.value;
+        const label = this.props.param.label || camelCaseToWords(this.props.name);
+        const p = getPrecision(this.props.param.step || 0.01)
+        const value = `[${v[0].toFixed(p)}, ${v[1].toFixed(p)}]`;
+        return <>
+            <div className='msp-control-row'>
+                <span>{label}</span>
+                <div>
+                    <button onClick={this.toggleExpanded}>{value}</button>
+                </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} />
+            </div>
+        </>;
     }
 }
 
@@ -399,9 +438,9 @@ export class Vec3Control extends React.PureComponent<ParamProps<PD.Vec3>, { isEx
     state = { isExpanded: false }
 
     components = {
-        0: PD.Numeric(0, void 0, { label: (this.props.param.fieldLabels && this.props.param.fieldLabels.x) || 'X' }),
-        1: PD.Numeric(0, void 0, { label: (this.props.param.fieldLabels && this.props.param.fieldLabels.y) || 'Y' }),
-        2: PD.Numeric(0, void 0, { label: (this.props.param.fieldLabels && this.props.param.fieldLabels.z) || 'Z' })
+        0: PD.Numeric(0, { step: this.props.param.step }, { label: (this.props.param.fieldLabels && this.props.param.fieldLabels.x) || 'X' }),
+        1: PD.Numeric(0, { step: this.props.param.step }, { label: (this.props.param.fieldLabels && this.props.param.fieldLabels.y) || 'Y' }),
+        2: PD.Numeric(0, { step: this.props.param.step }, { label: (this.props.param.fieldLabels && this.props.param.fieldLabels.z) || 'Z' })
     }
 
     change(value: PD.MultiSelect<any>['defaultValue']) {
@@ -422,7 +461,8 @@ export class Vec3Control extends React.PureComponent<ParamProps<PD.Vec3>, { isEx
     render() {
         const v = this.props.value;
         const label = this.props.param.label || camelCaseToWords(this.props.name);
-        const value = `[${v[0].toFixed(2)}, ${v[1].toFixed(2)}, ${v[2].toFixed(2)}]`;
+        const p = getPrecision(this.props.param.step || 0.01)
+        const value = `[${v[0].toFixed(p)}, ${v[1].toFixed(p)}, ${v[2].toFixed(p)}]`;
         return <>
             <div className='msp-control-row'>
                 <span>{label}</span>

+ 2 - 2
src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts

@@ -93,8 +93,8 @@ export namespace VolumeStreaming {
                 }, { description: 'Static box defined by cartesian coords.', isFlat: true }),
                 'selection-box': PD.Group({
                     radius: PD.Numeric(5, { min: 0, max: 50, step: 0.5 }, { description: 'Radius in \u212B within which the volume is shown.' }),
-                    bottomLeft: PD.Vec3(Vec3.create(0, 0, 0), { isHidden: true }),
-                    topRight: PD.Vec3(Vec3.create(0, 0, 0), { isHidden: true }),
+                    bottomLeft: PD.Vec3(Vec3.create(0, 0, 0), {}, { isHidden: true }),
+                    topRight: PD.Vec3(Vec3.create(0, 0, 0), {}, { isHidden: true }),
                 }, { description: 'Box around last-interacted element.', isFlat: true }),
                 'cell': PD.Group({}),
                 // 'auto': PD.Group({  }), // TODO based on camera distance/active selection/whatever, show whole structure or slice.

+ 3 - 3
src/mol-plugin/state/representation/model.ts

@@ -53,14 +53,14 @@ export namespace ModelStructureRepresentation {
                 radius: PD.Numeric(5)
             }, { isFlat: true }),
             'symmetry': PD.Group({
-                ijkMin: PD.Vec3(Vec3.create(-1, -1, -1), { label: 'Min IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } }),
-                ijkMax: PD.Vec3(Vec3.create(1, 1, 1), { label: 'Max IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
+                ijkMin: PD.Vec3(Vec3.create(-1, -1, -1), { step: 1 }, { label: 'Min IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } }),
+                ijkMax: PD.Vec3(Vec3.create(1, 1, 1), { step: 1 }, { label: 'Max IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
             }, { isFlat: true }),
             'symmetry-assembly': PD.Group({
                 generators: PD.ObjectList({
                     operators: PD.ObjectList({
                         index: PD.Select(0, operatorOptions),
-                        shift: PD.Vec3(Vec3(), { label: 'IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
+                        shift: PD.Vec3(Vec3(), { step: 1 }, { label: 'IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
                     }, e => `${e.index + 1}_${e.shift.map(a => a + 5).join('')}`, {
                         defaultValue: [] as { index: number, shift: Vec3 }[]
                     }),

+ 4 - 4
src/mol-util/param-definition.ts

@@ -111,11 +111,11 @@ export namespace ParamDefinition {
         return setInfo<Color>({ type: 'color', defaultValue }, info)
     }
 
-    export interface Vec3 extends Base<Vec3Data> {
+    export interface Vec3 extends Base<Vec3Data>, Range {
         type: 'vec3'
     }
-    export function Vec3(defaultValue: Vec3Data, info?: Info): Vec3 {
-        return setInfo<Vec3>({ type: 'vec3', defaultValue }, info)
+    export function Vec3(defaultValue: Vec3Data, range?: { min?: number, max?: number, step?: number }, info?: Info): Vec3 {
+        return setInfo<Vec3>(setRange({ type: 'vec3', defaultValue }, range), info)
     }
 
     export interface FileParam extends Base<File> {
@@ -149,7 +149,7 @@ export namespace ParamDefinition {
          */
         step?: number
     }
-    function setRange<T extends Numeric | Interval>(p: T, range?: { min?: number, max?: number, step?: number }) {
+    function setRange<T extends Numeric | Interval | Vec3>(p: T, range?: { min?: number, max?: number, step?: number }) {
         if (!range) return p;
         if (typeof range.min !== 'undefined') p.min = range.min;
         if (typeof range.max !== 'undefined') p.max = range.max;