Forum
    • Categories
    • Register
    • Login

    Centred text with setFontWithSpacing drifts left

    Scheduled Pinned Locked Moved Bug Reports
    1 Posts 1 Posters 11 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • dannytaurusD
      dannytaurus
      last edited by dannytaurus

      I noticed my 'centred' knob labels were shifted 1-2px to the left and it turns out that letter spacing adds extra space after the last character, which shifts the whole text left.

      Wider letter spacing = further shift to the left.

      Claude says it expected JUCE behaviour. Expected, maybe, but not cool. 😕

      Notice how the first row (zero spacing) is centred, then the text shifts progressively further left as the spacing increases. The last 2 rows show 2 different fixes that Claude suggested. No idea how robust the fixes are. They're in the snippet at the bottom.

      During this, Claude also found 2 HISE bugs. I'm still unpacking so I can submit bug fixes. Full explanation below the image.

      CleanShot 2026-08-18 at 14.53.45@2x.png

      1. Centred text with setFontWithSpacing drifts left (JUCE behaviour)

      setFontWithSpacing maps to Font::setExtraKerningFactor, and JUCE adds spacing × height after every glyph, including the last one. drawAlignedText(..., "centred") centres the advance box, which therefore has an invisible trailing gap, so the visible glyphs end up spacing × height / 2 px left of centre. Small at typical values (0.075 × 15 px ≈ 0.6 px) but visible on all-caps labels under a knob. Fine, that's how JUCE works, but the obvious fixes both fell over because of 2 and 3.

      2. "Default" ignores the font size

      g.setFont("Default", 30) and g.setFontWithSpacing("Default", 30, x) do not draw at 30 px. MainController::getFontFromString returns globalFont unchanged for "Default" (hi_core/hi_core/MainController.cpp ~line 2035), so the size argument is dropped and you get the global font at its own height (~14 px). No error, no warning. Every other font name goes through Font(typeface).withHeight(fontSize). I'd expect globalFont.withHeight(fontSize) here.

      3. g.getStringWidth doesn't measure the font that was set

      getStringWidth doesn't ask the current Font for its width; it looks up a per-character normalised width table (CustomTypeFace::getStringWidthFloat, MainController.h ~line 2318) for the current font name, and if the name isn't a loadFontAs font it falls back to defaultFont's table – then multiplies by the requested size. So with "Default" you get a different typeface's widths at a size that isn't being drawn. In my test the returned width was ~2.5× the rendered width. Combined with 2, both "shift by half the gap" and "measure and left-align" corrections came out wrong until I switched to a loadFontAs font.

      Suggestion: getStringWidth could just use currentFont.getStringWidthFloat(text) (the Font object is right there in setFontWithSpacing), which would honour size, kerning and the real typeface.

      Repro – snippet below. Six rows: a centred white bar with MMMMM "centred" beneath it at increasing spacing, then the last two rows apply the two corrections. Swap FONT to "Default" to see 2 and 3 (text renders ~14 px regardless of SIZE, +measure row lands far off).

      HiseSnippet 2430.3ocsX8taaibDmJI5ZsZu16.5CvT8kRYSq+cxWbsqQtDG4F2KN1vxWR6EDDrhbo3VSsKA4RKqdHE8MnEnen.8S8wnnesuI2KP6av0Y1kThx1W9iAJMLf3ryL672e6v8jTkOOKSk5TqwYyS3N09w0GMWpi1OhIjNG9XmZ+j5Gwxz7TvR5QySXYY7.mZ0t6ulHTas64Xd9uO3QrXlzmujjiyyUBe9SESE5kTS9huTDGe.KfelXZEtG7EG5qj6qhU4n8b25ccRX9mylveFiX6N0cdBKKxo15060se.eK+A7PVP+9a6u01C3C5ELX6s51cPX+t9L1u79r6O1o1GMLPnUoizLMOCU5iTAyGEolIsavyEYhwwb5kdNivc1R1Y+HQbvIkAmLGmZ26jkgp6ZCU+r5GIBDKnuLj8IlEfkRTMnU6NuMSp2GfIUqhIcOqI8o0G4mJRzKWgrmeT8CkXFLjg4lplhkWm67u9o06zANkmjp1AlzNHkM6gwhIRdvY7K0tsa21CZ5yk5TdPyVPPpHTmAOc3AmAyh3RPGwgPkTCQrrFnlPgRYPLWia5lYXRTHm.tYb8AHSuPniFUPqCPT1YGbogjLeIOUhzOf4iAnVsQcQp6Dp9CDRsBTxCkBMnBAFDlxyhfmb3ng.Z3+dtu9WjQbYcTHy3b.SF.9poIhXNoO3XIGRXRdrGDJtfCopYYsggL+H5m6f5MSEKBfTTeL4jXNT33npMNZgvndI007H5oI5cymNkqSE9vj34IQdnZfLQ.eywbVJ4qrBNlChLXpPJlxhoXIalznnx3a49jgE8vLQfNBBDj0DOGFykblNpMbpZFzkB2PY3saoEkEoxiCfXA5n4I6ZzkIiASHeEUIpwRo91+zeEc67IQnxKnsdl3Ov6zGRtzDuNCEOFS.fdlxDrvHSBZDF8hlGGWpTaFUyvvcJYuBkDXIIwBL1spskIYIvXr2FxkAHxBopEw6cHFAL4bIzTlGLg2DLloFqpLbgZA8FToohIQZX70rbWTVbYUXHVW0ph5lxYY4onBI8Mo8DtdjlxMufhxtsnrRdlwZvZQQL4RSXId1jDVOGp2zpsq9vrcKPQXgp2xIK7RvkeIFA7wZVS9EUowf9ZkZpg0k0qt6qSi6r+z.XCXpJOiS8VbrDAK6KLbfMAgXxLaBokEwLrvOhkF.bLbksKPUqT9GqyXomW3P4kUxlVhwJLUYXuciF6iMg3RsmxNmePJ9xB3B2Ac65AeV2ts1sQCDbF26KXoPhLF1CJEiEDbB0T31DoaPQZ5AnXjPHk1XVvsooRFoOn6Jji3TRrY4drf93I1yAHMc4AGzuK8GYDna+s+8+w+4e9mgixQqYLmPBHrmXEdfR.bgfY9IAr7vLO3YGeFz7w3AE4w5lH5lEDB8xo1buMNpySk1L+jX0XVrUk4RphJ.eIcoNvVcjHfIbEFmM84jbmagtH0g0LTOdYWw+9uA+wdC7.oRWk1nC+5gsL3HWqTrLemALReIHJpOleQTQrYwBInY3YDVbv0CDgg7TLSrNDXMRi42FdDkjW1MZvliUpyQWZFllKZXW5YjexujYfZzQpLpqjkgB1tRHEX997DD+mYvsXiQ7RrXGwE0VTODAcNBXO0FCw.QHAEQ5tDyt.ttcigxI3ZsWpb2lcFYDtySEiSYoy6Pzy5LJGAR3SQejE24goBVbasNDKNZZp2HlZhUGKqPO33mclo0buprTkCJ9WvQ+t6Vdz.0gLmh31SCJyWHlL5PtHdq8zSpo75mm0ZwwByhD3AJknHaVTbTEYDU.ANNGba1DMAoRxwC7VZdmd7KFgzeYi09lRqXGnaarsx.lsCfhU77Fuqxz82x6cxT+2GMs0GHSk.1uUlV.C+lFupZF4oO7QCeZQNydrZ0UOc39m85WXVsWuAHRPAVwIHjn9TUtFqjbCyklvqKBy9MMVijaFJfNRjQ8XE.86ZWAyvOoxhOw.EgGCzwD7aGykSzQ3FsFU65JPV6tKHfe0JKChM1nE5qMVyny4HWBXcit2sfVYQzdFAeo3UsKnTx.c3zxEw2nEvpneyWs+P.QWyV4DNfER3.Ce9vS+ckCaHj9w4AzlnKNutDXxpoxYXFqtzL0.ShhbgcRyUNrifTptYsKLQZo8V3Iqa5dnPCo7QECLY.g7qbTt2Bzjh8mz1DJoYA2cInc6CkSvkBwOL3TTb2WNCSC8gMKS63KdXvcC3y8JH4Aa+pVkl.Mm50GgJLON1NulE0zqXjA6TGB8By4J8wtD5gmwG8J84BC7p1996aN2Zs0Dgl4Nf81aYANVWXJLHKb3UmC.TxhI.NeSABJZw0cYAWPeCUwqKmHAS.sH60jMzTQ80Ffwz+zBiYHujIs10Gk2vhGrH5pmsLxRmQMyy1UrI91qPzUZlmlF+6M3+73LdEWpnaeG6.Y1IeJpyLyosX9rHVbXoSzlPRvwryPmdg+XUvdKifVM2BdfovirUDC4c3SFk786JK99Eq2TT5VTPeAKNGKWI20z3XFzkgyJgC3J0hPAcb6JkKE0H85eiEFaadJV5pFbyx1nlnoV96MrN+OeOJ97.bIXCZYhFA9hGs7xAVmCSW8Fz06pYHxkLeEGNOQNZ1ES.5VoIvNrUqcpNMnGjDmmYRQapHaQO2nGqzQ4SlPVmYbwkeRTwfi2P+P2t19gapU1bH.Y3dWCy8UVYppss69101RfAJE+NT7UEeiUvUnmueweC9e44JXS6yTZ9wRWy4KMdSC3pKEFdiqQCKmphi4o23xzMgj91DzUlOcLO0yVptfQ7K+W85D9n2uqSv2N6dEFseZ8wI7h2OPEGPWS.86qe4CNEC+i+5qN7wLMitOhBZHe3.TZAYN0dL+BgO2d6DqU+w7ry0pDCuSSvYdPMT6GnMq9wk2cAUq5HvstQ8xOnv4RmZ0qQWRz7xeX.HQc9Q+kZ1qOxVcST7JnT9QDDMLE+cFhW+RS9j5GoBxiY5UuCG51sJV.yDqbwIz2Ggeafdd0a+5C3hc59VuXm2WS7SqehP6Gcy13ctAaDyQ++vFKtNrOt9P76P70KMv6U+fe6s8tudGaucfuIGwvy+nZimkOcDlo843tKw5mLpL4NTcp88tkkMi3x.yKeG9TrXO58ZEK1qbQmoL+T0q8s8ezEt8CMTPaRZtPx0peD8NzywzSVMNOUDHdsu+pp5ZB1+1J3mcaEbvsUvstsB942VAu+sUvse2BRWO6Cy0po11FGmiNYnADqVsgR5ndS0py+CyHjtw
      

      This image shows the font set to "Default" which exposes the HISE bugs. The font size is ignored (point 2) and the width measurement is way off because it's measuring a different font size (bug 2).

      CleanShot 2026-08-18 at 15.04.21@2x.png

      HISE dev latest / super.engineering + Claude Fable / Figma + Affinity
      Meat Beats: https://meatbeats.com
      Klippr Video: https://klippr.video

      1 Reply Last reply Reply Quote 2
      • First post
        Last post

      21

      Online

      2.5k

      Users

      13.9k

      Topics

      121.2k

      Posts