Files
MonoGame.Extended/Source/MonoGame.Extended.Gui/Controls/GuiTextBox.cs
T
Dylan Wilson b3a631aff5 Gui dialogs (#410)
* started refactoring for gui windows

* a bit more work on gui windows

* fixed some bugs and broken build stuff

* fixed some bugs in gui controls

* a little code cleanup

* got gui dialogs positioning and experimenting with named styles by type

* apply control styles directly in the constructor of controls

* got everything compiling again

* all gui controls have skinnable constructors

* rework uniform grid desired size calculations

* turns out gui layouts are complicated

* include pdb files in nuget packages

* fixed a bug in find nearest glyph

* custom control styling

* added a range constructor overload that takes one value

* rethinking control desired size behaviour

* made particle emitters more editable at runtime

* moved the auto trigger code to the particle effect instead of the emitters

* tweaks

* changed the particle modifer interface to an abstract base with an optional name

* changed the particle modifer interface to an abstract base with an optional name

* an attempt at creating a gui combo box

* rolled back the nested control experiment

* pretty good (but not perfect) combo boxes

* tweaks

* name property bindings on lists

* removed and cleaned up the hacks from the gui combo box

* minor combo box styling tweaks

* minor bug fix in gui combo box

* experiments with data binding

* fixed a mistake on the texture region service interface

* working on the ability to serialize particles

* finished particle serialization

* more robust range deserialization

* added editor browable attributes

* fixed some broken demos

* made the particle modifiers editable at runtime

* fixed some issues with particle serialization

* fixed some issues with interpolators
2017-07-22 21:22:13 +10:00

147 lines
5.0 KiB
C#

using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using MonoGame.Extended.Input.InputListeners;
namespace MonoGame.Extended.Gui.Controls
{
public class GuiTextBox : GuiControl
{
public GuiTextBox()
: this(null)
{
}
public GuiTextBox(GuiSkin skin, string text = null)
: base(skin)
{
Text = text ?? string.Empty;
}
public int SelectionStart { get; set; }
public char? PasswordCharacter { get; set; }
protected override void OnTextChanged()
{
if (SelectionStart > Text.Length)
SelectionStart = Text.Length;
base.OnTextChanged();
}
public override void OnPointerDown(IGuiContext context, GuiPointerEventArgs args)
{
base.OnPointerDown(context, args);
SelectionStart = FindNearestGlyphIndex(context, args.Position);
_isCaretVisible = true;
}
private int FindNearestGlyphIndex(IGuiContext context, Point position)
{
var font = Font ?? context.DefaultFont;
var textInfo = GetTextInfo(context, Text, BoundingRectangle, HorizontalAlignment.Centre, VerticalAlignment.Centre);
var i = 0;
foreach (var glyph in font.GetGlyphs(textInfo.Text, textInfo.Position))
{
var fontRegionWidth = glyph.FontRegion?.Width ?? 0;
var glyphMiddle = (int)(glyph.Position.X + fontRegionWidth * 0.5f);
if (position.X >= glyphMiddle)
{
i++;
continue;
}
return i;
}
return i;
}
public override void OnKeyPressed(IGuiContext context, KeyboardEventArgs args)
{
base.OnKeyPressed(context, args);
switch (args.Key)
{
case Keys.Back:
if (SelectionStart > 0 && Text.Length > 0)
{
SelectionStart--;
Text = Text.Remove(SelectionStart, 1);
}
break;
case Keys.Delete:
if (SelectionStart < Text.Length)
Text = Text.Remove(SelectionStart, 1);
break;
case Keys.Left:
if (SelectionStart > 0)
SelectionStart--;
break;
case Keys.Right:
if (SelectionStart < Text.Length)
SelectionStart++;
break;
case Keys.Home:
SelectionStart = 0;
break;
case Keys.End:
SelectionStart = Text.Length;
break;
default:
if (args.Character != null)
{
Text = Text.Insert(SelectionStart, args.Character.ToString());
SelectionStart++;
}
break;
}
_isCaretVisible = true;
}
private const float _caretBlinkRate = 0.53f;
private float _nextCaretBlink = _caretBlinkRate;
private bool _isCaretVisible = true;
protected override void DrawForeground(IGuiContext context, IGuiRenderer renderer, float deltaSeconds, TextInfo textInfo)
{
if (PasswordCharacter.HasValue)
textInfo = GetTextInfo(context, new string(PasswordCharacter.Value, textInfo.Text.Length), BoundingRectangle, HorizontalAlignment.Centre, VerticalAlignment.Centre);
var caretRectangle = textInfo.Font.GetStringRectangle(textInfo.Text.Substring(0, SelectionStart), textInfo.Position);
// TODO: Finish the caret position stuff when it's outside the clipping rectangle
if (caretRectangle.Right > ClippingRectangle.Right)
textInfo.Position.X -= caretRectangle.Right - ClippingRectangle.Right;
caretRectangle.X = caretRectangle.Right < ClippingRectangle.Right ? caretRectangle.Right : ClippingRectangle.Right;
caretRectangle.Width = 1;
if (caretRectangle.Left < ClippingRectangle.Left)
{
textInfo.Position.X += ClippingRectangle.Left - caretRectangle.Left;
caretRectangle.X = ClippingRectangle.Left;
}
base.DrawForeground(context, renderer, deltaSeconds, textInfo);
if (IsFocused)
{
if (_isCaretVisible)
renderer.DrawRectangle((Rectangle)caretRectangle, TextColor);
_nextCaretBlink -= deltaSeconds;
if (_nextCaretBlink <= 0)
{
_isCaretVisible = !_isCaretVisible;
_nextCaretBlink = _caretBlinkRate;
}
}
}
}
}