TeaSpeak-Client/modules/renderer/menu.ts

246 lines
6.8 KiB
TypeScript
Raw Normal View History

2019-10-25 19:51:40 -04:00
import {class_to_image} from "./icon-helper";
import * as electron from "electron";
import * as mbar from "tc-shared/ui/frames/MenuBar";
2019-10-30 17:03:43 -04:00
import {Arguments, process_args} from "../shared/process-arguments";
2019-10-25 19:51:40 -04:00
import ipcRenderer = electron.ipcRenderer;
import {Icon} from "tc-shared/FileManager";
namespace native {
2019-10-25 19:51:40 -04:00
import ipcRenderer = electron.ipcRenderer;
let _item_index = 1;
2019-10-25 19:51:40 -04:00
abstract class NativeMenuBase {
protected _handle: NativeMenuBar;
protected _click: () => any;
id: string;
2019-10-25 19:51:40 -04:00
protected constructor(handle: NativeMenuBar, id?: string) {
this._handle = handle;
this.id = id || ("item_" + (_item_index++));
2019-10-25 19:51:40 -04:00
}
abstract build() : electron.MenuItemConstructorOptions;
abstract items(): (mbar.MenuItem | mbar.HRItem)[];
2019-10-25 19:51:40 -04:00
trigger_click() {
if(this._click)
this._click();
}
}
2019-10-25 19:51:40 -04:00
class NativeMenuItem extends NativeMenuBase implements mbar.MenuItem {
private _items: (NativeMenuItem | NativeHrItem)[] = [];
private _label: string;
private _enabled: boolean = true;
private _visible: boolean = true;
2019-10-25 19:51:40 -04:00
private _icon_data: string;
2019-10-25 19:51:40 -04:00
constructor(handle: NativeMenuBar) {
super(handle);
2019-10-25 19:51:40 -04:00
}
2019-10-25 19:51:40 -04:00
append_hr(): mbar.HRItem {
const item = new NativeHrItem(this._handle);
this._items.push(item);
return item;
}
2019-10-25 19:51:40 -04:00
append_item(label: string): mbar.MenuItem {
const item = new NativeMenuItem(this._handle);
item.label(label);
this._items.push(item);
return item;
}
2019-10-25 19:51:40 -04:00
click(callback: () => any): this {
this._click = callback;
return this;
}
2019-10-25 19:51:40 -04:00
delete_item(item: mbar.MenuItem | mbar.HRItem) {
const i_index = this._items.indexOf(item as any);
if(i_index < 0) return;
this._items.splice(i_index, 1);
}
2019-10-25 19:51:40 -04:00
disabled(value?: boolean): boolean {
if(typeof(value) === "boolean")
this._enabled = !value;
return !this._enabled;
}
2019-10-25 19:51:40 -04:00
icon(klass?: string | Promise<Icon> | Icon): string {
if(typeof(klass) === "string") {
const buffer = class_to_image(klass);
if(buffer)
this._icon_data = buffer.toDataURL();
2019-10-25 19:51:40 -04:00
}
return "";
}
2019-10-25 19:51:40 -04:00
items(): (mbar.MenuItem | mbar.HRItem)[] {
return this._items;
}
2019-10-25 19:51:40 -04:00
label(value?: string): string {
if(typeof(value) === "string")
this._label = value;
return this._label;
}
2019-10-25 19:51:40 -04:00
visible(value?: boolean): boolean {
if(typeof(value) === "boolean")
this._visible = value;
return this._visible;
}
2019-10-25 19:51:40 -04:00
build(): Electron.MenuItemConstructorOptions {
return {
id: this.id,
2019-10-25 19:51:40 -04:00
label: this._label || "",
2019-10-25 19:51:40 -04:00
submenu: this._items.length > 0 ? this._items.map(e => e.build()) : undefined,
enabled: this._enabled,
visible: this._visible,
2019-10-25 19:51:40 -04:00
icon: this._icon_data
2019-10-25 19:51:40 -04:00
}
}
}
class NativeHrItem extends NativeMenuBase implements mbar.HRItem {
constructor(handle: NativeMenuBar) {
super(handle);
}
2019-10-25 19:51:40 -04:00
build(): Electron.MenuItemConstructorOptions {
return {
type: 'separator',
id: this.id
2019-10-25 19:51:40 -04:00
}
}
items(): (mbar.MenuItem | mbar.HRItem)[] {
return [];
}
}
2019-10-25 19:51:40 -04:00
function is_similar_deep(a, b) {
if(typeof(a) !== typeof(b))
return false;
if(typeof(a) !== "object")
return a === b;
2019-10-25 19:51:40 -04:00
const aProps = Object.keys(a);
const bProps = Object.keys(b);
2019-10-25 19:51:40 -04:00
if (aProps.length != bProps.length)
return false;
2019-10-25 19:51:40 -04:00
for (let i = 0; i < aProps.length; i++) {
const propName = aProps[i];
2019-10-25 19:51:40 -04:00
if(!is_similar_deep(a[propName], b[propName]))
return false;
2019-10-25 19:51:40 -04:00
}
return true;
}
2019-10-25 19:51:40 -04:00
export class NativeMenuBar implements mbar.MenuBarDriver {
private static _instance: NativeMenuBar;
2019-10-25 19:51:40 -04:00
private menu: electron.Menu;
private _items: NativeMenuItem[] = [];
private _current_menu: electron.MenuItemConstructorOptions[];
2019-10-25 19:51:40 -04:00
public static instance() : NativeMenuBar {
if(!this._instance)
this._instance = new NativeMenuBar();
return this._instance;
}
2019-10-25 19:51:40 -04:00
append_item(label: string): mbar.MenuItem {
const item = new NativeMenuItem(this);
item.label(label);
this._items.push(item);
return item;
}
2019-10-25 19:51:40 -04:00
delete_item(item: mbar.MenuItem) {
const i_index = this._items.indexOf(item as any);
if(i_index < 0) return;
this._items.splice(i_index, 1);
}
2019-10-25 19:51:40 -04:00
flush_changes() {
const target_menu = this.build_menu();
if(is_similar_deep(target_menu, this._current_menu))
return;
2019-10-25 19:51:40 -04:00
this._current_menu = target_menu;
ipcRenderer.send('top-menu', target_menu);
}
2019-10-25 19:51:40 -04:00
private build_menu() : electron.MenuItemConstructorOptions[] {
return this._items.map(e => e.build());
}
2019-10-25 19:51:40 -04:00
items(): mbar.MenuItem[] {
return this._items;
2019-10-25 19:51:40 -04:00
}
initialize() {
this.menu = new electron.remote.Menu();
ipcRenderer.on('top-menu', (event, clicked_item) => {
console.log("Item %o clicked", clicked_item);
const check_item = (item: NativeMenuBase) => {
if(item.id == clicked_item) {
item.trigger_click();
return true;
}
for(const child of item.items())
if(check_item(child as NativeMenuBase))
return true;
};
2019-10-25 19:51:40 -04:00
for(const item of this._items)
if(check_item(item))
return;
});
}
}
}
2019-10-25 19:51:40 -04:00
mbar.set_driver(native.NativeMenuBar.instance());
// @ts-ignore
mbar.native_actions = {
open_change_log() {
call_basic_action("open-changelog");
},
2019-10-25 19:51:40 -04:00
check_native_update() {
call_basic_action("check-native-update");
},
2019-10-25 19:51:40 -04:00
quit() {
call_basic_action("quit");
},
2019-10-25 19:51:40 -04:00
open_dev_tools() {
call_basic_action("open-dev-tools");
},
2019-10-25 19:51:40 -04:00
reload_page() {
call_basic_action("reload-window")
},
2019-10-30 17:03:43 -04:00
show_dev_tools() { return process_args.has_flag(Arguments.DEV_TOOLS); }
};
2019-10-25 19:51:40 -04:00
const call_basic_action = (name: string, ...args: any[]) => ipcRenderer.send('basic-action', name, ...args);