TeaSpeak-Client/modules/renderer/MenuBar.ts

99 lines
3.6 KiB
TypeScript

import * as electron from "electron";
import {MenuBarDriver, MenuBarEntry} from "tc-shared/ui/frames/menu-bar";
import {IpcRendererEvent} from "electron";
import {getIconManager} from "tc-shared/file/Icons";
import {clientIconClassToImage, remoteIconDatafier, RemoteIconWrapper} from "./IconHelper";
import {NativeMenuBarEntry} from "../shared/MenuBarDefinitions";
let uniqueEntryIdIndex = 0;
export class NativeMenuBarDriver implements MenuBarDriver {
private readonly ipcChannelListener;
private menuEntries: NativeMenuBarEntry[] = [];
private remoteIconReferences: RemoteIconWrapper[] = [];
private remoteIconListeners: (() => void)[] = [];
private callbacks: {[key: string]: () => void} = {};
constructor() {
this.ipcChannelListener = this.handleMenuBarEvent.bind(this);
electron.ipcRenderer.on("menu-bar", this.ipcChannelListener);
}
destroy() {
electron.ipcRenderer.off("menu-bar", this.ipcChannelListener);
this.internalClearEntries();
}
private internalClearEntries() {
this.callbacks = {};
this.menuEntries = [];
this.remoteIconListeners.forEach(callback => callback());
this.remoteIconListeners = [];
this.remoteIconReferences.forEach(icon => remoteIconDatafier.unrefIcon(icon));
this.remoteIconReferences = [];
}
clearEntries() {
this.internalClearEntries()
electron.ipcRenderer.send("menu-bar", []);
}
setEntries(entries: MenuBarEntry[]) {
this.internalClearEntries();
this.menuEntries = entries.map(e => this.wrapEntry(e)).filter(e => !!e);
electron.ipcRenderer.send("menu-bar", this.menuEntries);
}
private wrapEntry(entry: MenuBarEntry) : NativeMenuBarEntry {
if(entry.type === "separator") {
return { type: "separator", uniqueId: entry.uniqueId || "item-" + (++uniqueEntryIdIndex) };
} else if(entry.type === "normal") {
if(typeof entry.visible === "boolean" && !entry.visible) {
return null;
}
let result = {
type: "normal",
uniqueId: entry.uniqueId || "item-" + (++uniqueEntryIdIndex),
label: entry.label,
disabled: entry.disabled,
children: entry.children?.map(e => this.wrapEntry(e)).filter(e => !!e)
} as NativeMenuBarEntry;
if(entry.click) {
this.callbacks[result.uniqueId] = entry.click;
}
if(typeof entry.icon === "object") {
/* we've a remote icon */
const remoteIcon = getIconManager().resolveIcon(entry.icon.iconId, entry.icon.serverUniqueId, entry.icon.handlerId);
const wrapped = remoteIconDatafier.resolveIcon(remoteIcon);
this.remoteIconReferences.push(wrapped);
wrapped.onDataUrlChange(url => {
result.icon = url;
electron.ipcRenderer.send("menu-bar", this.menuEntries);
});
result.icon = wrapped.getDataUrl();
} else if(typeof entry.icon === "string") {
result.icon = clientIconClassToImage(entry.icon).toDataURL();
}
return result;
} else {
return undefined;
}
}
private handleMenuBarEvent(_event: IpcRendererEvent, eventType: string, ...args) {
if(eventType === "item-click") {
const callback = this.callbacks[args[0]];
if(typeof callback === "function") {
callback();
}
}
}
}