Skip to content

Configurable UI font size: scale look-and-feel fonts, and the constants that clip - #1902

Closed
jcschaff wants to merge 2 commits into
masterfrom
feat/ui-font-scaling
Closed

Configurable UI font size: scale look-and-feel fonts, and the constants that clip#1902
jcschaff wants to merge 2 commits into
masterfrom
feat/ui-font-scaling

Conversation

@jcschaff

Copy link
Copy Markdown
Member

Groundwork for a user-settable UI font size, plus the first round of layout fallout. Inert at the default scale of 1.0 — nothing changes unless -Dvcell.ui.fontScale is set.

Why this route

-Dsun.java2d.uiScale was evaluated first, since it would have made most of this unnecessary. It won't:

macOS    uiScale=null/1.5/2.0  ->  Label.font 13.0pt, pref 130x16, gcScaleX 2.00 (identical)
Linux    uiScale=null/1.5/2.0/3.0 -> Label.font 12.0pt, pref 141x15, stringWidth 141 (identical)

On macOS the JDK derives scale from the display and ignores the property outright. Where it is honored, it multiplies only the device transform — Swing lays out in logical units, which the flag never touches. That is why it can never clip, and equally why it cannot make text more readable at a fixed window size. It magnifies; it does not enlarge. Worth keeping in mind as a separate, zero-code answer to "VCell is tiny on my 4K monitor".

What this does

VCellLookAndFeel walks the look-and-feel defaults after setLookAndFeel and multiplies every Font, before any window is built — Swing components resolve their font once, at construction. Fonts are written back as FontUIResource, not plain Font: a plain one reads as a user-set override and the L&F would stop managing it.

The scaling also now runs on every platform. The existing 39-key UIManager.put block sits inside if (isMac), so Windows and Linux had no font handling at all. Scaling is applied before that block, so the Mac path derives from it rather than undoing it.

Bad input can't stop the client starting — unparseable or out-of-range values log and fall back to 1.0.

What broke at 1.25x, and why

Measured against a live client via the debug bridge — 93 components matched across two runs, 17 grew wider, 71 kept their width.

Every visible defect was in the left navigation panel: tree labels clipped with no ellipsis (Parameters, Functions, Units, etc. lost its period), counts truncated mid-digit ((538)(53), the database tab strip pushed Pathway Comm out into scroll mode, and a spurious horizontal scrollbar appeared.

None of it came from a font. It came from splitPane.setDividerLocation(270) in DocumentEditor, pinning the panel's width in pixels. The component data is unambiguous: inside that panel LeftBottomTabbedPane, DatabaseWindowPanel and all three tree panels held their exact widths, while ModelDeleteButton (77→88) and ShowWarningsCheckBox (113→138) grew normally elsewhere. GridBag cells size from preferred size and adapt; pinned dividers don't.

Adds VCellLookAndFeel.scaleTextPixels for constants that bound text, applied to the two divider locations and two minimum sizes here. Icon sizes, insets and borders are deliberately out of scope — they should not move with the font.

After the fix at 1.25x: LeftBottomTabbedPane 264 → 332 and BioModelDbTreePanel1 222 → 290, both exactly the requested scale, and all four defects resolved.

What this deliberately does not do

The ~138 sites that construct a Font with a literal point size keep theirs — a plain Font is immune to the L&F. Converting them is the next phase.

Notably, none of those caused a visible defect at 1.25x, because most sit in layouts that adapt. That reorders the work: the pinned pixel constants matter more than the font constants. There are 26 further hard-coded setDividerLocation calls across the client that want the same treatment.

🤖 Generated with Claude Code

jcschaff and others added 2 commits August 11, 2026 10:04
Groundwork for a configurable UI font size. Walks the look-and-feel defaults
after setLookAndFeel and multiplies every Font, before any window is built,
because a Swing component resolves its font once at construction.

Fonts are written back as FontUIResource rather than plain Font: a plain Font
reads as a user-set override, which would stop the look and feel managing it.

This reaches only fonts obtained implicitly from the look and feel. The ~138
sites that construct a Font with a literal point size keep theirs and must be
converted separately - that is the next phase, and this commit is what makes
the cost of it measurable.

The scaling also runs on every platform. The existing 39-key UIManager.put
block is inside `if (isMac)`, so Windows and Linux had no font handling at all;
scaling is applied before that block so the Mac path derives from it rather
than undoing it.

Default 1.0 is a no-op. Unparseable or out-of-range values log and fall back to
1.0 rather than preventing the client from starting.

Measured at 1.25 against a live client (bridge-captured component trees, 93
components matched): 17 grew wider, 71 kept their width. Damage is confined to
fixed-width containers, chiefly the left navigation panel - tree labels clip
without an ellipsis, a database tab is pushed out of the tab strip into scroll
mode, and a horizontal scrollbar appears. Nothing failed to lay out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
At 1.25 the left navigation panel was where every visible defect was: tree
labels clipped without an ellipsis ("Parameters, Functions, Units, etc." lost
its period), counts truncated mid-digit ("(538)" became "(53"), the database
tab strip pushed "Pathway Comm" out into scroll mode, and a horizontal
scrollbar appeared.

None of that came from a font: it came from splitPane.setDividerLocation(270),
which pins the panel's width in pixels. Measured across two live runs, the
components inside it - LeftBottomTabbedPane, DatabaseWindowPanel and the three
tree panels - kept their exact widths while buttons and checkboxes elsewhere
grew normally, because those sit in GridBag cells that size from preferred
size.

Adds VCellLookAndFeel.scaleTextPixels for constants that bound text, and
applies it to the two divider locations and two minimum sizes here. Icon
sizes, insets and borders are deliberately out of scope - they should not move
with the font.

Verified at 1.25: LeftBottomTabbedPane 264 -> 332, BioModelDbTreePanel1
222 -> 290, both exactly the requested scale, and all four defects above are
gone. Inert at the default 1.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jcschaff jcschaff closed this Aug 13, 2026
@jcschaff
jcschaff deleted the feat/ui-font-scaling branch August 13, 2026 03:42
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.

1 participant