@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
203 lines (166 loc) • 5.51 kB
text/typescript
/*
* Deepkit Framework
* Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the MIT License.
*
* You should have received a copy of the MIT License along with this program.
*/
import {
AfterViewInit,
ContentChildren,
Directive,
EventEmitter,
forwardRef,
Input,
OnDestroy,
Output,
QueryList,
} from '@angular/core';
import { WindowMenuState } from '../window/window-menu';
import { arrayHasItem } from '@deepkit/core';
import { Subscription } from 'rxjs';
import { Electron } from '../../core/utils';
export class MenuBase implements AfterViewInit {
label?: string;
sublabel?: string;
icon?: string;
enabled: boolean = true;
accelerator?: string;
role?: string;
visible: boolean = true;
onlyMacOs: boolean | '' = false;
noMacOs: boolean | '' = false;
id?: string;
before?: string;
after?: string;
beforeGroupContaining?: string;
afterGroupContaining?: string;
click = new EventEmitter();
change = new EventEmitter;
public type = '';
protected registered = new Set<MenuBase>();
protected subscriptions = new Map<MenuBase, Subscription>();
public child?: QueryList<MenuBase>;
constructor() {
}
buildTemplate() {
const submenu: any[] = [];
if (this.child) {
for (const item of this.child.toArray()) {
if (item === this) continue;
if (!item.validOs()) {
continue;
}
submenu.push(item.buildTemplate());
}
}
const result: { [name: string]: any } = {
click: () => {
this.click.emit()
},
};
if (this.label) result['label'] = this.label;
if (this.sublabel) result['sublabel'] = this.sublabel;
if (!this.enabled) result['enabled'] = false;
if (this.type) result['type'] = this.type;
if (this.accelerator) result['accelerator'] = this.accelerator;
if (this.role) result['role'] = this.role;
if (this.type) result['type'] = this.type;
if (this.accelerator) result['accelerator'] = this.accelerator;
if (submenu.length) result['submenu'] = submenu;
return result;
}
public validOs(): boolean {
if (Electron.isAvailable()) {
if (this.onlyMacOs !== false && Electron.getProcess().platform !== 'darwin') {
return false;
}
if (this.noMacOs !== false && Electron.getProcess().platform === 'darwin') {
return false;
}
}
return true;
}
ngAfterViewInit() {
if (this.child) {
this.child!.changes.subscribe((items: MenuBase[]) => {
for (const item of items) {
if (!this.registered.has(item)) {
this.registered.add(item);
this.subscriptions.set(item, item.change.subscribe(() => {
this.change.emit();
}));
}
}
for (const item of this.registered) {
if (!arrayHasItem(items, item)) {
//got removed
this.registered.delete(item);
this.subscriptions.get(item)!.unsubscribe();
this.subscriptions.delete(item);
}
}
this.change.emit();
});
}
}
}
export class MenuItemDirective extends MenuBase {
}
export class MenuCheckboxDirective extends MenuBase {
checked: boolean = false;
type = 'checkbox';
buildTemplate() {
return { ...super.buildTemplate(), checked: this.checked };
}
}
export class MenuRadioDirective extends MenuBase {
checked: boolean = false;
type = 'radio';
buildTemplate() {
return { ...super.buildTemplate(), checked: this.checked };
}
}
export class MenuSeparatorDirective extends MenuBase {
type = 'separator';
}
export class MenuDirective extends MenuBase implements OnDestroy, AfterViewInit {
position: number = 0;
constructor(protected windowMenuState: WindowMenuState) {
super();
}
ngAfterViewInit() {
super.ngAfterViewInit();
this.windowMenuState.addMenu(this);
}
ngOnDestroy() {
this.windowMenuState.removeMenu(this);
}
}