Improve rich text layout for lines with different fonts in line to match baseline

This commit is contained in:
Wojciech Figat
2022-08-03 12:58:23 +02:00
parent ad37b8361b
commit 8f895e54cd

View File

@@ -27,6 +27,16 @@ namespace FlaxEngine.GUI
/// </summary>
public Float2 Caret;
/// <summary>
/// Index of the current line start character.
/// </summary>
public int LineStartCharacterIndex;
/// <summary>
/// Index of the current line start text block.
/// </summary>
public int LineStartTextBlockIndex;
/// <summary>
/// Text styles stack (new tags push modified style and pop on tag end).
/// </summary>
@@ -86,6 +96,9 @@ namespace FlaxEngine.GUI
{
Control = this,
Parser = _parser,
Caret = Float2.Zero,
LineStartCharacterIndex = 0,
LineStartTextBlockIndex = 0,
StyleStack = _styleStack,
};
@@ -155,15 +168,19 @@ namespace FlaxEngine.GUI
return;
for (int i = 0; i < lines.Length; i++)
{
if (i != 0)
context.Caret.X = 0;
ref var line = ref lines[i];
textBlock.Range = new TextRange
{
StartIndex = start + line.FirstCharIndex,
EndIndex = start + line.LastCharIndex,
};
textBlock.Bounds = new Rectangle(context.Caret + line.Location, line.Size);
if (i != 0)
{
context.Caret.X = 0;
OnLineAdded(ref context, textBlock.Range.StartIndex - 1);
}
textBlock.Bounds = new Rectangle(context.Caret, line.Size);
textBlock.Bounds.X += line.Location.X;
// Post-processing
PostProcessBlock?.Invoke(ref context, ref textBlock);
@@ -181,8 +198,41 @@ namespace FlaxEngine.GUI
else
{
context.Caret.X = lastLine.Size.X;
context.Caret.Y += lastLine.Location.Y;
}
}
private void OnLineAdded(ref ParsingContext context, int lineEnd)
{
// Calculate size of the line
var textBlocks = Utils.ExtractArrayFromList(_textBlocks);
var lineOrigin = textBlocks[context.LineStartTextBlockIndex].Bounds.Location;
var lineSize = Float2.Zero;
var lineAscender = 0.0f;
for(int i = context.LineStartTextBlockIndex; i < _textBlocks.Count; i++)
{
ref TextBlock textBlock = ref textBlocks[i];
var textBlockSize = textBlock.Bounds.BottomRight - lineOrigin;
var textBlockFont = textBlock.Style.Font.GetFont();
if (textBlockFont)
lineAscender = Mathf.Max(lineAscender, textBlockFont.Ascender);
lineSize = Float2.Max(lineSize, textBlockSize);
}
// Organize text blocks to match the baseline of the line (use ascender)
for(int i = context.LineStartTextBlockIndex; i < _textBlocks.Count; i++)
{
ref TextBlock textBlock = ref textBlocks[i];
var offset = lineSize.Y - textBlock.Bounds.Height;
var textBlockFont = textBlock.Style.Font.GetFont();
if (textBlockFont)
offset = lineAscender - textBlockFont.Ascender;
textBlock.Bounds.Location.Y += offset;
}
// Move to the next line
context.LineStartCharacterIndex = lineEnd + 1;
context.LineStartTextBlockIndex = _textBlocks.Count;
context.Caret.Y += lineSize.Y;
}
}
}