ProzillaOS/packages/core/src/features/windows/windowsManager.ts
2024-07-14 22:26:57 +02:00

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);
}
}