mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-24 12:06:37 +00:00
A mix between Tiled and GUI stuff (#553)
* mostly restored the tiled importer unit tests * code cleanup * code cleanup * almost got tiled maps serialization independent of the content pipeline * refactored the tiled map content importer so that tiled maps can be loaded at runtime * code cleanup * removed nuspec files * experimenting with an XML based GUI markup parser * a few more markup parser features * finally got a working open file dialog * experimenting with markup bindings * attached properties * working on the gui stuff again * working on a better textbox * multiline textboxing * new text box is really coming along * removed the content explorer experiment * restored the old gui demo back to the way it was before (for now)
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MonoGame.Extended.Input.InputListeners;
|
||||
|
||||
namespace MonoGame.Extended.Gui.Controls
|
||||
{
|
||||
public class TextBox2 : Control
|
||||
{
|
||||
public TextBox2()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public TextBox2(string text)
|
||||
{
|
||||
Text = text ?? string.Empty;
|
||||
HorizontalTextAlignment = HorizontalAlignment.Left;
|
||||
VerticalTextAlignment = VerticalAlignment.Top;
|
||||
}
|
||||
|
||||
|
||||
private const float _caretBlinkRate = 0.53f;
|
||||
private float _nextCaretBlink = _caretBlinkRate;
|
||||
private bool _isCaretVisible = true;
|
||||
|
||||
private readonly List<StringBuilder> _lines = new List<StringBuilder>();
|
||||
public string Text
|
||||
{
|
||||
get => string.Concat(_lines.SelectMany(s => $"{s}\n"));
|
||||
set
|
||||
{
|
||||
_lines.Clear();
|
||||
|
||||
var line = new StringBuilder();
|
||||
|
||||
for (var i = 0; i < value.Length; i++)
|
||||
{
|
||||
var c = value[i];
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
_lines.Add(line);
|
||||
line = new StringBuilder();
|
||||
}
|
||||
else if(c != '\r')
|
||||
{
|
||||
line.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
_lines.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
public int CaretIndex => ColumnIndex * LineIndex + ColumnIndex;
|
||||
public int LineIndex { get; set; }
|
||||
public int ColumnIndex { get; set; }
|
||||
public int TabStops { get; set; } = 4;
|
||||
|
||||
public override IEnumerable<Control> Children => Enumerable.Empty<Control>();
|
||||
|
||||
public string GetLineText(int lineIndex) => _lines[lineIndex].ToString();
|
||||
public int GetLineLength(int lineIndex) => _lines[lineIndex].Length;
|
||||
|
||||
public override Size GetContentSize(IGuiContext context)
|
||||
{
|
||||
var font = Font ?? context.DefaultFont;
|
||||
var stringSize = (Size)font.MeasureString(Text ?? string.Empty);
|
||||
return new Size(stringSize.Width, stringSize.Height < font.LineHeight ? font.LineHeight : stringSize.Height);
|
||||
}
|
||||
|
||||
public override bool OnKeyPressed(IGuiContext context, KeyboardEventArgs args)
|
||||
{
|
||||
switch (args.Key)
|
||||
{
|
||||
case Keys.Tab:
|
||||
Tab();
|
||||
break;
|
||||
case Keys.Back:
|
||||
Backspace();
|
||||
break;
|
||||
case Keys.Delete:
|
||||
Delete();
|
||||
break;
|
||||
case Keys.Left:
|
||||
Left();
|
||||
break;
|
||||
case Keys.Right:
|
||||
Right();
|
||||
break;
|
||||
case Keys.Up:
|
||||
Up();
|
||||
break;
|
||||
case Keys.Down:
|
||||
Down();
|
||||
break;
|
||||
case Keys.Home:
|
||||
Home();
|
||||
break;
|
||||
case Keys.End:
|
||||
End();
|
||||
break;
|
||||
case Keys.Enter:
|
||||
Type('\n');
|
||||
return true;
|
||||
default:
|
||||
if (args.Character.HasValue)
|
||||
Type(args.Character.Value);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
_isCaretVisible = true;
|
||||
return base.OnKeyPressed(context, args);
|
||||
}
|
||||
|
||||
public void Type(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
var lineText = GetLineText(LineIndex);
|
||||
var left = lineText.Substring(0, ColumnIndex);
|
||||
var right = lineText.Substring(ColumnIndex);
|
||||
_lines.Insert(LineIndex + 1, new StringBuilder(right));
|
||||
_lines[LineIndex] = new StringBuilder(left);
|
||||
LineIndex++;
|
||||
Home();
|
||||
break;
|
||||
case '\t':
|
||||
Tab();
|
||||
break;
|
||||
default:
|
||||
_lines[LineIndex].Insert(ColumnIndex, c);
|
||||
ColumnIndex++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Backspace()
|
||||
{
|
||||
if (ColumnIndex == 0 && LineIndex > 0)
|
||||
{
|
||||
var topLineLength = GetLineLength(LineIndex - 1);
|
||||
|
||||
if (RemoveLineBreak(LineIndex - 1))
|
||||
{
|
||||
LineIndex--;
|
||||
ColumnIndex = topLineLength;
|
||||
}
|
||||
}
|
||||
else if (Left())
|
||||
{
|
||||
RemoveCharacter(LineIndex, ColumnIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
var lineLength = GetLineLength(LineIndex);
|
||||
|
||||
if (ColumnIndex == lineLength)
|
||||
RemoveLineBreak(LineIndex);
|
||||
else
|
||||
RemoveCharacter(LineIndex, ColumnIndex);
|
||||
}
|
||||
|
||||
public void RemoveCharacter(int lineIndex, int columnIndex)
|
||||
{
|
||||
_lines[lineIndex].Remove(columnIndex, 1);
|
||||
}
|
||||
|
||||
public bool RemoveLineBreak(int lineIndex)
|
||||
{
|
||||
if (lineIndex < _lines.Count - 1)
|
||||
{
|
||||
var topLine = _lines[lineIndex];
|
||||
var bottomLine = _lines[lineIndex + 1];
|
||||
_lines.RemoveAt(lineIndex + 1);
|
||||
topLine.Append(bottomLine);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Home()
|
||||
{
|
||||
ColumnIndex = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool End()
|
||||
{
|
||||
ColumnIndex = GetLineLength(LineIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Up()
|
||||
{
|
||||
if (LineIndex > 0)
|
||||
{
|
||||
LineIndex--;
|
||||
|
||||
if (ColumnIndex > GetLineLength(LineIndex))
|
||||
ColumnIndex = GetLineLength(LineIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Down()
|
||||
{
|
||||
if (LineIndex < _lines.Count - 1)
|
||||
{
|
||||
LineIndex++;
|
||||
|
||||
if (ColumnIndex > GetLineLength(LineIndex))
|
||||
ColumnIndex = GetLineLength(LineIndex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Left()
|
||||
{
|
||||
if (ColumnIndex == 0)
|
||||
{
|
||||
if (LineIndex == 0)
|
||||
return false;
|
||||
|
||||
LineIndex--;
|
||||
ColumnIndex = GetLineLength(LineIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
ColumnIndex--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Right()
|
||||
{
|
||||
if (ColumnIndex == _lines[LineIndex].Length)
|
||||
{
|
||||
if (LineIndex == _lines.Count - 1)
|
||||
return false;
|
||||
|
||||
LineIndex++;
|
||||
ColumnIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ColumnIndex++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Tab()
|
||||
{
|
||||
var spaces = TabStops - ColumnIndex % TabStops;
|
||||
|
||||
for (var s = 0; s < spaces; s++)
|
||||
Type(' ');
|
||||
|
||||
return spaces > 0;
|
||||
}
|
||||
|
||||
public override void Draw(IGuiContext context, IGuiRenderer renderer, float deltaSeconds)
|
||||
{
|
||||
base.Draw(context, renderer, deltaSeconds);
|
||||
|
||||
var text = Text;
|
||||
var textInfo = GetTextInfo(context, text, ContentRectangle, HorizontalTextAlignment, VerticalTextAlignment);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(textInfo.Text))
|
||||
renderer.DrawText(textInfo.Font, textInfo.Text, textInfo.Position + TextOffset, textInfo.Color, textInfo.ClippingRectangle);
|
||||
|
||||
if (IsFocused)
|
||||
{
|
||||
var caretRectangle = GetCaretRectangle(textInfo);
|
||||
|
||||
if (_isCaretVisible)
|
||||
renderer.DrawRectangle(caretRectangle, TextColor);
|
||||
|
||||
_nextCaretBlink -= deltaSeconds;
|
||||
|
||||
if (_nextCaretBlink <= 0)
|
||||
{
|
||||
_isCaretVisible = !_isCaretVisible;
|
||||
_nextCaretBlink = _caretBlinkRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Rectangle GetCaretRectangle(TextInfo textInfo)
|
||||
{
|
||||
var font = textInfo.Font;
|
||||
var text = GetLineText(LineIndex);
|
||||
var offset = new Vector2(0, font.LineHeight * LineIndex);
|
||||
var caretRectangle = font.GetStringRectangle(text.Substring(0, ColumnIndex), textInfo.Position + offset);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return (Rectangle)caretRectangle;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user