Skip to content

fix(ui): make UI scale work in DAWs (live zoom + window resize)#4

Merged
Hornfisk merged 1 commit into
masterfrom
fix/ui-scale-daw
Jun 5, 2026
Merged

fix(ui): make UI scale work in DAWs (live zoom + window resize)#4
Hornfisk merged 1 commit into
masterfrom
fix/ui-scale-daw

Conversation

@Hornfisk

Copy link
Copy Markdown
Collaborator

Fixes #3.

Problem

The UI 1.5x badge only wrote ui_scale.txt (read solely by the standalone launcher via --dpi-scale). In a DAW nothing read it and Editor::set_scale_factor was never driven from it, so clicking the badge — and resizing the window — did nothing in every host.

Fix

Drive egui content zoom + a matching programmatic window resize from one scale value, every frame:

ctx.set_zoom_factor(scale);
if editor_state.size() != BASE_WINDOW_SIZE * scale {
    editor_state.set_requested_size(...);
}

With baseview's native scale pinned to 1.0 (DAW hosts default to it; the launcher now passes --dpi-scale 1.0), effective ppp == scale: the host window grows to 680×444 × scale physical px while the layout keeps drawing into a fixed 680×444 logical space. Uniform scale, no reflow — knob rows never move relative to each other.

Changes

  • src/ui/editor.rs — per-frame zoom + resize reconcile; honest badge tooltip/log.
  • src/params.rs — open pre-scaled (new BASE_WINDOW_SIZE const) to avoid a first-frame resize flash.
  • tools/niner-launch.sh — pin --dpi-scale 1.0; plugin owns scaling now.
  • Cargo.toml — repoint nih_plug/nih_plug_egui to Hornfisk/nih-plug@8b51e93 (upstream 28b149e + one line exposing EguiState::set_requested_size, private upstream — mirrors the existing Hornfisk/baseview patch pattern).

Verification

  • cargo check clean; cargo test green (7 tests).
  • ⚠️ Needs DAW verification on geek (couldn't test from WSL): open in Reaper, click badge through 1x/1.5x/2x → window + content scale live, layout intact, knobs aligned. Repeat in Bitwig (texture-cache reopen path) and standalone via niner-launch.sh. If a host ignores request_resize, it degrades to opening at the right size (still better than today).

🤖 Generated with Claude Code

The UI-scale badge only wrote `ui_scale.txt`, which is read solely by the
standalone launcher (`niner-launch.sh --dpi-scale`). In a DAW nothing read
it and `Editor::set_scale_factor` was never driven from it, so clicking the
badge was a no-op in every host (not distro/WM-specific). Resizing the
window also did nothing — the editor never participated in host resize.

Drive both egui's content zoom and a matching programmatic window resize
from a single scale value, every frame:

  ctx.set_zoom_factor(scale);
  if editor_state.size() != BASE * scale { editor_state.set_requested_size(..) }

With baseview's native scale pinned to 1.0 (DAW hosts default to it; the
standalone launcher now passes `--dpi-scale 1.0`), effective ppp == scale:
the host window grows to BASE × scale physical pixels while the layout keeps
drawing into a fixed 680×444 logical space. Uniform scale, no reflow — knob
rows never move relative to each other.

- src/ui/editor.rs: per-frame zoom + resize reconcile; honest badge tooltip/log.
- src/params.rs: open pre-scaled (new BASE_WINDOW_SIZE const) to avoid a
  first-frame resize flash.
- tools/niner-launch.sh: pin --dpi-scale 1.0; plugin owns scaling now.
- Cargo.toml: repoint nih_plug/nih_plug_egui to Hornfisk/nih-plug@8b51e93,
  which exposes EguiState::set_requested_size (private upstream).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Hornfisk Hornfisk merged commit 94310db into master Jun 5, 2026
8 checks passed
@Hornfisk Hornfisk deleted the fix/ui-scale-daw branch June 5, 2026 08:36
Hornfisk added a commit that referenced this pull request Jun 5, 2026
The UI-scale badge only wrote `ui_scale.txt`, which is read solely by the
standalone launcher (`niner-launch.sh --dpi-scale`). In a DAW nothing read
it and `Editor::set_scale_factor` was never driven from it, so clicking the
badge was a no-op in every host (not distro/WM-specific). Resizing the
window also did nothing — the editor never participated in host resize.

Drive both egui's content zoom and a matching programmatic window resize
from a single scale value, every frame:

  ctx.set_zoom_factor(scale);
  if editor_state.size() != BASE * scale { editor_state.set_requested_size(..) }

With baseview's native scale pinned to 1.0 (DAW hosts default to it; the
standalone launcher now passes `--dpi-scale 1.0`), effective ppp == scale:
the host window grows to BASE × scale physical pixels while the layout keeps
drawing into a fixed 680×444 logical space. Uniform scale, no reflow — knob
rows never move relative to each other.

