TeaSpeak-Client/modules/renderer/context-menu.ts
2019-06-30 17:24:10 +02:00

181 lines
6.0 KiB
TypeScript

window["require_setup"](module);
import * as electron from "electron";
const remote = electron.remote;
const {Menu, MenuItem} = remote;
import {isFunction} from "util";
import NativeImage = electron.NativeImage;
class ElectronContextMenu implements contextmenu.ContextMenuProvider {
private _close_listeners: (() => any)[] = [];
private _current_menu: electron.Menu;
private _icon_mash_url: string;
private _icon_mask_img: NativeImage;
private _div: JQuery;
despawn_context_menu() {
if(!this._current_menu)
return;
this._current_menu.closePopup();
this._current_menu = undefined;
for(const listener of this._close_listeners)
listener();
this._close_listeners = [];
}
finalize() {
this._icon_mask_img = undefined;
this._icon_mash_url = undefined;
if(this._div) this._div.detach();
this._div = undefined;
this._cache_klass_map = undefined;
}
initialize() {
this.initialize_icons();
}
private async initialize_icons() {
if(!this._div) {
this._div = $.spawn("div");
this._div.css('display', 'none');
this._div.appendTo(document.body);
}
const image = new Image();
image.src = 'img/client_icon_sprite.svg';
await new Promise((resolve, reject) => {
image.onload = resolve;
image.onerror = reject;
});
/* TODO: Get a size! */
const canvas = document.createElement("canvas");
canvas.width = 1024;
canvas.height = 1024;
canvas.getContext("2d").drawImage(image, 0, 0);
this._icon_mash_url = canvas.toDataURL();
this._icon_mask_img = remote.nativeImage.createFromDataURL(this._icon_mash_url);
}
private _cache_klass_map: {[key: string]: NativeImage} = {};
private class_to_image(klass: string) : NativeImage {
if(!klass || !this._icon_mask_img)
return undefined;
if(this._cache_klass_map[klass])
return this._cache_klass_map[klass];
this._div[0].classList.value = 'icon ' + klass;
const data = window.getComputedStyle(this._div[0]);
const offset_x = parseInt(data.backgroundPositionX.split(",")[0]);
const offset_y = parseInt(data.backgroundPositionY.split(",")[0]);
//http://localhost/home/TeaSpeak/Web-Client/web/environment/development/img/client_icon_sprite.svg
//const hight = element.css('height');
//const width = element.css('width');
console.log("Offset: x: %o y: %o;", offset_x, offset_y);
return this._cache_klass_map[klass] = this._icon_mask_img.crop({
height: 16,
width: 16,
x: offset_x == 0 ? 0 : -offset_x,
y: offset_y == 0 ? 0 : -offset_y
});
}
private _entry_id = 0;
private build_menu(entry: contextmenu.MenuEntry) : electron.MenuItem {
if(entry.type == contextmenu.MenuEntryType.CLOSE) {
this._close_listeners.push(entry.callback);
return undefined;
}
const click_callback = () => {
if(entry.callback)
entry.callback();
this.despawn_context_menu();
};
const _id = "entry_" + (this._entry_id++);
if(entry.type == contextmenu.MenuEntryType.ENTRY) {
return new MenuItem({
id: _id,
label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string,
type: "normal",
click: click_callback,
icon: this.class_to_image(entry.icon_class),
visible: entry.visible,
enabled: !entry.disabled
});
} else if(entry.type == contextmenu.MenuEntryType.HR) {
if(typeof(entry.visible) === "boolean" && !entry.visible)
return undefined;
return new MenuItem({
id: _id,
type: "separator",
label: '',
click: click_callback
})
} else if(entry.type == contextmenu.MenuEntryType.CHECKBOX) {
return new MenuItem({
id: _id,
label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string,
type: "checkbox",
checked: !!entry.checkbox_checked,
click: click_callback,
icon: this.class_to_image(entry.icon_class),
visible: entry.visible,
enabled: !entry.disabled
});
} else if (entry.type == contextmenu.MenuEntryType.SUB_MENU) {
const sub_menu = new Menu();
for(const e of entry.sub_menu) {
const build = this.build_menu(e);
if(!build)
continue;
sub_menu.append(build);
}
return new MenuItem({
id: _id,
label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string,
type: "submenu",
submenu: sub_menu,
click: click_callback,
icon: this.class_to_image(entry.icon_class),
visible: entry.visible,
enabled: !entry.disabled
});
}
return undefined;
}
spawn_context_menu(x: number, y: number, ...entries: contextmenu.MenuEntry[]) {
this.despawn_context_menu();
this._current_menu = new Menu();
for(const entry of entries) {
const build = this.build_menu(entry);
if(!build)
continue;
this._current_menu.append(build);
}
this._current_menu.popup({
window: remote.getCurrentWindow(),
x: x,
y: y,
callback: () => this.despawn_context_menu()
});
}
html_format_enabled() { return false; }
}
contextmenu.set_provider(new ElectronContextMenu());
export {};