neofunkin/src/lib/windowManager.ts

229 lines
No EOL
7 KiB
TypeScript

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