Browse Source

mol-plugin: improved SequenceView

David Sehnal 5 years ago
parent
commit
9f4a60572f

+ 1 - 1
src/mol-plugin/skin/base/components/controls-base.scss

@@ -167,7 +167,7 @@ select.msp-form-control {
     background-size: 8px 12px;
     background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAUCAMAAACzvE1FAAAADFBMVEUzMzMzMzMzMzMzMzMKAG/3AAAAA3RSTlMAf4C/aSLHAAAAPElEQVR42q3NMQ4AIAgEQTn//2cLdRKppSGzBYwzVXvznNWs8C58CiussPJj8h6NwgorrKRdTvuV9v16Afn0AYFOB7aYAAAAAElFTkSuQmCC);
     background-repeat: no-repeat;
-    background-position: right $control-spacing top (($row-height - 12px) / 2);
+    background-position: right $control-spacing center;
     padding-right: ($row-height - 8px);
 }
 

+ 39 - 6
src/mol-plugin/skin/base/components/sequence.scss

@@ -7,9 +7,35 @@
     background: $sequence-background;
 }
 
+$sequence-select-height: 22px;
 .msp-sequence-select {
-    float: left;
-    width: $sequence-select-width;
+    position: relative;
+    height: $sequence-select-height;
+    width: 100%;
+    margin-bottom: 1px;
+    background: $control-background;
+    text-align: left;
+
+    > span {
+        display: inline-block;
+        line-height: $sequence-select-height;
+        padding: 0 $control-spacing;
+        font-size: 85%;
+        font-weight: bold;
+        cursor: default;
+    }
+
+    > select {
+        display: inline-block;
+        max-width: 160px;
+        width: auto;
+        text-overflow: ellipsis;
+        font-size: 85%;
+        height: $sequence-select-height;
+        line-height: $sequence-select-height;
+        background-size: 6px 8px;
+        background-color: $control-background;
+    }
 }
 
 .msp-sequence-wrapper {
@@ -17,15 +43,22 @@
     // use $control-spacing for top to have space for sequence numebrs
     padding: $control-spacing $control-spacing $info-vertical-padding $control-spacing;
     user-select: none;
-    height: 100%;
+    width: 100%;
     overflow-y: auto;
     overflow-x: hidden;
-    font-size: 90%;
-    line-height: 180%;
+    position: absolute;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    right: 0;
 }
 
-.msp-sequence-wrapper-non-empty {
+.msp-sequence-wrapper-non-empty {    
+    font-size: 85%;
+    line-height: 180%;
     font-family: "Courier New", monospace;
+    background: $msp-form-control-background;
+    top: $sequence-select-height + 1px;
 }
 
 .msp-sequence-wrapper {

+ 22 - 0
src/mol-plugin/ui/controls/parameters.tsx

@@ -264,6 +264,28 @@ export class TextControl extends SimpleParam<PD.Text> {
     }
 }
 
+export class PureSelectControl extends  React.PureComponent<ParamProps<PD.Select<string | number>>> {
+    protected update(value: string | number) {
+        this.props.onChange({ param: this.props.param, name: this.props.name, value });
+    }
+
+    onChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
+        if (typeof this.props.param.defaultValue === 'number') {
+            this.update(parseInt(e.target.value, 10));
+        } else {
+            this.update(e.target.value);
+        }
+    }
+
+    render() {
+        const isInvalid = this.props.value !== void 0 && !this.props.param.options.some(e => e[0] === this.props.value);
+        return <select className='msp-form-control' value={this.props.value !== void 0 ? this.props.value : this.props.param.defaultValue} onChange={this.onChange} disabled={this.props.isDisabled}>
+            {isInvalid && <option key={this.props.value} value={this.props.value}>{`[Invalid] ${this.props.value}`}</option>}
+            {this.props.param.options.map(([value, label]) => <option key={value} value={value}>{label}</option>)}
+        </select>;
+    }
+}
+
 export class SelectControl extends SimpleParam<PD.Select<string | number>> {
     onChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
         if (typeof this.props.param.defaultValue === 'number') {

+ 17 - 2
src/mol-plugin/ui/sequence.tsx

@@ -14,7 +14,7 @@ import { SequenceWrapper } from './sequence/wrapper';
 import { PolymerSequenceWrapper } from './sequence/polymer';
 import { StructureElementSelectionManager } from '../util/structure-element-selection';
 import { MarkerAction } from '../../mol-util/marker-action';
-import { ParameterControls } from './controls/parameters';
+import { PureSelectControl } from './controls/parameters';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { HeteroSequenceWrapper } from './sequence/hetero';
 import { State, StateSelection } from '../../mol-state';
@@ -295,9 +295,24 @@ export class SequenceView extends PluginUIComponent<{ }, SequenceViewState> {
 
         const sequenceWrapper = this.getSequenceWrapper()
 
+        const params = this.params;
+        const values = this.values;
+
         return <div className='msp-sequence'>
             <div className='msp-sequence-select'>
-                <ParameterControls params={this.params} values={this.values} onChange={this.setParamProps} />
+                <span className={`msp-icon msp-icon-help-circle`} style={{ cursor: 'help', position: 'absolute', right: 0, top: 0 }}
+                    title='This shows a single sequence. Use the controls to the right to show a different sequence.' />
+
+                <span>Sequence of</span>
+                <PureSelectControl param={params.structure} name='structure' value={values.structure} onChange={this.setParamProps} />
+                <span>Entity</span>
+                <PureSelectControl param={params.entity} name='entity' value={values.entity} onChange={this.setParamProps} />
+                <span>Chain</span>
+                <PureSelectControl param={params.chain} name='chain' value={values.chain} onChange={this.setParamProps} />
+                {params.operator.options.length > 1 && <>
+                    <span>Instance</span>
+                    <PureSelectControl param={params.operator} name='operator' value={values.operator} onChange={this.setParamProps} />
+                </>}
             </div>
 
             {typeof sequenceWrapper === 'string'

+ 3 - 2
src/mol-plugin/ui/sequence/sequence.tsx

@@ -168,7 +168,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
         for (let i = 0, il = markerArray.length; i < il; i++) {
             if (hasNumbers && i % period === 0 && i < il) o++;
             // o + 1 to account for help icon
-            const span = xs[o + 1] as HTMLSpanElement;
+            const span = xs[o] as HTMLSpanElement;
             if (!span) return;
             o++;
 
@@ -236,6 +236,8 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
         // residue spans are updated as react won't update them
         this.updateMarker()
 
+        // <span className={`msp-icon msp-icon-help`} style={{ cursor: 'help' }} title='This shows a single sequence. Use the menu on the left to show a different sequence.' />
+
         return <div
             className='msp-sequence-wrapper msp-sequence-wrapper-non-empty'
             onContextMenu={this.contextMenu}
@@ -244,7 +246,6 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P> {
             onMouseLeave={this.mouseLeave}
             ref={this.parentDiv}
         >
-            <span className={`msp-icon msp-icon-help`} style={{ cursor: 'help' }} title='This shows a single sequence. Use the menu on the left to show a different sequence.' />
             {elems}
         </div>;
     }