From d31296062df88f9feade87e83b0104581b9885b5 Mon Sep 17 00:00:00 2001 From: Acylation <532117255@qq.com> Date: Thu, 13 Jul 2023 17:25:53 +0800 Subject: [PATCH 1/6] Clear global variables when plugin unload --- src/blocks.ts | 6 ++++++ src/drawer.ts | 4 ++++ src/main.ts | 6 ++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/blocks.ts b/src/blocks.ts index f220aee..7abd474 100644 --- a/src/blocks.ts +++ b/src/blocks.ts @@ -23,3 +23,9 @@ export const refreshBlocks = () => { block.render(); }); }; + +export const clearBlocks = () => { + gBlocks.forEach((block) => { + removeBlock(block); + }); +}; diff --git a/src/drawer.ts b/src/drawer.ts index 69431dd..d530a2b 100644 --- a/src/drawer.ts +++ b/src/drawer.ts @@ -6,3 +6,7 @@ export let gDrawer = new SmilesDrawer.SvgDrawer(DEFAULT_SD_OPTIONS); export const setDrawer = (options: Partial) => { gDrawer = new SmilesDrawer.SvgDrawer({ ...DEFAULT_SD_OPTIONS, ...options }); }; + +export const clearDrawer = () => { + gDrawer = {}; +}; diff --git a/src/main.ts b/src/main.ts index cbfeba7..a2f087d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,9 +2,9 @@ import { Plugin, MarkdownPostProcessorContext } from 'obsidian'; import { DEFAULT_SETTINGS, ChemPluginSettings } from './settings/base'; import { ChemSettingTab } from './settings/SettingTab'; import { SmilesBlock } from './SmilesBlock'; -import { setBlocks } from './blocks'; -import { setDrawer } from './drawer'; +import { setBlocks, clearBlocks } from './blocks'; +import { setDrawer, clearDrawer } from './drawer'; import { setObserver, detachObserver } from './themeObserver'; export default class ChemPlugin extends Plugin { @@ -29,6 +29,8 @@ export default class ChemPlugin extends Plugin { async onunload() { detachObserver(); + clearBlocks(); + clearDrawer(); } async loadSettings() { From acf7da7b84a2aa6286b1376ba3a4898539932761 Mon Sep 17 00:00:00 2001 From: Acylation <532117255@qq.com> Date: Thu, 13 Jul 2023 17:26:59 +0800 Subject: [PATCH 2/6] Reactive width config interface Refactor live preview component UX/UI for two width modes --- src/SmilesBlock.ts | 6 +- src/settings/LivePreview.ts | 90 +++++++++++++++ src/settings/SettingTab.ts | 216 +++++++++++++++--------------------- src/settings/base.ts | 15 ++- styles.css | 16 +-- 5 files changed, 199 insertions(+), 144 deletions(-) create mode 100644 src/settings/LivePreview.ts diff --git a/src/SmilesBlock.ts b/src/SmilesBlock.ts index 331ad22..2319b38 100644 --- a/src/SmilesBlock.ts +++ b/src/SmilesBlock.ts @@ -43,9 +43,6 @@ export class SmilesBlock extends MarkdownRenderChild { const cell = table.createDiv({ cls: 'chem-cell' }); const svgcell = cell.createSvg('svg'); this.renderCell(row, svgcell); - - // option1: keep the original size, according to the max - // option2: resize and limiting this if (parseFloat(svgcell.style.width) > maxWidth) svgcell.style.width = `${maxWidth.toString()}px`; }); @@ -57,6 +54,8 @@ export class SmilesBlock extends MarkdownRenderChild { } private renderCell = (source: string, target: SVGSVGElement) => { + if (this.settings.options.scale == 0) + target.style.width = `${this.settings.imgWidth}px`; SmilesDrawer.parse(source, (tree: object) => { gDrawer.draw( tree, @@ -67,7 +66,6 @@ export class SmilesBlock extends MarkdownRenderChild { : this.settings.lightTheme ); }); - console.log(this.settings.options.scale); }; async onload() { diff --git a/src/settings/LivePreview.ts b/src/settings/LivePreview.ts new file mode 100644 index 0000000..c289155 --- /dev/null +++ b/src/settings/LivePreview.ts @@ -0,0 +1,90 @@ +import { MarkdownRenderChild, MarkdownPostProcessorContext } from 'obsidian'; +import SmilesDrawer from 'smiles-drawer'; +import { gDrawer } from '../drawer'; +import { ChemPluginSettings } from '../settings/base'; +import { addBlock, removeBlock } from '../blocks'; + +/** + * Refer to plugin abcjs + * This class abstraction is needed to support load/unload hooks + * "If your post processor requires lifecycle management, for example, to clear an interval, kill a subprocess, etc when this element is removed from the app..." + * https://marcus.se.net/obsidian-plugin-docs/reference/typescript/interfaces/MarkdownPostProcessorContext#addchild + */ +export class LivePreview { + container: HTMLDivElement; + lightCard: HTMLDivElement; + darkCard: HTMLDivElement; + settings: ChemPluginSettings; + + constructor( + private readonly el: HTMLElement, + private readonly argSettings: ChemPluginSettings + ) { + this.container = this.el.createEl('div'); + this.container.style.display = `flex`; + + this.lightCard = this.container.createEl('div', { + cls: 'chemcard theme-light', + }); + this.darkCard = this.container.createEl('div', { + cls: 'chemcard theme-dark', + }); + + this.settings = this.argSettings; + } + + render = () => { + this.lightCard.empty(); + const lightWidth = this.renderCell( + this.settings.sample1, + this.lightCard, + this.settings.lightTheme + ); + + this.darkCard.empty(); + const darkWidth = this.renderCell( + this.settings.sample2, + this.darkCard, + this.settings.darkTheme + ); + + if (this.settings.options.scale == 0) + this.container.style.gridTemplateColumns = `repeat(auto-fill, minmax(${ + this.settings?.imgWidth ?? '300' + }px, 1fr)`; + else + this.container.style.gridTemplateColumns = `repeat(auto-fill, minmax(${(lightWidth > + darkWidth + ? lightWidth + : darkWidth + ).toString()}px, 1fr)`; + }; + + updateSettings = (argSettings: ChemPluginSettings) => { + this.settings = argSettings; + }; + + private renderCell = ( + source: string, + target: HTMLElement, + style: string + ) => { + const svg = target.createSvg('svg') as SVGSVGElement; + SmilesDrawer.parse(source, (tree: object) => { + gDrawer.draw(tree, svg, style); + }); + if (this.settings.options.scale == 0) + svg.style.width = `${this.settings?.imgWidth ?? '300'}px`; + else if ( + parseFloat(svg.style.width) > (this.settings.options?.width ?? 300) + ) { + svg.style.width = `${( + this.settings.options?.width ?? 300 + ).toString()}px`; + svg.style.height = `${( + this.settings.options?.height ?? 300 + ).toString()}px`; + } + return parseFloat(svg.style.width); + }; +} diff --git a/src/settings/SettingTab.ts b/src/settings/SettingTab.ts index d75fa98..689072c 100644 --- a/src/settings/SettingTab.ts +++ b/src/settings/SettingTab.ts @@ -1,7 +1,13 @@ import { App, PluginSettingTab, Setting, SliderComponent } from 'obsidian'; +import { LivePreview } from './LivePreview'; import ChemPlugin from '../main'; -import { DEFAULT_SD_OPTIONS, SAMPLE_SMILES, themeList } from './base'; +import { + DEFAULT_SD_OPTIONS, + SAMPLE_SMILES_1, + SAMPLE_SMILES_2, + themeList, +} from './base'; import { gDrawer, setDrawer } from 'src/drawer'; import { refreshBlocks } from 'src/blocks'; import SmilesDrawer from 'smiles-drawer'; @@ -24,27 +30,6 @@ export class ChemSettingTab extends PluginSettingTab { // TODO: Check styling instructions and remove this containerEl.createEl('h2', { text: 'Style Preferences' }); - // ban this - new Setting(containerEl) - .setName('Image Width') - .setDesc('Adjust the width of the molecule image.') - .addText((text) => - text - .setValue( - this.plugin.settings.options?.width?.toString() ?? '300' - ) - .setPlaceholder('300') - .onChange(async (value) => { - if (value == '') { - value = '300'; - } - this.plugin.settings.options.width = parseInt(value); - this.plugin.settings.options.height = parseInt(value); - await this.plugin.saveSettings(); - onOptionsChange(); - }) - ); - new Setting(containerEl) .setName('Light Theme') .setDesc('Active when Obsidian is under light mode.') @@ -55,7 +40,7 @@ export class ChemSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.lightTheme = value; await this.plugin.saveSettings(); - onLightStyleChange(value); + onSettingsChange(); }) ); @@ -69,45 +54,73 @@ export class ChemSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.darkTheme = value; await this.plugin.saveSettings(); - onDarkStyleChange(value); + onSettingsChange(); }) ); containerEl.createEl('h2', { text: 'Live Preview' }); new Setting(containerEl) - .setName('Sample Smiles') + .setName('Sample Smiles 1') .setDesc('Input smiles strings to see the styled structure.') .addText((text) => text - .setPlaceholder(SAMPLE_SMILES) - .setValue(this.plugin.settings.sample) + .setPlaceholder(SAMPLE_SMILES_1) + .setValue(this.plugin.settings.sample1) .onChange(async (value) => { if (value == '') { - value = SAMPLE_SMILES; + value = SAMPLE_SMILES_1; } - this.plugin.settings.sample = value; + this.plugin.settings.sample1 = value; await this.plugin.saveSettings(); - onSampleChange(value); + onSettingsChange(); }) ); - const div = containerEl.createEl('div'); - div.style.display = 'grid'; - div.style.gridTemplateColumns = `repeat(auto-fill, minmax(${this.plugin.settings.width}px, 1fr)`; + new Setting(containerEl) + .setName('Sample Smiles 2') + .setDesc('Input smiles strings to see the styled structure.') + .addText((text) => + text + .setPlaceholder(SAMPLE_SMILES_2) + .setValue(this.plugin.settings.sample2) + .onChange(async (value) => { + if (value == '') { + value = SAMPLE_SMILES_2; + } + this.plugin.settings.sample2 = value; + await this.plugin.saveSettings(); + onSettingsChange(); + }) + ); - const lightCard = div.createEl('div', { cls: 'chemcard theme-light' }); - const darkCard = div.createEl('div', { cls: 'chemcard theme-dark' }); + const preview = new LivePreview(containerEl, this.plugin.settings); + preview.render(); //initialize new Setting(containerEl) .setName('Advanced Settings') .setDesc('Configure smiles drawer options.') .setHeading(); + new Setting(containerEl) + .setName('Image Width') + .setDesc('Adjust the width of the molecule image.') + .addText((text) => { + text.setValue(this.plugin.settings?.imgWidth ?? '300') + .setPlaceholder('300') + .onChange(async (value) => { + if (value == '') { + value = '300'; + } + this.plugin.settings.imgWidth = value; + await this.plugin.saveSettings(); + onSettingsChange(); + }); + }); + const scaleSetting = new Setting(containerEl) .setName('Scale') .setDesc('Adjust the global molecule scale.') - // for reset .addExtraButton((button) => { button .setIcon('rotate-ccw') @@ -116,7 +129,11 @@ export class ChemSettingTab extends PluginSettingTab { this.plugin.settings.options.scale = 1; scaleSlider.setValue(50); await this.plugin.saveSettings(); - onOptionsChange(); + setDrawer({ + ...DEFAULT_SD_OPTIONS, + ...this.plugin.settings.options, + }); + onSettingsChange(); }); }); @@ -132,12 +149,39 @@ export class ChemSettingTab extends PluginSettingTab { this.plugin.settings.options.scale = value / 50; scaleLabel.setText((value / 50).toFixed(2).toString()); await this.plugin.saveSettings(); - onOptionsChange(); + setDrawer({ + ...DEFAULT_SD_OPTIONS, + ...this.plugin.settings.options, + }); + onSettingsChange(); }); + new Setting(containerEl) + .setName('Max width in table') // width limitation + .setDesc('Maximum width in multiline') + .addText((text) => + text + .setValue( + this.plugin.settings.options.width?.toString() ?? '300' + ) + .onChange(async (value) => { + if (value == '') { + value = '300'; + } + this.plugin.settings.options.width = parseInt(value); + this.plugin.settings.options.height = parseInt(value); + await this.plugin.saveSettings(); + setDrawer({ + ...DEFAULT_SD_OPTIONS, + ...this.plugin.settings.options, + }); + onSettingsChange(); + }) + ); + new Setting(containerEl) .setName('Compact Drawing') - .setDesc('Enable to linearize simple structures. (Unrecommanded)') + .setDesc('Linearize simple structures and functional groups.') .addToggle((toggle) => toggle .setValue( @@ -146,96 +190,18 @@ export class ChemSettingTab extends PluginSettingTab { .onChange(async (value) => { this.plugin.settings.options.compactDrawing = value; await this.plugin.saveSettings(); - onOptionsChange(); + setDrawer({ + ...DEFAULT_SD_OPTIONS, + ...this.plugin.settings.options, + }); + onSettingsChange(); }) ); - const onOptionsChange = () => { - setDrawer({ - ...DEFAULT_SD_OPTIONS, - ...this.plugin.settings.options, - }); - - lightCard.empty(); - const lightSvg = lightCard.createSvg('svg'); - SmilesDrawer.parse(this.plugin.settings.sample, (tree: object) => { - gDrawer.draw(tree, lightSvg, this.plugin.settings.lightTheme); - }); - - darkCard.empty(); - const darkSvg = darkCard.createSvg('svg'); - SmilesDrawer.parse(this.plugin.settings.sample, (tree: object) => { - gDrawer.draw(tree, darkSvg, this.plugin.settings.darkTheme); - }); - }; - - const onLightStyleChange = (style: string) => { - lightCard.empty(); - const lightSvg = lightCard.createSvg('svg'); - SmilesDrawer.parse(this.plugin.settings.sample, (tree: object) => { - gDrawer.draw(tree, lightSvg, style); - }); - }; - - const onDarkStyleChange = (style: string) => { - darkCard.empty(); - const darkSvg = darkCard.createSvg('svg'); - SmilesDrawer.parse(this.plugin.settings.sample, (tree: object) => { - gDrawer.draw(tree, darkSvg, style); - }); - }; - - const onSampleChange = (example: string) => { - lightCard.empty(); - const lightSvg = lightCard.createSvg('svg'); - SmilesDrawer.parse(example, (tree: object) => { - gDrawer.draw(tree, lightSvg, this.plugin.settings.lightTheme); - }); - - darkCard.empty(); - const darkSvg = darkCard.createSvg('svg'); - SmilesDrawer.parse(example, (tree: object) => { - gDrawer.draw(tree, darkSvg, this.plugin.settings.darkTheme); - }); - }; - - // initialize - const initialize = ( - sample: string, - lightTheme: string, - darkTheme: string - ) => { - lightCard.empty(); - const lightSvg = lightCard.createSvg('svg'); - SmilesDrawer.parse( - sample == '' ? SAMPLE_SMILES : sample, - (tree: object) => { - gDrawer.draw( - tree, - lightSvg, - lightTheme == '' ? 'light' : lightTheme - ); - } - ); - - darkCard.empty(); - const darkSvg = darkCard.createSvg('svg'); - SmilesDrawer.parse( - sample == '' ? SAMPLE_SMILES : sample, - (tree: object) => { - gDrawer.draw( - tree, - darkSvg, - darkTheme == '' ? 'dark' : darkTheme - ); - } - ); + const onSettingsChange = () => { + preview.updateSettings(this.plugin.settings); + preview.render(); }; - initialize( - this.plugin.settings.sample, - this.plugin.settings.lightTheme, - this.plugin.settings.darkTheme - ); } hide(): void { diff --git a/src/settings/base.ts b/src/settings/base.ts index 3079758..1d08416 100644 --- a/src/settings/base.ts +++ b/src/settings/base.ts @@ -1,24 +1,29 @@ // Global consts -export const SAMPLE_SMILES = 'CC(=O)NC1=C-C=C-C=C1-C(=O)O'; +export const SAMPLE_SMILES_1 = 'OC(=O)C=CC1=CC=CC=C1'; +export const SAMPLE_SMILES_2 = + 'OC(C(=O)O[C@H]1C[N+]2(CCCOC3=CC=CC=C3)CCC1CC2)(C1=CC=CS1)C1=CC=CS1'; // Plugin settings export interface ChemPluginSettings { - width: string; darkTheme: string; lightTheme: string; - sample: string; + sample1: string; + sample2: string; + imgWidth: string; options: Partial; } export const DEFAULT_SETTINGS: ChemPluginSettings = { - width: '300', darkTheme: 'dark', lightTheme: 'light', - sample: SAMPLE_SMILES, + sample1: SAMPLE_SMILES_1, + sample2: SAMPLE_SMILES_2, + imgWidth: '300', options: {}, }; // Smiles-drawer options +// Reference: https://smilesdrawer.surge.sh/playground.html export interface SMILES_DRAWER_OPTIONS { width: number; height: number; diff --git a/styles.css b/styles.css index fff21ed..59307ea 100644 --- a/styles.css +++ b/styles.css @@ -12,15 +12,11 @@ If your plugin does not need CSS, delete this file. border-radius: var(--radius-m); border: 1px solid var(--background-modifier-border); margin: 0 10px; - padding: 15px 30px; - display: flex; - flex-direction: column; - flex-grow: 1; - flex-wrap: nowrap; - align-content: center; - align-items: center; - justify-content: center; - align-items: center; + padding: 15px 10px; + display: grid; + place-content: center; + place-items: center; + user-select: none; } .chem-table { @@ -30,6 +26,6 @@ If your plugin does not need CSS, delete this file. } .chem-cell { - padding: 15px 30px; + padding: 15px 10px; user-select: none; } \ No newline at end of file From 7957747370e64434f1d4ae54aec7c116b69651b0 Mon Sep 17 00:00:00 2001 From: Acylation <532117255@qq.com> Date: Thu, 13 Jul 2023 17:32:00 +0800 Subject: [PATCH 3/6] Satisfy linter --- src/settings/LivePreview.ts | 5 ++--- src/settings/SettingTab.ts | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/settings/LivePreview.ts b/src/settings/LivePreview.ts index c289155..f6a9d73 100644 --- a/src/settings/LivePreview.ts +++ b/src/settings/LivePreview.ts @@ -1,8 +1,7 @@ -import { MarkdownRenderChild, MarkdownPostProcessorContext } from 'obsidian'; +import { ChemPluginSettings } from '../settings/base'; + import SmilesDrawer from 'smiles-drawer'; import { gDrawer } from '../drawer'; -import { ChemPluginSettings } from '../settings/base'; -import { addBlock, removeBlock } from '../blocks'; /** * Refer to plugin abcjs diff --git a/src/settings/SettingTab.ts b/src/settings/SettingTab.ts index 689072c..4e22023 100644 --- a/src/settings/SettingTab.ts +++ b/src/settings/SettingTab.ts @@ -1,5 +1,4 @@ import { App, PluginSettingTab, Setting, SliderComponent } from 'obsidian'; -import { LivePreview } from './LivePreview'; import ChemPlugin from '../main'; import { @@ -8,9 +7,10 @@ import { SAMPLE_SMILES_2, themeList, } from './base'; -import { gDrawer, setDrawer } from 'src/drawer'; + +import { setDrawer } from 'src/drawer'; import { refreshBlocks } from 'src/blocks'; -import SmilesDrawer from 'smiles-drawer'; +import { LivePreview } from './LivePreview'; //Reference: https://smilesdrawer.surge.sh/playground.html From fc8b64e82d47437c6ff324f82d7520a2cd7306b6 Mon Sep 17 00:00:00 2001 From: Acylation <532117255@qq.com> Date: Thu, 13 Jul 2023 19:50:49 +0800 Subject: [PATCH 4/6] Update sample smiles Provide example for terminal carbons --- src/settings/base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/base.ts b/src/settings/base.ts index 1d08416..f787a96 100644 --- a/src/settings/base.ts +++ b/src/settings/base.ts @@ -1,5 +1,5 @@ // Global consts -export const SAMPLE_SMILES_1 = 'OC(=O)C=CC1=CC=CC=C1'; +export const SAMPLE_SMILES_1 = 'OC(=O)C(C)=CC1=CC=CC=C1'; export const SAMPLE_SMILES_2 = 'OC(C(=O)O[C@H]1C[N+]2(CCCOC3=CC=CC=C3)CCC1CC2)(C1=CC=CS1)C1=CC=CS1'; From d5cfee2347cd45002addc2d1f8d5956c7fdbb9ad Mon Sep 17 00:00:00 2001 From: Acylation <532117255@qq.com> Date: Thu, 13 Jul 2023 19:54:45 +0800 Subject: [PATCH 5/6] Improve render styles and logic --- src/SmilesBlock.ts | 4 ++-- src/settings/LivePreview.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SmilesBlock.ts b/src/SmilesBlock.ts index 2319b38..b8e2f90 100644 --- a/src/SmilesBlock.ts +++ b/src/SmilesBlock.ts @@ -54,8 +54,6 @@ export class SmilesBlock extends MarkdownRenderChild { } private renderCell = (source: string, target: SVGSVGElement) => { - if (this.settings.options.scale == 0) - target.style.width = `${this.settings.imgWidth}px`; SmilesDrawer.parse(source, (tree: object) => { gDrawer.draw( tree, @@ -66,6 +64,8 @@ export class SmilesBlock extends MarkdownRenderChild { : this.settings.lightTheme ); }); + if (this.settings.options.scale == 0) + target.style.width = `${this.settings.imgWidth}px`; }; async onload() { diff --git a/src/settings/LivePreview.ts b/src/settings/LivePreview.ts index f6a9d73..2a55156 100644 --- a/src/settings/LivePreview.ts +++ b/src/settings/LivePreview.ts @@ -21,6 +21,8 @@ export class LivePreview { ) { this.container = this.el.createEl('div'); this.container.style.display = `flex`; + this.container.style.flexWrap = `wrap`; + this.container.style.justifyContent = `center`; this.lightCard = this.container.createEl('div', { cls: 'chemcard theme-light', From b2e8a471448b67bc8b4e273fcfb2564a7fcd1a58 Mon Sep 17 00:00:00 2001 From: Acylation <532117255@qq.com> Date: Thu, 13 Jul 2023 19:55:04 +0800 Subject: [PATCH 6/6] Adapting setting tab --- src/settings/SettingTab.ts | 201 +++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 84 deletions(-) diff --git a/src/settings/SettingTab.ts b/src/settings/SettingTab.ts index 4e22023..4d896f5 100644 --- a/src/settings/SettingTab.ts +++ b/src/settings/SettingTab.ts @@ -27,11 +27,53 @@ export class ChemSettingTab extends PluginSettingTab { containerEl.empty(); - // TODO: Check styling instructions and remove this - containerEl.createEl('h2', { text: 'Style Preferences' }); + const scaleSetting = new Setting(containerEl) + .setName('Scale') + .setDesc( + 'Adjust the global molecule scale. Set to zero to unify image widths, otherwise the structures will share the same bond length.' + ) + .addExtraButton((button) => { + button + .setIcon('rotate-ccw') + .setTooltip('Restore default') + .onClick(async () => { + this.plugin.settings.options.scale = 1; + scaleSlider.setValue(50); + await this.plugin.saveSettings(); + setDrawer({ + ...DEFAULT_SD_OPTIONS, + ...this.plugin.settings.options, + }); + onSettingsChange(); + unifyBondLength(); + }); + }); + + const scaleLabel = scaleSetting.controlEl.createDiv('slider-readout'); + scaleLabel.setText( + (this.plugin.settings.options.scale ?? 1.0).toFixed(2).toString() + ); + + const scaleSlider = new SliderComponent(scaleSetting.controlEl) + .setValue(50 * (this.plugin.settings.options.scale ?? 1.0)) + .setLimits(0.0, 100, 0.5) + .onChange(async (value) => { + this.plugin.settings.options.scale = value / 50; + scaleLabel.setText((value / 50).toFixed(2).toString()); + await this.plugin.saveSettings(); + setDrawer({ + ...DEFAULT_SD_OPTIONS, + ...this.plugin.settings.options, + }); + onSettingsChange(); + if (value == 0) unifyImageWidth(); + else unifyBondLength(); + }); + + const widthSettings = new Setting(containerEl); new Setting(containerEl) - .setName('Light Theme') + .setName('Light theme') .setDesc('Active when Obsidian is under light mode.') .addDropdown((dropdown) => dropdown @@ -45,7 +87,7 @@ export class ChemSettingTab extends PluginSettingTab { ); new Setting(containerEl) - .setName('Dark Theme') + .setName('Dark theme') .setDesc('Active when Obsidian is under dark mode.') .addDropdown((dropdown) => dropdown @@ -58,10 +100,10 @@ export class ChemSettingTab extends PluginSettingTab { }) ); - containerEl.createEl('h2', { text: 'Live Preview' }); + new Setting(containerEl).setName('Live Preview').setHeading(); new Setting(containerEl) - .setName('Sample Smiles 1') + .setName('Sample SMILES strings') .setDesc('Input smiles strings to see the styled structure.') .addText((text) => text @@ -75,11 +117,7 @@ export class ChemSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); onSettingsChange(); }) - ); - - new Setting(containerEl) - .setName('Sample Smiles 2') - .setDesc('Input smiles strings to see the styled structure.') + ) .addText((text) => text .setPlaceholder(SAMPLE_SMILES_2) @@ -95,81 +133,19 @@ export class ChemSettingTab extends PluginSettingTab { ); const preview = new LivePreview(containerEl, this.plugin.settings); - preview.render(); //initialize - new Setting(containerEl) - .setName('Advanced Settings') - .setDesc('Configure smiles drawer options.') - .setHeading(); + new Setting(containerEl).setName('Advanced Settings').setHeading(); new Setting(containerEl) - .setName('Image Width') - .setDesc('Adjust the width of the molecule image.') - .addText((text) => { - text.setValue(this.plugin.settings?.imgWidth ?? '300') - .setPlaceholder('300') - .onChange(async (value) => { - if (value == '') { - value = '300'; - } - this.plugin.settings.imgWidth = value; - await this.plugin.saveSettings(); - onSettingsChange(); - }); - }); - - const scaleSetting = new Setting(containerEl) - .setName('Scale') - .setDesc('Adjust the global molecule scale.') - .addExtraButton((button) => { - button - .setIcon('rotate-ccw') - .setTooltip('Restore default') - .onClick(async () => { - this.plugin.settings.options.scale = 1; - scaleSlider.setValue(50); - await this.plugin.saveSettings(); - setDrawer({ - ...DEFAULT_SD_OPTIONS, - ...this.plugin.settings.options, - }); - onSettingsChange(); - }); - }); - - const scaleLabel = scaleSetting.controlEl.createDiv('slider-readout'); - scaleLabel.setText( - (this.plugin.settings.options.scale ?? 1.0).toFixed(2).toString() - ); - - const scaleSlider = new SliderComponent(scaleSetting.controlEl) - .setValue(50 * (this.plugin.settings.options.scale ?? 1.0)) - .setLimits(0.0, 100, 0.5) - .onChange(async (value) => { - this.plugin.settings.options.scale = value / 50; - scaleLabel.setText((value / 50).toFixed(2).toString()); - await this.plugin.saveSettings(); - setDrawer({ - ...DEFAULT_SD_OPTIONS, - ...this.plugin.settings.options, - }); - onSettingsChange(); - }); - - new Setting(containerEl) - .setName('Max width in table') // width limitation - .setDesc('Maximum width in multiline') - .addText((text) => - text + .setName('Compact drawing') + .setDesc('Linearize simple structures and functional groups.') + .addToggle((toggle) => + toggle .setValue( - this.plugin.settings.options.width?.toString() ?? '300' + this.plugin.settings.options?.compactDrawing ?? false ) .onChange(async (value) => { - if (value == '') { - value = '300'; - } - this.plugin.settings.options.width = parseInt(value); - this.plugin.settings.options.height = parseInt(value); + this.plugin.settings.options.compactDrawing = value; await this.plugin.saveSettings(); setDrawer({ ...DEFAULT_SD_OPTIONS, @@ -180,15 +156,15 @@ export class ChemSettingTab extends PluginSettingTab { ); new Setting(containerEl) - .setName('Compact Drawing') - .setDesc('Linearize simple structures and functional groups.') + .setName('Show terminal carbons') + .setDesc('Explictly draw terminal carbons.') .addToggle((toggle) => toggle .setValue( - this.plugin.settings.options.compactDrawing ?? false + this.plugin.settings.options?.terminalCarbons ?? false ) .onChange(async (value) => { - this.plugin.settings.options.compactDrawing = value; + this.plugin.settings.options.terminalCarbons = value; await this.plugin.saveSettings(); setDrawer({ ...DEFAULT_SD_OPTIONS, @@ -202,6 +178,63 @@ export class ChemSettingTab extends PluginSettingTab { preview.updateSettings(this.plugin.settings); preview.render(); }; + + const unifyBondLength = () => { + widthSettings.controlEl.empty(); + widthSettings + .setName('Maximum width') + .setDesc( + 'Crop structure images that are too large in a multiline block.' + ) + .addText((text) => + text + .setValue( + this.plugin.settings.options.width?.toString() ?? + '300' + ) + .onChange(async (value) => { + if (value == '') { + value = '300'; + } + this.plugin.settings.options.width = + parseInt(value); + this.plugin.settings.options.height = + parseInt(value); + await this.plugin.saveSettings(); + setDrawer({ + ...DEFAULT_SD_OPTIONS, + ...this.plugin.settings.options, + }); + onSettingsChange(); + }) + ); + }; + + const unifyImageWidth = () => { + widthSettings.controlEl.empty(); + widthSettings + .setName('Image width') + .setDesc( + "Adjust the width of the molecule image. Only valid when 'scale' is set to zero." + ) + .addText((text) => { + text.setValue(this.plugin.settings?.imgWidth ?? '300') + .setPlaceholder('300') + .onChange(async (value) => { + if (value == '') { + value = '300'; + } + this.plugin.settings.imgWidth = value; + await this.plugin.saveSettings(); + onSettingsChange(); + }); + }); + }; + + // initialize + preview.render(); + if ((this.plugin.settings.options?.scale ?? 1) == 0) unifyImageWidth(); + else unifyBondLength(); } hide(): void {