fix(bridge): anchored fx-gui embed - dance dat window dung panel rect, khong park/restore cursor, resize view qua WM_FXGUI_RESIZE

This commit is contained in:
2026-08-19 09:25:43 +07:00
parent 346ada6e47
commit c6de0720f4
6 changed files with 153 additions and 6 deletions
+31 -2
View File
@@ -11908,6 +11908,7 @@ const ExportModal = ({ open, onClose, exportSettings, setExportSettings, isExpor
const imgRef = React.useRef(null);
const boxRef = React.useRef(null);
const deadRef = React.useRef(false);
const screenRectRef = React.useRef(null);
const [dead, setDead] = React.useState(false);
const post = (payload) => { try { fetch(url + '/input', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }).catch(() => {}); } catch (e) {} };
React.useEffect(() => {
@@ -11922,6 +11923,34 @@ const ExportModal = ({ open, onClose, exportSettings, setExportSettings, isExpor
return () => { clearInterval(tick); clearInterval(ping); };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url]);
// Embed panel screen rect (physical px) for the bridge's anchored real-input
// dance: Tauri innerPosition + scaleFactor; window.screenX/Y fallback when
// not running under Tauri. Refreshed ~500ms so scroll/resize stays current.
React.useEffect(() => {
let alive = true;
const refresh = () => {
const box = boxRef.current;
if (!box) return;
const r = box.getBoundingClientRect();
if (r.width < 4 || r.height < 4) return;
try {
const tw = window.__TAURI__ && window.__TAURI__.window;
if (tw && tw.getCurrentWindow) {
Promise.all([tw.getCurrentWindow().innerPosition(), tw.getCurrentWindow().scaleFactor()]).then(([pos, sf]) => {
if (!alive || !boxRef.current) return;
const rb = boxRef.current.getBoundingClientRect();
screenRectRef.current = { x: Math.round(pos.x + rb.left * sf), y: Math.round(pos.y + rb.top * sf), w: Math.round(rb.width * sf), h: Math.round(rb.height * sf) };
}).catch(() => {});
} else {
screenRectRef.current = { x: Math.round((window.screenX || 0) + r.left), y: Math.round((window.screenY || 0) + r.top), w: Math.round(r.width), h: Math.round(r.height) };
}
} catch (e) {}
};
refresh();
const iv = setInterval(refresh, 500);
return () => { alive = false; clearInterval(iv); };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url]);
const pt = (e) => {
const box = boxRef.current, img = imgRef.current;
if (!box || !img || !img.naturalWidth || !img.naturalHeight) return null;
@@ -11934,7 +11963,7 @@ const ExportModal = ({ open, onClose, exportSettings, setExportSettings, isExpor
};
const handle = (e) => {
const p = pt(e); if (!p) return;
post({ type: e.type === 'mousedown' ? 'mousedown' : e.type === 'mouseup' ? 'mouseup' : 'mousemove', x: p.x, y: p.y, button: e.button, buttons: e.buttons });
post({ type: e.type === 'mousedown' ? 'mousedown' : e.type === 'mouseup' ? 'mouseup' : 'mousemove', x: p.x, y: p.y, button: e.button, buttons: e.buttons, rect: screenRectRef.current || undefined });
};
const close = () => { try { fetch(url + '/close', { method: 'POST' }).catch(() => {}); } catch (e) {} onClose && onClose(); };
return (
@@ -11949,7 +11978,7 @@ const ExportModal = ({ open, onClose, exportSettings, setExportSettings, isExpor
<div ref={boxRef} tabIndex={0} className="flex-1 relative bg-slate-950 border border-slate-800 rounded-b-lg overflow-hidden outline-none"
onMouseDown={handle} onMouseUp={handle} onMouseMove={handle}
onMouseLeave={() => post({ type: 'mouseup', x: -1, y: -1, button: 0 })}
onWheel={e => { const p = pt(e); if (p) post({ type: 'wheel', x: p.x, y: p.y, deltaY: e.deltaY }); }}
onWheel={e => { const p = pt(e); if (p) post({ type: 'wheel', x: p.x, y: p.y, deltaY: e.deltaY, rect: screenRectRef.current || undefined }); }}
onKeyDown={e => { e.preventDefault(); post({ type: 'keydown', keyCode: e.keyCode || e.which }); }}
onKeyUp={e => { e.preventDefault(); post({ type: 'keyup', keyCode: e.keyCode || e.which }); }}>
<img ref={imgRef} alt="VST GUI" className="w-full h-full object-contain select-none pointer-events-none" draggable={false} />
File diff suppressed because one or more lines are too long