In my app, there are custom LookAndFeel members and I apply them during initialization.
I want to apply the same font to the all Label objects (and I don’t want to write vast amount of label.setFont()s).
I thought I can do it by LookAndFeel::setDefaultSansSerifTypefaceName(), but it does not work for the non-defaulted LookAndFeel(and strange thing is, it works defaulted LookAndFeel).
I’m using JUCE 6.1.0 and XCode 12.4.
I tested on iOS and Mac project, made by Audio App from Projucer.
If I remember properly, in previous version(6.0.0 or lower?), setDefaultSansSerifTypefaceName() apply custom(I specified) font to the all applied components.
Here’s my test code that represents my intention clearer than my bad English
Thanks.
/** Enable/Disable this macro and build.
You will find the characters at the center of the component
is different, which means setDefaultSansSerifTypefaceName()
does not do the same thing whether it's
defaulted LnF or custom LnF.
*/
#define USE_MEMBER_LnF 1
class MainComponent : public juce::AudioAppComponent
{
public:
MainComponent()
{
#if USE_MEMBER_LnF
LnF.setDefaultSansSerifTypefaceName("Hiragino Sans");
getTopLevelComponent()->setLookAndFeel(&LnF);
setLookAndFeel(&LnF);
#else
getLookAndFeel().setDefaultSansSerifTypefaceName("Hiragino Sans");
#endif
addAndMakeVisible(label);
/** This string represents Japanese Characters "アイウエオ".
Mac's defaulted font (maybe Helvetica?) can't draw these characters
and Hiragino Sans can properly.
*/
label.setText(juce::CharPointer_UTF8 ("\xe3\x82\xa2\xe3\x82\xa4\xe3\x82\xa6\xe3\x82\xa8\xe3\x82\xaa"), juce::dontSendNotification);
}
resized()
{
deviceName.setBounds(getLocalBounds().withSizeKeepingCentre(100, 40));
}
//...
private
juce::Label label;
juce::LookAndFeel_V4 LnF;
//...
}
I checked with 5.0.0 and 6.0.0 and saw the same behaviour as with 6.1.2, so I don’t think this is a recent regression. If I trace execution through the font loading process when drawing the label for the first time, I see that Font::getTypefacePtr() ends up calling LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font), where font is the ‘placeholder’ sans serif font.
The best option is probably to create a custom LookAndFeel and to override getLabelFont:
What setDefaultSansSerifTypefaceName() for?
When should I use it?
Why only default LnF’s default sans serif affects Label?
It seems like non-default LnF’s sans serif typeface does not affects Labels and no Components get a callback when it has changed (while default LnF does).
It’s a little weird, isn’t it?
I found there’re still garbled characters in my app, because it uses AudioDeviceSelectorComponent that uses juce::Graphics::drawText() in paintListBoxItem() callback.
I have an iPhone localized in Japanese.
In the input device list, it tried to draw “iPhone マイク”(マイク is Japanese characters that means microphone), but because juce::Graphics that passed in has typeface of Helvetica, it can’t draw texts correctly.
Though I can call getLookAndFeel().setDefaultSansSerifTypefaceName("Hiragino Sans"); at somewhere in my MainComponent, which can solve garbled text problem, but why the juce::Graphics object doesn’t have Hiragino Sans typeface?
I’m sure I attached my custom LnF whose defaultSanSerif is set Hiragino Sans to the AudioDeviceSelectorComponent.
It looks to me like setDefaultSansSerifTypefaceName() is designed to set the ‘default’ font for controls in your app, but it will normally only have an effect when called on the default look and feel. If you wanted to change the default font for all controls in your app, you would do something like LookAndFeel::getDefaultLookAndFeel().setDefaultSansSerifTypefaceName ("Futura");.
The AudioDeviceSelectorComponent draws items using AttributedStrings, passing a Font constructed with a height, but no typeface name:
This call will check whether the typeface name is equal to the placeholder sans-serif name, and load the specified default font in that case.
Note that the font object itself doesn’t keep a record of the Component that created it (it might not be used with a Component at all), so there’s no way of querying a specific Component’s LookAndFeel at the point where the typeface is loaded.
To make the AudioDeviceSelectorComponent paint in the way you’re expecting, we would have to modify the paint implementation to select the font like so:
const auto name = owner.getLookAndFeel().getDefaultSansSerifTypefaceName();
attributedString.setFont ({ name, "Regular", (float) textBounds.getHeight() * 0.6f });
However, this would be a breaking change, and would be inconsistent with other JUCE components, so I think we’re unlikely to make this change.
in any case you probably want to use TextLayout instead of having specific font that support non latin character and reimplement drawLabel to use it so fallback font is automatic.
So, the default LnF is special.
No other LnF can determine ‘default’ font.
If I want to change ‘default’ font, I should get default LnF and set some typeface.
TBH, I feel that’s a little weird behaviour, because non-static method does not affect its correspondance(when it is not a defaulted). But if so, there is no choice but to do so.
I suggest how about adding comment to setDefaultSansSerifTypefaceName()?
Anyway, I will go back to fix my codes!
Thanks again.