Add multifont rendering to editor
This commit is contained in:
@@ -39,7 +39,7 @@ namespace FlaxEditor.Content.Create
|
|||||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||||
Offsets = new Margin(0, 0, 0, 40),
|
Offsets = new Margin(0, 0, 0, 40),
|
||||||
Parent = this,
|
Parent = this,
|
||||||
Font = new FontReference(Style.Current.FontTitle)
|
Font = new MultiFontReference(Style.Current.FontTitle)
|
||||||
};
|
};
|
||||||
var infoLabel = new Label
|
var infoLabel = new Label
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace FlaxEditor.Content.Import
|
|||||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||||
Offsets = new Margin(0, 0, 0, 40),
|
Offsets = new Margin(0, 0, 0, 40),
|
||||||
Parent = this,
|
Parent = this,
|
||||||
Font = new FontReference(Style.Current.FontTitle)
|
Font = new MultiFontReference(Style.Current.FontTitle)
|
||||||
};
|
};
|
||||||
var infoLabel = new Label
|
var infoLabel = new Label
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ namespace FlaxEditor.Content
|
|||||||
var textRect = TextRect;
|
var textRect = TextRect;
|
||||||
for (int i = 0; i < ranges.Length; i++)
|
for (int i = 0; i < ranges.Length; i++)
|
||||||
{
|
{
|
||||||
var start = font.First().GetCharPosition(text, ranges[i].StartIndex);
|
var start = font.GetCharPosition(text, ranges[i].StartIndex);
|
||||||
var end = font.First().GetCharPosition(text, ranges[i].EndIndex);
|
var end = font.GetCharPosition(text, ranges[i].EndIndex);
|
||||||
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
|
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
|
||||||
}
|
}
|
||||||
isThisVisible = true;
|
isThisVisible = true;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
// Title
|
// Title
|
||||||
var title = new Label(2, 2, width - 4, 23.0f)
|
var title = new Label(2, 2, width - 4, 23.0f)
|
||||||
{
|
{
|
||||||
Font = new FontReference(FlaxEngine.GUI.Style.Current.FontLarge),
|
Font = new MultiFontReference(FlaxEngine.GUI.Style.Current.FontLarge),
|
||||||
Text = "Ragdoll Options",
|
Text = "Ragdoll Options",
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
|
|
||||||
// Add script button
|
// Add script button
|
||||||
var buttonText = "Add script";
|
var buttonText = "Add script";
|
||||||
var textSize = Style.Current.FontMedium.First().MeasureText(buttonText);
|
var textSize = Style.Current.FontMedium.MeasureText(buttonText);
|
||||||
float addScriptButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4;
|
float addScriptButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4;
|
||||||
var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4;
|
var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4;
|
||||||
_addScriptsButton = new Button
|
_addScriptsButton = new Button
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
// Title
|
// Title
|
||||||
var title = new Label(2, 2, DialogWidth - 4, TitleHeight)
|
var title = new Label(2, 2, DialogWidth - 4, TitleHeight)
|
||||||
{
|
{
|
||||||
Font = new FontReference(style.FontLarge),
|
Font = new MultiFontReference(style.FontLarge),
|
||||||
Text = "Anchor Presets",
|
Text = "Anchor Presets",
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
@@ -247,7 +247,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
// Info
|
// Info
|
||||||
var info = new Label(0, title.Bottom, DialogWidth, InfoHeight)
|
var info = new Label(0, title.Bottom, DialogWidth, InfoHeight)
|
||||||
{
|
{
|
||||||
Font = new FontReference(style.FontSmall.First()),
|
Font = new MultiFontReference(style.FontSmall),
|
||||||
Text = "Shift: also set bounds\nControl: also set pivot",
|
Text = "Shift: also set bounds\nControl: also set pivot",
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
@@ -423,7 +423,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
// Set control type button
|
// Set control type button
|
||||||
var space = layout.Space(20);
|
var space = layout.Space(20);
|
||||||
var buttonText = "Set Type";
|
var buttonText = "Set Type";
|
||||||
var textSize = FlaxEngine.GUI.Style.Current.FontMedium.First().MeasureText(buttonText);
|
var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(buttonText);
|
||||||
float setTypeButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4;
|
float setTypeButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4;
|
||||||
var setTypeButton = new Button
|
var setTypeButton = new Button
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
_linkButton.Clicked += ToggleLink;
|
_linkButton.Clicked += ToggleLink;
|
||||||
ToggleEnabled();
|
ToggleEnabled();
|
||||||
SetLinkStyle();
|
SetLinkStyle();
|
||||||
var textSize = FlaxEngine.GUI.Style.Current.FontMedium.First().MeasureText(LinkedLabel.Text.Value);
|
var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(LinkedLabel.Text.Value);
|
||||||
_linkButton.LocalX += textSize.X + 10;
|
_linkButton.LocalX += textSize.X + 10;
|
||||||
LinkedLabel.SetupContextMenu += (label, menu, editor) =>
|
LinkedLabel.SetupContextMenu += (label, menu, editor) =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -631,7 +631,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
TooltipText = "Edit...",
|
TooltipText = "Edit...",
|
||||||
Parent = _label,
|
Parent = _label,
|
||||||
};
|
};
|
||||||
var textSize = FlaxEngine.GUI.Style.Current.FontMedium.First().MeasureText(buttonText);
|
var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(buttonText);
|
||||||
if (textSize.Y > button.Width)
|
if (textSize.Y > button.Width)
|
||||||
button.Width = textSize.Y + 2;
|
button.Width = textSize.Y + 2;
|
||||||
|
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
public LabelElement Header(string text)
|
public LabelElement Header(string text)
|
||||||
{
|
{
|
||||||
var element = Label(text);
|
var element = Label(text);
|
||||||
element.Label.Font = new FontReference(Style.Current.FontLarge);
|
element.Label.Font = new MultiFontReference(Style.Current.FontLarge);
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
{
|
{
|
||||||
var element = Header(header.Text);
|
var element = Header(header.Text);
|
||||||
if (header.FontSize != -1)
|
if (header.FontSize != -1)
|
||||||
element.Label.Font = new FontReference(element.Label.Font.Font, header.FontSize);
|
element.Label.Font = new MultiFontReference(element.Label.Font, header.FontSize);
|
||||||
if (header.Color != 0)
|
if (header.Color != 0)
|
||||||
element.Label.TextColor = Color.FromRGBA(header.Color);
|
element.Label.TextColor = Color.FromRGBA(header.Color);
|
||||||
return element;
|
return element;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace FlaxEditor
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string PrimaryFont = "Editor/Fonts/Roboto-Regular";
|
public static string PrimaryFont = "Editor/Fonts/Roboto-Regular";
|
||||||
|
|
||||||
public static string CJKFont = "Editor/Fonts/NotoSansSC-Regular";
|
public static string CjkFont = "Editor/Fonts/NotoSansSC-Regular";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Inconsolata Regular font.
|
/// The Inconsolata Regular font.
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace FlaxEditor.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The title font.
|
/// The title font.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Font TitleFont;
|
public MultiFont TitleFont;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The column title text color.
|
/// The column title text color.
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ namespace FlaxEditor.GUI
|
|||||||
/// Gets or sets the font used to draw text.
|
/// Gets or sets the font used to draw text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Style"), EditorOrder(2000)]
|
[EditorDisplay("Style"), EditorOrder(2000)]
|
||||||
public FontReference Font { get; set; }
|
public MultiFontReference Font { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the color of the text.
|
/// Gets or sets the color of the text.
|
||||||
@@ -273,7 +273,7 @@ namespace FlaxEditor.GUI
|
|||||||
MaximumItemsInViewCount = 20;
|
MaximumItemsInViewCount = 20;
|
||||||
|
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
Font = new FontReference(style.FontMedium.First());
|
Font = new MultiFontReference(style.FontMedium);
|
||||||
TextColor = style.Foreground;
|
TextColor = style.Foreground;
|
||||||
BackgroundColor = style.BackgroundNormal;
|
BackgroundColor = style.BackgroundNormal;
|
||||||
BackgroundColorHighlighted = BackgroundColor;
|
BackgroundColorHighlighted = BackgroundColor;
|
||||||
@@ -554,7 +554,7 @@ namespace FlaxEditor.GUI
|
|||||||
var textRect = new Rectangle(margin, 0, clientRect.Width - boxSize - 2.0f * margin, clientRect.Height);
|
var textRect = new Rectangle(margin, 0, clientRect.Width - boxSize - 2.0f * margin, clientRect.Height);
|
||||||
Render2D.PushClip(textRect);
|
Render2D.PushClip(textRect);
|
||||||
var textColor = TextColor;
|
var textColor = TextColor;
|
||||||
Render2D.DrawText(Font.GetFont(), text, textRect, enabled ? textColor : textColor * 0.5f, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, textScale);
|
Render2D.DrawText(Font.GetMultiFont(), text, textRect, enabled ? textColor : textColor * 0.5f, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, textScale);
|
||||||
Render2D.PopClip();
|
Render2D.PopClip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -234,11 +234,11 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
float width = 20;
|
float width = 20;
|
||||||
if (style.FontMedium.First())
|
if (style.FontMedium)
|
||||||
{
|
{
|
||||||
width += style.FontMedium.First().MeasureText(Text).X;
|
width += style.FontMedium.MeasureText(Text).X;
|
||||||
if (!string.IsNullOrEmpty(ShortKeys))
|
if (!string.IsNullOrEmpty(ShortKeys))
|
||||||
width += 40 + style.FontMedium.First().MeasureText(ShortKeys).X;
|
width += 40 + style.FontMedium.MeasureText(ShortKeys).X;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Mathf.Max(width, base.MinimumWidth);
|
return Mathf.Max(width, base.MinimumWidth);
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ namespace FlaxEditor.GUI
|
|||||||
private Color _contentsColor;
|
private Color _contentsColor;
|
||||||
private Color _linesColor;
|
private Color _linesColor;
|
||||||
private Color _labelsColor;
|
private Color _labelsColor;
|
||||||
private Font _labelsFont;
|
private MultiFont _labelsFont;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The keyframe UI points.
|
/// The keyframe UI points.
|
||||||
@@ -437,7 +437,7 @@ namespace FlaxEditor.GUI
|
|||||||
_contentsColor = style.Background.RGBMultiplied(0.7f);
|
_contentsColor = style.Background.RGBMultiplied(0.7f);
|
||||||
_linesColor = style.ForegroundDisabled.RGBMultiplied(0.7f);
|
_linesColor = style.ForegroundDisabled.RGBMultiplied(0.7f);
|
||||||
_labelsColor = style.ForegroundDisabled;
|
_labelsColor = style.ForegroundDisabled;
|
||||||
_labelsFont = style.FontSmall.First();
|
_labelsFont = style.FontSmall;
|
||||||
|
|
||||||
_mainPanel = new Panel(ScrollBars.Both)
|
_mainPanel = new Panel(ScrollBars.Both)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
if (style?.FontMedium != null)
|
if (style?.FontMedium != null)
|
||||||
_titleSize = style.FontMedium.First().MeasureText(_title);
|
_titleSize = style.FontMedium.MeasureText(_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.PerformLayoutBeforeChildren();
|
base.PerformLayoutBeforeChildren();
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ namespace FlaxEditor.GUI
|
|||||||
var font = style.FontSmall;
|
var font = style.FontSmall;
|
||||||
for (int i = 0; i < ranges.Length; i++)
|
for (int i = 0; i < ranges.Length; i++)
|
||||||
{
|
{
|
||||||
var start = font.First().GetCharPosition(Name, ranges[i].StartIndex);
|
var start = font.GetCharPosition(Name, ranges[i].StartIndex);
|
||||||
var end = font.First().GetCharPosition(Name, ranges[i].EndIndex);
|
var end = font.GetCharPosition(Name, ranges[i].EndIndex);
|
||||||
_highlights.Add(new Rectangle(start.X + 2, 0, end.X - start.X, Height));
|
_highlights.Add(new Rectangle(start.X + 2, 0, end.X - start.X, Height));
|
||||||
}
|
}
|
||||||
Visible = true;
|
Visible = true;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace FlaxEditor.GUI
|
|||||||
|
|
||||||
var windowIcon = FlaxEngine.Content.LoadAsyncInternal<Texture>(EditorAssets.WindowIcon);
|
var windowIcon = FlaxEngine.Content.LoadAsyncInternal<Texture>(EditorAssets.WindowIcon);
|
||||||
FontAsset windowIconsFont = FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.WindowIconsFont);
|
FontAsset windowIconsFont = FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.WindowIconsFont);
|
||||||
Font iconFont = windowIconsFont?.CreateFont(9);
|
MultiFont iconFont = new MultiFontReference([windowIconsFont], 9).GetMultiFont();
|
||||||
|
|
||||||
_window = mainWindow.RootWindow.Window;
|
_window = mainWindow.RootWindow.Window;
|
||||||
_window.HitTest += OnHitTest;
|
_window.HitTest += OnHitTest;
|
||||||
@@ -108,7 +108,7 @@ namespace FlaxEditor.GUI
|
|||||||
_closeButton = new Button
|
_closeButton = new Button
|
||||||
{
|
{
|
||||||
Text = ((char)EditorAssets.SegMDL2Icons.ChromeClose).ToString(),
|
Text = ((char)EditorAssets.SegMDL2Icons.ChromeClose).ToString(),
|
||||||
Font = new FontReference(iconFont),
|
Font = new MultiFontReference(iconFont),
|
||||||
BackgroundColor = Color.Transparent,
|
BackgroundColor = Color.Transparent,
|
||||||
BorderColor = Color.Transparent,
|
BorderColor = Color.Transparent,
|
||||||
BorderColorHighlighted = Color.Transparent,
|
BorderColorHighlighted = Color.Transparent,
|
||||||
@@ -124,7 +124,7 @@ namespace FlaxEditor.GUI
|
|||||||
_minimizeButton = new Button
|
_minimizeButton = new Button
|
||||||
{
|
{
|
||||||
Text = ((char)EditorAssets.SegMDL2Icons.ChromeMinimize).ToString(),
|
Text = ((char)EditorAssets.SegMDL2Icons.ChromeMinimize).ToString(),
|
||||||
Font = new FontReference(iconFont),
|
Font = new MultiFontReference(iconFont),
|
||||||
BackgroundColor = Color.Transparent,
|
BackgroundColor = Color.Transparent,
|
||||||
BorderColor = Color.Transparent,
|
BorderColor = Color.Transparent,
|
||||||
BorderColorHighlighted = Color.Transparent,
|
BorderColorHighlighted = Color.Transparent,
|
||||||
@@ -139,7 +139,7 @@ namespace FlaxEditor.GUI
|
|||||||
_maximizeButton = new Button
|
_maximizeButton = new Button
|
||||||
{
|
{
|
||||||
Text = ((char)(_window.IsMaximized ? EditorAssets.SegMDL2Icons.ChromeRestore : EditorAssets.SegMDL2Icons.ChromeMaximize)).ToString(),
|
Text = ((char)(_window.IsMaximized ? EditorAssets.SegMDL2Icons.ChromeRestore : EditorAssets.SegMDL2Icons.ChromeMaximize)).ToString(),
|
||||||
Font = new FontReference(iconFont),
|
Font = new MultiFontReference(iconFont),
|
||||||
BackgroundColor = Color.Transparent,
|
BackgroundColor = Color.Transparent,
|
||||||
BorderColor = Color.Transparent,
|
BorderColor = Color.Transparent,
|
||||||
BorderColorHighlighted = Color.Transparent,
|
BorderColorHighlighted = Color.Transparent,
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ namespace FlaxEditor.GUI
|
|||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
float width = 18;
|
float width = 18;
|
||||||
|
|
||||||
if (style.FontMedium.First())
|
if (style.FontMedium)
|
||||||
width += style.FontMedium.First().MeasureText(Text).X;
|
width += style.FontMedium.MeasureText(Text).X;
|
||||||
|
|
||||||
Width = width;
|
Width = width;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
|
|
||||||
if (style.FontMedium.First())
|
if (style.FontMedium)
|
||||||
{
|
{
|
||||||
Width = style.FontMedium.First().MeasureText(Text).X + 2 * DefaultMargin;
|
Width = style.FontMedium.MeasureText(Text).X + 2 * DefaultMargin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
Depth = -1;
|
Depth = -1;
|
||||||
|
|
||||||
if (Height < Style.Current.FontMedium.First().Height)
|
if (Height < Style.Current.FontMedium.MaxHeight)
|
||||||
Height = Style.Current.FontMedium.First().Height + 4;
|
Height = Style.Current.FontMedium.MaxHeight + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ namespace FlaxEditor.GUI
|
|||||||
Render2D.FillRectangle(rect, column.TitleBackgroundColor);
|
Render2D.FillRectangle(rect, column.TitleBackgroundColor);
|
||||||
|
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var font = column.TitleFont ?? style.FontMedium.First();
|
var font = column.TitleFont ?? style.FontMedium;
|
||||||
Render2D.DrawText(font, column.Title, rect, column.TitleColor, TextAlignment.Center, TextAlignment.Center);
|
Render2D.DrawText(font, column.Title, rect, column.TitleColor, TextAlignment.Center, TextAlignment.Center);
|
||||||
|
|
||||||
if (columnIndex < _columns.Length - 1)
|
if (columnIndex < _columns.Length - 1)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
@@ -36,16 +37,16 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
string labelText;
|
string labelText;
|
||||||
switch (_timeline.TimeShowMode)
|
switch (_timeline.TimeShowMode)
|
||||||
{
|
{
|
||||||
case Timeline.TimeShowModes.Frames:
|
case Timeline.TimeShowModes.Frames:
|
||||||
labelText = _timeline.CurrentFrame.ToString("###0", CultureInfo.InvariantCulture);
|
labelText = _timeline.CurrentFrame.ToString("###0", CultureInfo.InvariantCulture);
|
||||||
break;
|
break;
|
||||||
case Timeline.TimeShowModes.Seconds:
|
case Timeline.TimeShowModes.Seconds:
|
||||||
labelText = _timeline.CurrentTime.ToString("###0.##'s'", CultureInfo.InvariantCulture);
|
labelText = _timeline.CurrentTime.ToString("###0.##'s'", CultureInfo.InvariantCulture);
|
||||||
break;
|
break;
|
||||||
case Timeline.TimeShowModes.Time:
|
case Timeline.TimeShowModes.Time:
|
||||||
labelText = TimeSpan.FromSeconds(_timeline.CurrentTime).ToString("g");
|
labelText = TimeSpan.FromSeconds(_timeline.CurrentTime).ToString("g");
|
||||||
break;
|
break;
|
||||||
default: throw new ArgumentOutOfRangeException();
|
default: throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
var color = (_timeline.IsMovingPositionHandle ? style.ProgressNormal : style.Foreground).AlphaMultiplied(0.6f);
|
var color = (_timeline.IsMovingPositionHandle ? style.ProgressNormal : style.Foreground).AlphaMultiplied(0.6f);
|
||||||
Matrix3x3.RotationZ(Mathf.PiOverTwo, out var m1);
|
Matrix3x3.RotationZ(Mathf.PiOverTwo, out var m1);
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
|||||||
if (_previewValue != null)
|
if (_previewValue != null)
|
||||||
{
|
{
|
||||||
// Based on Track.Draw for track text placement
|
// Based on Track.Draw for track text placement
|
||||||
var left = _xOffset + 16 + Style.Current.FontSmall.First().MeasureText(Title ?? Name).X;
|
var left = _xOffset + 16 + Style.Current.FontSmall.MeasureText(Title ?? Name).X;
|
||||||
if (Icon.IsValid)
|
if (Icon.IsValid)
|
||||||
left += 18;
|
left += 18;
|
||||||
if (IsExpanded)
|
if (IsExpanded)
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ namespace FlaxEditor.GUI
|
|||||||
|
|
||||||
if (hasSprite)
|
if (hasSprite)
|
||||||
width += iconSize;
|
width += iconSize;
|
||||||
if (!string.IsNullOrEmpty(_text) && style.FontMedium.First())
|
if (!string.IsNullOrEmpty(_text) && style.FontMedium)
|
||||||
width += style.FontMedium.First().MeasureText(_text).X + (hasSprite ? DefaultMargin : 0);
|
width += style.FontMedium.MeasureText(_text).X + (hasSprite ? DefaultMargin : 0);
|
||||||
|
|
||||||
Width = width;
|
Width = width;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
/// Gets or sets the font used to render text.
|
/// Gets or sets the font used to render text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Style"), EditorOrder(2000)]
|
[EditorDisplay("Style"), EditorOrder(2000)]
|
||||||
public FontReference TextFont { get; set; }
|
public MultiFontReference TextFont { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the color of the background when tree node is selected.
|
/// Gets or sets the color of the background when tree node is selected.
|
||||||
@@ -318,7 +318,7 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
BackgroundColorSelected = style.BackgroundSelected;
|
BackgroundColorSelected = style.BackgroundSelected;
|
||||||
BackgroundColorHighlighted = style.BackgroundHighlighted;
|
BackgroundColorHighlighted = style.BackgroundHighlighted;
|
||||||
BackgroundColorSelectedUnfocused = style.LightBackground;
|
BackgroundColorSelectedUnfocused = style.LightBackground;
|
||||||
TextFont = new FontReference(style.FontSmall.First());
|
TextFont = new MultiFontReference(style.FontSmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -573,7 +573,7 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
{
|
{
|
||||||
if (_textChanged)
|
if (_textChanged)
|
||||||
{
|
{
|
||||||
var font = TextFont.GetFont();
|
var font = TextFont.GetMultiFont();
|
||||||
if (font)
|
if (font)
|
||||||
{
|
{
|
||||||
_textWidth = font.MeasureText(_text).X;
|
_textWidth = font.MeasureText(_text).X;
|
||||||
@@ -657,7 +657,7 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
Render2D.DrawText(TextFont.GetFont(), _text, textRect, _cachedTextColor, TextAlignment.Near, TextAlignment.Center);
|
Render2D.DrawText(TextFont.GetMultiFont(), _text, textRect, _cachedTextColor, TextAlignment.Near, TextAlignment.Center);
|
||||||
|
|
||||||
// Draw drag and drop effect
|
// Draw drag and drop effect
|
||||||
if (IsDragOver && _tree.DraggedOverNode == this)
|
if (IsDragOver && _tree.DraggedOverNode == this)
|
||||||
|
|||||||
@@ -166,15 +166,13 @@ namespace FlaxEditor.Options
|
|||||||
/// Gets or sets the output log text font.
|
/// Gets or sets the output log text font.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Output Log", "Text Font"), EditorOrder(320), Tooltip("The output log text font.")]
|
[EditorDisplay("Output Log", "Text Font"), EditorOrder(320), Tooltip("The output log text font.")]
|
||||||
public FontReference OutputLogTextFont
|
public MultiFontReference OutputLogTextFont
|
||||||
{
|
{
|
||||||
get => _outputLogFont;
|
get => _outputLogFont;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null || !value.Verify())
|
||||||
_outputLogFont = new FontReference(FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.InconsolataRegularFont), 10);
|
_outputLogFont = new MultiFontReference(ConsoleFonts, 10);
|
||||||
else if (!value.Font)
|
|
||||||
_outputLogFont.Font = FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.InconsolataRegularFont);
|
|
||||||
else
|
else
|
||||||
_outputLogFont = value;
|
_outputLogFont = value;
|
||||||
}
|
}
|
||||||
@@ -236,32 +234,31 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("Cook & Run"), EditorOrder(500)]
|
[EditorDisplay("Cook & Run"), EditorOrder(500)]
|
||||||
public int NumberOfGameClientsToLaunch = 1;
|
public int NumberOfGameClientsToLaunch = 1;
|
||||||
|
|
||||||
private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.PrimaryFont);
|
private static FontAsset[] DefaultFonts =>
|
||||||
private static FontAsset _cjkFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.CJKFont);
|
[FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.PrimaryFont),
|
||||||
private FontReference _titleFont = new FontReference(DefaultFont, 18);
|
FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.CjkFont)];
|
||||||
private FontReference _largeFont = new FontReference(DefaultFont, 14);
|
|
||||||
private FontReference _mediumFont = new FontReference(DefaultFont, 9);
|
private static FontAsset[] ConsoleFonts => [FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.PrimaryFont),
|
||||||
private FontReference _smallFont = new FontReference(DefaultFont, 9);
|
FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.CjkFont)];
|
||||||
private FontReference _outputLogFont = new FontReference(FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.InconsolataRegularFont), 10);
|
|
||||||
|
private MultiFontReference _titleFont = new MultiFontReference(DefaultFonts, 18);
|
||||||
|
private MultiFontReference _largeFont = new MultiFontReference(DefaultFonts, 14);
|
||||||
|
private MultiFontReference _mediumFont = new MultiFontReference(DefaultFonts, 9);
|
||||||
|
private MultiFontReference _smallFont = new MultiFontReference(DefaultFonts, 9);
|
||||||
|
private MultiFontReference _outputLogFont = new MultiFontReference(ConsoleFonts, 10);
|
||||||
|
|
||||||
public FontReference CJKFont
|
|
||||||
{
|
|
||||||
get => new FontReference(_cjkFont, 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the title font for editor UI.
|
/// Gets or sets the title font for editor UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Fonts"), EditorOrder(600), Tooltip("The title font for editor UI.")]
|
[EditorDisplay("Fonts"), EditorOrder(600), Tooltip("The title font for editor UI.")]
|
||||||
public FontReference TitleFont
|
public MultiFontReference TitleFont
|
||||||
{
|
{
|
||||||
get => _titleFont;
|
get => _titleFont;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null || !value.Verify())
|
||||||
_titleFont = new FontReference(DefaultFont, 18);
|
_titleFont = new MultiFontReference(DefaultFonts, 18);
|
||||||
else if (!value.Font)
|
|
||||||
_titleFont.Font = DefaultFont;
|
|
||||||
else
|
else
|
||||||
_titleFont = value;
|
_titleFont = value;
|
||||||
}
|
}
|
||||||
@@ -271,15 +268,13 @@ namespace FlaxEditor.Options
|
|||||||
/// Gets or sets the large font for editor UI.
|
/// Gets or sets the large font for editor UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Fonts"), EditorOrder(610), Tooltip("The large font for editor UI.")]
|
[EditorDisplay("Fonts"), EditorOrder(610), Tooltip("The large font for editor UI.")]
|
||||||
public FontReference LargeFont
|
public MultiFontReference LargeFont
|
||||||
{
|
{
|
||||||
get => _largeFont;
|
get => _largeFont;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null || !value.Verify())
|
||||||
_largeFont = new FontReference(DefaultFont, 14);
|
_largeFont = new MultiFontReference(DefaultFonts, 14);
|
||||||
else if (!value.Font)
|
|
||||||
_largeFont.Font = DefaultFont;
|
|
||||||
else
|
else
|
||||||
_largeFont = value;
|
_largeFont = value;
|
||||||
}
|
}
|
||||||
@@ -289,15 +284,13 @@ namespace FlaxEditor.Options
|
|||||||
/// Gets or sets the medium font for editor UI.
|
/// Gets or sets the medium font for editor UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Fonts"), EditorOrder(620), Tooltip("The medium font for editor UI.")]
|
[EditorDisplay("Fonts"), EditorOrder(620), Tooltip("The medium font for editor UI.")]
|
||||||
public FontReference MediumFont
|
public MultiFontReference MediumFont
|
||||||
{
|
{
|
||||||
get => _mediumFont;
|
get => _mediumFont;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null || !value.Verify())
|
||||||
_mediumFont = new FontReference(DefaultFont, 9);
|
_mediumFont = new MultiFontReference(DefaultFonts, 9);
|
||||||
else if (!value.Font)
|
|
||||||
_mediumFont.Font = DefaultFont;
|
|
||||||
else
|
else
|
||||||
_mediumFont = value;
|
_mediumFont = value;
|
||||||
}
|
}
|
||||||
@@ -307,15 +300,13 @@ namespace FlaxEditor.Options
|
|||||||
/// Gets or sets the small font for editor UI.
|
/// Gets or sets the small font for editor UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Fonts"), EditorOrder(630), Tooltip("The small font for editor UI.")]
|
[EditorDisplay("Fonts"), EditorOrder(630), Tooltip("The small font for editor UI.")]
|
||||||
public FontReference SmallFont
|
public MultiFontReference SmallFont
|
||||||
{
|
{
|
||||||
get => _smallFont;
|
get => _smallFont;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null || !value.Verify())
|
||||||
_smallFont = new FontReference(DefaultFont, 9);
|
_smallFont = new MultiFontReference(DefaultFonts, 9);
|
||||||
else if (!value.Font)
|
|
||||||
_smallFont.Font = DefaultFont;
|
|
||||||
else
|
else
|
||||||
_smallFont = value;
|
_smallFont = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,11 +259,10 @@ namespace FlaxEditor.Options
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
FontTitle = options.Interface.TitleFont.GetFont(),
|
FontTitle = options.Interface.TitleFont.GetMultiFont(),
|
||||||
FontLarge = options.Interface.LargeFont.GetFont(),
|
FontLarge = options.Interface.LargeFont.GetMultiFont(),
|
||||||
FontMedium = new Font[] { options.Interface.MediumFont.GetFont(), options.Interface.CJKFont.GetFont() },
|
FontMedium = options.Interface.MediumFont.GetMultiFont(),
|
||||||
FontSmall = new Font[] { options.Interface.SmallFont.GetFont(), options.Interface.CJKFont.GetFont() },
|
FontSmall = options.Interface.SmallFont.GetMultiFont(),
|
||||||
FontCJK = options.Interface.CJKFont.GetFont(),
|
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
ArrowDown = Editor.Icons.ArrowDown12,
|
ArrowDown = Editor.Icons.ArrowDown12,
|
||||||
@@ -313,10 +312,10 @@ namespace FlaxEditor.Options
|
|||||||
ProgressNormal = new Color(0.03f, 0.65f, 0.12f, 1f),
|
ProgressNormal = new Color(0.03f, 0.65f, 0.12f, 1f),
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
FontTitle = options.Interface.TitleFont.GetFont(),
|
FontTitle = options.Interface.TitleFont.GetMultiFont(),
|
||||||
FontLarge = options.Interface.LargeFont.GetFont(),
|
FontLarge = options.Interface.LargeFont.GetMultiFont(),
|
||||||
FontMedium = new Font[] { options.Interface.MediumFont.GetFont(), options.Interface.CJKFont.GetFont() },
|
FontMedium = options.Interface.MediumFont.GetMultiFont(),
|
||||||
FontSmall = new Font[] { options.Interface.SmallFont.GetFont(), options.Interface.CJKFont.GetFont() },
|
FontSmall = options.Interface.SmallFont.GetMultiFont(),
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
ArrowDown = Editor.Icons.ArrowDown12,
|
ArrowDown = Editor.Icons.ArrowDown12,
|
||||||
|
|||||||
@@ -142,8 +142,8 @@ namespace FlaxEditor.SceneGraph.GUI
|
|||||||
var textRect = TextRect;
|
var textRect = TextRect;
|
||||||
for (int i = 0; i < ranges.Length; i++)
|
for (int i = 0; i < ranges.Length; i++)
|
||||||
{
|
{
|
||||||
var start = font.First().GetCharPosition(text, ranges[i].StartIndex);
|
var start = font.GetCharPosition(text, ranges[i].StartIndex);
|
||||||
var end = font.First().GetCharPosition(text, ranges[i].EndIndex);
|
var end = font.GetCharPosition(text, ranges[i].EndIndex);
|
||||||
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
|
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
|
||||||
}
|
}
|
||||||
isThisVisible = true;
|
isThisVisible = true;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
// Title
|
// Title
|
||||||
var title = new Label(2, 2, width - 4, 23.0f)
|
var title = new Label(2, 2, width - 4, 23.0f)
|
||||||
{
|
{
|
||||||
Font = new FontReference(Style.Current.FontLarge),
|
Font = new MultiFontReference(Style.Current.FontLarge),
|
||||||
Text = transition.SurfaceName,
|
Text = transition.SurfaceName,
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
_debugRelevant = Behavior.GetNodeDebugRelevancy(instance, behavior);
|
_debugRelevant = Behavior.GetNodeDebugRelevancy(instance, behavior);
|
||||||
_debugInfo = Behavior.GetNodeDebugInfo(instance, behavior);
|
_debugInfo = Behavior.GetNodeDebugInfo(instance, behavior);
|
||||||
if (!string.IsNullOrEmpty(_debugInfo))
|
if (!string.IsNullOrEmpty(_debugInfo))
|
||||||
_debugInfoSize = Style.Current.FontSmall.First().MeasureText(_debugInfo);
|
_debugInfoSize = Style.Current.FontSmall.MeasureText(_debugInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1407,7 +1407,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
// Title
|
// Title
|
||||||
var title = new Label(2, 2, width - 4, 23.0f)
|
var title = new Label(2, 2, width - 4, 23.0f)
|
||||||
{
|
{
|
||||||
Font = new FontReference(Style.Current.FontLarge),
|
Font = new MultiFontReference(Style.Current.FontLarge),
|
||||||
Text = "Edit function signature",
|
Text = "Edit function signature",
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace FlaxEditor.Surface
|
|||||||
// Title
|
// Title
|
||||||
var title = new Label(2, 2, width - 4, 23.0f)
|
var title = new Label(2, 2, width - 4, 23.0f)
|
||||||
{
|
{
|
||||||
Font = new FontReference(Style.Current.FontLarge),
|
Font = new MultiFontReference(Style.Current.FontLarge),
|
||||||
Text = "Edit attributes",
|
Text = "Edit attributes",
|
||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Title bar
|
// Title bar
|
||||||
var titleFontReference = new FontReference(Style.Current.FontLarge.Asset, 10);
|
var titleFontReference = new MultiFontReference(Style.Current.FontLarge);
|
||||||
var titleLabel = new Label
|
var titleLabel = new Label
|
||||||
{
|
{
|
||||||
Width = Width * 0.5f - 8f,
|
Width = Width * 0.5f - 8f,
|
||||||
|
|||||||
@@ -200,8 +200,8 @@ namespace FlaxEditor.Surface.ContextMenu
|
|||||||
var font = style.FontSmall;
|
var font = style.FontSmall;
|
||||||
for (int i = 0; i < ranges.Length; i++)
|
for (int i = 0; i < ranges.Length; i++)
|
||||||
{
|
{
|
||||||
var start = font.First().GetCharPosition(_archetype.Title, ranges[i].StartIndex);
|
var start = font.GetCharPosition(_archetype.Title, ranges[i].StartIndex);
|
||||||
var end = font.First().GetCharPosition(_archetype.Title, ranges[i].EndIndex);
|
var end = font.GetCharPosition(_archetype.Title, ranges[i].EndIndex);
|
||||||
_highlights.Add(new Rectangle(start.X + textRect.X, 0, end.X - start.X, Height));
|
_highlights.Add(new Rectangle(start.X + textRect.X, 0, end.X - start.X, Height));
|
||||||
|
|
||||||
if (ranges[i].StartIndex <= 0)
|
if (ranges[i].StartIndex <= 0)
|
||||||
@@ -222,8 +222,8 @@ namespace FlaxEditor.Surface.ContextMenu
|
|||||||
_highlights.Clear();
|
_highlights.Clear();
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var font = style.FontSmall;
|
var font = style.FontSmall;
|
||||||
var start = font.First().GetCharPosition(_archetype.Title, 0);
|
var start = font.GetCharPosition(_archetype.Title, 0);
|
||||||
var end = font.First().GetCharPosition(_archetype.Title, _archetype.Title.Length - 1);
|
var end = font.GetCharPosition(_archetype.Title, _archetype.Title.Length - 1);
|
||||||
_highlights.Add(new Rectangle(start.X + textRect.X, 0, end.X - start.X, Height));
|
_highlights.Add(new Rectangle(start.X + textRect.X, 0, end.X - start.X, Height));
|
||||||
_isFullMatch = true;
|
_isFullMatch = true;
|
||||||
Visible = true;
|
Visible = true;
|
||||||
@@ -237,8 +237,8 @@ namespace FlaxEditor.Surface.ContextMenu
|
|||||||
_highlights.Clear();
|
_highlights.Clear();
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var font = style.FontSmall;
|
var font = style.FontSmall;
|
||||||
var start = font.First().GetCharPosition(_archetype.Title, 0);
|
var start = font.GetCharPosition(_archetype.Title, 0);
|
||||||
var end = font.First().GetCharPosition(_archetype.Title, _archetype.Title.Length - 1);
|
var end = font.GetCharPosition(_archetype.Title, _archetype.Title.Length - 1);
|
||||||
_highlights.Add(new Rectangle(start.X + textRect.X, 0, end.X - start.X, Height));
|
_highlights.Add(new Rectangle(start.X + textRect.X, 0, end.X - start.X, Height));
|
||||||
Visible = true;
|
Visible = true;
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
|||||||
Render2D.DrawText(style.FontSmall, _archetype.Title, textRect, Enabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center);
|
Render2D.DrawText(style.FontSmall, _archetype.Title, textRect, Enabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center);
|
||||||
if (_archetype.SubTitle != null)
|
if (_archetype.SubTitle != null)
|
||||||
{
|
{
|
||||||
var titleLength = style.FontSmall.First().MeasureText(_archetype.Title).X;
|
var titleLength = style.FontSmall.MeasureText(_archetype.Title).X;
|
||||||
var subTitleRect = new Rectangle(textRect.X + titleLength, textRect.Y, textRect.Width - titleLength, textRect.Height);
|
var subTitleRect = new Rectangle(textRect.X + titleLength, textRect.Y, textRect.Width - titleLength, textRect.Height);
|
||||||
Render2D.DrawText(style.FontSmall, _archetype.SubTitle, subTitleRect, style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center);
|
Render2D.DrawText(style.FontSmall, _archetype.SubTitle, subTitleRect, style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1428,7 +1428,7 @@ namespace FlaxEditor.Surface.Elements
|
|||||||
|
|
||||||
if (_defaultValueEditor != null)
|
if (_defaultValueEditor != null)
|
||||||
{
|
{
|
||||||
_defaultValueEditor.Location = new Float2(X + Width + 8 + Style.Current.FontSmall.First().MeasureText(Text).X, Y);
|
_defaultValueEditor.Location = new Float2(X + Width + 8 + Style.Current.FontSmall.MeasureText(Text).X, Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1635,7 +1635,7 @@ namespace FlaxEditor.Surface.Elements
|
|||||||
{
|
{
|
||||||
if (DefaultValueEditors[i].CanUse(this, ref _currentType))
|
if (DefaultValueEditors[i].CanUse(this, ref _currentType))
|
||||||
{
|
{
|
||||||
var bounds = new Rectangle(X + Width + 8 + Style.Current.FontSmall.First().MeasureText(Text).X, Y, 90, Height);
|
var bounds = new Rectangle(X + Width + 8 + Style.Current.FontSmall.MeasureText(Text).X, Y, 90, Height);
|
||||||
_editor = DefaultValueEditors[i];
|
_editor = DefaultValueEditors[i];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ namespace FlaxEditor.Surface
|
|||||||
continue;
|
continue;
|
||||||
if (child is InputBox inputBox)
|
if (child is InputBox inputBox)
|
||||||
{
|
{
|
||||||
var boxWidth = boxLabelFont.First().MeasureText(inputBox.Text).X + 20;
|
var boxWidth = boxLabelFont.MeasureText(inputBox.Text).X + 20;
|
||||||
if (inputBox.DefaultValueEditor != null)
|
if (inputBox.DefaultValueEditor != null)
|
||||||
boxWidth += inputBox.DefaultValueEditor.Width + 4;
|
boxWidth += inputBox.DefaultValueEditor.Width + 4;
|
||||||
leftWidth = Mathf.Max(leftWidth, boxWidth);
|
leftWidth = Mathf.Max(leftWidth, boxWidth);
|
||||||
@@ -208,7 +208,7 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
else if (child is OutputBox outputBox)
|
else if (child is OutputBox outputBox)
|
||||||
{
|
{
|
||||||
rightWidth = Mathf.Max(rightWidth, boxLabelFont.First().MeasureText(outputBox.Text).X + 20);
|
rightWidth = Mathf.Max(rightWidth, boxLabelFont.MeasureText(outputBox.Text).X + 20);
|
||||||
rightHeight = Mathf.Max(rightHeight, outputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderSize + 20.0f);
|
rightHeight = Mathf.Max(rightHeight, outputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderSize + 20.0f);
|
||||||
}
|
}
|
||||||
else if (child is Control control)
|
else if (child is Control control)
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ namespace FlaxEditor.Tools.Foliage
|
|||||||
Parent = _noFoliagePanel,
|
Parent = _noFoliagePanel,
|
||||||
Enabled = false
|
Enabled = false
|
||||||
};
|
};
|
||||||
var textSize = Style.Current.FontMedium.First().MeasureText(buttonText);
|
var textSize = Style.Current.FontMedium.MeasureText(buttonText);
|
||||||
if (_createNewFoliage.Width < textSize.X)
|
if (_createNewFoliage.Width < textSize.X)
|
||||||
{
|
{
|
||||||
_createNewFoliage.LocalX -= (textSize.X - _createNewFoliage.Width) / 2;
|
_createNewFoliage.LocalX -= (textSize.X - _createNewFoliage.Width) / 2;
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ namespace FlaxEditor.Tools.Terrain
|
|||||||
Parent = _noTerrainPanel,
|
Parent = _noTerrainPanel,
|
||||||
Enabled = false
|
Enabled = false
|
||||||
};
|
};
|
||||||
var textSize = Style.Current.FontMedium.First().MeasureText(buttonText);
|
var textSize = Style.Current.FontMedium.MeasureText(buttonText);
|
||||||
if (_createTerrainButton.Width < textSize.X)
|
if (_createTerrainButton.Width < textSize.X)
|
||||||
{
|
{
|
||||||
_createTerrainButton.LocalX -= (textSize.X - _createTerrainButton.Width) / 2;
|
_createTerrainButton.LocalX -= (textSize.X - _createTerrainButton.Width) / 2;
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ namespace FlaxEditor.Tools.Terrain
|
|||||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||||
Offsets = new Margin(0, 0, 0, 40),
|
Offsets = new Margin(0, 0, 0, 40),
|
||||||
Parent = this,
|
Parent = this,
|
||||||
Font = new FontReference(Style.Current.FontTitle)
|
Font = new MultiFontReference(Style.Current.FontTitle)
|
||||||
};
|
};
|
||||||
var infoLabel = new Label
|
var infoLabel = new Label
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -548,9 +548,9 @@ namespace FlaxEditor.Viewport
|
|||||||
#region Camera settings widget
|
#region Camera settings widget
|
||||||
|
|
||||||
var largestText = "Relative Panning";
|
var largestText = "Relative Panning";
|
||||||
var textSize = Style.Current.FontMedium.First().MeasureText(largestText);
|
var textSize = Style.Current.FontMedium.MeasureText(largestText);
|
||||||
var xLocationForExtras = textSize.X + 5;
|
var xLocationForExtras = textSize.X + 5;
|
||||||
var cameraSpeedTextWidth = Style.Current.FontMedium.First().MeasureText("0.00").X;
|
var cameraSpeedTextWidth = Style.Current.FontMedium.MeasureText("0.00").X;
|
||||||
|
|
||||||
// Camera Settings Widget
|
// Camera Settings Widget
|
||||||
_cameraWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
|
_cameraWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
|
||||||
@@ -801,7 +801,7 @@ namespace FlaxEditor.Viewport
|
|||||||
#region View mode widget
|
#region View mode widget
|
||||||
|
|
||||||
largestText = "Brightness";
|
largestText = "Brightness";
|
||||||
textSize = Style.Current.FontMedium.First().MeasureText(largestText);
|
textSize = Style.Current.FontMedium.MeasureText(largestText);
|
||||||
xLocationForExtras = textSize.X + 5;
|
xLocationForExtras = textSize.X + 5;
|
||||||
|
|
||||||
var viewMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperLeft);
|
var viewMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperLeft);
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ namespace FlaxEditor.Viewport.Widgets
|
|||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
|
|
||||||
if (style != null && style.FontMedium.First())
|
if (style != null && style.FontMedium)
|
||||||
Width = CalculateButtonWidth(_forcedTextWidth > 0.0f ? _forcedTextWidth : style.FontMedium.First().MeasureText(_text).X, Icon.IsValid);
|
Width = CalculateButtonWidth(_forcedTextWidth > 0.0f ? _forcedTextWidth : style.FontMedium.MeasureText(_text).X, Icon.IsValid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace FlaxEditor.Windows
|
|||||||
var nameLabel = new Label(icon.Right + 10, icon.Top, 200, 34)
|
var nameLabel = new Label(icon.Right + 10, icon.Top, 200, 34)
|
||||||
{
|
{
|
||||||
Text = "Flax Engine",
|
Text = "Flax Engine",
|
||||||
Font = new FontReference(Style.Current.FontTitle),
|
Font = new MultiFontReference(Style.Current.FontTitle),
|
||||||
HorizontalAlignment = TextAlignment.Near,
|
HorizontalAlignment = TextAlignment.Near,
|
||||||
VerticalAlignment = TextAlignment.Center,
|
VerticalAlignment = TextAlignment.Center,
|
||||||
Parent = this
|
Parent = this
|
||||||
@@ -54,7 +54,7 @@ namespace FlaxEditor.Windows
|
|||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
var buttonText = "Copy version info";
|
var buttonText = "Copy version info";
|
||||||
var fontSize = Style.Current.FontMedium.First().MeasureText(buttonText);
|
var fontSize = Style.Current.FontMedium.MeasureText(buttonText);
|
||||||
var copyVersionButton = new Button(Width - fontSize.X - 8, 6, fontSize.X + 4, 20)
|
var copyVersionButton = new Button(Width - fontSize.X - 8, 6, fontSize.X + 4, 20)
|
||||||
{
|
{
|
||||||
Text = buttonText,
|
Text = buttonText,
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
protected override void OnAssetLinked()
|
protected override void OnAssetLinked()
|
||||||
{
|
{
|
||||||
Asset.WaitForLoaded();
|
Asset.WaitForLoaded();
|
||||||
_textPreview.Font = new FontReference(Asset.CreateFont(30));
|
_textPreview.Font = new MultiFontReference([Asset], 30);
|
||||||
_inputText.Text = string.Format("This is a sample text using font {0}.", Asset.FamilyName);
|
_inputText.Text = string.Format("This is a sample text using font {0}.", Asset.FamilyName);
|
||||||
var options = Asset.Options;
|
var options = Asset.Options;
|
||||||
_proxy.Set(ref options);
|
_proxy.Set(ref options);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace FlaxEditor.Windows
|
|||||||
var textRect = new Rectangle(margin, 0, clientRect.Width - boxSize - 2.0f * margin, clientRect.Height);
|
var textRect = new Rectangle(margin, 0, clientRect.Width - boxSize - 2.0f * margin, clientRect.Height);
|
||||||
Render2D.PushClip(textRect);
|
Render2D.PushClip(textRect);
|
||||||
var textColor = TextColor;
|
var textColor = TextColor;
|
||||||
Render2D.DrawText(Font.GetFont(), "View", textRect, enabled ? textColor : textColor * 0.5f, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, textScale);
|
Render2D.DrawText(Font.GetMultiFont(), "View", textRect, enabled ? textColor : textColor * 0.5f, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, textScale);
|
||||||
Render2D.PopClip();
|
Render2D.PopClip();
|
||||||
|
|
||||||
// Arrow
|
// Arrow
|
||||||
|
|||||||
@@ -470,9 +470,9 @@ namespace FlaxEditor.Windows
|
|||||||
var wasEmpty = _output.TextLength == 0;
|
var wasEmpty = _output.TextLength == 0;
|
||||||
|
|
||||||
// Cache fonts
|
// Cache fonts
|
||||||
_output.DefaultStyle.Font.GetFont();
|
_output.DefaultStyle.Font.GetMultiFont();
|
||||||
_output.WarningStyle.Font.GetFont();
|
_output.WarningStyle.Font.GetMultiFont();
|
||||||
_output.ErrorStyle.Font.GetFont();
|
_output.ErrorStyle.Font.GetMultiFont();
|
||||||
|
|
||||||
// Generate the output log
|
// Generate the output log
|
||||||
Span<Entry> entries = CollectionsMarshal.AsSpan(_entries);
|
Span<Entry> entries = CollectionsMarshal.AsSpan(_entries);
|
||||||
@@ -536,7 +536,7 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
var prevBlockBottom = _textBlocks.Count == 0 ? 0.0f : _textBlocks[_textBlocks.Count - 1].Bounds.Bottom;
|
var prevBlockBottom = _textBlocks.Count == 0 ? 0.0f : _textBlocks[_textBlocks.Count - 1].Bounds.Bottom;
|
||||||
var entryText = _textBuffer.ToString(startIndex, endIndex - startIndex);
|
var entryText = _textBuffer.ToString(startIndex, endIndex - startIndex);
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
continue;
|
continue;
|
||||||
var style = textBlock.Style;
|
var style = textBlock.Style;
|
||||||
@@ -544,46 +544,52 @@ namespace FlaxEditor.Windows
|
|||||||
for (int j = 0; j < lines.Length; j++)
|
for (int j = 0; j < lines.Length; j++)
|
||||||
{
|
{
|
||||||
ref var line = ref lines[j];
|
ref var line = ref lines[j];
|
||||||
textBlock.Range.StartIndex = startIndex + line.FirstCharIndex;
|
for (int k = 0; k < line.Blocks.Length; k++)
|
||||||
textBlock.Range.EndIndex = startIndex + line.LastCharIndex + 1;
|
|
||||||
textBlock.Bounds = new Rectangle(new Float2(0.0f, prevBlockBottom), line.Size);
|
|
||||||
|
|
||||||
if (textBlock.Range.Length > 0)
|
|
||||||
{
|
{
|
||||||
// Parse compilation error/warning
|
ref var block = ref line.Blocks[k];
|
||||||
var regexStart = line.FirstCharIndex;
|
|
||||||
if (j == 0)
|
textBlock.Range.StartIndex = startIndex + block.FirstCharIndex;
|
||||||
regexStart += prefixLength;
|
textBlock.Range.EndIndex = startIndex + block.LastCharIndex + 1;
|
||||||
var regexLength = line.LastCharIndex + 1 - regexStart;
|
textBlock.Bounds = new Rectangle(new Float2(block.Location.X, prevBlockBottom), block.Size);
|
||||||
if (regexLength > 0)
|
|
||||||
|
if (textBlock.Range.Length > 0)
|
||||||
{
|
{
|
||||||
var match = _compileRegex.Match(entryText, regexStart, regexLength);
|
// Parse compilation error/warning
|
||||||
if (match.Success)
|
var regexStart = block.FirstCharIndex;
|
||||||
|
if (j == 0)
|
||||||
|
regexStart += prefixLength;
|
||||||
|
var regexLength = block.LastCharIndex + 1 - regexStart;
|
||||||
|
if (regexLength > 0)
|
||||||
{
|
{
|
||||||
switch (match.Groups["level"].Value)
|
var match = _compileRegex.Match(entryText, regexStart, regexLength);
|
||||||
|
if (match.Success)
|
||||||
{
|
{
|
||||||
case "error":
|
switch (match.Groups["level"].Value)
|
||||||
textBlock.Style = _output.ErrorStyle;
|
{
|
||||||
break;
|
case "error":
|
||||||
case "warning":
|
textBlock.Style = _output.ErrorStyle;
|
||||||
textBlock.Style = _output.WarningStyle;
|
break;
|
||||||
break;
|
case "warning":
|
||||||
|
textBlock.Style = _output.WarningStyle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
textBlock.Tag = new TextBlockTag
|
||||||
|
{
|
||||||
|
Type = TextBlockTag.Types.CodeLocation,
|
||||||
|
Url = match.Groups["path"].Value,
|
||||||
|
Line = int.Parse(match.Groups["line"].Value),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
textBlock.Tag = new TextBlockTag
|
// TODO: parsing hyperlinks with link
|
||||||
{
|
// TODO: parsing file paths with link
|
||||||
Type = TextBlockTag.Types.CodeLocation,
|
|
||||||
Url = match.Groups["path"].Value,
|
|
||||||
Line = int.Parse(match.Groups["line"].Value),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
// TODO: parsing hyperlinks with link
|
|
||||||
// TODO: parsing file paths with link
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_textBlocks.Add(textBlock);
|
||||||
|
textBlock.Style = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
prevBlockBottom += line.Size.Y;
|
prevBlockBottom += line.Size.Y;
|
||||||
_textBlocks.Add(textBlock);
|
|
||||||
textBlock.Style = style;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using FlaxEditor.GUI.Tabs;
|
|||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Json;
|
using FlaxEngine.Json;
|
||||||
|
using FlaxEngine.Utilities;
|
||||||
|
|
||||||
namespace FlaxEditor.Windows
|
namespace FlaxEditor.Windows
|
||||||
{
|
{
|
||||||
@@ -78,7 +79,7 @@ namespace FlaxEditor.Windows
|
|||||||
HorizontalAlignment = TextAlignment.Near,
|
HorizontalAlignment = TextAlignment.Near,
|
||||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||||
Text = desc.Name,
|
Text = desc.Name,
|
||||||
Font = new FontReference(Style.Current.FontLarge),
|
Font = new MultiFontReference(Style.Current.FontLarge),
|
||||||
Parent = this,
|
Parent = this,
|
||||||
Bounds = new Rectangle(tmp1, margin, Width - tmp1 - margin, 28),
|
Bounds = new Rectangle(tmp1, margin, Width - tmp1 - margin, 28),
|
||||||
};
|
};
|
||||||
@@ -119,8 +120,8 @@ namespace FlaxEditor.Windows
|
|||||||
url = desc.HomepageUrl;
|
url = desc.HomepageUrl;
|
||||||
else if (!string.IsNullOrEmpty(desc.RepositoryUrl))
|
else if (!string.IsNullOrEmpty(desc.RepositoryUrl))
|
||||||
url = desc.RepositoryUrl;
|
url = desc.RepositoryUrl;
|
||||||
versionLabel.Font.Font.WaitForLoaded();
|
versionLabel.Font.ForEach(x => x.Font.WaitForLoaded());
|
||||||
var font = versionLabel.Font.GetFont();
|
var font = versionLabel.Font.GetMultiFont();
|
||||||
var authorWidth = font.MeasureText(desc.Author).X + 8;
|
var authorWidth = font.MeasureText(desc.Author).X + 8;
|
||||||
var authorLabel = new ClickableLabel
|
var authorLabel = new ClickableLabel
|
||||||
{
|
{
|
||||||
@@ -391,7 +392,7 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
|
|
||||||
Editor.Log("Plugin project has been cloned.");
|
Editor.Log("Plugin project has been cloned.");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Start git submodule clone
|
// Start git submodule clone
|
||||||
|
|||||||
@@ -85,8 +85,8 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
Render2D.FillRectangle(bounds, color);
|
Render2D.FillRectangle(bounds, color);
|
||||||
Render2D.DrawRectangle(bounds, color * 0.5f);
|
Render2D.DrawRectangle(bounds, color * 0.5f);
|
||||||
|
|
||||||
if (_nameLength < 0 && style.FontMedium.First())
|
if (_nameLength < 0 && style.FontMedium)
|
||||||
_nameLength = style.FontMedium.First().MeasureText(_name).X;
|
_nameLength = style.FontMedium.MeasureText(_name).X;
|
||||||
|
|
||||||
if (_nameLength < bounds.Width + 4)
|
if (_nameLength < bounds.Width + 4)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -273,8 +273,8 @@ namespace FlaxEditor.Windows
|
|||||||
var textRect = item.TextRect;
|
var textRect = item.TextRect;
|
||||||
for (int i = 0; i < ranges.Length; i++)
|
for (int i = 0; i < ranges.Length; i++)
|
||||||
{
|
{
|
||||||
var start = font.First().GetCharPosition(text, ranges[i].StartIndex);
|
var start = font.GetCharPosition(text, ranges[i].StartIndex);
|
||||||
var end = font.First().GetCharPosition(text, ranges[i].EndIndex);
|
var end = font.GetCharPosition(text, ranges[i].EndIndex);
|
||||||
highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
|
highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
|
||||||
}
|
}
|
||||||
item.SetHighlights(highlights);
|
item.SetHighlights(highlights);
|
||||||
|
|||||||
@@ -293,249 +293,6 @@ void Font::ProcessText(const StringView& text, Array<FontLineCache>& outputLines
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::ProcessText(const Array<Font*>& fonts, const StringView& text, Array<MultiFontLineCache>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout)
|
|
||||||
{
|
|
||||||
float cursorX = 0;
|
|
||||||
int32 kerning;
|
|
||||||
MultiFontLineCache tmpLine;
|
|
||||||
MultiFontSegmentCache tmpSegment;
|
|
||||||
FontCharacterEntry entry;
|
|
||||||
FontCharacterEntry previous;
|
|
||||||
int32 textLength = text.Length();
|
|
||||||
float scale = layout.Scale / FontManager::FontScale;
|
|
||||||
float boundsWidth = layout.Bounds.GetWidth();
|
|
||||||
float baseLinesDistanceScale = layout.BaseLinesGapScale * scale;
|
|
||||||
|
|
||||||
tmpSegment.Location = Float2::Zero;
|
|
||||||
tmpSegment.Height = 0;
|
|
||||||
tmpSegment.FirstCharIndex = 0;
|
|
||||||
tmpSegment.LastCharIndex = -1;
|
|
||||||
|
|
||||||
tmpLine.Location = Float2::Zero;
|
|
||||||
tmpLine.Size = Float2::Zero;
|
|
||||||
tmpLine.Segments = Array<MultiFontSegmentCache>();
|
|
||||||
|
|
||||||
if (textLength == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 lastWrapCharIndex = INVALID_INDEX;
|
|
||||||
float lastWrapCharX = 0;
|
|
||||||
bool lastMoveLine = false;
|
|
||||||
// The index of the font used by the current segment
|
|
||||||
int32 currentFontIndex = GetCharFontIndex(fonts, text[0], 0);
|
|
||||||
// The maximum font height of the current line
|
|
||||||
float maxHeight = 0;
|
|
||||||
float maxAscender = 0;
|
|
||||||
|
|
||||||
// Process each character to split text into single lines
|
|
||||||
for (int32 currentIndex = 0; currentIndex < textLength;)
|
|
||||||
{
|
|
||||||
bool moveLine = false;
|
|
||||||
bool moveSegment = false;
|
|
||||||
float xAdvance = 0;
|
|
||||||
int32 nextCharIndex = currentIndex + 1;
|
|
||||||
|
|
||||||
// Submit line and segment if text ends
|
|
||||||
if (nextCharIndex == textLength) {
|
|
||||||
moveLine = moveSegment = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache current character
|
|
||||||
const Char currentChar = text[currentIndex];
|
|
||||||
const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
|
|
||||||
|
|
||||||
// Check if character can wrap words
|
|
||||||
const bool isWrapChar = !StringUtils::IsAlnum(currentChar) || isWhitespace || StringUtils::IsUpper(currentChar) || (currentChar >= 0x3040 && currentChar <= 0x9FFF);
|
|
||||||
if (isWrapChar && currentIndex != 0)
|
|
||||||
{
|
|
||||||
lastWrapCharIndex = currentIndex;
|
|
||||||
lastWrapCharX = cursorX;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 nextFontIndex = currentFontIndex;
|
|
||||||
// Check if it's a newline character
|
|
||||||
if (currentChar == '\n')
|
|
||||||
{
|
|
||||||
// Break line
|
|
||||||
moveLine = moveSegment = true;
|
|
||||||
tmpSegment.LastCharIndex++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get character entry
|
|
||||||
if (nextCharIndex < textLength) {
|
|
||||||
nextFontIndex = GetCharFontIndex(fonts, text[nextCharIndex], currentFontIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get character entry
|
|
||||||
fonts[currentFontIndex]->GetCharacter(currentChar, entry);
|
|
||||||
maxHeight = Math::Max(maxHeight, static_cast<float>(fonts[currentFontIndex]->GetHeight()));
|
|
||||||
maxAscender = Math::Max(maxAscender, static_cast<float>(fonts[currentFontIndex]->GetAscender()));
|
|
||||||
|
|
||||||
// Move segment if the font changes or text ends
|
|
||||||
if (nextFontIndex != currentFontIndex || nextCharIndex == textLength) {
|
|
||||||
moveSegment = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get kerning, only when the font hasn't changed
|
|
||||||
if (!isWhitespace && previous.IsValid && !moveSegment)
|
|
||||||
{
|
|
||||||
kerning = fonts[currentFontIndex]->GetKerning(previous.Character, entry.Character);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
kerning = 0;
|
|
||||||
}
|
|
||||||
previous = entry;
|
|
||||||
xAdvance = (kerning + entry.AdvanceX) * scale;
|
|
||||||
|
|
||||||
// Check if character fits the line or skip wrapping
|
|
||||||
if (cursorX + xAdvance <= boundsWidth || layout.TextWrapping == TextWrapping::NoWrap)
|
|
||||||
{
|
|
||||||
// Move character
|
|
||||||
cursorX += xAdvance;
|
|
||||||
tmpSegment.LastCharIndex++;
|
|
||||||
}
|
|
||||||
else if (layout.TextWrapping == TextWrapping::WrapWords)
|
|
||||||
{
|
|
||||||
if (lastWrapCharIndex != INVALID_INDEX)
|
|
||||||
{
|
|
||||||
// Skip moving twice for the same character
|
|
||||||
int32 lastLineLastCharIndex = outputLines.HasItems() && outputLines.Last().Segments.HasItems() ? outputLines.Last().Segments.Last().LastCharIndex : -10000;
|
|
||||||
if (lastLineLastCharIndex == lastWrapCharIndex || lastLineLastCharIndex == lastWrapCharIndex - 1 || lastLineLastCharIndex == lastWrapCharIndex - 2)
|
|
||||||
{
|
|
||||||
currentIndex = nextCharIndex;
|
|
||||||
lastMoveLine = moveLine;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move line
|
|
||||||
const Char wrapChar = text[lastWrapCharIndex];
|
|
||||||
moveLine = true;
|
|
||||||
moveSegment = tmpSegment.FirstCharIndex < lastWrapCharIndex;
|
|
||||||
|
|
||||||
cursorX = lastWrapCharX;
|
|
||||||
if (StringUtils::IsWhitespace(wrapChar))
|
|
||||||
{
|
|
||||||
// Skip whitespaces
|
|
||||||
tmpSegment.LastCharIndex = lastWrapCharIndex - 1;
|
|
||||||
nextCharIndex = currentIndex = lastWrapCharIndex + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmpSegment.LastCharIndex = lastWrapCharIndex - 1;
|
|
||||||
nextCharIndex = currentIndex = lastWrapCharIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (layout.TextWrapping == TextWrapping::WrapChars)
|
|
||||||
{
|
|
||||||
// Move line
|
|
||||||
moveLine = true;
|
|
||||||
moveSegment = tmpSegment.FirstCharIndex < currentChar;
|
|
||||||
nextCharIndex = currentIndex;
|
|
||||||
|
|
||||||
// Skip moving twice for the same character
|
|
||||||
if (lastMoveLine)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moveSegment) {
|
|
||||||
// Add segment
|
|
||||||
tmpSegment.Height = baseLinesDistanceScale * fonts[currentFontIndex]->GetHeight();
|
|
||||||
tmpSegment.LastCharIndex = Math::Max(tmpSegment.LastCharIndex, tmpSegment.FirstCharIndex);
|
|
||||||
tmpSegment.FontIndex = currentFontIndex;
|
|
||||||
tmpLine.Segments.Add(tmpSegment);
|
|
||||||
|
|
||||||
// Reset segment
|
|
||||||
tmpSegment.Location.X = cursorX;
|
|
||||||
tmpSegment.FirstCharIndex = nextCharIndex;
|
|
||||||
tmpSegment.LastCharIndex = nextCharIndex - 1;
|
|
||||||
|
|
||||||
currentFontIndex = nextFontIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if move to another line
|
|
||||||
if (moveLine)
|
|
||||||
{
|
|
||||||
// Add line
|
|
||||||
tmpLine.Size.X = cursorX;
|
|
||||||
tmpLine.Size.Y = baseLinesDistanceScale * maxHeight;
|
|
||||||
tmpLine.MaxAscender = maxAscender;
|
|
||||||
outputLines.Add(tmpLine);
|
|
||||||
|
|
||||||
// Reset line
|
|
||||||
tmpLine.Segments.Clear();
|
|
||||||
tmpLine.Location.Y += baseLinesDistanceScale * maxHeight;
|
|
||||||
cursorX = 0;
|
|
||||||
tmpSegment.Location.X = cursorX;
|
|
||||||
lastWrapCharIndex = INVALID_INDEX;
|
|
||||||
lastWrapCharX = 0;
|
|
||||||
previous.IsValid = false;
|
|
||||||
|
|
||||||
// Reset max font height
|
|
||||||
maxHeight = 0;
|
|
||||||
maxAscender = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentIndex = nextCharIndex;
|
|
||||||
lastMoveLine = moveLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if an additional line should be created
|
|
||||||
if (text[textLength - 1] == '\n')
|
|
||||||
{
|
|
||||||
// Add line
|
|
||||||
tmpLine.Size.X = cursorX;
|
|
||||||
tmpLine.Size.Y = baseLinesDistanceScale * maxHeight;
|
|
||||||
outputLines.Add(tmpLine);
|
|
||||||
|
|
||||||
tmpLine.Location.Y += baseLinesDistanceScale * maxHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check amount of lines
|
|
||||||
if (outputLines.IsEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
float totalHeight = tmpLine.Location.Y;
|
|
||||||
|
|
||||||
Float2 offset = Float2::Zero;
|
|
||||||
if (layout.VerticalAlignment == TextAlignment::Center)
|
|
||||||
{
|
|
||||||
offset.Y += (layout.Bounds.GetHeight() - totalHeight) * 0.5f;
|
|
||||||
}
|
|
||||||
else if (layout.VerticalAlignment == TextAlignment::Far)
|
|
||||||
{
|
|
||||||
offset.Y += layout.Bounds.GetHeight() - totalHeight;
|
|
||||||
}
|
|
||||||
for (int32 i = 0; i < outputLines.Count(); i++)
|
|
||||||
{
|
|
||||||
MultiFontLineCache& line = outputLines[i];
|
|
||||||
Float2 rootPos = line.Location + offset;
|
|
||||||
|
|
||||||
// Fix upper left line corner to match desire text alignment
|
|
||||||
if (layout.HorizontalAlignment == TextAlignment::Center)
|
|
||||||
{
|
|
||||||
rootPos.X += (layout.Bounds.GetWidth() - line.Size.X) * 0.5f;
|
|
||||||
}
|
|
||||||
else if (layout.HorizontalAlignment == TextAlignment::Far)
|
|
||||||
{
|
|
||||||
rootPos.X += layout.Bounds.GetWidth() - line.Size.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
line.Location = rootPos;
|
|
||||||
|
|
||||||
// Align all segments to center in case they have different heights
|
|
||||||
for (int32 j = 0; j < line.Segments.Count(); j++)
|
|
||||||
{
|
|
||||||
MultiFontSegmentCache& segment = line.Segments[j];
|
|
||||||
segment.Location.Y += (line.MaxAscender - fonts[segment.FontIndex]->GetAscender()) / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Float2 Font::MeasureText(const StringView& text, const TextLayoutOptions& layout)
|
Float2 Font::MeasureText(const StringView& text, const TextLayoutOptions& layout)
|
||||||
{
|
{
|
||||||
// Check if there is no need to do anything
|
// Check if there is no need to do anything
|
||||||
@@ -643,7 +400,7 @@ Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayo
|
|||||||
ASSERT(lines.HasItems());
|
ASSERT(lines.HasItems());
|
||||||
float scale = layout.Scale / FontManager::FontScale;
|
float scale = layout.Scale / FontManager::FontScale;
|
||||||
float baseLinesDistance = static_cast<float>(_height) * layout.BaseLinesGapScale * scale;
|
float baseLinesDistance = static_cast<float>(_height) * layout.BaseLinesGapScale * scale;
|
||||||
Float2 rootOffset = layout.Bounds.Location + lines.First().Location;
|
Float2 rootOffset = layout.Bounds.Location;
|
||||||
|
|
||||||
// Find line with that position
|
// Find line with that position
|
||||||
FontCharacterEntry previous;
|
FontCharacterEntry previous;
|
||||||
@@ -682,10 +439,10 @@ Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Position after last character in the last line
|
// Position after last character in the last line
|
||||||
return rootOffset + Float2(lines.Last().Size.X, static_cast<float>((lines.Count() - 1) * baseLinesDistance));
|
return rootOffset + Float2(lines.Last().Location.X + lines.Last().Size.X, static_cast<float>((lines.Count() - 1) * baseLinesDistance));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Font::ContainsChar(Char c)
|
bool Font::ContainsChar(Char c) const
|
||||||
{
|
{
|
||||||
return FT_Get_Char_Index(GetAsset()->GetFTFace(), c) > 0;
|
return FT_Get_Char_Index(GetAsset()->GetFTFace(), c) > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "Engine/Content/AssetReference.h"
|
#include "Engine/Content/AssetReference.h"
|
||||||
#include "Engine/Scripting/ScriptingObject.h"
|
#include "Engine/Scripting/ScriptingObject.h"
|
||||||
#include "TextLayoutOptions.h"
|
#include "TextLayoutOptions.h"
|
||||||
#include "MultiFont.h"
|
|
||||||
|
|
||||||
class FontAsset;
|
class FontAsset;
|
||||||
struct FontTextureAtlasSlot;
|
struct FontTextureAtlasSlot;
|
||||||
@@ -341,15 +340,6 @@ public:
|
|||||||
/// <param name="outputLines">The output lines list.</param>
|
/// <param name="outputLines">The output lines list.</param>
|
||||||
void ProcessText(const StringView& text, Array<FontLineCache>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
|
void ProcessText(const StringView& text, Array<FontLineCache>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Processes text to get cached lines for rendering.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fonts">The font list.</param>
|
|
||||||
/// <param name="text">The input text.</param>
|
|
||||||
/// <param name="layout">The layout properties.</param>
|
|
||||||
/// <param name="outputLines">The output lines list.</param>
|
|
||||||
static void ProcessText(const Array<Font*>& fonts, const StringView& text, Array<MultiFontLineCache>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes text to get cached lines for rendering.
|
/// Processes text to get cached lines for rendering.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -406,17 +396,6 @@ public:
|
|||||||
/// <returns>The minimum size for that text and fot to render properly.</returns>
|
/// <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);
|
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="fonts">The fonts to render with.</param>
|
|
||||||
/// <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() static Float2 MeasureText(const Array<Font*>& fonts, const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Measures minimum size of the rectangle that will be needed to draw given text.
|
/// Measures minimum size of the rectangle that will be needed to draw given text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -504,18 +483,6 @@ public:
|
|||||||
/// <returns>The character position (upper left corner which can be used for a caret position).</returns>
|
/// <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);
|
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="fonts">The fonts to use.</param>
|
|
||||||
/// <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() static Float2 GetCharPosition(const Array<Font*>& fonts, const StringView& text, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates character position for given text and character index.
|
/// Calculates character position for given text and character index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -557,28 +524,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="c">The char to test.</param>
|
/// <param name="c">The char to test.</param>
|
||||||
/// <returns>True if the font contains the glyph of the char, otherwise false.</returns>
|
/// <returns>True if the font contains the glyph of the char, otherwise false.</returns>
|
||||||
API_FUNCTION() FORCE_INLINE bool ContainsChar(Char c);
|
API_FUNCTION() FORCE_INLINE bool ContainsChar(Char c) const;
|
||||||
|
|
||||||
/// <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 static int32 GetCharFontIndex(const Array<Font*>& fonts, Char c, int32 missing = -1) {
|
|
||||||
int32 fontIndex = 0;
|
|
||||||
while (fontIndex < fonts.Count() && !fonts[fontIndex]->ContainsChar(c))
|
|
||||||
{
|
|
||||||
fontIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fontIndex == fonts.Count()) {
|
|
||||||
return missing;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fontIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flushes the size of the face with the Free Type library backend.
|
/// Flushes the size of the face with the Free Type library backend.
|
||||||
|
|||||||
@@ -1 +1,431 @@
|
|||||||
#include "MultiFont.h"
|
#include "MultiFont.h"
|
||||||
|
#include "FontManager.h"
|
||||||
|
#include "Engine/Core/Math/Math.h"
|
||||||
|
|
||||||
|
MultiFont::MultiFont(const Array<Font*>& fonts)
|
||||||
|
: ManagedScriptingObject(SpawnParams(Guid::New(), Font::TypeInitializer)),
|
||||||
|
_fonts(fonts)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiFont::ProcessText(const StringView& text, Array<MultiFontLineCache>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout)
|
||||||
|
{
|
||||||
|
float cursorX = 0;
|
||||||
|
int32 kerning;
|
||||||
|
MultiFontLineCache tmpLine;
|
||||||
|
MultiFontBlockCache tmpBlock;
|
||||||
|
FontCharacterEntry entry;
|
||||||
|
FontCharacterEntry previous;
|
||||||
|
int32 textLength = text.Length();
|
||||||
|
float scale = layout.Scale / FontManager::FontScale;
|
||||||
|
float boundsWidth = layout.Bounds.GetWidth();
|
||||||
|
float baseLinesDistanceScale = layout.BaseLinesGapScale * scale;
|
||||||
|
|
||||||
|
tmpBlock.Location = Float2::Zero;
|
||||||
|
tmpBlock.Size = Float2::Zero;
|
||||||
|
tmpBlock.FirstCharIndex = 0;
|
||||||
|
tmpBlock.LastCharIndex = -1;
|
||||||
|
|
||||||
|
tmpLine.Location = Float2::Zero;
|
||||||
|
tmpLine.Size = Float2::Zero;
|
||||||
|
tmpLine.Blocks = Array<MultiFontBlockCache>();
|
||||||
|
|
||||||
|
if (textLength == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 lastWrapCharIndex = INVALID_INDEX;
|
||||||
|
float lastWrapCharX = 0;
|
||||||
|
bool lastMoveLine = false;
|
||||||
|
// The index of the font used by the current block
|
||||||
|
int32 currentFontIndex = GetCharFontIndex(text[0], 0);
|
||||||
|
// The maximum font height of the current line
|
||||||
|
float maxHeight = 0;
|
||||||
|
float maxAscender = 0;
|
||||||
|
float lastCursorX = 0;
|
||||||
|
|
||||||
|
// Process each character to split text into single lines
|
||||||
|
for (int32 currentIndex = 0; currentIndex < textLength;)
|
||||||
|
{
|
||||||
|
bool moveLine = false;
|
||||||
|
bool moveBlock = false;
|
||||||
|
float xAdvance = 0;
|
||||||
|
int32 nextCharIndex = currentIndex + 1;
|
||||||
|
|
||||||
|
// Submit line and block if text ends
|
||||||
|
if (nextCharIndex == textLength) {
|
||||||
|
moveLine = moveBlock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache current character
|
||||||
|
const Char currentChar = text[currentIndex];
|
||||||
|
const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
|
||||||
|
|
||||||
|
// Check if character can wrap words
|
||||||
|
const bool isWrapChar = !StringUtils::IsAlnum(currentChar) || isWhitespace || StringUtils::IsUpper(currentChar) || (currentChar >= 0x3040 && currentChar <= 0x9FFF);
|
||||||
|
if (isWrapChar && currentIndex != 0)
|
||||||
|
{
|
||||||
|
lastWrapCharIndex = currentIndex;
|
||||||
|
lastWrapCharX = cursorX;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 nextFontIndex = currentFontIndex;
|
||||||
|
// Check if it's a newline character
|
||||||
|
if (currentChar == '\n')
|
||||||
|
{
|
||||||
|
// Break line
|
||||||
|
moveLine = moveBlock = true;
|
||||||
|
tmpBlock.LastCharIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get character entry
|
||||||
|
if (nextCharIndex < textLength) {
|
||||||
|
nextFontIndex = GetCharFontIndex(text[nextCharIndex], currentFontIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get character entry
|
||||||
|
_fonts[currentFontIndex]->GetCharacter(currentChar, entry);
|
||||||
|
maxHeight = Math::Max(maxHeight, static_cast<float>(_fonts[currentFontIndex]->GetHeight()));
|
||||||
|
maxAscender = Math::Max(maxAscender, static_cast<float>(_fonts[currentFontIndex]->GetAscender()));
|
||||||
|
|
||||||
|
// Move block if the font changes or text ends
|
||||||
|
if (nextFontIndex != currentFontIndex || nextCharIndex == textLength) {
|
||||||
|
moveBlock = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get kerning, only when the font hasn't changed
|
||||||
|
if (!isWhitespace && previous.IsValid && !moveBlock)
|
||||||
|
{
|
||||||
|
kerning = _fonts[currentFontIndex]->GetKerning(previous.Character, entry.Character);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kerning = 0;
|
||||||
|
}
|
||||||
|
previous = entry;
|
||||||
|
xAdvance = (kerning + entry.AdvanceX) * scale;
|
||||||
|
|
||||||
|
// Check if character fits the line or skip wrapping
|
||||||
|
if (cursorX + xAdvance <= boundsWidth || layout.TextWrapping == TextWrapping::NoWrap)
|
||||||
|
{
|
||||||
|
// Move character
|
||||||
|
cursorX += xAdvance;
|
||||||
|
tmpBlock.LastCharIndex++;
|
||||||
|
}
|
||||||
|
else if (layout.TextWrapping == TextWrapping::WrapWords)
|
||||||
|
{
|
||||||
|
if (lastWrapCharIndex != INVALID_INDEX)
|
||||||
|
{
|
||||||
|
// Skip moving twice for the same character
|
||||||
|
int32 lastLineLastCharIndex = outputLines.HasItems() && outputLines.Last().Blocks.HasItems() ? outputLines.Last().Blocks.Last().LastCharIndex : -10000;
|
||||||
|
if (lastLineLastCharIndex == lastWrapCharIndex || lastLineLastCharIndex == lastWrapCharIndex - 1 || lastLineLastCharIndex == lastWrapCharIndex - 2)
|
||||||
|
{
|
||||||
|
currentIndex = nextCharIndex;
|
||||||
|
lastMoveLine = moveLine;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move line
|
||||||
|
const Char wrapChar = text[lastWrapCharIndex];
|
||||||
|
moveLine = true;
|
||||||
|
moveBlock = tmpBlock.FirstCharIndex < lastWrapCharIndex;
|
||||||
|
|
||||||
|
cursorX = lastWrapCharX;
|
||||||
|
if (StringUtils::IsWhitespace(wrapChar))
|
||||||
|
{
|
||||||
|
// Skip whitespaces
|
||||||
|
tmpBlock.LastCharIndex = lastWrapCharIndex - 1;
|
||||||
|
nextCharIndex = currentIndex = lastWrapCharIndex + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmpBlock.LastCharIndex = lastWrapCharIndex - 1;
|
||||||
|
nextCharIndex = currentIndex = lastWrapCharIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (layout.TextWrapping == TextWrapping::WrapChars)
|
||||||
|
{
|
||||||
|
// Move line
|
||||||
|
moveLine = true;
|
||||||
|
moveBlock = tmpBlock.FirstCharIndex < currentChar;
|
||||||
|
nextCharIndex = currentIndex;
|
||||||
|
|
||||||
|
// Skip moving twice for the same character
|
||||||
|
if (lastMoveLine)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moveBlock) {
|
||||||
|
// Add block
|
||||||
|
tmpBlock.Size.X = lastCursorX - cursorX;
|
||||||
|
tmpBlock.Size.Y = baseLinesDistanceScale * _fonts[currentFontIndex]->GetHeight();
|
||||||
|
tmpBlock.LastCharIndex = Math::Max(tmpBlock.LastCharIndex, tmpBlock.FirstCharIndex);
|
||||||
|
tmpBlock.FontIndex = currentFontIndex;
|
||||||
|
tmpLine.Blocks.Add(tmpBlock);
|
||||||
|
|
||||||
|
// Reset block
|
||||||
|
tmpBlock.Location.X = cursorX;
|
||||||
|
tmpBlock.FirstCharIndex = nextCharIndex;
|
||||||
|
tmpBlock.LastCharIndex = nextCharIndex - 1;
|
||||||
|
|
||||||
|
currentFontIndex = nextFontIndex;
|
||||||
|
lastCursorX = cursorX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if move to another line
|
||||||
|
if (moveLine)
|
||||||
|
{
|
||||||
|
// Add line
|
||||||
|
tmpLine.Size.X = cursorX;
|
||||||
|
tmpLine.Size.Y = baseLinesDistanceScale * maxHeight;
|
||||||
|
tmpLine.MaxAscender = maxAscender;
|
||||||
|
outputLines.Add(tmpLine);
|
||||||
|
|
||||||
|
// Reset line
|
||||||
|
tmpLine.Blocks.Clear();
|
||||||
|
tmpLine.Location.Y += baseLinesDistanceScale * maxHeight;
|
||||||
|
cursorX = 0;
|
||||||
|
tmpBlock.Location.X = cursorX;
|
||||||
|
lastWrapCharIndex = INVALID_INDEX;
|
||||||
|
lastWrapCharX = 0;
|
||||||
|
previous.IsValid = false;
|
||||||
|
|
||||||
|
// Reset max font height
|
||||||
|
maxHeight = 0;
|
||||||
|
maxAscender = 0;
|
||||||
|
lastCursorX = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentIndex = nextCharIndex;
|
||||||
|
lastMoveLine = moveLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if an additional line should be created
|
||||||
|
if (text[textLength - 1] == '\n')
|
||||||
|
{
|
||||||
|
// Add line
|
||||||
|
tmpLine.Size.X = cursorX;
|
||||||
|
tmpLine.Size.Y = baseLinesDistanceScale * maxHeight;
|
||||||
|
outputLines.Add(tmpLine);
|
||||||
|
|
||||||
|
tmpLine.Location.Y += baseLinesDistanceScale * maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check amount of lines
|
||||||
|
if (outputLines.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
float totalHeight = tmpLine.Location.Y;
|
||||||
|
|
||||||
|
Float2 offset = Float2::Zero;
|
||||||
|
if (layout.VerticalAlignment == TextAlignment::Center)
|
||||||
|
{
|
||||||
|
offset.Y += (layout.Bounds.GetHeight() - totalHeight) * 0.5f;
|
||||||
|
}
|
||||||
|
else if (layout.VerticalAlignment == TextAlignment::Far)
|
||||||
|
{
|
||||||
|
offset.Y += layout.Bounds.GetHeight() - totalHeight;
|
||||||
|
}
|
||||||
|
for (int32 i = 0; i < outputLines.Count(); i++)
|
||||||
|
{
|
||||||
|
MultiFontLineCache& line = outputLines[i];
|
||||||
|
Float2 rootPos = line.Location + offset;
|
||||||
|
|
||||||
|
// Fix upper left line corner to match desire text alignment
|
||||||
|
if (layout.HorizontalAlignment == TextAlignment::Center)
|
||||||
|
{
|
||||||
|
rootPos.X += (layout.Bounds.GetWidth() - line.Size.X) * 0.5f;
|
||||||
|
}
|
||||||
|
else if (layout.HorizontalAlignment == TextAlignment::Far)
|
||||||
|
{
|
||||||
|
rootPos.X += layout.Bounds.GetWidth() - line.Size.X;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.Location = rootPos;
|
||||||
|
|
||||||
|
// Align all blocks to center in case they have different heights
|
||||||
|
for (int32 j = 0; j < line.Blocks.Count(); j++)
|
||||||
|
{
|
||||||
|
MultiFontBlockCache& block = line.Blocks[j];
|
||||||
|
block.Location.Y += (line.MaxAscender - _fonts[block.FontIndex]->GetAscender()) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Float2 MultiFont::GetCharPosition(const StringView& text, int32 index, const TextLayoutOptions& layout)
|
||||||
|
{
|
||||||
|
// Check if there is no need to do anything
|
||||||
|
if (text.IsEmpty())
|
||||||
|
return layout.Bounds.Location;
|
||||||
|
|
||||||
|
// Process text
|
||||||
|
Array<MultiFontLineCache> lines;
|
||||||
|
ProcessText(text, lines, layout);
|
||||||
|
ASSERT(lines.HasItems());
|
||||||
|
float scale = layout.Scale / FontManager::FontScale;
|
||||||
|
float baseLinesDistance = layout.BaseLinesGapScale * scale;
|
||||||
|
Float2 rootOffset = layout.Bounds.Location;
|
||||||
|
|
||||||
|
// Find line with that position
|
||||||
|
FontCharacterEntry previous;
|
||||||
|
FontCharacterEntry entry;
|
||||||
|
for (int32 lineIndex = 0; lineIndex < lines.Count(); lineIndex++)
|
||||||
|
{
|
||||||
|
const MultiFontLineCache& line = lines[lineIndex];
|
||||||
|
for (int32 blockIndex = 0; blockIndex < line.Blocks.Count(); blockIndex++)
|
||||||
|
{
|
||||||
|
const MultiFontBlockCache& block = line.Blocks[blockIndex];
|
||||||
|
// Check if desire position is somewhere inside characters in line range
|
||||||
|
if (Math::IsInRange(index, block.FirstCharIndex, block.LastCharIndex))
|
||||||
|
{
|
||||||
|
float x = line.Location.X + block.Location.X;
|
||||||
|
float y = line.Location.Y + block.Location.Y;
|
||||||
|
|
||||||
|
// Check all characters in the line
|
||||||
|
for (int32 currentIndex = block.FirstCharIndex; currentIndex < index; currentIndex++)
|
||||||
|
{
|
||||||
|
// Cache current character
|
||||||
|
const Char currentChar = text[currentIndex];
|
||||||
|
_fonts[block.FontIndex]->GetCharacter(currentChar, entry);
|
||||||
|
const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
|
||||||
|
|
||||||
|
// Apply kerning
|
||||||
|
if (!isWhitespace && previous.IsValid)
|
||||||
|
{
|
||||||
|
x += _fonts[block.FontIndex]->GetKerning(previous.Character, entry.Character);
|
||||||
|
}
|
||||||
|
previous = entry;
|
||||||
|
|
||||||
|
// Move
|
||||||
|
x += entry.AdvanceX * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upper left corner of the character
|
||||||
|
return rootOffset + Float2(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position after last character in the last line
|
||||||
|
return rootOffset + Float2(lines.Last().Location.X + lines.Last().Size.X, lines.Last().Location.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 MultiFont::HitTestText(const StringView& text, const Float2& location, const TextLayoutOptions& layout)
|
||||||
|
{
|
||||||
|
// Check if there is no need to do anything
|
||||||
|
if (text.Length() <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Process text
|
||||||
|
Array<MultiFontLineCache> lines;
|
||||||
|
ProcessText(text, lines, layout);
|
||||||
|
ASSERT(lines.HasItems());
|
||||||
|
float scale = layout.Scale / FontManager::FontScale;
|
||||||
|
|
||||||
|
// Offset position to match lines origin space
|
||||||
|
Float2 rootOffset = layout.Bounds.Location + lines.First().Location;
|
||||||
|
Float2 testPoint = location - rootOffset;
|
||||||
|
|
||||||
|
// Get block which may intersect with the position (it's possible because lines have fixed height)
|
||||||
|
int32 lineIndex = 0;
|
||||||
|
while (lineIndex < lines.Count())
|
||||||
|
{
|
||||||
|
if (lines[lineIndex].Location.Y + lines[lineIndex].Size.Y >= location.Y) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lineIndex++;
|
||||||
|
}
|
||||||
|
lineIndex = Math::Clamp(lineIndex, 0, lines.Count() - 1);
|
||||||
|
const MultiFontLineCache& line = lines[lineIndex];
|
||||||
|
|
||||||
|
int32 blockIndex = 0;
|
||||||
|
while (blockIndex < line.Blocks.Count() - 1)
|
||||||
|
{
|
||||||
|
if (line.Location.X + line.Blocks[blockIndex + 1].Location.X >= location.X) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockIndex++;
|
||||||
|
}
|
||||||
|
const MultiFontBlockCache& block = line.Blocks[blockIndex];
|
||||||
|
float x = line.Location.X;
|
||||||
|
|
||||||
|
// Check all characters in the line to find hit point
|
||||||
|
FontCharacterEntry previous;
|
||||||
|
FontCharacterEntry entry;
|
||||||
|
int32 smallestIndex = INVALID_INDEX;
|
||||||
|
float dst, smallestDst = MAX_float;
|
||||||
|
for (int32 currentIndex = block.FirstCharIndex; currentIndex <= block.LastCharIndex; currentIndex++)
|
||||||
|
{
|
||||||
|
// Cache current character
|
||||||
|
const Char currentChar = text[currentIndex];
|
||||||
|
|
||||||
|
_fonts[block.FontIndex]->GetCharacter(currentChar, entry);
|
||||||
|
const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
|
||||||
|
|
||||||
|
// Apply kerning
|
||||||
|
if (!isWhitespace && previous.IsValid)
|
||||||
|
{
|
||||||
|
x += _fonts[block.FontIndex]->GetKerning(previous.Character, entry.Character);
|
||||||
|
}
|
||||||
|
previous = entry;
|
||||||
|
|
||||||
|
// Test
|
||||||
|
dst = Math::Abs(testPoint.X - x);
|
||||||
|
if (dst < smallestDst)
|
||||||
|
{
|
||||||
|
// Found closer character
|
||||||
|
smallestIndex = currentIndex;
|
||||||
|
smallestDst = dst;
|
||||||
|
}
|
||||||
|
else if (dst > smallestDst)
|
||||||
|
{
|
||||||
|
// Current char is worse so return the best result
|
||||||
|
return smallestIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move
|
||||||
|
x += entry.AdvanceX * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test line end edge
|
||||||
|
dst = Math::Abs(testPoint.X - x);
|
||||||
|
if (dst < smallestDst)
|
||||||
|
{
|
||||||
|
// Pointer is behind the last character in the line
|
||||||
|
smallestIndex = block.LastCharIndex;
|
||||||
|
|
||||||
|
// Fix for last line
|
||||||
|
if (lineIndex == lines.Count() - 1)
|
||||||
|
smallestIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return smallestIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float2 MultiFont::MeasureText(const StringView& text, const TextLayoutOptions& layout)
|
||||||
|
{
|
||||||
|
// Check if there is no need to do anything
|
||||||
|
if (text.IsEmpty())
|
||||||
|
return Float2::Zero;
|
||||||
|
|
||||||
|
// Process text
|
||||||
|
Array<MultiFontLineCache> lines;
|
||||||
|
ProcessText(text, lines, layout);
|
||||||
|
|
||||||
|
// Calculate bounds
|
||||||
|
Float2 max = Float2::Zero;
|
||||||
|
for (int32 i = 0; i < lines.Count(); i++)
|
||||||
|
{
|
||||||
|
const MultiFontLineCache& line = lines[i];
|
||||||
|
max = Float2::Max(max, line.Location + line.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,28 @@
|
|||||||
#include "Engine/Core/Collections/Array.h"
|
#include "Engine/Core/Collections/Array.h"
|
||||||
#include "Engine/Core/Collections/Dictionary.h"
|
#include "Engine/Core/Collections/Dictionary.h"
|
||||||
#include "Font.h"
|
#include "Font.h"
|
||||||
|
#include "FontAsset.h"
|
||||||
|
|
||||||
|
struct TextRange;
|
||||||
|
class Font;
|
||||||
|
class FontAsset;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font segment info generated during text processing.
|
/// The font block info generated during text processing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_STRUCT(NoDefault) struct MultiFontSegmentCache
|
API_STRUCT(NoDefault) struct MultiFontBlockCache
|
||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_MINIMAL(MultiFontSegmentCache);
|
DECLARE_SCRIPTING_TYPE_MINIMAL(MultiFontBlockCache);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The root position of the segment (upper left corner), relative to line.
|
/// The root position of the block (upper left corner), relative to line.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() Float2 Location;
|
API_FIELD() Float2 Location;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The height of the current segment
|
/// The height of the current block
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float Height;
|
API_FIELD() Float2 Size;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The first character index (from the input text).
|
/// The first character index (from the input text).
|
||||||
@@ -38,13 +43,13 @@ API_STRUCT(NoDefault) struct MultiFontSegmentCache
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct TIsPODType<MultiFontSegmentCache>
|
struct TIsPODType<MultiFontBlockCache>
|
||||||
{
|
{
|
||||||
enum { Value = true };
|
enum { Value = true };
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Line of font segments info generated during text processing.
|
/// Line of font blocks info generated during text processing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_STRUCT(NoDefault) struct MultiFontLineCache
|
API_STRUCT(NoDefault) struct MultiFontLineCache
|
||||||
{
|
{
|
||||||
@@ -61,17 +66,288 @@ API_STRUCT(NoDefault) struct MultiFontLineCache
|
|||||||
API_FIELD() Float2 Size;
|
API_FIELD() Float2 Size;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum ascendent of the line.
|
/// The maximum ascender of the line.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float MaxAscender;
|
API_FIELD() float MaxAscender;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The index of the font to render with
|
/// The index of the font to render with
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() Array<MultiFontSegmentCache> Segments;
|
API_FIELD() Array<MultiFontBlockCache> Blocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API MultiFont : public ManagedScriptingObject
|
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API MultiFont : public ManagedScriptingObject
|
||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(MultiFont);
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
74
Source/Engine/Render2D/MultiFontReference.cs
Normal file
74
Source/Engine/Render2D/MultiFontReference.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace FlaxEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reference to multiple font references
|
||||||
|
/// </summary>
|
||||||
|
public class MultiFontReference : List<FontReference>
|
||||||
|
{
|
||||||
|
public MultiFontReference()
|
||||||
|
{
|
||||||
|
_cachedFont = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiFontReference(IEnumerable<FontReference> other)
|
||||||
|
{
|
||||||
|
AddRange(other);
|
||||||
|
_cachedFont = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiFontReference(MultiFontReference other)
|
||||||
|
{
|
||||||
|
AddRange(other);
|
||||||
|
_cachedFont = other._cachedFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiFontReference(MultiFontReference other, float size)
|
||||||
|
{
|
||||||
|
AddRange(other.Select(x => new FontReference(x) { Size = size }));
|
||||||
|
_cachedFont = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiFontReference(MultiFont other)
|
||||||
|
{
|
||||||
|
AddRange(other.Fonts.Select(x => new FontReference(x)));
|
||||||
|
_cachedFont = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiFontReference(FontAsset[] assets, float size)
|
||||||
|
{
|
||||||
|
AddRange(assets.Select(x => new FontReference(x, size)));
|
||||||
|
_cachedFont = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[EditorOrder(0), Tooltip("The font asset to use as characters source.")]
|
||||||
|
public MultiFont GetMultiFont()
|
||||||
|
{
|
||||||
|
if (_cachedFont)
|
||||||
|
return _cachedFont;
|
||||||
|
var fontList = this.Where(x => x.Font).Select(x => x.GetFont()).ToArray();
|
||||||
|
_cachedFont = MultiFont.Create(fontList);
|
||||||
|
return _cachedFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Verify()
|
||||||
|
{
|
||||||
|
foreach (var i in this)
|
||||||
|
{
|
||||||
|
if (!i.Font)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NoSerialize]
|
||||||
|
private MultiFont _cachedFont;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1370,10 +1370,11 @@ void Render2D::DrawText(Font* font, const StringView& text, const TextRange& tex
|
|||||||
DrawText(font, textRange.Substring(text), color, layout, customMaterial);
|
DrawText(font, textRange.Substring(text), color, layout, customMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial)
|
void Render2D::DrawText(MultiFont* multiFont, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial)
|
||||||
{
|
{
|
||||||
RENDER2D_CHECK_RENDERING_STATE;
|
RENDER2D_CHECK_RENDERING_STATE;
|
||||||
|
|
||||||
|
const Array<Font*>& fonts = multiFont->GetFonts();
|
||||||
// Check if there is no need to do anything
|
// Check if there is no need to do anything
|
||||||
if (fonts.IsEmpty() || text.Length() < 0)
|
if (fonts.IsEmpty() || text.Length() < 0)
|
||||||
return;
|
return;
|
||||||
@@ -1408,7 +1409,7 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
for (int32 currentIndex = 0; currentIndex < text.Length(); currentIndex++)
|
for (int32 currentIndex = 0; currentIndex < text.Length(); currentIndex++)
|
||||||
{
|
{
|
||||||
if (text[currentIndex] != '\n') {
|
if (text[currentIndex] != '\n') {
|
||||||
int32 fontIndex = Font::GetCharFontIndex(fonts, text[currentIndex], 0);
|
int32 fontIndex = multiFont->GetCharFontIndex(text[currentIndex], 0);
|
||||||
maxAscenders[lineIndex] = Math::Max(maxAscenders[lineIndex], static_cast<float>(fonts[fontIndex]->GetAscender()));
|
maxAscenders[lineIndex] = Math::Max(maxAscenders[lineIndex], static_cast<float>(fonts[fontIndex]->GetAscender()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1418,12 +1419,12 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
lineIndex = 0;
|
lineIndex = 0;
|
||||||
// The following code cut the text into segments, according to the font used to render
|
// The following code cut the text into blocks, according to the font used to render
|
||||||
Float2 pointer = location;
|
Float2 pointer = location;
|
||||||
// The starting index of the current segment
|
// The starting index of the current block
|
||||||
int32 startIndex = 0;
|
int32 startIndex = 0;
|
||||||
// The index of the font used by the current segment
|
// The index of the font used by the current block
|
||||||
int32 currentFontIndex = Font::GetCharFontIndex(fonts, text[0], 0);
|
int32 currentFontIndex = multiFont->GetCharFontIndex(text[0], 0);
|
||||||
// The maximum font height of the current line
|
// The maximum font height of the current line
|
||||||
float maxHeight = 0;
|
float maxHeight = 0;
|
||||||
for (int32 currentIndex = 0; currentIndex < text.Length(); currentIndex++)
|
for (int32 currentIndex = 0; currentIndex < text.Length(); currentIndex++)
|
||||||
@@ -1431,13 +1432,13 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
// Cache current character
|
// Cache current character
|
||||||
const Char currentChar = text[currentIndex];
|
const Char currentChar = text[currentIndex];
|
||||||
int32 nextCharIndex = currentIndex + 1;
|
int32 nextCharIndex = currentIndex + 1;
|
||||||
bool moveSegment = false;
|
bool moveBlock = false;
|
||||||
bool moveLine = false;
|
bool moveLine = false;
|
||||||
int32 nextFontIndex = currentFontIndex;
|
int32 nextFontIndex = currentFontIndex;
|
||||||
|
|
||||||
// Submit segment if text ends
|
// Submit block if text ends
|
||||||
if (nextCharIndex == text.Length()) {
|
if (nextCharIndex == text.Length()) {
|
||||||
moveSegment = true;
|
moveBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it isn't a newline character
|
// Check if it isn't a newline character
|
||||||
@@ -1445,21 +1446,21 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
{
|
{
|
||||||
// Get character entry
|
// Get character entry
|
||||||
if (nextCharIndex < text.Length()) {
|
if (nextCharIndex < text.Length()) {
|
||||||
nextFontIndex = Font::GetCharFontIndex(fonts, text[nextCharIndex], currentFontIndex);
|
nextFontIndex = multiFont->GetCharFontIndex(text[nextCharIndex], currentFontIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextFontIndex != currentFontIndex) {
|
if (nextFontIndex != currentFontIndex) {
|
||||||
moveSegment = true;
|
moveBlock = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Move
|
// Move
|
||||||
moveLine = moveSegment = true;
|
moveLine = moveBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moveSegment) {
|
if (moveBlock) {
|
||||||
// Render the pending segment before beginning the new segment
|
// Render the pending block before beginning the new block
|
||||||
auto fontHeight = fonts[currentFontIndex]->GetHeight();
|
auto fontHeight = fonts[currentFontIndex]->GetHeight();
|
||||||
maxHeight = Math::Max(maxHeight, static_cast<float>(fontHeight));
|
maxHeight = Math::Max(maxHeight, static_cast<float>(fontHeight));
|
||||||
auto fontDescender = fonts[currentFontIndex]->GetDescender();
|
auto fontDescender = fonts[currentFontIndex]->GetDescender();
|
||||||
@@ -1533,22 +1534,23 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
lineIndex++;
|
lineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start new segment
|
// Start new block
|
||||||
startIndex = nextCharIndex;
|
startIndex = nextCharIndex;
|
||||||
currentFontIndex = nextFontIndex;
|
currentFontIndex = nextFontIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial)
|
void Render2D::DrawText(MultiFont* multiFont, const StringView& text, const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial)
|
||||||
{
|
{
|
||||||
DrawText(fonts, textRange.Substring(text), color, location, customMaterial);
|
DrawText(multiFont, textRange.Substring(text), color, location, customMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
|
void Render2D::DrawText(MultiFont* multiFont, const StringView& text, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
|
||||||
{
|
{
|
||||||
RENDER2D_CHECK_RENDERING_STATE;
|
RENDER2D_CHECK_RENDERING_STATE;
|
||||||
|
|
||||||
|
const Array<Font*>& fonts = multiFont->GetFonts();
|
||||||
// Check if there is no need to do anything
|
// Check if there is no need to do anything
|
||||||
if (fonts.IsEmpty() || text.IsEmpty() || layout.Scale <= ZeroTolerance)
|
if (fonts.IsEmpty() || text.IsEmpty() || layout.Scale <= ZeroTolerance)
|
||||||
return;
|
return;
|
||||||
@@ -1563,7 +1565,7 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
|
|
||||||
// Process text to get lines
|
// Process text to get lines
|
||||||
MultiFontLines.Clear();
|
MultiFontLines.Clear();
|
||||||
Font::ProcessText(fonts, text, MultiFontLines, layout);
|
multiFont->ProcessText(text, MultiFontLines, layout);
|
||||||
|
|
||||||
// Render all lines
|
// Render all lines
|
||||||
FontCharacterEntry entry;
|
FontCharacterEntry entry;
|
||||||
@@ -1582,14 +1584,14 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
for (int32 lineIndex = 0; lineIndex < MultiFontLines.Count(); lineIndex++)
|
for (int32 lineIndex = 0; lineIndex < MultiFontLines.Count(); lineIndex++)
|
||||||
{
|
{
|
||||||
const MultiFontLineCache& line = MultiFontLines[lineIndex];
|
const MultiFontLineCache& line = MultiFontLines[lineIndex];
|
||||||
for (int32 segmentIndex = 0; segmentIndex < line.Segments.Count(); segmentIndex++)
|
for (int32 blockIndex = 0; blockIndex < line.Blocks.Count(); blockIndex++)
|
||||||
{
|
{
|
||||||
const MultiFontSegmentCache& segment = MultiFontLines[lineIndex].Segments[segmentIndex];
|
const MultiFontBlockCache& block = MultiFontLines[lineIndex].Blocks[blockIndex];
|
||||||
auto fontHeight = fonts[segment.FontIndex]->GetHeight();
|
auto fontHeight = fonts[block.FontIndex]->GetHeight();
|
||||||
auto fontDescender = fonts[segment.FontIndex]->GetDescender();
|
auto fontDescender = fonts[block.FontIndex]->GetDescender();
|
||||||
Float2 pointer = line.Location + segment.Location;
|
Float2 pointer = line.Location + block.Location;
|
||||||
|
|
||||||
for (int32 charIndex = segment.FirstCharIndex; charIndex <= segment.LastCharIndex; charIndex++)
|
for (int32 charIndex = block.FirstCharIndex; charIndex <= block.LastCharIndex; charIndex++)
|
||||||
{
|
{
|
||||||
Char c = text[charIndex];
|
Char c = text[charIndex];
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
@@ -1598,7 +1600,7 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get character entry
|
// Get character entry
|
||||||
fonts[segment.FontIndex]->GetCharacter(c, entry);
|
fonts[block.FontIndex]->GetCharacter(c, entry);
|
||||||
|
|
||||||
// Check if need to select/change font atlas (since characters even in the same font may be located in different atlases)
|
// Check if need to select/change font atlas (since characters even in the same font may be located in different atlases)
|
||||||
if (fontAtlas == nullptr || entry.TextureIndex != fontAtlasIndex)
|
if (fontAtlas == nullptr || entry.TextureIndex != fontAtlasIndex)
|
||||||
@@ -1623,7 +1625,7 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
const bool isWhitespace = StringUtils::IsWhitespace(c);
|
const bool isWhitespace = StringUtils::IsWhitespace(c);
|
||||||
if (!isWhitespace && previous.IsValid)
|
if (!isWhitespace && previous.IsValid)
|
||||||
{
|
{
|
||||||
kerning = fonts[segment.FontIndex]->GetKerning(previous.Character, entry.Character);
|
kerning = fonts[block.FontIndex]->GetKerning(previous.Character, entry.Character);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1659,9 +1661,9 @@ void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render2D::DrawText(const Array<Font*>& fonts, const StringView& text, const TextRange& textRange, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
|
void Render2D::DrawText(MultiFont* multiFont, const StringView& text, const TextRange& textRange, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
|
||||||
{
|
{
|
||||||
DrawText(fonts, textRange.Substring(text), color, layout, customMaterial);
|
DrawText(multiFont, textRange.Substring(text), color, layout, customMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool NeedAlphaWithTint(const Color& color)
|
FORCE_INLINE bool NeedAlphaWithTint(const Color& color)
|
||||||
@@ -2165,22 +2167,22 @@ void Render2D::DrawBezier(const Float2& p1, const Float2& p2, const Float2& p3,
|
|||||||
{
|
{
|
||||||
RENDER2D_CHECK_RENDERING_STATE;
|
RENDER2D_CHECK_RENDERING_STATE;
|
||||||
|
|
||||||
// Find amount of segments to use
|
// Find amount of blocks to use
|
||||||
const Float2 d1 = p2 - p1;
|
const Float2 d1 = p2 - p1;
|
||||||
const Float2 d2 = p3 - p2;
|
const Float2 d2 = p3 - p2;
|
||||||
const Float2 d3 = p4 - p3;
|
const Float2 d3 = p4 - p3;
|
||||||
const float len = d1.Length() + d2.Length() + d3.Length();
|
const float len = d1.Length() + d2.Length() + d3.Length();
|
||||||
const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
|
const int32 blockCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
|
||||||
const float segmentCountInv = 1.0f / segmentCount;
|
const float blockCountInv = 1.0f / blockCount;
|
||||||
|
|
||||||
// Draw segmented curve
|
// Draw blocked curve
|
||||||
Float2 p;
|
Float2 p;
|
||||||
AnimationUtils::Bezier(p1, p2, p3, p4, 0, p);
|
AnimationUtils::Bezier(p1, p2, p3, p4, 0, p);
|
||||||
Lines2.Clear();
|
Lines2.Clear();
|
||||||
Lines2.Add(p);
|
Lines2.Add(p);
|
||||||
for (int32 i = 1; i <= segmentCount; i++)
|
for (int32 i = 1; i <= blockCount; i++)
|
||||||
{
|
{
|
||||||
const float t = i * segmentCountInv;
|
const float t = i * blockCountInv;
|
||||||
AnimationUtils::Bezier(p1, p2, p3, p4, t, p);
|
AnimationUtils::Bezier(p1, p2, p3, p4, t, p);
|
||||||
Lines2.Add(p);
|
Lines2.Add(p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ namespace FlaxEngine
|
|||||||
/// <param name="textWrapping">Describes how wrap text inside a layout rectangle.</param>
|
/// <param name="textWrapping">Describes how wrap text inside a layout rectangle.</param>
|
||||||
/// <param name="baseLinesGapScale">The scale for distance one baseline from another. Default is 1.</param>
|
/// <param name="baseLinesGapScale">The scale for distance one baseline from another. Default is 1.</param>
|
||||||
/// <param name="scale">The text drawing scale. Default is 1.</param>
|
/// <param name="scale">The text drawing scale. Default is 1.</param>
|
||||||
public static void DrawText(Font[] fonts, string text, Rectangle layoutRect, Color color, TextAlignment horizontalAlignment = TextAlignment.Near, TextAlignment verticalAlignment = TextAlignment.Near, TextWrapping textWrapping = TextWrapping.NoWrap, float baseLinesGapScale = 1.0f, float scale = 1.0f)
|
public static void DrawText(MultiFont fonts, string text, Rectangle layoutRect, Color color, TextAlignment horizontalAlignment = TextAlignment.Near, TextAlignment verticalAlignment = TextAlignment.Near, TextWrapping textWrapping = TextWrapping.NoWrap, float baseLinesGapScale = 1.0f, float scale = 1.0f)
|
||||||
{
|
{
|
||||||
var layout = new TextLayoutOptions
|
var layout = new TextLayoutOptions
|
||||||
{
|
{
|
||||||
@@ -175,6 +175,8 @@ namespace FlaxEngine
|
|||||||
Scale = scale,
|
Scale = scale,
|
||||||
BaseLinesGapScale = baseLinesGapScale,
|
BaseLinesGapScale = baseLinesGapScale,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
DrawText(fonts, text, color, ref layout);
|
DrawText(fonts, text, color, ref layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +193,7 @@ namespace FlaxEngine
|
|||||||
/// <param name="textWrapping">Describes how wrap text inside a layout rectangle.</param>
|
/// <param name="textWrapping">Describes how wrap text inside a layout rectangle.</param>
|
||||||
/// <param name="baseLinesGapScale">The scale for distance one baseline from another. Default is 1.</param>
|
/// <param name="baseLinesGapScale">The scale for distance one baseline from another. Default is 1.</param>
|
||||||
/// <param name="scale">The text drawing scale. Default is 1.</param>
|
/// <param name="scale">The text drawing scale. Default is 1.</param>
|
||||||
public static void DrawText(Font[] fonts, MaterialBase customMaterial, string text, Rectangle layoutRect, Color color, TextAlignment horizontalAlignment = TextAlignment.Near, TextAlignment verticalAlignment = TextAlignment.Near, TextWrapping textWrapping = TextWrapping.NoWrap, float baseLinesGapScale = 1.0f, float scale = 1.0f)
|
public static void DrawText(MultiFont fonts, MaterialBase customMaterial, string text, Rectangle layoutRect, Color color, TextAlignment horizontalAlignment = TextAlignment.Near, TextAlignment verticalAlignment = TextAlignment.Near, TextWrapping textWrapping = TextWrapping.NoWrap, float baseLinesGapScale = 1.0f, float scale = 1.0f)
|
||||||
{
|
{
|
||||||
var layout = new TextLayoutOptions
|
var layout = new TextLayoutOptions
|
||||||
{
|
{
|
||||||
@@ -202,6 +204,7 @@ namespace FlaxEngine
|
|||||||
Scale = scale,
|
Scale = scale,
|
||||||
BaseLinesGapScale = baseLinesGapScale,
|
BaseLinesGapScale = baseLinesGapScale,
|
||||||
};
|
};
|
||||||
|
|
||||||
DrawText(fonts, text, color, ref layout, customMaterial);
|
DrawText(fonts, text, color, ref layout, customMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ struct Matrix3x3;
|
|||||||
struct Viewport;
|
struct Viewport;
|
||||||
struct TextRange;
|
struct TextRange;
|
||||||
class Font;
|
class Font;
|
||||||
|
class MultiFont;
|
||||||
class GPUPipelineState;
|
class GPUPipelineState;
|
||||||
class GPUTexture;
|
class GPUTexture;
|
||||||
class GPUTextureView;
|
class GPUTextureView;
|
||||||
@@ -224,7 +225,7 @@ public:
|
|||||||
/// <param name="color">The text color.</param>
|
/// <param name="color">The text color.</param>
|
||||||
/// <param name="location">The text location.</param>
|
/// <param name="location">The text location.</param>
|
||||||
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
||||||
API_FUNCTION() static void DrawText(const Array<Font*, HeapAllocation>& fonts, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
|
API_FUNCTION() static void DrawText(MultiFont* multiFont, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws a text with formatting.
|
/// Draws a text with formatting.
|
||||||
@@ -234,7 +235,7 @@ public:
|
|||||||
/// <param name="color">The text color.</param>
|
/// <param name="color">The text color.</param>
|
||||||
/// <param name="layout">The text layout properties.</param>
|
/// <param name="layout">The text layout properties.</param>
|
||||||
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
||||||
API_FUNCTION() static void DrawText(const Array<Font*, HeapAllocation>& fonts, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
|
API_FUNCTION() static void DrawText(MultiFont* multiFont, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws a text with formatting.
|
/// Draws a text with formatting.
|
||||||
@@ -245,7 +246,7 @@ public:
|
|||||||
/// <param name="color">The text color.</param>
|
/// <param name="color">The text color.</param>
|
||||||
/// <param name="layout">The text layout properties.</param>
|
/// <param name="layout">The text layout properties.</param>
|
||||||
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
||||||
API_FUNCTION() static void DrawText(const Array<Font*, HeapAllocation>& fonts, const StringView& text, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
|
API_FUNCTION() static void DrawText(MultiFont* multiFont, const StringView& text, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws a text with formatting.
|
/// Draws a text with formatting.
|
||||||
@@ -256,7 +257,7 @@ public:
|
|||||||
/// <param name="color">The text color.</param>
|
/// <param name="color">The text color.</param>
|
||||||
/// <param name="layout">The text layout properties.</param>
|
/// <param name="layout">The text layout properties.</param>
|
||||||
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
/// <param name="customMaterial">The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.</param>
|
||||||
API_FUNCTION() static void DrawText(const Array<Font*, HeapAllocation>& fonts, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
|
API_FUNCTION() static void DrawText(MultiFont* multiFont, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills a rectangle area.
|
/// Fills a rectangle area.
|
||||||
|
|||||||
@@ -294,15 +294,12 @@ namespace FlaxEngine
|
|||||||
style.DragWindow = style.BackgroundSelected * 0.7f;
|
style.DragWindow = style.BackgroundSelected * 0.7f;
|
||||||
|
|
||||||
// Use optionally bundled default font (matches Editor)
|
// Use optionally bundled default font (matches Editor)
|
||||||
var defaultFont = Content.LoadAsyncInternal<FontAsset>("Editor/Fonts/Roboto-Regular");
|
FontAsset[] defaultFont = [Content.LoadAsyncInternal<FontAsset>("Editor/Fonts/Roboto-Regular"), Content.LoadAsyncInternal<FontAsset>("Editor/Fonts/NotoSansSC-Regular")];
|
||||||
var cjkFont = Content.LoadAsyncInternal<FontAsset>("NotoSansSC-Medium");
|
|
||||||
if (defaultFont)
|
style.FontTitle = new MultiFontReference(defaultFont, 18).GetMultiFont();
|
||||||
{
|
style.FontLarge = new MultiFontReference(defaultFont, 14).GetMultiFont();
|
||||||
style.FontTitle = defaultFont.CreateFont(18);
|
style.FontMedium = new MultiFontReference(defaultFont, 9).GetMultiFont();
|
||||||
style.FontLarge = defaultFont.CreateFont(14);
|
style.FontSmall = new MultiFontReference(defaultFont, 9).GetMultiFont();
|
||||||
style.FontMedium = new Font[] { defaultFont.CreateFont(9), cjkFont.CreateFont(9) };
|
|
||||||
style.FontSmall = new Font[] { defaultFont.CreateFont(9), cjkFont.CreateFont(9) };
|
|
||||||
}
|
|
||||||
|
|
||||||
Style.Current = style;
|
Style.Current = style;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font.
|
/// The font.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected FontReference _font;
|
protected MultiFontReference _font;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The text.
|
/// The text.
|
||||||
@@ -44,7 +44,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// Gets or sets the font used to draw button text.
|
/// Gets or sets the font used to draw button text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2022), ExpandGroups]
|
[EditorDisplay("Text Style"), EditorOrder(2022), ExpandGroups]
|
||||||
public FontReference Font
|
public MultiFontReference Font
|
||||||
{
|
{
|
||||||
get => _font;
|
get => _font;
|
||||||
set => _font = value;
|
set => _font = value;
|
||||||
@@ -156,7 +156,7 @@ namespace FlaxEngine.GUI
|
|||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
if (style != null)
|
if (style != null)
|
||||||
{
|
{
|
||||||
_font = new FontReference(style.FontMedium.First());
|
_font = new MultiFontReference(style.FontMedium);
|
||||||
TextColor = style.Foreground;
|
TextColor = style.Foreground;
|
||||||
BackgroundColor = style.BackgroundNormal;
|
BackgroundColor = style.BackgroundNormal;
|
||||||
BorderColor = style.BorderNormal;
|
BorderColor = style.BorderNormal;
|
||||||
@@ -262,7 +262,7 @@ namespace FlaxEngine.GUI
|
|||||||
Render2D.DrawRectangle(clientRect, borderColor, BorderThickness);
|
Render2D.DrawRectangle(clientRect, borderColor, BorderThickness);
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
Render2D.DrawText(_font?.GetFont(), TextMaterial, _text, clientRect, textColor, TextAlignment.Center, TextAlignment.Center);
|
Render2D.DrawText(_font?.GetMultiFont(), TextMaterial, _text, clientRect, textColor, TextAlignment.Center, TextAlignment.Center);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// Gets or sets the font used to draw text.
|
/// Gets or sets the font used to draw text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2021)]
|
[EditorDisplay("Text Style"), EditorOrder(2021)]
|
||||||
public FontReference Font { get; set; }
|
public MultiFontReference Font { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
||||||
@@ -359,7 +359,7 @@ namespace FlaxEngine.GUI
|
|||||||
: base(0, 0, 120, 18.0f)
|
: base(0, 0, 120, 18.0f)
|
||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
Font = new FontReference(style.FontMedium.First());
|
Font = new MultiFontReference(style.FontMedium);
|
||||||
TextColor = style.Foreground;
|
TextColor = style.Foreground;
|
||||||
BackgroundColor = style.BackgroundNormal;
|
BackgroundColor = style.BackgroundNormal;
|
||||||
BackgroundColorHighlighted = BackgroundColor;
|
BackgroundColorHighlighted = BackgroundColor;
|
||||||
@@ -674,7 +674,7 @@ namespace FlaxEngine.GUI
|
|||||||
var textRect = new Rectangle(margin, 0, clientRect.Width - boxSize - 2.0f * margin, clientRect.Height);
|
var textRect = new Rectangle(margin, 0, clientRect.Width - boxSize - 2.0f * margin, clientRect.Height);
|
||||||
Render2D.PushClip(textRect);
|
Render2D.PushClip(textRect);
|
||||||
var textColor = TextColor;
|
var textColor = TextColor;
|
||||||
Render2D.DrawText(Font.GetFont(), FontMaterial, _items[_selectedIndex], textRect, enabled ? textColor : textColor * 0.5f, TextAlignment.Near, TextAlignment.Center);
|
Render2D.DrawText(Font.GetMultiFont(), FontMaterial, _items[_selectedIndex], textRect, enabled ? textColor : textColor * 0.5f, TextAlignment.Near, TextAlignment.Center);
|
||||||
Render2D.PopClip();
|
Render2D.PopClip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font.
|
/// The font.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected FontReference _font;
|
protected MultiFontReference _font;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the text.
|
/// Gets or sets the text.
|
||||||
@@ -86,7 +86,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// Gets or sets the font.
|
/// Gets or sets the font.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2024)]
|
[EditorDisplay("Text Style"), EditorOrder(2024)]
|
||||||
public FontReference Font
|
public MultiFontReference Font
|
||||||
{
|
{
|
||||||
get => _font;
|
get => _font;
|
||||||
set
|
set
|
||||||
@@ -192,7 +192,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
AutoFocus = false;
|
AutoFocus = false;
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
Font = new FontReference(style.FontMedium.First());
|
Font = new MultiFontReference(style.FontMedium);
|
||||||
TextColor = style.Foreground;
|
TextColor = style.Foreground;
|
||||||
TextColorHighlighted = style.Foreground;
|
TextColorHighlighted = style.Foreground;
|
||||||
}
|
}
|
||||||
@@ -203,7 +203,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
AutoFocus = false;
|
AutoFocus = false;
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
Font = new FontReference(style.FontMedium.First());
|
Font = new MultiFontReference(style.FontMedium);
|
||||||
TextColor = style.Foreground;
|
TextColor = style.Foreground;
|
||||||
TextColorHighlighted = style.Foreground;
|
TextColorHighlighted = style.Foreground;
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ namespace FlaxEngine.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Render2D.DrawText([_font.GetFont(), Style.Current.FontCJK], Material, _text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale);
|
Render2D.DrawText(_font.GetMultiFont(), Material, _text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale);
|
||||||
|
|
||||||
if (ClipText)
|
if (ClipText)
|
||||||
Render2D.PopClip();
|
Render2D.PopClip();
|
||||||
@@ -246,7 +246,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
if (_autoWidth || _autoHeight || _autoFitText)
|
if (_autoWidth || _autoHeight || _autoFitText)
|
||||||
{
|
{
|
||||||
var font = _font.GetFont();
|
var font = _font.GetMultiFont();
|
||||||
if (font)
|
if (font)
|
||||||
{
|
{
|
||||||
// Calculate text size
|
// Calculate text size
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using FlaxEngine.Utilities;
|
using FlaxEngine.Utilities;
|
||||||
@@ -185,7 +186,7 @@ namespace FlaxEngine.GUI
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Process text into text blocks (handle newlines etc.)
|
// Process text into text blocks (handle newlines etc.)
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
return;
|
return;
|
||||||
var lines = font.ProcessText(_text, ref textBlock.Range);
|
var lines = font.ProcessText(_text, ref textBlock.Range);
|
||||||
@@ -194,20 +195,27 @@ namespace FlaxEngine.GUI
|
|||||||
for (int i = 0; i < lines.Length; i++)
|
for (int i = 0; i < lines.Length; i++)
|
||||||
{
|
{
|
||||||
ref var line = ref lines[i];
|
ref var line = ref lines[i];
|
||||||
textBlock.Range = new TextRange
|
|
||||||
{
|
|
||||||
StartIndex = start + line.FirstCharIndex,
|
|
||||||
EndIndex = start + line.LastCharIndex,
|
|
||||||
};
|
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
context.Caret.X = 0;
|
context.Caret.X = 0;
|
||||||
OnLineAdded(ref context, textBlock.Range.StartIndex - 1);
|
OnLineAdded(ref context, textBlock.Range.StartIndex - 1);
|
||||||
}
|
}
|
||||||
textBlock.Bounds = new Rectangle(context.Caret, line.Size);
|
for (int k = 0; k < line.Blocks.Length; k++)
|
||||||
textBlock.Bounds.X += line.Location.X;
|
{
|
||||||
|
ref var block = ref line.Blocks[k];
|
||||||
|
|
||||||
context.AddTextBlock(ref textBlock);
|
textBlock.Range = new TextRange
|
||||||
|
{
|
||||||
|
StartIndex = start + block.FirstCharIndex,
|
||||||
|
EndIndex = start + block.LastCharIndex,
|
||||||
|
};
|
||||||
|
|
||||||
|
textBlock.Bounds = new Rectangle(context.Caret, block.Size);
|
||||||
|
textBlock.Bounds.X += block.Location.X;
|
||||||
|
|
||||||
|
context.AddTextBlock(ref textBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the caret location
|
// Update the caret location
|
||||||
@@ -236,9 +244,9 @@ namespace FlaxEngine.GUI
|
|||||||
var ascender = textBlock.Ascender;
|
var ascender = textBlock.Ascender;
|
||||||
//if (ascender <= 0)
|
//if (ascender <= 0)
|
||||||
{
|
{
|
||||||
var textBlockFont = textBlock.Style.Font.GetFont();
|
var textBlockFont = textBlock.Style.Font.GetMultiFont();
|
||||||
if (textBlockFont)
|
if (textBlockFont)
|
||||||
ascender = textBlockFont.Ascender;
|
ascender = textBlockFont.MaxAscender;
|
||||||
}
|
}
|
||||||
lineAscender = Mathf.Max(lineAscender, ascender);
|
lineAscender = Mathf.Max(lineAscender, ascender);
|
||||||
lineSize = Float2.Max(lineSize, textBlockSize);
|
lineSize = Float2.Max(lineSize, textBlockSize);
|
||||||
@@ -259,9 +267,9 @@ namespace FlaxEngine.GUI
|
|||||||
var ascender = textBlock.Ascender;
|
var ascender = textBlock.Ascender;
|
||||||
if (ascender <= 0)
|
if (ascender <= 0)
|
||||||
{
|
{
|
||||||
var textBlockFont = textBlock.Style.Font.GetFont();
|
var textBlockFont = textBlock.Style.Font.GetMultiFont();
|
||||||
if (textBlockFont)
|
if (textBlockFont)
|
||||||
ascender = textBlockFont.Ascender;
|
ascender = textBlockFont.MaxAscender;
|
||||||
}
|
}
|
||||||
vOffset = lineAscender - ascender;
|
vOffset = lineAscender - ascender;
|
||||||
textBlock.Bounds.Location.Y += vOffset;
|
textBlock.Bounds.Location.Y += vOffset;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using FlaxEngine.Utilities;
|
using FlaxEngine.Utilities;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace FlaxEngine.GUI
|
namespace FlaxEngine.GUI
|
||||||
{
|
{
|
||||||
@@ -10,9 +11,9 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
context.Caret.X = 0;
|
context.Caret.X = 0;
|
||||||
var style = context.StyleStack.Peek();
|
var style = context.StyleStack.Peek();
|
||||||
var font = style.Font.GetFont();
|
var font = style.Font.GetMultiFont();
|
||||||
if (font)
|
if (font)
|
||||||
context.Caret.Y += font.Height;
|
context.Caret.Y += font.MaxHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ProcessColor(ref ParsingContext context, ref HtmlTag tag)
|
private static void ProcessColor(ref ParsingContext context, ref HtmlTag tag)
|
||||||
@@ -86,15 +87,14 @@ namespace FlaxEngine.GUI
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var style = context.StyleStack.Peek();
|
var style = context.StyleStack.Peek();
|
||||||
style.Font = new FontReference(style.Font);
|
style.Font = new MultiFontReference(style.Font);
|
||||||
if (tag.Attributes.TryGetValue(string.Empty, out var fontName))
|
if (tag.Attributes.TryGetValue("size", out var sizeText) && int.TryParse(sizeText, out var size) && tag.Attributes.TryGetValue(string.Empty, out var fontName))
|
||||||
{
|
{
|
||||||
var font = (FontAsset)FindAsset(fontName, typeof(FontAsset));
|
var font = (FontAsset)FindAsset(fontName, typeof(FontAsset));
|
||||||
if (font)
|
if (font)
|
||||||
style.Font.Font = font;
|
style.Font = new MultiFontReference([font], size);
|
||||||
}
|
}
|
||||||
if (tag.Attributes.TryGetValue("size", out var sizeText) && int.TryParse(sizeText, out var size))
|
|
||||||
style.Font.Size = size;
|
|
||||||
context.StyleStack.Push(style);
|
context.StyleStack.Push(style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ namespace FlaxEngine.GUI
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var style = context.StyleStack.Peek();
|
var style = context.StyleStack.Peek();
|
||||||
style.Font = style.Font.GetBold();
|
// style.Font = style.Font.GetBold();
|
||||||
context.StyleStack.Push(style);
|
context.StyleStack.Push(style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ namespace FlaxEngine.GUI
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var style = context.StyleStack.Peek();
|
var style = context.StyleStack.Peek();
|
||||||
style.Font = style.Font.GetItalic();
|
// style.Font = style.Font.GetItalic();
|
||||||
context.StyleStack.Push(style);
|
context.StyleStack.Push(style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,9 +136,9 @@ namespace FlaxEngine.GUI
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var style = context.StyleStack.Peek();
|
var style = context.StyleStack.Peek();
|
||||||
style.Font = new FontReference(style.Font);
|
style.Font = new MultiFontReference(style.Font);
|
||||||
TryParseNumberTag(ref tag, string.Empty, style.Font.Size, out var size);
|
TryParseNumberTag(ref tag, string.Empty, style.Font.First().Size, out var size);
|
||||||
style.Font.Size = (int)size;
|
style.Font = new MultiFontReference(style.Font, (int)size);
|
||||||
context.StyleStack.Push(style);
|
context.StyleStack.Push(style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,9 +173,9 @@ namespace FlaxEngine.GUI
|
|||||||
imageBlock.Style.BackgroundBrush = image;
|
imageBlock.Style.BackgroundBrush = image;
|
||||||
|
|
||||||
// Setup size
|
// Setup size
|
||||||
var font = imageBlock.Style.Font.GetFont();
|
var font = imageBlock.Style.Font.GetMultiFont();
|
||||||
if (font)
|
if (font)
|
||||||
imageBlock.Bounds.Size = new Float2(font.Height);
|
imageBlock.Bounds.Size = new Float2(font.MaxHeight);
|
||||||
imageBlock.Bounds.Size.X *= image.Size.X / image.Size.Y; // Keep original aspect ratio
|
imageBlock.Bounds.Size.X *= image.Size.X / image.Size.Y; // Keep original aspect ratio
|
||||||
bool hasWidth = TryParseNumberTag(ref tag, "width", imageBlock.Bounds.Width, out var width);
|
bool hasWidth = TryParseNumberTag(ref tag, "width", imageBlock.Bounds.Width, out var width);
|
||||||
imageBlock.Bounds.Width = width;
|
imageBlock.Bounds.Width = width;
|
||||||
@@ -213,18 +213,18 @@ namespace FlaxEngine.GUI
|
|||||||
style.Alignment &= ~TextBlockStyle.Alignments.VerticalMask;
|
style.Alignment &= ~TextBlockStyle.Alignments.VerticalMask;
|
||||||
switch (valign)
|
switch (valign)
|
||||||
{
|
{
|
||||||
case "top":
|
case "top":
|
||||||
style.Alignment = TextBlockStyle.Alignments.Top;
|
style.Alignment = TextBlockStyle.Alignments.Top;
|
||||||
break;
|
break;
|
||||||
case "bottom":
|
case "bottom":
|
||||||
style.Alignment = TextBlockStyle.Alignments.Bottom;
|
style.Alignment = TextBlockStyle.Alignments.Bottom;
|
||||||
break;
|
break;
|
||||||
case "middle":
|
case "middle":
|
||||||
style.Alignment = TextBlockStyle.Alignments.Middle;
|
style.Alignment = TextBlockStyle.Alignments.Middle;
|
||||||
break;
|
break;
|
||||||
case "baseline":
|
case "baseline":
|
||||||
style.Alignment = TextBlockStyle.Alignments.Baseline;
|
style.Alignment = TextBlockStyle.Alignments.Baseline;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.StyleStack.Push(style);
|
context.StyleStack.Push(style);
|
||||||
@@ -245,15 +245,15 @@ namespace FlaxEngine.GUI
|
|||||||
style.Alignment &= ~TextBlockStyle.Alignments.VerticalMask;
|
style.Alignment &= ~TextBlockStyle.Alignments.VerticalMask;
|
||||||
switch (valign)
|
switch (valign)
|
||||||
{
|
{
|
||||||
case "left":
|
case "left":
|
||||||
style.Alignment = TextBlockStyle.Alignments.Left;
|
style.Alignment = TextBlockStyle.Alignments.Left;
|
||||||
break;
|
break;
|
||||||
case "right":
|
case "right":
|
||||||
style.Alignment = TextBlockStyle.Alignments.Right;
|
style.Alignment = TextBlockStyle.Alignments.Right;
|
||||||
break;
|
break;
|
||||||
case "center":
|
case "center":
|
||||||
style.Alignment = TextBlockStyle.Alignments.Center;
|
style.Alignment = TextBlockStyle.Alignments.Center;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.StyleStack.Push(style);
|
context.StyleStack.Push(style);
|
||||||
@@ -280,7 +280,7 @@ namespace FlaxEngine.GUI
|
|||||||
foreach (var id in ids)
|
foreach (var id in ids)
|
||||||
{
|
{
|
||||||
var path = Content.GetEditorAssetPath(id);
|
var path = Content.GetEditorAssetPath(id);
|
||||||
if (!string.IsNullOrEmpty(path) &&
|
if (!string.IsNullOrEmpty(path) &&
|
||||||
string.Equals(name, System.IO.Path.GetFileNameWithoutExtension(path), System.StringComparison.OrdinalIgnoreCase))
|
string.Equals(name, System.IO.Path.GetFileNameWithoutExtension(path), System.StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return Content.LoadAsync(id, type);
|
return Content.LoadAsync(id, type);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace FlaxEngine.GUI
|
|||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
_textStyle = new TextBlockStyle
|
_textStyle = new TextBlockStyle
|
||||||
{
|
{
|
||||||
Font = new FontReference(style.FontMedium.First()),
|
Font = new MultiFontReference(style.FontMedium),
|
||||||
Color = style.Foreground,
|
Color = style.Foreground,
|
||||||
BackgroundSelectedBrush = new SolidColorBrush(style.BackgroundSelected),
|
BackgroundSelectedBrush = new SolidColorBrush(style.BackgroundSelected),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -123,10 +123,10 @@ namespace FlaxEngine.GUI
|
|||||||
if (index <= 0)
|
if (index <= 0)
|
||||||
{
|
{
|
||||||
ref TextBlock textBlock = ref textBlocks[0];
|
ref TextBlock textBlock = ref textBlocks[0];
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (font)
|
if (font)
|
||||||
{
|
{
|
||||||
height = font.Height / DpiScale;
|
height = font.MaxHeight / DpiScale;
|
||||||
return textBlock.Bounds.UpperLeft;
|
return textBlock.Bounds.UpperLeft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,10 +135,10 @@ namespace FlaxEngine.GUI
|
|||||||
if (index >= _text.Length)
|
if (index >= _text.Length)
|
||||||
{
|
{
|
||||||
ref TextBlock textBlock = ref textBlocks[count - 1];
|
ref TextBlock textBlock = ref textBlocks[count - 1];
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (font)
|
if (font)
|
||||||
{
|
{
|
||||||
height = font.Height / DpiScale;
|
height = font.MaxHeight / DpiScale;
|
||||||
return textBlock.Bounds.UpperRight;
|
return textBlock.Bounds.UpperRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,10 +150,10 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
if (textBlock.Range.Contains(index))
|
if (textBlock.Range.Contains(index))
|
||||||
{
|
{
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
break;
|
break;
|
||||||
height = font.Height / DpiScale;
|
height = font.MaxHeight / DpiScale;
|
||||||
return textBlock.Bounds.Location + font.GetCharPosition(_text, ref textBlock.Range, index - textBlock.Range.StartIndex);
|
return textBlock.Bounds.Location + font.GetCharPosition(_text, ref textBlock.Range, index - textBlock.Range.StartIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,10 +165,10 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
if (index >= textBlock.Range.EndIndex)
|
if (index >= textBlock.Range.EndIndex)
|
||||||
{
|
{
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
break;
|
break;
|
||||||
height = font.Height / DpiScale;
|
height = font.MaxHeight / DpiScale;
|
||||||
return textBlock.Bounds.UpperRight;
|
return textBlock.Bounds.UpperRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
if (containsY && (containsX || (i + 1 < count && textBlocks[i + 1].Bounds.Location.Y > textBlock.Bounds.Location.Y + 1.0f)))
|
if (containsY && (containsX || (i + 1 < count && textBlocks[i + 1].Bounds.Location.Y > textBlock.Bounds.Location.Y + 1.0f)))
|
||||||
{
|
{
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font && textBlock.Range.Length > 0)
|
if (!font && textBlock.Range.Length > 0)
|
||||||
break;
|
break;
|
||||||
return font.HitTestText(_text, ref textBlock.Range, location - textBlock.Bounds.Location) + textBlock.Range.StartIndex;
|
return font.HitTestText(_text, ref textBlock.Range, location - textBlock.Bounds.Location) + textBlock.Range.StartIndex;
|
||||||
@@ -281,7 +281,7 @@ namespace FlaxEngine.GUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pick font
|
// Pick font
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -290,7 +290,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
var leftEdge = selection.StartIndex <= textBlock.Range.StartIndex ? textBlock.Bounds.UpperLeft : font.GetCharPosition(_text, selection.StartIndex);
|
var leftEdge = selection.StartIndex <= textBlock.Range.StartIndex ? textBlock.Bounds.UpperLeft : font.GetCharPosition(_text, selection.StartIndex);
|
||||||
var rightEdge = selection.EndIndex >= textBlock.Range.EndIndex ? textBlock.Bounds.UpperRight : font.GetCharPosition(_text, selection.EndIndex);
|
var rightEdge = selection.EndIndex >= textBlock.Range.EndIndex ? textBlock.Bounds.UpperRight : font.GetCharPosition(_text, selection.EndIndex);
|
||||||
float height = font.Height / DpiScale;
|
float height = font.MaxHeight / DpiScale;
|
||||||
float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);
|
float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);
|
||||||
alpha *= alpha;
|
alpha *= alpha;
|
||||||
Color selectionColor = Color.White * alpha;
|
Color selectionColor = Color.White * alpha;
|
||||||
@@ -305,7 +305,7 @@ namespace FlaxEngine.GUI
|
|||||||
ref TextBlock textBlock = ref textBlocks[i];
|
ref TextBlock textBlock = ref textBlocks[i];
|
||||||
|
|
||||||
// Pick font
|
// Pick font
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ namespace FlaxEngine.GUI
|
|||||||
ref TextBlock textBlock = ref textBlocks[i];
|
ref TextBlock textBlock = ref textBlocks[i];
|
||||||
|
|
||||||
// Pick font
|
// Pick font
|
||||||
var font = textBlock.Style.Font.GetFont();
|
var font = textBlock.Style.Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ namespace FlaxEngine.GUI
|
|||||||
if (textBlock.Style.UnderlineBrush != null)
|
if (textBlock.Style.UnderlineBrush != null)
|
||||||
{
|
{
|
||||||
var underLineHeight = 2.0f;
|
var underLineHeight = 2.0f;
|
||||||
var height = font.Height / DpiScale;
|
var height = font.MaxHeight / DpiScale;
|
||||||
var underlineRect = new Rectangle(textBlock.Bounds.Location.X, textBlock.Bounds.Location.Y + height - underLineHeight * 0.5f, textBlock.Bounds.Width, underLineHeight);
|
var underlineRect = new Rectangle(textBlock.Bounds.Location.X, textBlock.Bounds.Location.Y + height - underLineHeight * 0.5f, textBlock.Bounds.Width, underLineHeight);
|
||||||
textBlock.Style.UnderlineBrush.Draw(underlineRect, textBlock.Style.Color);
|
textBlock.Style.UnderlineBrush.Draw(underlineRect, textBlock.Style.Color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// Gets or sets the font.
|
/// Gets or sets the font.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2024)]
|
[EditorDisplay("Text Style"), EditorOrder(2024)]
|
||||||
public FontReference Font { get; set; }
|
public MultiFontReference Font { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
||||||
@@ -90,7 +90,7 @@ namespace FlaxEngine.GUI
|
|||||||
_layout.Bounds = new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2);
|
_layout.Bounds = new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2);
|
||||||
|
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
Font = new FontReference(style.FontMedium.First());
|
Font = new MultiFontReference(style.FontMedium);
|
||||||
TextColor = style.Foreground;
|
TextColor = style.Foreground;
|
||||||
WatermarkTextColor = style.ForegroundDisabled;
|
WatermarkTextColor = style.ForegroundDisabled;
|
||||||
SelectionColor = style.BackgroundSelected;
|
SelectionColor = style.BackgroundSelected;
|
||||||
@@ -99,7 +99,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Float2 GetTextSize()
|
public override Float2 GetTextSize()
|
||||||
{
|
{
|
||||||
var font = Font.GetFont();
|
var font = Font.GetMultiFont();
|
||||||
if (font == null)
|
if (font == null)
|
||||||
{
|
{
|
||||||
return Float2.Zero;
|
return Float2.Zero;
|
||||||
@@ -111,21 +111,21 @@ namespace FlaxEngine.GUI
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Float2 GetCharPosition(int index, out float height)
|
public override Float2 GetCharPosition(int index, out float height)
|
||||||
{
|
{
|
||||||
var font = Font.GetFont();
|
var font = Font.GetMultiFont();
|
||||||
if (font == null)
|
if (font == null)
|
||||||
{
|
{
|
||||||
height = Height;
|
height = Height;
|
||||||
return Float2.Zero;
|
return Float2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
height = font.Height / DpiScale;
|
height = font.MaxHeight / DpiScale;
|
||||||
return font.GetCharPosition(_text, index, ref _layout);
|
return font.GetCharPosition(_text, index, ref _layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int HitTestText(Float2 location)
|
public override int HitTestText(Float2 location)
|
||||||
{
|
{
|
||||||
var font = Font.GetFont();
|
var font = Font.GetMultiFont();
|
||||||
if (font == null)
|
if (font == null)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -148,7 +148,7 @@ namespace FlaxEngine.GUI
|
|||||||
// Cache data
|
// Cache data
|
||||||
var rect = new Rectangle(Float2.Zero, Size);
|
var rect = new Rectangle(Float2.Zero, Size);
|
||||||
bool enabled = EnabledInHierarchy;
|
bool enabled = EnabledInHierarchy;
|
||||||
var font = Font.GetFont();
|
var font = Font.GetMultiFont();
|
||||||
if (!font)
|
if (!font)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
var leftEdge = font.GetCharPosition(_text, SelectionLeft, ref _layout);
|
var leftEdge = font.GetCharPosition(_text, SelectionLeft, ref _layout);
|
||||||
var rightEdge = font.GetCharPosition(_text, SelectionRight, ref _layout);
|
var rightEdge = font.GetCharPosition(_text, SelectionRight, ref _layout);
|
||||||
float fontHeight = font.Height / DpiScale;
|
float fontHeight = font.MaxHeight / DpiScale;
|
||||||
|
|
||||||
// Draw selection background
|
// Draw selection background
|
||||||
float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);
|
float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// Gets or sets the font used to render panel header text.
|
/// Gets or sets the font used to render panel header text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Header Text Style"), EditorOrder(2020), ExpandGroups]
|
[EditorDisplay("Header Text Style"), EditorOrder(2020), ExpandGroups]
|
||||||
public FontReference HeaderTextFont { get; set; }
|
public MultiFontReference HeaderTextFont { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
||||||
@@ -238,7 +238,7 @@ namespace FlaxEngine.GUI
|
|||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
HeaderColor = style.BackgroundNormal;
|
HeaderColor = style.BackgroundNormal;
|
||||||
HeaderColorMouseOver = style.BackgroundHighlighted;
|
HeaderColorMouseOver = style.BackgroundHighlighted;
|
||||||
HeaderTextFont = new FontReference(style.FontMedium.First());
|
HeaderTextFont = new MultiFontReference(style.FontMedium);
|
||||||
HeaderTextColor = style.Foreground;
|
HeaderTextColor = style.Foreground;
|
||||||
ArrowImageOpened = new SpriteBrush(style.ArrowDown);
|
ArrowImageOpened = new SpriteBrush(style.ArrowDown);
|
||||||
ArrowImageClosed = new SpriteBrush(style.ArrowRight);
|
ArrowImageClosed = new SpriteBrush(style.ArrowRight);
|
||||||
@@ -375,7 +375,7 @@ namespace FlaxEngine.GUI
|
|||||||
textColor *= 0.6f;
|
textColor *= 0.6f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Render2D.DrawText(HeaderTextFont.GetFont(), HeaderTextMaterial, HeaderText, textRect, textColor, TextAlignment.Near, TextAlignment.Center);
|
Render2D.DrawText(HeaderTextFont.GetMultiFont(), HeaderTextMaterial, HeaderText, textRect, textColor, TextAlignment.Near, TextAlignment.Center);
|
||||||
|
|
||||||
if (!_isClosed && EnableContainmentLines)
|
if (!_isClosed && EnableContainmentLines)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,68 +14,60 @@ namespace FlaxEngine.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static Style Current { get; set; }
|
public static Style Current { get; set; }
|
||||||
|
|
||||||
public Font FontCJK
|
|
||||||
{
|
|
||||||
get => _fontCJK?.GetFont();
|
|
||||||
set => _fontCJK = new FontReference(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private FontReference _fontCJK;
|
|
||||||
|
|
||||||
[Serialize]
|
[Serialize]
|
||||||
private FontReference _fontTitle;
|
private MultiFontReference _fontTitle;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font title.
|
/// The font title.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NoSerialize]
|
[NoSerialize]
|
||||||
[EditorOrder(10)]
|
[EditorOrder(10)]
|
||||||
public Font FontTitle
|
public MultiFont FontTitle
|
||||||
{
|
{
|
||||||
get => _fontTitle?.GetFont();
|
get => _fontTitle?.GetMultiFont();
|
||||||
set => _fontTitle = new FontReference(value);
|
set => _fontTitle = new MultiFontReference(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serialize]
|
[Serialize]
|
||||||
private FontReference _fontLarge;
|
private MultiFontReference _fontLarge;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font large.
|
/// The font large.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NoSerialize]
|
[NoSerialize]
|
||||||
[EditorOrder(20)]
|
[EditorOrder(20)]
|
||||||
public Font FontLarge
|
public MultiFont FontLarge
|
||||||
{
|
{
|
||||||
get => _fontLarge?.GetFont();
|
get => _fontLarge?.GetMultiFont();
|
||||||
set => _fontLarge = new FontReference(value);
|
set => _fontLarge = new MultiFontReference(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serialize]
|
[Serialize]
|
||||||
private FontReference[] _fontMedium;
|
private MultiFontReference _fontMedium;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font medium.
|
/// The font medium.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NoSerialize]
|
[NoSerialize]
|
||||||
[EditorOrder(30)]
|
[EditorOrder(30)]
|
||||||
public Font[] FontMedium
|
public MultiFont FontMedium
|
||||||
{
|
{
|
||||||
get => _fontMedium?.Select((x)=>x.GetFont()).ToArray();
|
get => _fontMedium?.GetMultiFont();
|
||||||
set => _fontMedium = value.Select((x)=>new FontReference(x)).ToArray();
|
set => _fontMedium = new MultiFontReference(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serialize]
|
[Serialize]
|
||||||
private FontReference[] _fontSmall;
|
private MultiFontReference _fontSmall;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font small.
|
/// The font small.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[NoSerialize]
|
[NoSerialize]
|
||||||
[EditorOrder(40)]
|
[EditorOrder(40)]
|
||||||
public Font[] FontSmall
|
public MultiFont FontSmall
|
||||||
{
|
{
|
||||||
get => _fontSmall?.Select((x) => x.GetFont()).ToArray();
|
get => _fontSmall?.GetMultiFont();
|
||||||
set => _fontSmall = value.Select((x) => new FontReference(x)).ToArray();
|
set => _fontSmall = new MultiFontReference(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// The text font.
|
/// The text font.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(0)]
|
[EditorOrder(0)]
|
||||||
public FontReference Font;
|
public MultiFontReference Font;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The custom material for the text rendering (must be GUI domain).
|
/// The custom material for the text rendering (must be GUI domain).
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ namespace FlaxEngine.GUI
|
|||||||
TextAlignment.Center,
|
TextAlignment.Center,
|
||||||
TextWrapping.WrapWords
|
TextWrapping.WrapWords
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -256,14 +257,14 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
// Calculate size of the tooltip
|
// Calculate size of the tooltip
|
||||||
var size = Float2.Zero;
|
var size = Float2.Zero;
|
||||||
if (style != null && style.FontMedium.First() && !string.IsNullOrEmpty(_currentText))
|
if (style != null && style.FontMedium && !string.IsNullOrEmpty(_currentText))
|
||||||
{
|
{
|
||||||
var layout = TextLayoutOptions.Default;
|
var layout = TextLayoutOptions.Default;
|
||||||
layout.Bounds = new Rectangle(0, 0, MaxWidth, 10000000);
|
layout.Bounds = new Rectangle(0, 0, MaxWidth, 10000000);
|
||||||
layout.HorizontalAlignment = TextAlignment.Center;
|
layout.HorizontalAlignment = TextAlignment.Center;
|
||||||
layout.VerticalAlignment = TextAlignment.Center;
|
layout.VerticalAlignment = TextAlignment.Center;
|
||||||
layout.TextWrapping = TextWrapping.WrapWords;
|
layout.TextWrapping = TextWrapping.WrapWords;
|
||||||
var items = style.FontMedium.First().ProcessText(_currentText, ref layout);
|
var items = style.FontMedium.ProcessText(_currentText, ref layout);
|
||||||
for (int i = 0; i < items.Length; i++)
|
for (int i = 0; i < items.Length; i++)
|
||||||
{
|
{
|
||||||
ref var item = ref items[i];
|
ref var item = ref items[i];
|
||||||
|
|||||||
Reference in New Issue
Block a user