244 lines
No EOL
5.6 KiB
TypeScript
244 lines
No EOL
5.6 KiB
TypeScript
import { randomRange } from "../_utils/math.utils";
|
|
import { App } from "../";
|
|
import { Vector2 } from "../math/vector2";
|
|
import { SystemManager } from "../system/systemManager";
|
|
import { TrackingManager } from "../tracking/trackingManager";
|
|
import { VirtualFile } from "../virtual-drive/file";
|
|
|
|
export interface WindowOptions {
|
|
id?: string;
|
|
app?: App;
|
|
size?: Vector2;
|
|
position?: Vector2;
|
|
fullscreen?: boolean | string;
|
|
options?: object;
|
|
isFocused?: boolean;
|
|
lastInteraction?: number;
|
|
minimized?: boolean;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
export class WindowsManager {
|
|
windows: { [id: string]: WindowOptions };
|
|
updateWindows: Function;
|
|
startupComplete: boolean;
|
|
|
|
#systemManager: SystemManager;
|
|
#trackingManager: TrackingManager;
|
|
|
|
constructor(systemManager: SystemManager, trackingManager: TrackingManager) {
|
|
this.#systemManager = systemManager;
|
|
this.#trackingManager = trackingManager;
|
|
this.windows = {};
|
|
this.updateWindows = () => {};
|
|
this.startupComplete = false;
|
|
}
|
|
|
|
open(appId: string, options?: WindowOptions | null): object | null {
|
|
const { appsConfig, windowsConfig, taskbarConfig } = this.#systemManager;
|
|
const app = appsConfig.getAppById(appId);
|
|
|
|
if (app == null) {
|
|
console.warn(`Failed to open app ${appId}: app not found`);
|
|
return null;
|
|
}
|
|
|
|
const size = options?.size ?? app.windowOptions?.size ?? new Vector2(700, 400);
|
|
|
|
const availableScreenSpace = new Vector2(
|
|
window.innerWidth - windowsConfig.screenMargin * 2,
|
|
window.innerHeight - windowsConfig.screenMargin * 2 - taskbarConfig.height
|
|
);
|
|
|
|
let fullscreen = false;
|
|
|
|
if (size.x > availableScreenSpace.x) {
|
|
size.x = availableScreenSpace.x;
|
|
fullscreen = true;
|
|
} else if (size.y > availableScreenSpace.y) {
|
|
size.y = availableScreenSpace.y;
|
|
fullscreen = true;
|
|
}
|
|
|
|
const position = new Vector2(
|
|
windowsConfig.screenMargin + randomRange(0, availableScreenSpace.x - size.x),
|
|
windowsConfig.screenMargin + randomRange(0, availableScreenSpace.y - size.y)
|
|
);
|
|
|
|
if (options?.fullscreen) {
|
|
if (typeof(options.fullscreen) == "string") {
|
|
fullscreen = options.fullscreen.toLowerCase() === "true";
|
|
} else {
|
|
fullscreen = options.fullscreen;
|
|
}
|
|
|
|
delete options.fullscreen;
|
|
}
|
|
|
|
let id: number | string = 0;
|
|
while (this.windowIds.includes(id.toString())) {
|
|
id++;
|
|
}
|
|
|
|
id = id.toString();
|
|
|
|
this.#trackingManager.event({
|
|
category: "Actions",
|
|
action: "Opened window",
|
|
label: app.id
|
|
});
|
|
|
|
console.info(`Opening window ${id}:${app.id}`);
|
|
|
|
this.windows[id] = {
|
|
id,
|
|
app,
|
|
size,
|
|
position,
|
|
fullscreen,
|
|
options: options as object | undefined,
|
|
};
|
|
|
|
this.focus(id);
|
|
|
|
app.isActive = true;
|
|
|
|
this.updateWindows(this.windows);
|
|
return this.windows[id];
|
|
// console.log(this);
|
|
}
|
|
|
|
openFile(file: VirtualFile, options: object = {}): object | null {
|
|
if (file.extension == null) return null;
|
|
|
|
const { appsConfig } = this.#systemManager;
|
|
const app = appsConfig.getAppByFileExtension(file?.extension);
|
|
if (app != null) {
|
|
return this.open(app.id, { file, ...options });
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
close(windowId: string) {
|
|
windowId = windowId.toString();
|
|
|
|
if (!this.windowIds.includes(windowId)) {
|
|
console.warn(`Failed to close window ${windowId}: window not found`);
|
|
return;
|
|
}
|
|
|
|
const { app } = this.windows[windowId];
|
|
if (app != null) app.isActive = this.isAppActive(app.id);
|
|
|
|
console.info(`Closing window ${windowId}`);
|
|
delete this.windows[windowId];
|
|
|
|
this.updateWindows(this.windows);
|
|
// console.log(this);
|
|
}
|
|
|
|
focus(windowId: string) {
|
|
windowId = windowId.toString();
|
|
|
|
if (!this.windowIds.includes(windowId)) {
|
|
console.warn(`Failed to focus window ${windowId}: window not found`);
|
|
return;
|
|
}
|
|
|
|
Object.values(this.windows).forEach((window) => {
|
|
const isFocused = (window.id === windowId);
|
|
window.isFocused = isFocused;
|
|
|
|
if (isFocused) {
|
|
window.lastInteraction = Date.now().valueOf();
|
|
window.minimized = false;
|
|
}
|
|
});
|
|
|
|
this.updateWindows(this.windows);
|
|
}
|
|
|
|
isFocused(windowId: string) {
|
|
return this.windows[windowId].isFocused;
|
|
}
|
|
|
|
isAnyFocused() {
|
|
let anyFocused = false;
|
|
|
|
Object.values(this.windows).forEach((window) => {
|
|
if (window.isFocused)
|
|
return anyFocused = true;
|
|
});
|
|
|
|
return anyFocused;
|
|
}
|
|
|
|
/**
|
|
* @param minimized - Leave as undefined to toggle the window's minimization state
|
|
*/
|
|
setMinimized(windowId: string, minimized?: boolean) {
|
|
windowId = windowId.toString();
|
|
|
|
if (!this.windowIds.includes(windowId)) {
|
|
console.warn(`Failed to set minimized on window ${windowId}: window not found`);
|
|
return;
|
|
}
|
|
|
|
const window = this.windows[windowId];
|
|
window.minimized = minimized ?? !window.minimized;
|
|
|
|
this.updateWindows(this.windows);
|
|
}
|
|
|
|
minimizeAll() {
|
|
Object.values(this.windows).forEach((window) => {
|
|
window.minimized = true;
|
|
});
|
|
|
|
this.updateWindows(this.windows);
|
|
}
|
|
|
|
isAppActive(appId: string): boolean {
|
|
let active = false;
|
|
|
|
Object.values(this.windows).forEach((window) => {
|
|
if (window.app?.id === appId) {
|
|
active = true;
|
|
return;
|
|
}
|
|
});
|
|
|
|
return active;
|
|
}
|
|
|
|
getAppWindowId(appId: string): string | null {
|
|
let windowId: string | null = null;
|
|
|
|
Object.values(this.windows).forEach((window) => {
|
|
if (window.app?.id == appId)
|
|
windowId = window.id as string;
|
|
});
|
|
|
|
return windowId;
|
|
}
|
|
|
|
setUpdateWindows(updateWindows: Function) {
|
|
this.updateWindows = updateWindows;
|
|
}
|
|
|
|
startup(appIds: string[], options: {}) {
|
|
if (appIds == null || this.startupComplete)
|
|
return;
|
|
|
|
appIds.forEach((appId) => {
|
|
this.open(appId, options);
|
|
});
|
|
|
|
this.startupComplete = true;
|
|
}
|
|
|
|
get windowIds(): string[] {
|
|
return Object.keys(this.windows);
|
|
}
|
|
} |