Add img tag to rich text box

This commit is contained in:
Wojciech Figat
2022-08-04 12:43:05 +02:00
parent 8d990018b5
commit 3089cc3b59
5 changed files with 109 additions and 27 deletions

View File

@@ -41,6 +41,19 @@ namespace FlaxEngine.GUI
/// Text styles stack (new tags push modified style and pop on tag end).
/// </summary>
public Stack<TextBlockStyle> StyleStack;
/// <summary>
/// Adds the text block to the control
/// </summary>
/// <param name="textBlock">The text block to add.</param>
public void AddTextBlock(ref TextBlock textBlock)
{
// Post-processing
Control.PostProcessBlock?.Invoke(ref this, ref textBlock);
// Add to the text blocks
Control._textBlocks.Add(textBlock);
}
}
/// <summary>
@@ -76,6 +89,7 @@ namespace FlaxEngine.GUI
{ "b", ProcessBold },
{ "i", ProcessItalic },
{ "size", ProcessSize },
{ "img", ProcessImage },
};
private HtmlParser _parser = new HtmlParser();
@@ -184,11 +198,7 @@ namespace FlaxEngine.GUI
textBlock.Bounds = new Rectangle(context.Caret, line.Size);
textBlock.Bounds.X += line.Location.X;
// Post-processing
PostProcessBlock?.Invoke(ref context, ref textBlock);
// Add to the text blocks
_textBlocks.Add(textBlock);
context.AddTextBlock(ref textBlock);
}
// Update the caret location

View File

@@ -47,13 +47,9 @@ namespace FlaxEngine.GUI
if (tag.Attributes.TryGetValue(string.Empty, out var alphaText))
{
if (alphaText.Length == 3 && alphaText[0] == '#')
{
style.Color.A = ((StringUtils.HexDigit(alphaText[1]) << 4) + StringUtils.HexDigit(alphaText[2])) / 255.0f;
}
else if (alphaText.Length > 1 && alphaText[alphaText.Length - 1] == '%')
{
style.Color.A = float.Parse(alphaText.Substring(0, alphaText.Length - 1)) / 100.0f;
}
}
context.StyleStack.Push(style);
}
@@ -93,16 +89,9 @@ namespace FlaxEngine.GUI
style.Font = new FontReference(style.Font);
if (tag.Attributes.TryGetValue(string.Empty, out var fontName))
{
var ids = Content.GetAllAssetsByType(typeof(FontAsset));
foreach (var id in ids)
{
if (Content.GetAssetInfo(id, out var info) && string.Equals(fontName, System.IO.Path.GetFileNameWithoutExtension(info.Path), System.StringComparison.OrdinalIgnoreCase))
{
var font = Content.LoadAsync<FontAsset>(id);
if (font != null)
style.Font.Font = font;
}
}
var font = (FontAsset)FindAsset(fontName, typeof(FontAsset));
if (font)
style.Font.Font = font;
}
if (tag.Attributes.TryGetValue("size", out var sizeText) && int.TryParse(sizeText, out var size))
style.Font.Size = size;
@@ -148,15 +137,80 @@ namespace FlaxEngine.GUI
{
var style = context.StyleStack.Peek();
style.Font = new FontReference(style.Font);
if (tag.Attributes.TryGetValue(string.Empty, out var sizeText))
{
if (int.TryParse(sizeText, out var sizeInt))
style.Font.Size = sizeInt;
if (sizeText.Length > 1 && sizeText[sizeText.Length - 1] == '%')
style.Font.Size = (int)(style.Font.Size * float.Parse(sizeText.Substring(0, sizeText.Length - 1)) / 100.0f);
}
TryParseNumberTag(ref tag, string.Empty, style.Font.Size, out var size);
style.Font.Size = (int)size;
context.StyleStack.Push(style);
}
}
private static void ProcessImage(ref ParsingContext context, ref HtmlTag tag)
{
// Get image brush
IBrush image = null;
if (tag.Attributes.TryGetValue(string.Empty, out var srcText) || tag.Attributes.TryGetValue("src", out srcText))
{
if (!context.Control.Images.TryGetValue(srcText, out image))
{
var tex = (Texture)FindAsset(srcText, typeof(Texture));
if (tex)
image = new TextureBrush(tex);
}
}
if (image == null)
return;
// Create image block
var imageBlock = new TextBlock
{
Range = new TextRange
{
StartIndex = tag.StartPosition,
EndIndex = tag.StartPosition,
},
Style = context.StyleStack.Peek(),
Bounds = new Rectangle(context.Caret, new Float2(64.0f)),
};
imageBlock.Style.BackgroundBrush = image;
// Setup size
var font = imageBlock.Style.Font.GetFont();
if (font)
imageBlock.Bounds.Size = new Float2(font.Height);
imageBlock.Bounds.Size.X *= image.Size.X / image.Size.Y; // Keep aspect ration
TryParseNumberTag(ref tag, "width", imageBlock.Bounds.Width, out var width);
imageBlock.Bounds.Width = width;
TryParseNumberTag(ref tag, "height", imageBlock.Bounds.Height, out var height);
imageBlock.Bounds.Height = height;
TryParseNumberTag(ref tag, "scale", 1.0f, out var scale);
imageBlock.Bounds.Size *= scale;
context.AddTextBlock(ref imageBlock);
context.Caret.X += imageBlock.Bounds.Size.X;
}
private static Asset FindAsset(string name, System.Type type)
{
var ids = Content.GetAllAssetsByType(type);
foreach (var id in ids)
{
if (Content.GetAssetInfo(id, out var info) && string.Equals(name, System.IO.Path.GetFileNameWithoutExtension(info.Path), System.StringComparison.OrdinalIgnoreCase))
{
return Content.LoadAsync(id, type);
}
}
return null;
}
private static void TryParseNumberTag(ref HtmlTag tag, string name, float input, out float output)
{
output = input;
if (tag.Attributes.TryGetValue(name, out var text))
{
if (float.TryParse(text, out var width))
output = width;
if (text.Length > 1 && text[text.Length - 1] == '%')
output = input * float.Parse(text.Substring(0, text.Length - 1)) / 100.0f;
}
}
}
}