- src/ui/editor.rs: per-frame zoom + resize reconcile; honest badge tooltip/log.
- src/params.rs: open pre-scaled (new BASE_WINDOW_SIZE const) to avoid a
  first-frame resize flash.
- tools/niner-launch.sh: pin --dpi-scale 1.0; plugin owns scaling now.
- Cargo.toml: repoint nih_plug/nih_plug_egui to Hornfisk/nih-plug@8b51e93,
  which exposes EguiState::set_requested_size (private upstream).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Hornfisk added a commit that referenced this pull request Jun 5, 2026
⚠️ WORK IN PROGRESS — not release-ready. If you cloned this, the GUI is
mid-rework: the chassis is a placeholder bare plate whose baked NINER logo is
misaligned/clipped. A clean logo-less plate + an isolated code-drawn logo are
pending. Do not tag/release from this commit.

GUI rework — bare-plate strategy:
- assets/chassis.png: replaced the FALLOUT photoreal chassis with a bare
  battered-metal plate. The art carries no knob grid / labels / sockets, so the
  whole faceplate-vs-grid alignment problem is gone — every interactive element
  is code-drawn and grid-locked by construction.
- Re-enable procedural chrome over the bare plate: SHOW_KNOB_LABELS (knob.rs),
  SHOW_SECTION_LABELS + SHOW_CORNER_SCREWS (panels.rs) = true. Header logo
  stays baked for now (SHOW_HEADER_LOGO=false) — KNOWN misalignment, to be
  replaced by an isolated code-drawn logo (inverted-N), pending assets.
- knob.rs: NINER_ALIGN_TEMPLATE=1 dev overlay (magenta knob-grid rings) kept as
  a gated authoring aid.

UI-scale regression fix (PR #4 broke standalone scaling):
- Root cause: PR #4 swapped the working baseview *native* scaling lever for
  ctx.set_zoom_factor(), which upstream egui-baseview (BillyDM @ec70c3f)
  ignores — it tessellates/renders at its own pixels_per_point (the baseview
  scale policy, pinned to 1.0). So at 1.5x the window grew but content stayed
  1x, with per-frame "pixels_per_point changed between text layout and
  tessellation" warnings.
- Fix: restore native scaling.
  * tools/niner-launch.sh: forward --dpi-scale "$SCALE" (from ui_scale.txt)
    again instead of pinning 1.0.
  * params.rs: open the editor at the logical BASE size (no pre-multiply by
    ui_scale) so baseview's ppp does the scaling once.
  * editor.rs: drop the dead set_zoom_factor + set_requested_size reconcile
    block (and the now-unused editor_state_clone). Badge tooltip/log are honest:
    scale persists and applies on plugin reopen.
  1x / 1.5x / 2x all render correctly at launch.
- FOLLOW-UP: truly live in-DAW rescale needs an egui-baseview fork that renders
  at the zoom-aware ppp (egui_ctx.pixels_per_point()). Deferred.

TODO on this branch: regen bare plate without the baked logo + wire the isolated
inverted-N logo as a code-drawn header asset; recolor the small grey labels to
bone-white for legibility on the lower-contrast plate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hornfisk added a commit that referenced this pull request Jun 6, 2026
…4cf59

Replaces the parallel bd4cf59 WIP ('bare-metal faceplate + native scaling') with the iterated, in-app-verified result from this session. (Note: drops bd4cf59's one-line .gitignore add.)

UI scaling (issue #3 cont.): PR #4's egui-zoom broke the standalone (window grew to ~680x scale^2, content splayed). Standalone-only causes: the fork's nih_plug_egui resize emits a logical-points ViewportCommand::InnerSize beside queue.resize, so with zoom_factor=scale the host-less window over-sizes (a DAW host overrides it); and EguiState was pre-scaled by ui_scale, compounding with the launcher --dpi-scale. Fix: crate::IS_STANDALONE (set in run_standalone) — the standalone skips the zoom + set_requested_size path and keeps EguiState at base 680x444, so baseview --dpi-scale is the sole scale; DAW path unchanged. niner-launch passes --dpi-scale <saved>. Bumped to 0.8.0.

GUI (Fallout faceplate): flat dark distressed plate for legibility, with Niner's logo + correctly-spelled labels drawn live (the genai full-faceplates baked wrong labels — ANT/BW — and misaligned sockets). New MasterRow.display_bg glossy LCD panel; per-section glossy knob caps (assets/knob_<section>.png) blitted untinted for true white speculars, falling back to the tinted neutral cap; TEXT_DIM raised + widgets::outlined_text halo on knob labels for legibility; removed the vestigial preset-bar divider.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UI scale control has no effect in DAWs (only standalone)

1 participant