Use enums for ActionTypes in InputField, use ReadOnlySpan<char> for Font measurements, only measure placeholderSize if the input is empty.

This commit is contained in:
2026-06-01 22:30:54 +02:00
parent 828ff3561b
commit 7bbfab8359
2 changed files with 35 additions and 21 deletions

View File

@@ -83,16 +83,26 @@ public class Font : Resource, IUpdatableResource, IDisposable
/// <returns>A <see cref="Rect"/> with the sizes of a given text using this font.</returns> /// <returns>A <see cref="Rect"/> with the sizes of a given text using this font.</returns>
public Rect Measure(string text) public Rect Measure(string text)
{ {
if (string.IsNullOrEmpty(text)) return Measure(text.AsSpan());
}
/// <summary>
/// Measures a given <see cref="ReadOnlySpan"/> of characters.
/// </summary>
/// <param name="chars"></param>
/// <returns>A <see cref="Rect"/> with the sizes of a given text using this font.</returns>
public Rect Measure(ReadOnlySpan<char> chars)
{
if (chars.Length == 0)
return Rect.Zero; return Rect.Zero;
float totalWidth = 0; float totalWidth = 0;
float maxAscent = 0; float maxAscent = 0;
float maxDescent = 0; float maxDescent = 0;
for (int i = 0; i < text.Length; i++) for (int i = 0; i < chars.Length; i++)
{ {
char c = text[i]; char c = chars[i];
Glyph glyph = GetGlyph(c); Glyph glyph = GetGlyph(c);
totalWidth += glyph.Advance * SpacingScale + LetterSpacing; totalWidth += glyph.Advance * SpacingScale + LetterSpacing;
@@ -107,7 +117,7 @@ public class Font : Resource, IUpdatableResource, IDisposable
if (i > 0) if (i > 0)
{ {
char prevChar = text[i - 1]; char prevChar = chars[i - 1];
totalWidth += GetKerning(prevChar, c); totalWidth += GetKerning(prevChar, c);
} }
} }

View File

@@ -7,6 +7,8 @@ namespace Voile.UI.Widgets;
public class InputField : Widget, ITickableElement public class InputField : Widget, ITickableElement
{ {
enum ActionType { None, Backspace, Left, Right }
public override Rect MinimumSize => _placeholderSize + _padding; public override Rect MinimumSize => _placeholderSize + _padding;
public override string? StyleElementName => nameof(InputField); public override string? StyleElementName => nameof(InputField);
@@ -58,7 +60,7 @@ public class InputField : Widget, ITickableElement
if (!_isFocused) if (!_isFocused)
{ {
_lastActiveAction = string.Empty; _lastActiveAction = ActionType.None;
_repeatTimer = 0.0f; _repeatTimer = 0.0f;
return; return;
} }
@@ -100,15 +102,15 @@ public class InputField : Widget, ITickableElement
private void HandleRepeatingActions(float dt, InputSystem input) private void HandleRepeatingActions(float dt, InputSystem input)
{ {
string currentAction = string.Empty; ActionType currentAction = ActionType.None;
if (input.IsKeyboardKeyDown(KeyboardKey.Backspace)) currentAction = "backspace"; if (input.IsKeyboardKeyDown(KeyboardKey.Backspace)) currentAction = ActionType.Backspace;
else if (input.IsKeyboardKeyDown(KeyboardKey.Left)) currentAction = "left"; else if (input.IsKeyboardKeyDown(KeyboardKey.Left)) currentAction = ActionType.Left;
else if (input.IsKeyboardKeyDown(KeyboardKey.Right)) currentAction = "right"; else if (input.IsKeyboardKeyDown(KeyboardKey.Right)) currentAction = ActionType.Right;
if (string.IsNullOrEmpty(currentAction)) if (currentAction == ActionType.None)
{ {
_lastActiveAction = string.Empty; _lastActiveAction = ActionType.None;
_repeatTimer = 0.0f; _repeatTimer = 0.0f;
return; return;
} }
@@ -138,11 +140,11 @@ public class InputField : Widget, ITickableElement
} }
} }
private void ExecuteAction(string actionName) private void ExecuteAction(ActionType action)
{ {
switch (actionName) switch (action)
{ {
case "backspace": case ActionType.Backspace:
if (_cursor > 0 && _input.Length > 0) if (_cursor > 0 && _input.Length > 0)
{ {
_input = _input.Remove(_cursor - 1, 1); _input = _input.Remove(_cursor - 1, 1);
@@ -151,7 +153,7 @@ public class InputField : Widget, ITickableElement
} }
break; break;
case "left": case ActionType.Left:
if (_cursor > 0) if (_cursor > 0)
{ {
_cursor--; _cursor--;
@@ -159,7 +161,7 @@ public class InputField : Widget, ITickableElement
} }
break; break;
case "right": case ActionType.Right:
if (_cursor < _input.Length) if (_cursor < _input.Length)
{ {
_cursor++; _cursor++;
@@ -211,7 +213,7 @@ public class InputField : Widget, ITickableElement
// Caret // Caret
if (_isFocused && _blink) if (_isFocused && _blink)
{ {
var caretX = MeasureTextWidth(_input.Substring(0, _cursor)); var caretX = MeasureTextWidth(_input.AsSpan(0, _cursor));
renderer.SetTransform( renderer.SetTransform(
new Vector2(GlobalPosition.X + caretX + _padding.Left, GlobalPosition.Y + _padding.Top), new Vector2(GlobalPosition.X + caretX + _padding.Left, GlobalPosition.Y + _padding.Top),
@@ -247,7 +249,9 @@ public class InputField : Widget, ITickableElement
var font = _suitableFont.Value; var font = _suitableFont.Value;
_textSize = font.Measure(_input); _textSize = font.Measure(_input);
_placeholderSize = font.Measure(PlaceholderText);
if (string.IsNullOrEmpty(_input))
_placeholderSize = font.Measure(PlaceholderText);
} }
var size = Rect.MaxWidth(_placeholderSize, _textSize); var size = Rect.MaxWidth(_placeholderSize, _textSize);
@@ -255,18 +259,18 @@ public class InputField : Widget, ITickableElement
Size = _padding + size; Size = _padding + size;
} }
private float MeasureTextWidth(string text) private float MeasureTextWidth(ReadOnlySpan<char> chars)
{ {
if (!_suitableFont.HasValue) if (!_suitableFont.HasValue)
{ {
return 0.0f; return 0.0f;
} }
return _suitableFont.Value.Measure(text).Width; return _suitableFont.Value.Measure(chars).Width;
} }
private float _repeatTimer = 0.0f; private float _repeatTimer = 0.0f;
private string _lastActiveAction = string.Empty; private ActionType _lastActiveAction = ActionType.None;
private const float INITIAL_DELAY = 0.5f; private const float INITIAL_DELAY = 0.5f;
private const float REPEAT_RATE = 0.05f; private const float REPEAT_RATE = 0.05f;