Browse Source

added more descriptions and titles

- added description prop to action-item
- use for presets and selection queries
Alexander Rose 5 years ago
parent
commit
2cb0d63750

+ 16 - 4
src/mol-plugin-state/builder/structure/hierarchy-preset.ts

@@ -41,7 +41,10 @@ const DefaultParams = (a: PluginStateObject.Molecule.Trajectory | undefined, plu
 
 const defaultPreset = TrajectoryHierarchyPresetProvider({
     id: 'preset-trajectory-default',
-    display: { name: 'Default (Assembly)', group: 'Preset' },
+    display: {
+        name: 'Default (Assembly)', group: 'Preset',
+        description: 'Shows the first assembly or, if that is unavailable, the first deposited model.'
+    },
     isApplicable: o => {
         return true
     },
@@ -71,7 +74,10 @@ const defaultPreset = TrajectoryHierarchyPresetProvider({
 
 const allModels = TrajectoryHierarchyPresetProvider({
     id: 'preset-trajectory-all-models',
-    display: { name: 'All Models', group: 'Preset' },
+    display: {
+        name: 'All Models', group: 'Preset',
+        description: 'Shows all models; colored by model-index.'
+    },
     isApplicable: o => {
         return o.data.length > 1
     },
@@ -133,7 +139,10 @@ async function applyCrystalSymmetry(props: { ijkMin: Vec3, ijkMax: Vec3, theme?:
 
 const unitcell = TrajectoryHierarchyPresetProvider({
     id: 'preset-trajectory-unitcell',
-    display: { name: 'Unitcell', group: 'Preset' },
+    display: {
+        name: 'Unitcell', group: 'Preset',
+        description: 'Shows the fully populated unitcell.'
+    },
     isApplicable: o => {
         return Model.hasCrystalSymmetry(o.data[0])
     },
@@ -145,7 +154,10 @@ const unitcell = TrajectoryHierarchyPresetProvider({
 
 const supercell = TrajectoryHierarchyPresetProvider({
     id: 'preset-trajectory-supercell',
-    display: { name: 'Supercell', group: 'Preset' },
+    display: {
+        name: 'Supercell', group: 'Preset',
+        description: 'Shows the supercell, i.e. the central unitcell and all adjacent unitcells.'
+    },
     isApplicable: o => {
         return Model.hasCrystalSymmetry(o.data[0])
     },

+ 25 - 7
src/mol-plugin-state/builder/structure/representation-preset.ts

@@ -56,7 +56,10 @@ const reprBuilder = StructureRepresentationPresetProvider.reprBuilder
 
 const auto = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-auto',
-    display: { name: 'Automatic' },
+    display: {
+        name: 'Automatic',
+        description: 'Show representations based on the size of the structure. Smaller structures are shown with more detail than larger ones, ranging from atomistic display to coarse surfaces.'
+    },
     params: () => CommonParams,
     apply(ref, params, plugin) {
         const structure = StateObjectRef.resolveAndCheck(plugin.state.data, ref)?.obj?.data;
@@ -79,7 +82,7 @@ const auto = StructureRepresentationPresetProvider({
 
 const empty = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-empty',
-    display: { name: 'Empty' },
+    display: { name: 'Empty', description: 'Removes all existing representations.' },
     async apply(ref, params, plugin) {
         return {  };
     }
@@ -89,7 +92,10 @@ const BuiltInPresetGroupName = 'Basic'
 
 const polymerAndLigand = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-polymer-and-ligand',
-    display: { name: 'Polymer & Ligand', group: BuiltInPresetGroupName },
+    display: {
+        name: 'Polymer & Ligand', group: BuiltInPresetGroupName,
+        description: 'Shows polymers as Cartoon, ligands as Ball & Stick, carbohydrates as 3D-SNFG and water molecules semi-transparent.'
+    },
     params: () => CommonParams,
     async apply(ref, params, plugin) {
         const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
@@ -122,7 +128,10 @@ const polymerAndLigand = StructureRepresentationPresetProvider({
 
 const proteinAndNucleic = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-protein-and-nucleic',
-    display: { name: 'Protein & Nucleic', group: BuiltInPresetGroupName },
+    display: {
+        name: 'Protein & Nucleic', group: BuiltInPresetGroupName,
+        description: 'Shows proteins as Cartoon and RNA/DNA as Gaussian Surface.'
+    },
     params: () => CommonParams,
     async apply(ref, params, plugin) {
         const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
@@ -146,7 +155,10 @@ const proteinAndNucleic = StructureRepresentationPresetProvider({
 
 const coarseSurface = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-coarse-surface',
-    display: { name: 'Coarse Surface', group: BuiltInPresetGroupName },
+    display: {
+        name: 'Coarse Surface', group: BuiltInPresetGroupName,
+        description: 'Shows polymers as coarse Gaussian Surface.'
+    },
     params: () => CommonParams,
     async apply(ref, params, plugin) {
         const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
@@ -184,7 +196,10 @@ const coarseSurface = StructureRepresentationPresetProvider({
 
 const polymerCartoon = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-polymer-cartoon',
-    display: { name: 'Polymer Cartoon', group: BuiltInPresetGroupName },
+    display: {
+        name: 'Polymer Cartoon', group: BuiltInPresetGroupName,
+        description: 'Shows polymers as Cartoon.'
+    },
     params: () => CommonParams,
     async apply(ref, params, plugin) {
         const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
@@ -206,7 +221,10 @@ const polymerCartoon = StructureRepresentationPresetProvider({
 
 const atomicDetail = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-atomic-detail',
-    display: { name: 'Atomic Detail', group: BuiltInPresetGroupName },
+    display: {
+        name: 'Atomic Detail', group: BuiltInPresetGroupName,
+        description: 'Shows everything in atomic detail with Ball & Stick.'
+    },
     params: () => CommonParams,
     async apply(ref, params, plugin) {
         const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);

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

@@ -2,6 +2,7 @@
  * Copyright (c) 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>
  */
 
 import * as React from 'react'
@@ -36,18 +37,15 @@ export namespace ActionMenu {
     export type OnSelectMany = (itemOrItems: Item[] | undefined) => void
 
     export type Items =  Header | Item | Items[]
-    export type Header = { kind: 'header', label: string, isIndependent?: boolean, initiallyExpanded?: boolean }
-    export type Item = { kind: 'item', label: string, icon?: IconName, disabled?: boolean, selected?: boolean, value: unknown, addOn?: JSX.Element }
+    export type Header = { kind: 'header', label: string, isIndependent?: boolean, initiallyExpanded?: boolean, description?: string }
+    export type Item = { kind: 'item', label: string, icon?: IconName, disabled?: boolean, selected?: boolean, value: unknown, addOn?: JSX.Element, description?: string }
 
-    export function Header(label: string, options?: { isIndependent?: boolean, initiallyExpanded?: boolean }): Header {
+    export function Header(label: string, options?: { isIndependent?: boolean, initiallyExpanded?: boolean, description?: string }): Header {
         return options ? { kind: 'header', label, ...options } : { kind: 'header', label };
     }
 
-    export function Item(label: string, value: unknown): Item
-    export function Item(label: string, icon: IconName, value: unknown): Item
-    export function Item(label: string, iconOrValue: any, value?: unknown): Item {
-        if (value) return { kind: 'item', label, icon: iconOrValue, value };
-        return { kind: 'item', label, value: iconOrValue };
+    export function Item(label: string, value: unknown, options?: { icon?: IconName, description?: string }): Item {
+        return { kind: 'item', label, value, ...options };
     }
 
     export interface CreateItemsParams<T> {
@@ -58,10 +56,11 @@ export namespace ActionMenu {
         icon?: (t: T) => IconName | undefined,
         selected?: (t: T) => boolean | undefined,
         addOn?: (t: T) => JSX.Element | undefined
+        description?: (t: T) => string | undefined,
     }
 
     export function createItems<T>(xs: ArrayLike<T>, params?: CreateItemsParams<T>): Items[] {
-        const { label, value, category, selected, icon, addOn } = params || { };
+        const { label, value, category, selected, icon, addOn, description } = params || { };
         let cats: Map<string, (ActionMenu.Item | ActionMenu.Header)[]> | undefined = void 0;
         const items: (ActionMenu.Item | (ActionMenu.Item | ActionMenu.Header)[])[] = [];
         for (let i = 0; i < xs.length; i++) {
@@ -72,6 +71,7 @@ export namespace ActionMenu {
             const catName = category?.(x);
             const l = label ? label(x) : '' + x;
             const v = value ? value(x) : x;
+            const d = description ? description(x) : '' + x;
 
             let cat: (ActionMenu.Item | ActionMenu.Header)[] | undefined;
             if (!!catName) {
@@ -89,7 +89,7 @@ export namespace ActionMenu {
 
             const ao = addOn?.(x);
 
-            cat!.push({ kind: 'item', label: l, value: v, icon: icon ? icon(x) : void 0, selected: selected ? selected(x) : void 0, addOn: ao });
+            cat!.push({ kind: 'item', label: l, value: v, icon: icon ? icon(x) : void 0, selected: selected ? selected(x) : void 0, addOn: ao, description: d });
         }
         return items;
     }
@@ -185,7 +185,7 @@ class Section extends React.PureComponent<SectionProps, SectionState> {
         const { header, hasCurrent } = this.state;
 
         return <div className='msp-flex-row msp-control-group-header'>
-            <Button icon={this.state.isExpanded ? 'collapse' : 'expand'} flex noOverflow onClick={this.toggleExpanded}>
+            <Button icon={this.state.isExpanded ? 'collapse' : 'expand'} flex noOverflow onClick={this.toggleExpanded} title={`Click to ${this.state.isExpanded ? 'collapse' : 'expand'}.${header?.description ? header?.description : ''}`}>
                 {hasCurrent ? <b>{header?.label}</b> : header?.label}
             </Button>
             <Button icon='check' flex onClick={this.selectAll} style={{ flex: '0 0 50px', textAlign: 'right' }}>
@@ -201,7 +201,7 @@ class Section extends React.PureComponent<SectionProps, SectionState> {
         const { header, hasCurrent } = this.state;
 
         return <div className='msp-control-group-header' style={{ marginTop: '1px' }}>
-            <Button noOverflow icon={this.state.isExpanded ? 'collapse' : 'expand'} onClick={this.toggleExpanded}>
+            <Button noOverflow icon={this.state.isExpanded ? 'collapse' : 'expand'} onClick={this.toggleExpanded} title={`Click to ${this.state.isExpanded ? 'collapse' : 'expand'}.${header?.description ? header?.description : ''}`}>
                 {hasCurrent ? <b>{header?.label}</b> : header?.label}
             </Button>
         </div>;
@@ -236,7 +236,7 @@ const Action: React.FC<{
 
     const style: React.CSSProperties | undefined = item.addOn ? { position: 'relative' } : void 0;
 
-    return <Button icon={item.icon} noOverflow className='msp-action-menu-button' onClick={() => onSelect(multiselect ? [item] : item as any)} disabled={item.disabled} style={style}>
+    return <Button icon={item.icon} noOverflow className='msp-action-menu-button' onClick={() => onSelect(multiselect ? [item] : item as any)} disabled={item.disabled} style={style} title={item.description}>
         {isCurrent || item.selected ? <b>{item.label}</b> : item.label}
         {item.addOn}
     </Button>;

+ 10 - 10
src/mol-plugin-ui/structure/components.tsx

@@ -91,7 +91,7 @@ class ComponentEditorControls extends PurePluginUIComponent<{}, ComponentEditorC
     get presetActions() {
         const pivot = this.plugin.managers.structure.component.pivotStructure;
         const providers = this.plugin.builders.structure.representation.getPresets(pivot?.cell.obj);
-        return ActionMenu.createItems(providers, { label: p => p.display.name, category: p => p.display.group });
+        return ActionMenu.createItems(providers, { label: p => p.display.name, category: p => p.display.group, description: p => p.display.description });
     }
 
     applyPreset: ActionMenu.OnSelect = item => {
@@ -116,9 +116,9 @@ class ComponentEditorControls extends PurePluginUIComponent<{}, ComponentEditorC
             : 'Some mistakes of the past can be undone.';
         return <>
             <div className='msp-flex-row'>
-                <ToggleButton icon='bookmarks' label='Preset' toggle={this.togglePreset} isSelected={this.state.action === 'preset'} disabled={this.isDisabled} />
-                <ToggleButton icon='plus' label='Add' toggle={this.toggleAdd} isSelected={this.state.action === 'add'} disabled={this.isDisabled} />
-                <ToggleButton icon='cog' label='' title='Options' style={{ flex: '0 0 40px', padding: 0 }} toggle={this.toggleOptions} isSelected={this.state.action === 'options'} disabled={this.isDisabled} />
+                <ToggleButton icon='bookmarks' label='Preset' title='Apply a representation preset for the current structure(s).' toggle={this.togglePreset} isSelected={this.state.action === 'preset'} disabled={this.isDisabled} />
+                <ToggleButton icon='plus' label='Add' title='Add a new representation component for a selection.' toggle={this.toggleAdd} isSelected={this.state.action === 'add'} disabled={this.isDisabled} />
+                <ToggleButton icon='cog' label='' title='Options that are applied to all representations.' style={{ flex: '0 0 40px', padding: 0 }} toggle={this.toggleOptions} isSelected={this.state.action === 'options'} disabled={this.isDisabled} />
                 <IconButton className='msp-flex-item' flex='40px' onClick={this.undo} disabled={!this.state.canUndo || this.isDisabled} icon='back' title={undoTitle} />
             </div>
             {this.state.action === 'preset' && this.presetControls}
@@ -255,13 +255,13 @@ class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureCo
         if (mng.canBeModified(this.props.group[0])) {
             ret.push([
                 ActionMenu.Header('Modify by Selection'),
-                ActionMenu.Item('Include', 'union', () => mng.modifyByCurrentSelection(this.props.group, 'union')),
-                ActionMenu.Item('Subtract', 'subtract', () => mng.modifyByCurrentSelection(this.props.group, 'subtract')),
-                ActionMenu.Item('Intersect', 'intersect', () => mng.modifyByCurrentSelection(this.props.group, 'intersect'))
+                ActionMenu.Item('Include', () => mng.modifyByCurrentSelection(this.props.group, 'union'), { icon: 'union' }),
+                ActionMenu.Item('Subtract', () => mng.modifyByCurrentSelection(this.props.group, 'subtract'), { icon: 'subtract' }),
+                ActionMenu.Item('Intersect', () => mng.modifyByCurrentSelection(this.props.group, 'intersect'), { icon: 'intersect' })
             ]);
         }
 
-        ret.push(ActionMenu.Item('Select This', 'set', () => mng.selectThis(this.props.group)));
+        ret.push(ActionMenu.Item('Select This', () => mng.selectThis(this.props.group), { icon: 'set' }));
 
         return ret;
     }
@@ -274,7 +274,7 @@ class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureCo
 
     get removeActions(): ActionMenu.Items {
         const ret = [
-            ActionMenu.Item('Remove', 'remove', () => this.plugin.managers.structure.hierarchy.remove(this.props.group, true))
+            ActionMenu.Item('Remove', () => this.plugin.managers.structure.hierarchy.remove(this.props.group, true), { icon: 'remove' })
         ];
 
         const reprs = this.pivot.representations;
@@ -282,7 +282,7 @@ class StructureComponentGroup extends PurePluginUIComponent<{ group: StructureCo
             return ret;
         }
 
-        ret.push(ActionMenu.Item(`Remove Representation${reprs.length > 1 ? 's' : ''}`, 'remove', () => this.plugin.managers.structure.component.removeRepresentations(this.props.group)));
+        ret.push(ActionMenu.Item(`Remove Representation${reprs.length > 1 ? 's' : ''}`, () => this.plugin.managers.structure.component.removeRepresentations(this.props.group), { icon: 'remove' }));
 
         return ret;
     }

+ 1 - 1
src/mol-plugin-ui/structure/focus.tsx

@@ -213,7 +213,7 @@ export class StructureFocusControls extends PluginUIComponent<{}, StructureFocus
                     {label}
                 </Button>
                 {current && <IconButton onClick={this.clear} icon='cancel' title='Clear' className='msp-form-control' flex disabled={this.isDisabled} />}
-                <ToggleButton icon='book-open' title='Select Target' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px', padding: 0 }} />
+                <ToggleButton icon='book-open' title='Select a focus target to center on an show its surroundings.' toggle={this.toggleAction} isSelected={this.state.showAction} disabled={this.isDisabled} style={{ flex: '0 0 40px', padding: 0 }} />
             </div>
             {this.state.showAction && <ActionMenu items={this.actionItems} onSelect={this.selectAction} />}
         </>;

+ 3 - 3
src/mol-plugin-ui/structure/measurements.tsx

@@ -276,7 +276,7 @@ class MeasurementEntry extends PurePluginUIComponent<{ cell: StructureMeasuremen
 
     get actions(): ActionMenu.Items {
         this.props.cell.sourceRef
-        return [ActionMenu.Item('Select This', 'flash', () => this.plugin.managers.structure.selection.fromSelections(this.props.cell.sourceRef!))];
+        return [ActionMenu.Item('Select This', () => this.plugin.managers.structure.selection.fromSelections(this.props.cell.sourceRef!), { icon: 'set' })];
     }
 
     selectAction: ActionMenu.OnSelect = item => {
@@ -300,8 +300,8 @@ class MeasurementEntry extends PurePluginUIComponent<{ cell: StructureMeasuremen
                 <IconButton className='msp-form-control' onClick={this.toggleUpdate} icon='dot-3' flex title='Actions' toggleState={this.state.showUpdate} />
             </div>
             {this.state.showUpdate && <>
-                <ActionMenu items={this.actions} onSelect={this.selectAction} />
-                <div className='msp-control-offset'>
+                <div className='msp-accent-offset'>
+                    <ActionMenu items={this.actions} onSelect={this.selectAction} noOffset />
                     <ExpandGroup header='Options' noOffset>
                         <UpdateTransformControl state={cell.parent} transform={cell.transform} customHeader='none' autoHideApply />
                     </ExpandGroup>

+ 2 - 1
src/mol-plugin-ui/structure/selection.tsx

@@ -114,7 +114,8 @@ export class StructureSelectionControls<P, S extends StructureSelectionControlsS
             this.queriesItems = ActionMenu.createItems(registry.list, {
                 filter: q => q !== StructureSelectionQueries.current,
                 label: q => q.label,
-                category: q => q.category
+                category: q => q.category,
+                description: q => q.description
             });
             this.queriesVersion = registry.version
         }

+ 2 - 2
src/mol-plugin-ui/structure/source.tsx

@@ -195,7 +195,7 @@ export class StructureSourceControls extends CollapsableControls<{}, StructureSo
 
         const providers = this.plugin.builders.structure.hierarchy.getPresets(trajectories[0].cell.obj)
         for (const p of providers) {
-            actions.push(ActionMenu.Item(p.display.name, p));
+            actions.push(ActionMenu.Item(p.display.name, p, { description: p.display.description }));
         }
         return actions;
     }
@@ -253,7 +253,7 @@ export class StructureSourceControls extends CollapsableControls<{}, StructureSo
         return <>
             <div className='msp-flex-row' style={{ marginTop: '1px' }}>
                 <Button noOverflow flex onClick={this.toggleHierarchy} disabled={disabled} title={label}>{label}</Button>
-                {presets.length > 0 && <IconButton className='msp-form-control' flex='40px' onClick={this.togglePreset} icon='bookmarks' title='Presets' toggleState={this.state.show === 'presets'} disabled={disabled} />}
+                {presets.length > 0 && <IconButton className='msp-form-control' flex='40px' onClick={this.togglePreset} icon='bookmarks' title='Apply a structure presets to the current hierarchy.' toggleState={this.state.show === 'presets'} disabled={disabled} />}
             </div>
             {this.state.show === 'hierarchy' && <ActionMenu items={this.hierarchyItems} onSelect={this.selectHierarchy} multiselect />}
             {this.state.show === 'presets' && <ActionMenu items={presets} onSelect={this.applyPreset} />}

+ 4 - 1
src/mol-plugin/behavior/dynamic/custom-props/rcsb/assembly-symmetry.ts

@@ -151,7 +151,10 @@ const AssemblySymmetryPresetParams = {
 
 export const AssemblySymmetryPreset = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-rcsb-assembly-symmetry',
-    display: { name: 'Assembly Symmetry', group: 'Annotation' },
+    display: {
+        name: 'Assembly Symmetry', group: 'Annotation',
+        description: 'Shows Assembly Symmetry axes and cage; colors structure according to assembly symmetry cluster membership. Data calculated with BioJava, obtained via RCSB PDB.'
+    },
     params: () => AssemblySymmetryPresetParams,
     async apply(ref, params, plugin) {
         const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);

+ 4 - 1
src/mol-plugin/behavior/dynamic/custom-props/rcsb/validation-report.ts

@@ -290,7 +290,10 @@ const hasClash = StructureSelectionQuery('Residues with Clashes', MS.struct.modi
 
 export const ValidationReportPreset = StructureRepresentationPresetProvider({
     id: 'preset-structure-representation-rcsb-validation-report',
-    display: { name: 'Validation Report', group: 'Annotation' },
+    display: {
+        name: 'Validation Report', group: 'Annotation',
+        description: 'Color structure based on geometry quality; show geometry clashes. Data from wwPDB Validation Report, obtained via RCSB PDB.'
+    },
     params: () => StructureRepresentationPresetProvider.CommonParams,
     async apply(ref, params, plugin) {
         const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);