diff --git a/Source/Editor/GUI/Row.cs b/Source/Editor/GUI/Row.cs
index c7be48626..9868ab456 100644
--- a/Source/Editor/GUI/Row.cs
+++ b/Source/Editor/GUI/Row.cs
@@ -38,8 +38,9 @@ namespace FlaxEditor.GUI
{
Depth = -1;
- if (Height < Style.Current.FontMedium.Height)
- Height = Style.Current.FontMedium.Height + 4;
+ var mediumHeight = FallbackTextUtils.GetMaxHeight(Style.Current.FontMedium);
+ if (Height < mediumHeight)
+ Height = mediumHeight + 4;
}
///
diff --git a/Source/Engine/Render2D/FallbackFonts.h b/Source/Engine/Render2D/FallbackFonts.h
index 5861354fc..040ca8087 100644
--- a/Source/Engine/Render2D/FallbackFonts.h
+++ b/Source/Engine/Render2D/FallbackFonts.h
@@ -9,36 +9,55 @@ struct TextRange;
class Font;
class FontAsset;
+///
+/// Defines a list of fonts that can be used as a fallback, ordered by priority.
+///
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API FallbackFonts : public ManagedScriptingObject
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(FallbackFonts);
private:
- ///
- /// The list of fallback fonts, ordered by priority.
- /// The first element is reserved for the primary font, fallback fonts starts from the second element.
- ///
Array _fontAssets;
+ // Cache fallback fonts of various sizes
Dictionary*> _cache;
public:
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The fallback font assets.
FallbackFonts(const Array& fonts);
+ ///
+ /// Initializes a new instance of the class, exposed for C#.
+ ///
+ /// The fallback font assets.
+ /// The new instance.
API_FUNCTION() FORCE_INLINE static FallbackFonts* Create(const Array& fonts) {
return New(fonts);
}
+ ///
+ /// Get the parent assets of fallback fonts.
+ ///
+ /// The font assets.
API_PROPERTY() FORCE_INLINE Array& GetFonts() {
return _fontAssets;
}
+ ///
+ /// Set the fallback fonts.
+ ///
+ /// The parent assets of the new fonts.
API_PROPERTY() FORCE_INLINE void SetFonts(const Array& val) {
_fontAssets = val;
}
///
- /// Combine the primary fonts with the fallback fonts to get a font list
+ /// Gets the fallback fonts with the given size.
///
+ /// The size.
+ /// The generated fonts.
API_FUNCTION() FORCE_INLINE Array& GetFontList(float size) {
Array* result;
if (_cache.TryGet(size, result)) {
@@ -61,6 +80,8 @@ public:
/// Gets the index of the fallback font that should be used to render the char
///
/// The char.
+ /// The primary font.
+ /// The number to return if none of the fonts can render.
/// -1 if char can be rendered with primary font, index if it matches a fallback font.
API_FUNCTION() FORCE_INLINE int32 GetCharFallbackIndex(Char c, Font* primaryFont = nullptr, int32 missing = -1) {
if (primaryFont && primaryFont->GetAsset()->ContainsChar(c)) {
@@ -81,6 +102,10 @@ public:
return missing;
}
+ ///
+ /// Checks if every font is properly loaded.
+ ///
+ /// True if every font asset is non-null, otherwise false.
API_FUNCTION() FORCE_INLINE bool Verify() {
for (int32 i = 0; i < _fontAssets.Count(); i++)
{
diff --git a/Source/Engine/Render2D/FallbackTextUtils.cs b/Source/Engine/Render2D/FallbackTextUtils.cs
index b6d8770e2..486a354bf 100644
--- a/Source/Engine/Render2D/FallbackTextUtils.cs
+++ b/Source/Engine/Render2D/FallbackTextUtils.cs
@@ -227,5 +227,42 @@ namespace FlaxEngine
return font.GetCharPosition(text, ref textRange, index, ref layout);
}
}
+
+ ///
+ /// Gets the max font height among the font and all fallback fonts of the same size.
+ ///
+ /// The primary font to use.
+ /// The fallback fonts.
+ /// The max height.
+ public static float GetMaxHeight(Font font, FallbackFonts fallbacks)
+ {
+ float height = font.Height;
+
+ var fallbackFonts = fallbacks.GetFontList(font.Size);
+ foreach (var item in fallbackFonts)
+ {
+ height = Mathf.Max(height, item.Height);
+ }
+
+ return height;
+ }
+
+ ///
+ /// Gets the max font height among the font and all fallback fonts of the same size.
+ ///
+ /// The primary font to use.
+ /// Whether to enable fallback fonts, uses if true.
+ /// The max height.
+ public static float GetMaxHeight(Font font, bool useFallback = true)
+ {
+ if(Fallbacks != null && useFallback)
+ {
+ return GetMaxHeight(font, Fallbacks);
+ }
+ else
+ {
+ return font.Height;
+ }
+ }
}
}
diff --git a/Source/Engine/Render2D/Font.h b/Source/Engine/Render2D/Font.h
index d932888fb..110a8fe70 100644
--- a/Source/Engine/Render2D/Font.h
+++ b/Source/Engine/Render2D/Font.h
@@ -122,7 +122,8 @@ struct TIsPODType
};
///
-/// The font block info generated during text processing.
+/// The font block info generated during text processing.
+/// A block means a range of text that belongs to the same line and can be rendered with the same font.
///
API_STRUCT(NoDefault) struct FontBlockCache
{
@@ -134,7 +135,7 @@ API_STRUCT(NoDefault) struct FontBlockCache
API_FIELD() Float2 Location;
///
- /// The height of the current block
+ /// The size of the current block
///
API_FIELD() Float2 Size;
@@ -183,7 +184,7 @@ API_STRUCT(NoDefault) struct BlockedTextLineCache
API_FIELD() float MaxAscender;
///
- /// The index of the font to render with
+ /// The blocks that belongs to this line
///
API_FIELD() Array Blocks;
};
diff --git a/Source/Engine/Render2D/FontAsset.cpp b/Source/Engine/Render2D/FontAsset.cpp
index 1e94b19b1..ea629367f 100644
--- a/Source/Engine/Render2D/FontAsset.cpp
+++ b/Source/Engine/Render2D/FontAsset.cpp
@@ -199,6 +199,13 @@ bool FontAsset::Save(const StringView& path)
#endif
+
+///
+/// Check if the font contains the glyph of a char
+///
+/// The char to test.
+/// True if the font contains the glyph of the char, otherwise false.
+
bool FontAsset::ContainsChar(Char c) const {
return FT_Get_Char_Index(GetFTFace(), c) > 0;
}
diff --git a/Source/Engine/Render2D/FontAsset.h b/Source/Engine/Render2D/FontAsset.h
index a773a8ad6..f3c909911 100644
--- a/Source/Engine/Render2D/FontAsset.h
+++ b/Source/Engine/Render2D/FontAsset.h
@@ -179,7 +179,7 @@ public:
///
/// The char to test.
/// True if the font contains the glyph of the char, otherwise false.
- API_FUNCTION() FORCE_INLINE bool ContainsChar(Char c) const;
+ API_FUNCTION() bool ContainsChar(Char c) const;
///
/// Invalidates all cached dynamic font atlases using this font. Can be used to reload font characters after changing font asset options.
diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs
index a30d8e603..8d7858af0 100644
--- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs
+++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs
@@ -316,6 +316,7 @@ namespace FlaxEngine.GUI
color = textBlock.Style.ShadowColor;
if (!enabled)
color *= 0.6f;
+ // We don't need font fallbacks for rich text since the font is user-selected
Render2D.DrawText(font, _text, ref textBlock.Range, color, textBlock.Bounds.Location + textBlock.Style.ShadowOffset, textBlock.Style.CustomMaterial);
}
diff --git a/Source/Engine/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs
index 70a153faf..b1861df56 100644
--- a/Source/Engine/UI/GUI/Common/TextBox.cs
+++ b/Source/Engine/UI/GUI/Common/TextBox.cs
@@ -117,7 +117,7 @@ namespace FlaxEngine.GUI
return Float2.Zero;
}
- height = font.Height / DpiScale;
+ height = FallbackTextUtils.GetMaxHeight(font) / DpiScale;
return FallbackTextUtils.GetCharPosition(font, _text, index, ref _layout);
}
@@ -171,7 +171,7 @@ namespace FlaxEngine.GUI
{
var leftEdge = FallbackTextUtils.GetCharPosition(font, _text, SelectionLeft, ref _layout);
var rightEdge = FallbackTextUtils.GetCharPosition(font, _text, SelectionRight, ref _layout);
- float fontHeight = font.Height / DpiScale;
+ float fontHeight = FallbackTextUtils.GetMaxHeight(font) / DpiScale;
// Draw selection background
float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);