Browse Source

add Quick Styles panel

Alexander Rose 3 years ago
parent
commit
9c1d59a2c8

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Fix ``xrayShader`` & ``ignoreLight`` params not working at the same time
 - Add ``ignoreLight`` to component params
 - Fix representation preset side effects (changing post-processing parameters, see #363)
+- Add Quick Styles panel (reset, illustrative, stylized)
 
 ## [v3.0.2] - 2022-01-30
 

+ 1 - 1
src/mol-plugin-state/builder/structure/representation.ts

@@ -29,7 +29,7 @@ export class StructureRepresentationBuilder {
 
     readonly defaultProvider = PresetStructureRepresentations.auto;
 
-    private resolveProvider(ref: StructureRepresentationPresetProviderRef) {
+    resolveProvider(ref: StructureRepresentationPresetProviderRef) {
         return typeof ref === 'string'
             ? PresetStructureRepresentations[ref as keyof PresetStructureRepresentations] ?? arrayFind(this._providers, p => p.id === ref)
             : ref;

+ 3 - 1
src/mol-plugin-ui/controls.tsx

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2022 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>
@@ -24,6 +24,7 @@ import { StructureSourceControls } from './structure/source';
 import { VolumeStreamingControls, VolumeSourceControls } from './structure/volume';
 import { PluginConfig } from '../mol-plugin/config';
 import { StructureSuperpositionControls } from './structure/superposition';
+import { StructureQuickStylesControls } from './structure/quick-styles';
 
 export class TrajectoryViewportControls extends PluginUIComponent<{}, { show: boolean, label: string }> {
     state = { show: false, label: '' };
@@ -292,6 +293,7 @@ export class DefaultStructureTools extends PluginUIComponent {
             <StructureSourceControls />
             <StructureMeasurementsControls />
             <StructureSuperpositionControls />
+            <StructureQuickStylesControls />
             <StructureComponentControls />
             {this.plugin.config.get(PluginConfig.VolumeStreaming.Enabled) && <VolumeStreamingControls />}
             <VolumeSourceControls />

+ 7 - 4
src/mol-plugin-ui/controls/icons.tsx

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2020-2022 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>
@@ -38,10 +38,10 @@ export function MoleculeSvg() { return _Molecule; }
 // The following icons are adapted from https://materialdesignicons.com/ and
 // licensed with https://github.com/Templarian/MaterialDesign/blob/master/LICENSE
 
-const _CubeOutline = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path d="M21,16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V7.5C3,7.12 3.21,6.79 3.53,6.62L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.79,6.79 21,7.12 21,7.5V16.5M12,4.15L6.04,7.5L12,10.85L17.96,7.5L12,4.15M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V9.21L13,12.58V19.29L19,15.91Z" /></svg>;
+const _CubeOutline = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path d='M21,16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V7.5C3,7.12 3.21,6.79 3.53,6.62L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.79,6.79 21,7.12 21,7.5V16.5M12,4.15L6.04,7.5L12,10.85L17.96,7.5L12,4.15M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V9.21L13,12.58V19.29L19,15.91Z' /></svg>;
 export function CubeOutlineSvg() { return _CubeOutline; }
 
-const _CubeScan = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path d="M17,22V20H20V17H22V20.5C22,20.89 21.84,21.24 21.54,21.54C21.24,21.84 20.89,22 20.5,22H17M7,22H3.5C3.11,22 2.76,21.84 2.46,21.54C2.16,21.24 2,20.89 2,20.5V17H4V20H7V22M17,2H20.5C20.89,2 21.24,2.16 21.54,2.46C21.84,2.76 22,3.11 22,3.5V7H20V4H17V2M7,2V4H4V7H2V3.5C2,3.11 2.16,2.76 2.46,2.46C2.76,2.16 3.11,2 3.5,2H7M13,17.25L17,14.95V10.36L13,12.66V17.25M12,10.92L16,8.63L12,6.28L8,8.63L12,10.92M7,14.95L11,17.25V12.66L7,10.36V14.95M18.23,7.59C18.73,7.91 19,8.34 19,8.91V15.23C19,15.8 18.73,16.23 18.23,16.55L12.75,19.73C12.25,20.05 11.75,20.05 11.25,19.73L5.77,16.55C5.27,16.23 5,15.8 5,15.23V8.91C5,8.34 5.27,7.91 5.77,7.59L11.25,4.41C11.5,4.28 11.75,4.22 12,4.22C12.25,4.22 12.5,4.28 12.75,4.41L18.23,7.59Z" /></svg>;
+const _CubeScan = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path d='M17,22V20H20V17H22V20.5C22,20.89 21.84,21.24 21.54,21.54C21.24,21.84 20.89,22 20.5,22H17M7,22H3.5C3.11,22 2.76,21.84 2.46,21.54C2.16,21.24 2,20.89 2,20.5V17H4V20H7V22M17,2H20.5C20.89,2 21.24,2.16 21.54,2.46C21.84,2.76 22,3.11 22,3.5V7H20V4H17V2M7,2V4H4V7H2V3.5C2,3.11 2.16,2.76 2.46,2.46C2.76,2.16 3.11,2 3.5,2H7M13,17.25L17,14.95V10.36L13,12.66V17.25M12,10.92L16,8.63L12,6.28L8,8.63L12,10.92M7,14.95L11,17.25V12.66L7,10.36V14.95M18.23,7.59C18.73,7.91 19,8.34 19,8.91V15.23C19,15.8 18.73,16.23 18.23,16.55L12.75,19.73C12.25,20.05 11.75,20.05 11.25,19.73L5.77,16.55C5.27,16.23 5,15.8 5,15.23V8.91C5,8.34 5.27,7.91 5.77,7.59L11.25,4.41C11.5,4.28 11.75,4.22 12,4.22C12.25,4.22 12.5,4.28 12.75,4.41L18.23,7.59Z' /></svg>;
 export function CubeScanSvg() { return _CubeScan; }
 
 const _CubeSend = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path d="M16,4L9,8.04V15.96L16,20L23,15.96V8.04M16,6.31L19.8,8.5L16,10.69L12.21,8.5M0,7V9H7V7M11,10.11L15,12.42V17.11L11,14.81M21,10.11V14.81L17,17.11V12.42M2,11V13H7V11M4,15V17H7V15" /></svg>;
@@ -53,9 +53,12 @@ export function CursorDefaultOutlineSvg() { return _CursorDefaultOutline; }
 const _FileOutline = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path fill='currentColor' d='M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z' /></svg>;
 export function FileOutlineSvg() { return _FileOutline; }
 
-const _PencilRuler = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path d="M3 17.25V21H6.75L17.81 9.93L14.06 6.18L3 17.25M22.61 18.36L18.36 22.61L13.16 17.41L14.93 15.64L15.93 16.64L18.4 14.16L19.82 15.58L18.36 17L19.42 18L20.84 16.6L22.61 18.36M6.61 10.83L1.39 5.64L5.64 1.39L7.4 3.16L4.93 5.64L6 6.7L8.46 4.22L9.88 5.64L8.46 7.05L9.46 8.05L6.61 10.83M20.71 7C21.1 6.61 21.1 6 20.71 5.59L18.37 3.29C18 2.9 17.35 2.9 16.96 3.29L15.12 5.12L18.87 8.87L20.71 7Z" /></svg>;
+const _PencilRuler = <svg width='24px' height='24px' viewBox='0 0 24 24' strokeWidth='0.1px'><path d='M3 17.25V21H6.75L17.81 9.93L14.06 6.18L3 17.25M22.61 18.36L18.36 22.61L13.16 17.41L14.93 15.64L15.93 16.64L18.4 14.16L19.82 15.58L18.36 17L19.42 18L20.84 16.6L22.61 18.36M6.61 10.83L1.39 5.64L5.64 1.39L7.4 3.16L4.93 5.64L6 6.7L8.46 4.22L9.88 5.64L8.46 7.05L9.46 8.05L6.61 10.83M20.71 7C21.1 6.61 21.1 6 20.71 5.59L18.37 3.29C18 2.9 17.35 2.9 16.96 3.29L15.12 5.12L18.87 8.87L20.71 7Z' /></svg>;
 export function PencilRulerSvg() { return _PencilRuler; }
 
+const _MagicWand = <svg width='24px' height='24px' viewBox='0 0 24 24'><path fill='currentColor' d='M7.5,5.6L5,7L6.4,4.5L5,2L7.5,3.4L10,2L8.6,4.5L10,7L7.5,5.6M19.5,15.4L22,14L20.6,16.5L22,19L19.5,17.6L17,19L18.4,16.5L17,14L19.5,15.4M22,2L20.6,4.5L22,7L19.5,5.6L17,7L18.4,4.5L17,2L19.5,3.4L22,2M13.34,12.78L15.78,10.34L13.66,8.22L11.22,10.66L13.34,12.78M14.37,7.29L16.71,9.63C17.1,10 17.1,10.65 16.71,11.04L5.04,22.71C4.65,23.1 4,23.1 3.63,22.71L1.29,20.37C0.9,20 0.9,19.35 1.29,18.96L12.96,7.29C13.35,6.9 14,6.9 14.37,7.29Z' /></svg>;
+export function MagicWandSvg() { return _MagicWand; }
+
 // The following icons are adapted from https://material-ui.com/components/material-icons/ and
 // licensed with https://github.com/mui-org/material-ui/blob/master/LICENSE
 

+ 107 - 0
src/mol-plugin-ui/structure/quick-styles.tsx

@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { PresetStructureRepresentations } from '../../mol-plugin-state/builder/structure/representation-preset';
+import { Color } from '../../mol-util/color';
+import { CollapsableControls, PurePluginUIComponent } from '../base';
+import { Button } from '../controls/common';
+import { MagicWandSvg } from '../controls/icons';
+import { ParamDefinition as PD } from '../../mol-util/param-definition';
+import { PostprocessingParams } from '../../mol-canvas3d/passes/postprocessing';
+import { PluginConfig } from '../../mol-plugin/config';
+import { StructureComponentManager } from '../../mol-plugin-state/manager/structure/component';
+
+export class StructureQuickStylesControls extends CollapsableControls {
+    defaultState() {
+        return {
+            isCollapsed: false,
+            header: 'Quick Styles',
+            brand: { accent: 'gray' as const, svg: MagicWandSvg }
+        };
+    }
+
+    renderControls() {
+        return <>
+            <QuickStyles />
+        </>;
+    }
+}
+
+export class QuickStyles extends PurePluginUIComponent {
+    async reset() {
+        const { structures } = this.plugin.managers.structure.hierarchy.selection;
+        const preset = this.plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
+        const provider = this.plugin.builders.structure.representation.resolveProvider(preset);
+        await this.plugin.managers.structure.component.applyPreset(structures, provider);
+
+        this.plugin.managers.structure.component.setOptions(PD.getDefaultValues(StructureComponentManager.OptionsParams));
+
+        if (this.plugin.canvas3d) {
+            const p = PD.getDefaultValues(PostprocessingParams);
+            this.plugin.canvas3d.setProps({
+                postprocessing: { outline: p.outline, occlusion: p.occlusion }
+            });
+        }
+    }
+
+    async illustrative() {
+        const { structures } = this.plugin.managers.structure.hierarchy.selection;
+        await this.plugin.managers.structure.component.applyPreset(structures, PresetStructureRepresentations.illustrative);
+
+        if (this.plugin.canvas3d) {
+            this.plugin.canvas3d.setProps({
+                postprocessing: {
+                    outline: {
+                        name: 'on',
+                        params: { scale: 1, color: Color(0x000000), threshold: 0.25 }
+                    },
+                    occlusion: {
+                        name: 'on',
+                        params: { bias: 0.9, blurKernelSize: 15, radius: 5, samples: 32 }
+                    },
+                }
+            });
+        }
+    }
+
+    async stylized() {
+        this.plugin.managers.structure.component.setOptions({ ...this.plugin.managers.structure.component.state.options, ignoreLight: true });
+
+        if (this.plugin.canvas3d) {
+            const pp = this.plugin.canvas3d.props.postprocessing;
+            this.plugin.canvas3d.setProps({
+                postprocessing: {
+                    outline: {
+                        name: 'on',
+                        params: pp.outline.name === 'on'
+                            ? pp.outline.params
+                            : { scale: 1, color: Color(0x000000), threshold: 0.33 }
+                    },
+                    occlusion: {
+                        name: 'on',
+                        params: pp.occlusion.name === 'on'
+                            ? pp.occlusion.params
+                            : { bias: 0.9, blurKernelSize: 15, radius: 5, samples: 32 }
+                    },
+                }
+            });
+        }
+    }
+
+    render() {
+        return <div className='msp-flex-row'>
+            <Button noOverflow title='Applies default representation preset. Set outline and occlusion effects to defaults.' onClick={() => this.reset()} style={{ width: 'auto' }}>
+                Reset
+            </Button>
+            <Button noOverflow title='Applies illustrative representation preset. Enables outline and occlusion effects. Enables ignore-light parameter.' onClick={() => this.illustrative()} style={{ width: 'auto' }}>
+                Illustrative
+            </Button>
+            <Button noOverflow title='Applies no representation preset. Enables outline and occlusion effects. Enables ignore-light representation parameter.' onClick={() => this.stylized()} style={{ width: 'auto' }}>
+                Stylized
+            </Button>
+        </div>;
+    }
+}