View File

@@ -31,6 +31,12 @@ namespace FlaxEngine.GUI
[EditorOrder(30)]
public Dictionary<string, TextBlockStyle> Styles = new Dictionary<string, TextBlockStyle>();
/// <summary>
/// The collection of custom images/sprites that can be inlined in text (named).
/// </summary>
[EditorOrder(40)]
public Dictionary<string, IBrush> Images = new Dictionary<string, IBrush>();
/// <summary>
/// Initializes a new instance of the <see cref="RichTextBox"/> class.
/// </summary>

View File

@@ -267,11 +267,17 @@ namespace FlaxEngine.GUI
}
}
// Draw selection background
// Draw background
for (int i = firstTextBlock; i < endTextBlock; i++)
{
ref TextBlock textBlock = ref textBlocks[i];
// Background
if (textBlock.Style.BackgroundBrush != null)
{
textBlock.Style.BackgroundBrush.Draw(textBlock.Bounds, textBlock.Style.Color);
}
// Pick font
var font = textBlock.Style.Font.GetFont();
if (!font)

View File

@@ -37,6 +37,12 @@ namespace FlaxEngine.GUI
[EditorOrder(40), Tooltip("The text shadow offset from the text location. Set to zero to disable shadow drawing.")]
public Float2 ShadowOffset;
/// <summary>
/// The background brush for the text range.
/// </summary>
[EditorOrder(45), Tooltip("The background brush for the text range.")]
public IBrush BackgroundBrush;
/// <summary>
/// The background brush for the selected text range.
/// </summary>