From 343b9992e296c2b6ce14a0dabafac31b45620e30 Mon Sep 17 00:00:00 2001 From: Tyler Hoang Date: Thu, 28 May 2026 18:13:06 -0700 Subject: aero: fix 1:1 drag at non-1.0 zoom, scale window text on resize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drag and resize handlers were reading pointer deltas in visual pixels but writing to style.left/width which live in the (zoomed) layout coord space — so dragging at zoom 0.7 lagged 30% behind the cursor. Now divide deltas by window.__uiScale (set by the desktop-fit script). Also: when a window is resized, scale its title bar and body via `zoom` so the text inside grows/shrinks with the window. Baseline is captured on first resize. --- aero.js | 31 +++++++++++++++++++++++-------- index.html | 9 +++++---- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/aero.js b/aero.js index 8a950e9..695331f 100644 --- a/aero.js +++ b/aero.js @@ -69,16 +69,18 @@ function makeDraggable(el, handle) { if (e.target.closest('.no-drag')) return; dragging = true; sx = e.clientX; sy = e.clientY; + const z = window.__uiScale || 1; const r = el.getBoundingClientRect(); const p = el.offsetParent.getBoundingClientRect(); - ox = r.left - p.left; oy = r.top - p.top; + ox = (r.left - p.left) / z; oy = (r.top - p.top) / z; el.style.zIndex = (++window.__zTop || (window.__zTop = 100)); e.preventDefault(); }); window.addEventListener('mousemove', (e) => { if (!dragging) return; - el.style.left = (ox + e.clientX - sx) + 'px'; - el.style.top = (oy + e.clientY - sy) + 'px'; + const z = window.__uiScale || 1; + el.style.left = (ox + (e.clientX - sx) / z) + 'px'; + el.style.top = (oy + (e.clientY - sy) / z) + 'px'; }); window.addEventListener('mouseup', () => { dragging = false; }); } @@ -98,8 +100,12 @@ function makeResizable(el, options = {}) { e.preventDefault(); e.stopPropagation(); mode = m; sx = e.clientX; sy = e.clientY; + const z = window.__uiScale || 1; const r = el.getBoundingClientRect(); - sw = r.width; sh = r.height; + sw = r.width / z; sh = r.height / z; + // Lock the baseline the first time this window is resized — content + // scale is measured against this so text grows/shrinks with the window. + if (el.__baseW == null) { el.__baseW = sw; el.__baseH = sh; } // pin current size as inline so first move doesn't snap el.style.width = sw + 'px'; el.style.height = sh + 'px'; @@ -109,12 +115,21 @@ function makeResizable(el, options = {}) { window.addEventListener('mousemove', onMove); window.addEventListener('mouseup', onUp); } + function applyContentScale(w, h) { + const cs = Math.min(w / el.__baseW, h / el.__baseH); + el.querySelectorAll(':scope > .body, :scope > .browser, :scope > .titlebar') + .forEach(n => { n.style.zoom = cs; }); + } function onMove(e) { if (!mode) return; - const dx = e.clientX - sx; - const dy = e.clientY - sy; - if (mode.includes('e')) el.style.width = Math.max(minW, sw + dx) + 'px'; - if (mode.includes('s')) el.style.height = Math.max(minH, sh + dy) + 'px'; + const z = window.__uiScale || 1; + const dx = (e.clientX - sx) / z; + const dy = (e.clientY - sy) / z; + const w = mode.includes('e') ? Math.max(minW, sw + dx) : parseFloat(el.style.width) || sw; + const h = mode.includes('s') ? Math.max(minH, sh + dy) : parseFloat(el.style.height) || sh; + if (mode.includes('e')) el.style.width = w + 'px'; + if (mode.includes('s')) el.style.height = h + 'px'; + applyContentScale(w, h); } function onUp() { mode = null; diff --git a/index.html b/index.html index 940919e..3e6f6a6 100755 --- a/index.html +++ b/index.html @@ -293,6 +293,7 @@ var s = Math.min(window.innerWidth / BASE_W, window.innerHeight / BASE_H); s = Math.min(1, Math.max(MIN, s)); document.documentElement.style.zoom = s; + window.__uiScale = s; } fit(); window.addEventListener('resize', fit); @@ -545,7 +546,7 @@