import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { Modal, Setting, TFile } from "obsidian";
import { getEA } from "src";
import { DEVICE } from "src/constants/constants";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import ExcalidrawView from "src/ExcalidrawView";
import ExcalidrawPlugin from "src/main";
import { fragWithHTML, getExportPadding, getExportTheme, getPNGScale, getWithBackground } from "src/utils/Utils";
export class ExportDialog extends Modal {
private ea: ExcalidrawAutomate;
private api: ExcalidrawImperativeAPI;
public padding: number;
public scale: number;
public theme: string;
public transparent: boolean;
public saveSettings: boolean;
public dirty: boolean = false;
private selectedOnlySetting: Setting;
private hasSelectedElements: boolean = false;
private boundingBox: {
topX: number;
topY: number;
width: number;
height: number;
};
public embedScene: boolean;
public exportSelectedOnly: boolean;
public saveToVault: boolean;
constructor(
private plugin: ExcalidrawPlugin,
private view: ExcalidrawView,
private file: TFile,
) {
super(app);
this.ea = getEA(this.view);
this.api = this.ea.getExcalidrawAPI() as ExcalidrawImperativeAPI;
this.padding = getExportPadding(this.plugin,this.file);
this.scale = getPNGScale(this.plugin,this.file)
this.theme = getExportTheme(this.plugin, this.file, (this.api).getAppState().theme)
this.boundingBox = this.ea.getBoundingBox(this.ea.getViewElements());
this.embedScene = false;
this.exportSelectedOnly = false;
this.saveToVault = true;
this.transparent = !getWithBackground(this.plugin, this.file);
this.saveSettings = false;
}
onOpen(): void {
this.containerEl.classList.add("excalidraw-release");
this.titleEl.setText(`Export Image`);
this.hasSelectedElements = this.view.getViewSelectedElements().length > 0;
//@ts-ignore
this.selectedOnlySetting.setVisibility(this.hasSelectedElements);
}
async onClose() {
this.dirty = this.saveSettings;
}
async createForm() {
let scaleSetting:Setting;
let paddingSetting: Setting;
this.contentEl.createEl("h1",{text: "Image settings"});
this.contentEl.createEl("p",{text: "Transparency only affects PNGs. Excalidraw files can only be exported outside the Vault. PNGs copied to clipboard may not include the scene."})
const size = ():DocumentFragment => {
const width = Math.round(this.scale*this.boundingBox.width + this.padding*2);
const height = Math.round(this.scale*this.boundingBox.height + this.padding*2);
return fragWithHTML(`The lager the scale, the larger the image.
Scale: ${this.scale}
Image size: ${width}x${height}`);
}
const padding = ():DocumentFragment => {
return fragWithHTML(`Current image padding is ${this.padding}`);
}
paddingSetting = new Setting(this.contentEl)
.setName("Image padding")
.setDesc(padding())
.addSlider(slider => {
slider
.setLimits(0,50,1)
.setValue(this.padding)
.onChange(value => {
this.padding = value;
scaleSetting.setDesc(size());
paddingSetting.setDesc(padding());
})
})
scaleSetting = new Setting(this.contentEl)
.setName("PNG Scale")
.setDesc(size())
.addSlider(slider =>
slider
.setLimits(0.5,5,0.5)
.setValue(this.scale)
.onChange(value => {
this.scale = value;
scaleSetting.setDesc(size());
})
)
new Setting(this.contentEl)
.setName("Export theme")
.addDropdown(dropdown =>
dropdown
.addOption("light","Light")
.addOption("dark","Dark")
.setValue(this.theme)
.onChange(value => {
this.theme = value;
})
)
new Setting(this.contentEl)
.setName("Background color")
.addDropdown(dropdown =>
dropdown
.addOption("transparent","Transparent")
.addOption("with-color","Use scene background color")
.setValue(this.transparent?"transparent":"with-color")
.onChange(value => {
this.transparent = value === "transparent";
})
)
new Setting(this.contentEl)
.setName("Save or one-time settings?")
.addDropdown(dropdown =>
dropdown
.addOption("save","Save these settings as the preset for this image")
.addOption("one-time","These are one-time settings")
.setValue(this.saveSettings?"save":"one-time")
.onChange(value => {
this.saveSettings = value === "save";
})
)
this.contentEl.createEl("h1",{text:"Export settings"});
new Setting(this.contentEl)
.setName("Embed the Excalidraw scene in the exported file?")
.addDropdown(dropdown =>
dropdown
.addOption("embed","Embed scene")
.addOption("no-embed","Do not embed scene")
.setValue(this.embedScene?"embed":"no-embed")
.onChange(value => {
this.embedScene = value === "embed";
})
)
if(DEVICE.isDesktop) {
new Setting(this.contentEl)
.setName("Where to save the image?")
.addDropdown(dropdown =>
dropdown
.addOption("vault","Save image to your Vault")
.addOption("outside","Export image outside your Vault")
.setValue(this.saveToVault?"vault":"outside")
.onChange(value => {
this.saveToVault = value === "vault";
})
)
}
this.selectedOnlySetting = new Setting(this.contentEl)
.setName("Export entire scene or just selected elements?")
.addDropdown(dropdown =>
dropdown
.addOption("all","Export entire scene")
.addOption("selected","Export selected elements")
.setValue(this.exportSelectedOnly?"selected":"all")
.onChange(value => {
this.exportSelectedOnly = value === "selected";
})
)
const div = this.contentEl.createDiv({cls: "excalidraw-prompt-buttons-div"});
const bPNG = div.createEl("button", { text: "PNG to File", cls: "excalidraw-prompt-button"});
bPNG.onclick = () => {
this.saveToVault
? this.view.savePNG(this.view.getScene(this.hasSelectedElements && this.exportSelectedOnly))
: this.view.exportPNG(this.embedScene,this.hasSelectedElements && this.exportSelectedOnly);
this.close();
};
const bSVG = div.createEl("button", { text: "SVG to File", cls: "excalidraw-prompt-button" });
bSVG.onclick = () => {
this.saveToVault
? this.view.saveSVG(this.view.getScene(this.hasSelectedElements && this.exportSelectedOnly))
: this.view.exportSVG(this.embedScene,this.hasSelectedElements && this.exportSelectedOnly);
this.close();
};
const bExcalidraw = div.createEl("button", { text: "Excalidraw", cls: "excalidraw-prompt-button" });
bExcalidraw.onclick = () => {
this.view.exportExcalidraw(this.hasSelectedElements && this.exportSelectedOnly);
this.close();
};
if(DEVICE.isDesktop) {
const bPNGClipboard = div.createEl("button", { text: "PNG to Clipboard", cls: "excalidraw-prompt-button" });
bPNGClipboard.onclick = () => {
this.view.exportPNGToClipboard(this.embedScene, this.hasSelectedElements && this.exportSelectedOnly);
this.close();
};
}
}
}