Files
FlaxEngine/Source/Engine/Render2D/MultiFont.h
2023-11-30 13:41:45 +08:00

354 lines
14 KiB
C++

#pragma once
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Font.h"
#include "FontAsset.h"
struct TextRange;
class Font;
class FontAsset;
/// <summary>
/// The font block info generated during text processing.
/// </summary>
API_STRUCT(NoDefault) struct MultiFontBlockCache
{
DECLARE_SCRIPTING_TYPE_MINIMAL(MultiFontBlockCache);
/// <summary>
/// The root position of the block (upper left corner), relative to line.
/// </summary>
API_FIELD() Float2 Location;
/// <summary>
/// The height of the current block
/// </summary>
API_FIELD() Float2 Size;
/// <summary>
/// The first character index (from the input text).
/// </summary>
API_FIELD() int32 FirstCharIndex;
/// <summary>
/// The last character index (from the input text), inclusive.
/// </summary>
API_FIELD() int32 LastCharIndex;
/// <summary>
/// The index of the font to render with
/// </summary>
API_FIELD() int32 FontIndex;
};
template<>
struct TIsPODType<MultiFontBlockCache>
{
enum { Value = true };
};
/// <summary>
/// Line of font blocks info generated during text processing.
/// </summary>
API_STRUCT(NoDefault) struct MultiFontLineCache
{
DECLARE_SCRIPTING_TYPE_MINIMAL(MultiFontLineCache);
/// <summary>
/// The root position of the line (upper left corner).
/// </summary>
API_FIELD() Float2 Location;
/// <summary>
/// The line bounds (width and height).
/// </summary>
API_FIELD() Float2 Size;
/// <summary>
/// The maximum ascender of the line.
/// </summary>
API_FIELD() float MaxAscender;
/// <summary>
/// The index of the font to render with
/// </summary>
API_FIELD() Array<MultiFontBlockCache> Blocks;
};
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API MultiFont : public ManagedScriptingObject
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(MultiFont);
private:
Array<Font*> _fonts;
public:
MultiFont(const Array<Font*>& fonts);
API_FUNCTION() FORCE_INLINE static MultiFont* Create(const Array<Font*>& fonts) {
return New<MultiFont>(fonts);
}
API_FUNCTION() FORCE_INLINE static MultiFont* Create(const Array<FontAsset*>& fontAssets, float size) {
Array<Font*> fonts;
fonts.Resize(fontAssets.Count());
for (int32 i = 0; i < fontAssets.Count(); i++)
{
fonts[i] = fontAssets[i]->CreateFont(size);
}
return New<MultiFont>(fonts);
}
API_PROPERTY() FORCE_INLINE Array<Font*>& GetFonts() {
return _fonts;
}
API_PROPERTY() FORCE_INLINE void SetFonts(const Array<Font*>& val) {
_fonts = val;
}
API_PROPERTY() FORCE_INLINE int32 GetMaxHeight() {
int32 maxHeight = 0;
for (int32 i = 0; i < _fonts.Count(); i++)
{
if (_fonts[i]) {
maxHeight = Math::Max(maxHeight, _fonts[i]->GetHeight());
}
}
return maxHeight;
}
API_PROPERTY() FORCE_INLINE int32 GetMaxAscender() {
int32 maxAsc = 0;
for (int32 i = 0; i < _fonts.Count(); i++)
{
if (_fonts[i]) {
maxAsc = Math::Max(maxAsc, _fonts[i]->GetAscender());
}
}
return maxAsc;
}
/// <summary>
/// Processes text to get cached lines for rendering.
/// </summary>
/// <param name="text">The input text.</param>
/// <param name="layout">The layout properties.</param>
/// <param name="outputLines">The output lines list.</param>
void ProcessText(const StringView& text, Array<MultiFontLineCache>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
/// <summary>
/// Processes text to get cached lines for rendering.
/// </summary>
/// <param name="text">The input text.</param>
/// <param name="layout">The layout properties.</param>
/// <returns>The output lines list.</returns>
API_FUNCTION() Array<MultiFontLineCache> ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout)
{
Array<MultiFontLineCache> lines;
ProcessText(text, lines, layout);
return lines;
}
/// <summary>
/// Processes text to get cached lines for rendering.
/// </summary>
/// <param name="text">The input text.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <param name="layout">The layout properties.</param>
/// <returns>The output lines list.</returns>
API_FUNCTION() Array<MultiFontLineCache> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
{
Array<MultiFontLineCache> lines;
ProcessText(textRange.Substring(text), lines, layout);
return lines;
}
/// <summary>
/// Processes text to get cached lines for rendering.
/// </summary>
/// <param name="text">The input text.</param>
/// <returns>The output lines list.</returns>
API_FUNCTION() FORCE_INLINE Array<MultiFontLineCache> ProcessText(const StringView& text)
{
return ProcessText(text, TextLayoutOptions());
}
/// <summary>
/// Processes text to get cached lines for rendering.
/// </summary>
/// <param name="text">The input text.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <returns>The output lines list.</returns>
API_FUNCTION() FORCE_INLINE Array<MultiFontLineCache> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange)
{
return ProcessText(textRange.Substring(text), TextLayoutOptions());
}
/// <summary>
/// Measures minimum size of the rectangle that will be needed to draw given text.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="layout">The layout properties.</param>
/// <returns>The minimum size for that text and fot to render properly.</returns>
API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout);
/// <summary>
/// Measures minimum size of the rectangle that will be needed to draw given text.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <param name="layout">The layout properties.</param>
/// <returns>The minimum size for that text and fot to render properly.</returns>
API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
{
return MeasureText(textRange.Substring(text), layout);
}
/// <summary>
/// Measures minimum size of the rectangle that will be needed to draw given text
/// </summary>.
/// <param name="text">The input text to test.</param>
/// <returns>The minimum size for that text and fot to render properly.</returns>
API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text)
{
return MeasureText(text, TextLayoutOptions());
}
/// <summary>
/// Measures minimum size of the rectangle that will be needed to draw given text
/// </summary>.
/// <param name="text">The input text to test.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <returns>The minimum size for that text and fot to render properly.</returns>
API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange)
{
return MeasureText(textRange.Substring(text), TextLayoutOptions());
}
/// <summary>
/// Calculates hit character index at given location.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <param name="location">The input location to test.</param>
/// <param name="layout">The text layout properties.</param>
/// <returns>The selected character position index (can be equal to text length if location is outside of the layout rectangle).</returns>
API_FUNCTION() int32 HitTestText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout)
{
return HitTestText(textRange.Substring(text), location, layout);
}
/// <summary>
/// Calculates hit character index at given location.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="location">The input location to test.</param>
/// <param name="layout">The text layout properties.</param>
/// <returns>The selected character position index (can be equal to text length if location is outside of the layout rectangle).</returns>
API_FUNCTION() int32 HitTestText(const StringView& text, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout);
/// <summary>
/// Calculates hit character index at given location.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="location">The input location to test.</param>
/// <returns>The selected character position index (can be equal to text length if location is outside of the layout rectangle).</returns>
API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, const Float2& location)
{
return HitTestText(text, location, TextLayoutOptions());
}
/// <summary>
/// Calculates hit character index at given location.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <param name="location">The input location to test.</param>
/// <returns>The selected character position index (can be equal to text length if location is outside of the layout rectangle).</returns>
API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location)
{
return HitTestText(textRange.Substring(text), location, TextLayoutOptions());
}
/// <summary>
/// Calculates character position for given text and character index.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="index">The text position to get coordinates of.</param>
/// <param name="layout">The text layout properties.</param>
/// <returns>The character position (upper left corner which can be used for a caret position).</returns>
API_FUNCTION() Float2 GetCharPosition(const StringView& text, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout);
/// <summary>
/// Calculates character position for given text and character index.
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <param name="index">The text position to get coordinates of.</param>
/// <param name="layout">The text layout properties.</param>
/// <returns>The character position (upper left corner which can be used for a caret position).</returns>
API_FUNCTION() Float2 GetCharPosition(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout)
{
return GetCharPosition(textRange.Substring(text), index, layout);
}
/// <summary>
/// Calculates character position for given text and character index
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="index">The text position to get coordinates of.</param>
/// <returns>The character position (upper left corner which can be used for a caret position).</returns>
API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, int32 index)
{
return GetCharPosition(text, index, TextLayoutOptions());
}
/// <summary>
/// Calculates character position for given text and character index
/// </summary>
/// <param name="text">The input text to test.</param>
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
/// <param name="index">The text position to get coordinates of.</param>
/// <returns>The character position (upper left corner which can be used for a caret position).</returns>
API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index)
{
return GetCharPosition(textRange.Substring(text), index, TextLayoutOptions());
}
/// <summary>
/// Gets the index of the font that should be used to render the char
/// </summary>
/// <param name="fonts">The font list.</param>
/// <param name="c">The char.</param>
/// <param name="missing">Number to return if char cannot be found.</param>
/// <returns></returns>
API_FUNCTION() FORCE_INLINE int32 GetCharFontIndex(Char c, int32 missing = -1) {
int32 fontIndex = 0;
while (fontIndex < _fonts.Count() && _fonts[fontIndex] && !_fonts[fontIndex]->ContainsChar(c))
{
fontIndex++;
}
if (fontIndex == _fonts.Count()) {
return missing;
}
return fontIndex;
}
API_FUNCTION() FORCE_INLINE bool Verify() {
for (int32 i = 0; i < _fonts.Count(); i++)
{
if (!_fonts[i]) {
return false;
}
}
return true;
}
};