import { BrowserWindow, screen } from 'electron'; import { wm_create_conf, wm_move_conf, wm_resize_conf } from './../types/wm'; interface WindowData { win: BrowserWindow; conf: wm_create_conf; } let wdata: { [key: string]: WindowData } = {}; function toP(value: number, percentage: number) { return value * (percentage / 100) as number; } const wm = { create: function (c: wm_create_conf) { const wid = Array.from({ length: 8 }, () => '0123456789abcdef'[Math.floor(Math.random() * 16)]).join(''); const { width: sw, height: sh } = screen.getPrimaryDisplay().bounds; console.log('[wm] create', wid); const win = new BrowserWindow({ width: c.whp ? toP(sw, c.w!) : c.w, height: c.whp ? toP(sh, c.h!) : c.h, x: c.xyp ? toP(sw, c.x!) : c.x, y: c.xyp ? toP(sh, c.y!) : c.x, frame: !c.noBorder, transparent: c.noBackground, webPreferences: { nodeIntegration: true, contextIsolation: false, }, }); wdata[wid] = { win: win, conf: c }; // for further pullin win.setMenuBarVisibility(false); // tell me WHY should i NOT make this the default if (typeof c.onMinimize === 'function') win.on('minimize', () => c.onMinimize!(win)); if (typeof c.onMaximize === 'function') win.on('maximize', () => c.onMaximize!(win)); if (typeof c.onRestore === 'function') win.on('restore', () => c.onRestore!(win)); if (typeof c.onFocus === 'function') win.on('focus', () => c.onFocus!(win)); if (typeof c.onUnfocus === 'function') win.on('blur', () => c.onUnfocus!(win)); if (typeof c.onClose === 'function') win.on('close', () => c.onClose!(win)); if (c.onCreate) c.onCreate(win); return wid // just so you can reference it later on }, destroy: async function (id: number) { console.log('[wm] destroy', id); const win = wdata[id]; if (typeof win.conf.onDestroy === 'function') await win.conf.onDestroy!(win.win); win.win.destroy(); delete wdata[id]; }, move: function (c: wm_move_conf) { console.log('[wm] move', c.id); const win = wdata[c.id]; const { width: sw, height: sh } = screen.getPrimaryDisplay().bounds; let wb = win.win.getBounds(); const sX = wb.x; const sY = wb.y; c.x = c.x === undefined ? sX : c.x; c.y = c.y === undefined ? sY : c.y; const duration = c.duration || 500; const tick = c.tick || 16; const totalSteps = Math.floor(duration / tick); let targetX = toP(c.p ? sw : 1, c.x); let targetY = toP(c.p ? sh : 1, c.y); if (c.fromCenter) { wb = win.win.getBounds(); targetX = targetX - wb.width * 0.5; targetY = targetY - wb.height * 0.5; } const animate = () => { let currentStep = 0; const startX = sX; const startY = sY; const step = () => { currentStep++; const t = currentStep / totalSteps; const eT = c.ease ? c.ease(t) : t; const newX = startX + (targetX - startX) * eT; const newY = startY + (targetY - startY) * eT; win.win.setPosition(Math.round(newX), Math.round(newY)); if (currentStep < totalSteps) { setTimeout(step, tick); } else { win.win.setPosition(Math.round(targetX), Math.round(targetY)); } }; step(); }; if (c.smooth) { animate(); } else { win.win.setPosition(Math.round(targetX), Math.round(targetY)); } }, resize: function (c: wm_resize_conf) { console.log('[wm] resize', c.id); const win = wdata[c.id]; let wb = win.win.getBounds(); const sW = wb.width, sH = wb.height; c.w = c.w === undefined ? sW : c.w; c.h = c.h === undefined ? sH : c.h; const duration = c.duration || 500; const tick = c.tick || 16; const totalSteps = Math.floor(duration / tick); const { width: sw, height: sh } = screen.getPrimaryDisplay().bounds; let targetW = toP(c.p ? sw : 1, c.w); let targetH = toP(c.p ? sh : 1, c.h); const centerX = wb.x + wb.width / 2; const centerY = wb.y + wb.height / 2; const getAnchoredPosition = (curWidth: number, curHeight: number) => { let newX = wb.x; let newY = wb.y; if (!c.fromCenter && c.anchor) { switch (c.anchor) { case 'top': newX = wb.x; newY = wb.y; break; case 'bottom': newX = wb.x; newY = wb.y + wb.height - curHeight; break; case 'left': newX = wb.x; newY = wb.y; break; case 'right': newX = wb.x + wb.width - curWidth; newY = wb.y; break; default: newX = wb.x; newY = wb.y; } } return { newX, newY }; }; const animate = () => { let currentStep = 0; const startW = wb.width; const startH = wb.height; const step = () => { currentStep++; const t = currentStep / totalSteps; const eT = c.ease ? c.ease(t) : t; const newW = startW + (targetW - startW) * eT; const newH = startH + (targetH - startH) * eT; let newX: number, newY: number; if (c.fromCenter) { newX = Math.round(centerX - newW / 2); newY = Math.round(centerY - newH / 2); } else { const pos = getAnchoredPosition(Math.round(newW), Math.round(newH)); newX = pos.newX; newY = pos.newY; } win.win.setBounds({ x: newX, y: newY, width: Math.round(newW), height: Math.round(newH) }); if (currentStep < totalSteps) { setTimeout(step, tick); } else { let finalX: number, finalY: number; if (c.fromCenter) { finalX = Math.round(centerX - targetW / 2); finalY = Math.round(centerY - targetH / 2); } else { const pos = getAnchoredPosition(Math.round(targetW), Math.round(targetH)); finalX = pos.newX; finalY = pos.newY; } win.win.setBounds({ x: finalX, y: finalY, width: Math.round(targetW), height: Math.round(targetH) }); } }; step(); }; if (c.smooth) { animate(); } else { let finalX: number, finalY: number; if (c.fromCenter) { finalX = Math.round(centerX - targetW / 2); finalY = Math.round(centerY - targetH / 2); } else { const pos = getAnchoredPosition(Math.round(targetW), Math.round(targetH)); finalX = pos.newX; finalY = pos.newY; } win.win.setBounds({ x: finalX, y: finalY, width: Math.round(targetW), height: Math.round(targetH) }); } }, eval: async function (id: string, code: string) { console.log('[wm] eval', id); try { return await wdata[id].win.webContents.executeJavaScript(code); } catch (error) { console.error('Error executing JavaScript:', error); } } }; export default wm; export { wdata, wm };