/* * "Fenster wachsen aus dem Knopf": Ein Popup-Fenster (Optionen, Mods, Skin, * Freunde …) erscheint nicht schlagartig, sondern wächst aus dem angeklickten * Knopf heraus. Dafür wird das noch unsichtbare Fenster abfotografiert und das * Bild in einem durchsichtigen Hilfsfenster vom Knopf aus groß gezogen; am Ende * übernimmt das echte Fenster an exakt derselben Stelle. * * Das Hilfsfenster entsteht jedes Mal neu und gleich in der richtigen Größe: * Unter Windows färbt sich ein durchsichtiges Fenster schwarz, sobald es * nachträglich vergrößert wird, und ein verstecktes Fenster zeichnet nicht mehr. * Abschaltbar unter Optionen → Darstellung → Animationen („Bewegte Oberfläche“). */ const path = require('path'); const { BrowserWindow } = require('electron'); const DAUER_MS = 280; const HOECHSTENS_MS = 2000; // spätestens dann ist das Fenster in jedem Fall zu sehen const warte = (ms) => new Promise((r) => setTimeout(r, ms)); function vereinigung(a, b) { const x = Math.min(a.x, b.x); const y = Math.min(a.y, b.y); return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y, }; } // Rechteck in Koordinaten des Hilfsfensters umrechnen const relativ = (r, box) => ({ x: r.x - box.x, y: r.y - box.y, width: r.width, height: r.height }); async function abspielen(ziel, von, merke) { // unsichtbar zeigen, damit Chromium den Inhalt zeichnet, dann abfotografieren ziel.setOpacity(0); ziel.setIgnoreMouseEvents(true); ziel.show(); await warte(90); if (ziel.isDestroyed()) return; const bild = await ziel.webContents.capturePage(); if (bild.isEmpty() || ziel.isDestroyed()) return; const nach = ziel.getBounds(); const box = vereinigung(von, nach); const hilfe = new BrowserWindow({ x: box.x, y: box.y, width: box.width, height: box.height, show: false, frame: false, transparent: true, resizable: false, movable: false, minimizable: false, maximizable: false, fullscreenable: false, focusable: false, skipTaskbar: true, hasShadow: false, alwaysOnTop: true, backgroundColor: '#00000000', title: 'AeroMC', webPreferences: { contextIsolation: true, nodeIntegration: false, sandbox: true }, }); merke(hilfe); hilfe.setIgnoreMouseEvents(true); await hilfe.loadFile(path.join(__dirname, 'aufbau.html')); const ok = await hilfe.webContents.executeJavaScript( `vorbereiten(${JSON.stringify(bild.toDataURL())}, ${JSON.stringify(relativ(nach, box))}, ${JSON.stringify(relativ(von, box))})`); if (!ok || hilfe.isDestroyed()) return; hilfe.showInactive(); await hilfe.webContents.executeJavaScript(`abspielen(${DAUER_MS})`); } /** * Zeigt `ziel` (geladen, aber noch nicht sichtbar) mit Wachs-Animation an. * `von` ist das Rechteck des angeklickten Knopfs in Bildschirmkoordinaten. */ async function wachsen(ziel, von) { let hilfe = null; try { await Promise.race([abspielen(ziel, von, (h) => { hilfe = h; }), warte(HOECHSTENS_MS)]); } catch { // Animation ist nur Zierde – im Fehlerfall das Fenster einfach zeigen } finally { if (!ziel.isDestroyed()) { ziel.setOpacity(1); ziel.setIgnoreMouseEvents(false); if (!ziel.isVisible()) ziel.show(); ziel.focus(); } // Hilfsfenster erst nach dem Umschalten schließen, sonst blitzt der Hintergrund durch setTimeout(() => { if (hilfe && !hilfe.isDestroyed()) hilfe.destroy(); }, 60); } } module.exports = { wachsen };