Browse Source

Merge branch 'master' of https://github.com/molstar/molstar

dsehnal 1 year ago
parent
commit
6b5e90c5fa

+ 3 - 0
CHANGELOG.md

@@ -7,6 +7,8 @@ Note that since we don't clearly distinguish between a public and private interf
 ## [Unreleased]
 
 - Fix display issue with SIFTS mapping
+- Update `getStateSnapshot` to only overwrite current snapshot if it was created automatically
+- Fix distinct palette's `getSamples` infinite loop
 - Add 'NH2', 'FOR', 'FMT' to `CommonProteinCaps`
 - Add `opened` event to `PluginStateSnapshotManager`
 - Properly switch-off fog
@@ -17,6 +19,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Add `Euler` math primitive
 - Add stride option to element sphere & point visuals
 - Add `LRUCache.remove`
+- Add 'Chain Instance' and 'Uniform' options for 'Carbon Color' param (in Color Theme: Element Symbol)
 
 ## [v3.37.1] - 2023-06-20
 

+ 17 - 7
src/mol-plugin-state/manager/snapshots.ts

@@ -29,6 +29,7 @@ class PluginStateSnapshotManager extends StatefulPluginComponent<{
     static DefaultNextSnapshotDelayInMs = 1500;
 
     private entryMap = new Map<string, PluginStateSnapshotManager.Entry>();
+    private defaultSnapshotId: UUID | undefined = undefined;
 
     readonly events = {
         changed: this.ev(),
@@ -67,6 +68,8 @@ class PluginStateSnapshotManager extends StatefulPluginComponent<{
         const old = this.getEntry(id);
         if (!old) return;
 
+        this.defaultSnapshotId = undefined;
+
         if (old?.image) this.plugin.managers.asset.delete(old.image);
         const idx = this.getIndex(old);
         // The id changes here!
@@ -172,20 +175,27 @@ class PluginStateSnapshotManager extends StatefulPluginComponent<{
     }
 
     private async syncCurrent(options?: { name?: string, description?: string, params?: PluginState.SnapshotParams }) {
+        const isEmpty = this.state.entries.size === 0;
+        const canReplace = this.state.entries.size === 1 && this.state.current && this.state.current === this.defaultSnapshotId;
+
+        if (!isEmpty && !canReplace) return;
+
         const snapshot = this.plugin.state.getSnapshot(options?.params);
-        if (this.state.entries.size === 0 || !this.state.current) {
-            this.add(PluginStateSnapshotManager.Entry(snapshot, { name: options?.name, description: options?.description }));
-        } else {
+        const image = (options?.params?.image ?? this.plugin.state.snapshotParams.value.image) ? await PluginStateSnapshotManager.getCanvasImageAsset(this.plugin, `${snapshot.id}-image.png`) : undefined;
+
+        if (isEmpty) {
+            this.add(PluginStateSnapshotManager.Entry(snapshot, { name: options?.name, description: options?.description, image }));
+        } else if (canReplace) {
+            // Replace the current state only if there is a single snapshot that has been created automatically
             const current = this.getEntry(this.state.current);
             if (current?.image) this.plugin.managers.asset.delete(current.image);
-            const image = (options?.params?.image ?? this.plugin.state.snapshotParams.value.image) ? await PluginStateSnapshotManager.getCanvasImageAsset(this.plugin, `${snapshot.id}-image.png`) : undefined;
-            // TODO: this replaces the current snapshot which is not always intended
-            this.replace(this.state.current, snapshot, { image });
+            this.replace(this.state.current!, snapshot, { image });
         }
+
+        this.defaultSnapshotId = snapshot.id;
     }
 
     async getStateSnapshot(options?: { name?: string, description?: string, playOnLoad?: boolean, params?: PluginState.SnapshotParams }): Promise<PluginStateSnapshotManager.StateSnapshot> {
-        // TODO: diffing and all that fancy stuff
         await this.syncCurrent(options);
 
         return {

+ 9 - 2
src/mol-theme/color/element-symbol.ts

@@ -2,6 +2,7 @@
  * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author Adam Midlik <midlik@gmail.com>
  */
 
 import { ElementSymbol } from '../../mol-model/structure/model/types';
@@ -22,6 +23,8 @@ import { EntitySourceColorTheme, EntitySourceColorThemeParams } from './entity-s
 import { ModelIndexColorTheme, ModelIndexColorThemeParams } from './model-index';
 import { StructureIndexColorTheme, StructureIndexColorThemeParams } from './structure-index';
 import { ColorThemeCategory } from './categories';
+import { UnitIndexColorTheme, UnitIndexColorThemeParams } from './unit-index';
+import { UniformColorTheme, UniformColorThemeParams } from './uniform';
 
 // from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF)
 export const ElementSymbolColors = ColorMap({
@@ -35,12 +38,14 @@ const Description = 'Assigns a color to every atom according to its chemical ele
 export const ElementSymbolColorThemeParams = {
     carbonColor: PD.MappedStatic('chain-id', {
         'chain-id': PD.Group(ChainIdColorThemeParams),
+        'unit-index': PD.Group(UnitIndexColorThemeParams, { label: 'Chain Instance' }),
         'entity-id': PD.Group(EntityIdColorThemeParams),
         'entity-source': PD.Group(EntitySourceColorThemeParams),
         'operator-name': PD.Group(OperatorNameColorThemeParams),
         'model-index': PD.Group(ModelIndexColorThemeParams),
         'structure-index': PD.Group(StructureIndexColorThemeParams),
-        'element-symbol': PD.EmptyGroup()
+        'uniform': PD.Group(UniformColorThemeParams),
+        'element-symbol': PD.EmptyGroup(),
     }, { description: 'Use chain-id coloring for carbon atoms.' }),
     saturation: PD.Numeric(0, { min: -6, max: 6, step: 0.1 }),
     lightness: PD.Numeric(0.2, { min: -6, max: 6, step: 0.1 }),
@@ -64,11 +69,13 @@ export function elementSymbolColor(colorMap: ElementSymbolColors, element: Eleme
 function getCarbonTheme(ctx: ThemeDataContext, props: ElementSymbolColorThemeProps['carbonColor']) {
     switch (props.name) {
         case 'chain-id': return ChainIdColorTheme(ctx, props.params);
+        case 'unit-index': return UnitIndexColorTheme(ctx, props.params);
         case 'entity-id': return EntityIdColorTheme(ctx, props.params);
         case 'entity-source': return EntitySourceColorTheme(ctx, props.params);
         case 'operator-name': return OperatorNameColorTheme(ctx, props.params);
         case 'model-index': return ModelIndexColorTheme(ctx, props.params);
         case 'structure-index': return StructureIndexColorTheme(ctx, props.params);
+        case 'uniform': return UniformColorTheme(ctx, props.params);
         case 'element-symbol': return undefined;
         default: assertUnreachable(props);
     }
@@ -101,7 +108,7 @@ export function ElementSymbolColorTheme(ctx: ThemeDataContext, props: PD.Values<
         return DefaultElementSymbolColor;
     }
 
-    const granularity = props.carbonColor.name === 'operator-name' ? 'groupInstance' : 'group';
+    const granularity = (props.carbonColor.name === 'operator-name' || props.carbonColor.name === 'unit-index') ? 'groupInstance' : 'group';
 
     return {
         factory: ElementSymbolColorTheme,

+ 5 - 4
src/mol-util/color/distinct.ts

@@ -1,7 +1,8 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
  *
  * adapted from https://github.com/internalfx/distinct-colors (ISC License Copyright (c) 2015, InternalFX Inc.)
  * which is heavily inspired by http://tools.medialab.sciences-po.fr/iwanthue/
@@ -81,9 +82,9 @@ function getSamples(count: number, p: DistinctColorsProps) {
     const samples = new Map<string, Lab>();
     const rangeDivider = Math.cbrt(count) * 1.001;
 
-    const hStep = (p.hue[1] - p.hue[0]) / rangeDivider;
-    const cStep = (p.chroma[1] - p.chroma[0]) / rangeDivider;
-    const lStep = (p.luminance[1] - p.luminance[0]) / rangeDivider;
+    const hStep = Math.max((p.hue[1] - p.hue[0]) / rangeDivider, 1);
+    const cStep = Math.max((p.chroma[1] - p.chroma[0]) / rangeDivider, 1);
+    const lStep = Math.max((p.luminance[1] - p.luminance[0]) / rangeDivider, 1);
     for (let h = p.hue[0]; h <= p.hue[1]; h += hStep) {
         for (let c = p.chroma[0]; c <= p.chroma[1]; c += cStep) {
             for (let l = p.luminance[0]; l <= p.luminance[1]; l += lStep) {