@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
145 lines (115 loc) • 4.06 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 { Injectable, Signal, signal, TemplateRef, ViewContainerRef } from '@angular/core';
import { arrayRemoveItem } from '@deepkit/core';
import { WindowMenuState } from './window-menu';
import { BrowserWindow } from '../../core/utils';
export interface WinHeader {
getBottomPosition(): number;
}
export interface Win {
id: number;
browserWindow: BrowserWindow;
getClosestNonDialogWindow(): Win | undefined;
header: Signal<WinHeader | undefined>;
viewContainerRef: ViewContainerRef;
}
export class WindowRegistry {
id = 0;
registry = new Map<Win, {
state: WindowState,
menu: WindowMenuState,
viewContainerRef: ViewContainerRef
}>();
windowHistory: Win[] = [];
activeWindow?: Win;
getAllElectronWindows(): BrowserWindow[] {
return [...this.registry.keys()].filter(v => v.browserWindow.isElectron()).map(v => v.browserWindow);
}
register(win: Win, state: WindowState, menu: WindowMenuState, viewContainerRef: ViewContainerRef) {
this.id++;
win.id = this.id;
this.registry.set(win, { state, menu, viewContainerRef });
}
/**
* Finds the activeWindow and returns its most outer parent.
*/
getOuterActiveWindow(): Win | undefined {
if (this.activeWindow) return this.activeWindow.getClosestNonDialogWindow();
}
getCurrentViewContainerRef(): ViewContainerRef {
if (this.activeWindow) {
return this.activeWindow.viewContainerRef;
// const reg = this.registry.get(this.activeWindow);
// if (reg) {
// return reg.viewContainerRef;
// }
}
throw new Error('No active window');
}
focus(win: Win) {
if (this.activeWindow === win) return;
const reg = this.registry.get(win);
if (!reg) throw new Error('Window not registered');
this.activeWindow = win;
arrayRemoveItem(this.windowHistory, win);
this.windowHistory.push(win);
reg.state.focus.set(true);
reg.menu.focus();
}
blur(win: Win) {
const reg = this.registry.get(win);
if (reg) {
reg.state.focus.set(false);
}
if (this.activeWindow === win) {
this.activeWindow = undefined;
}
}
unregister(win: Win) {
const reg = this.registry.get(win);
if (reg) {
reg.state.focus.set(false);
}
this.registry.delete(win);
arrayRemoveItem(this.windowHistory, win);
if (this.activeWindow === win) {
this.activeWindow = undefined;
}
if (this.windowHistory.length) {
this.focus(this.windowHistory[this.windowHistory.length - 1]);
}
}
}
export interface AlignedButtonGroup {
activateOneTimeAnimation: () => void;
}
export class WindowState {
public buttonGroupAlignedToSidebar = signal<AlignedButtonGroup | undefined>(undefined);
public focus = signal(false);
public disableInputs = signal(false);
public toolbars = signal<{ [name: string]: TemplateRef<any>[] }>({});
public addToolbarContainer(forName: string, template: TemplateRef<any>) {
let toolbars = this.toolbars()[forName];
if (!toolbars) {
toolbars = [];
}
toolbars.push(template);
this.toolbars.update(v => ({ ...v, [forName]: toolbars.slice() }));
}
public removeToolbarContainer(forName: string, template: TemplateRef<any>) {
const toolbars = this.toolbars()[forName];
if (!toolbars) return;
arrayRemoveItem(toolbars, template);
this.toolbars.update(v => ({ ...v, [forName]: toolbars.slice() }));
}
}