diff --git a/Source/MonoGame.Extended.Gui/Controls/GuiButton.cs b/Source/MonoGame.Extended.Gui/Controls/GuiButton.cs index 49532413..252228e0 100644 --- a/Source/MonoGame.Extended.Gui/Controls/GuiButton.cs +++ b/Source/MonoGame.Extended.Gui/Controls/GuiButton.cs @@ -48,9 +48,9 @@ namespace MonoGame.Extended.Gui.Controls private bool _isPointerDown; - public override void OnPointerDown(GuiPointerEventArgs args) + public override void OnPointerDown(IGuiContext context, GuiPointerEventArgs args) { - base.OnPointerDown(args); + base.OnPointerDown(context, args); if (IsEnabled) { @@ -59,9 +59,9 @@ namespace MonoGame.Extended.Gui.Controls } } - public override void OnPointerUp(GuiPointerEventArgs args) + public override void OnPointerUp(IGuiContext context, GuiPointerEventArgs args) { - base.OnPointerUp(args); + base.OnPointerUp(context, args); _isPointerDown = false; @@ -74,17 +74,17 @@ namespace MonoGame.Extended.Gui.Controls } } - public override void OnPointerEnter(GuiPointerEventArgs args) + public override void OnPointerEnter(IGuiContext context, GuiPointerEventArgs args) { - base.OnPointerEnter(args); + base.OnPointerEnter(context, args); if (IsEnabled && _isPointerDown) IsPressed = true; } - public override void OnPointerLeave(GuiPointerEventArgs args) + public override void OnPointerLeave(IGuiContext context, GuiPointerEventArgs args) { - base.OnPointerLeave(args); + base.OnPointerLeave(context, args); if (IsEnabled) IsPressed = false; diff --git a/Source/MonoGame.Extended.Gui/Controls/GuiCheckBox.cs b/Source/MonoGame.Extended.Gui/Controls/GuiCheckBox.cs index 24641fcf..bc3f967d 100644 --- a/Source/MonoGame.Extended.Gui/Controls/GuiCheckBox.cs +++ b/Source/MonoGame.Extended.Gui/Controls/GuiCheckBox.cs @@ -47,15 +47,15 @@ namespace MonoGame.Extended.Gui.Controls } } - public override void OnPointerUp(GuiPointerEventArgs args) + public override void OnPointerUp(IGuiContext context, GuiPointerEventArgs args) { - base.OnPointerUp(args); + base.OnPointerUp(context, args); if (IsFocused && BoundingRectangle.Contains(args.Position)) IsChecked = !IsChecked; } - protected override void DrawBackground(IGuiRenderer renderer, float deltaSeconds) + protected override void DrawBackground(IGuiContext context, IGuiRenderer renderer, float deltaSeconds) { var boundingRectangle = BoundingRectangle; var checkRectangle = new Rectangle(boundingRectangle.X, boundingRectangle.Y, BackgroundRegion.Width, BackgroundRegion.Height); @@ -63,12 +63,12 @@ namespace MonoGame.Extended.Gui.Controls renderer.DrawRegion(BackgroundRegion, checkRectangle, Color); } - protected override void DrawText(IGuiRenderer renderer, float deltaSeconds, TextInfo textInfo) + protected override void DrawText(IGuiContext context, IGuiRenderer renderer, float deltaSeconds, TextInfo textInfo) { textInfo.Position = BoundingRectangle.Location.ToVector2() + new Vector2(BackgroundRegion.Width + 5, BackgroundRegion.Height * 0.5f - textInfo.Font.LineHeight * 0.5f); - base.DrawText(renderer, deltaSeconds, textInfo); + base.DrawText(context, renderer, deltaSeconds, textInfo); } } } diff --git a/Source/MonoGame.Extended.Gui/Controls/GuiControl.cs b/Source/MonoGame.Extended.Gui/Controls/GuiControl.cs index b29f243f..314cb635 100644 --- a/Source/MonoGame.Extended.Gui/Controls/GuiControl.cs +++ b/Source/MonoGame.Extended.Gui/Controls/GuiControl.cs @@ -116,45 +116,45 @@ namespace MonoGame.Extended.Gui.Controls } } - public virtual void OnKeyTyped(KeyboardEventArgs args) { } - public virtual void OnKeyPressed(KeyboardEventArgs args) { } + public virtual void OnKeyTyped(IGuiContext context, KeyboardEventArgs args) { } + public virtual void OnKeyPressed(IGuiContext context, KeyboardEventArgs args) { } - public virtual void OnPointerDown(GuiPointerEventArgs args) { } - public virtual void OnPointerUp(GuiPointerEventArgs args) { } + public virtual void OnPointerDown(IGuiContext context, GuiPointerEventArgs args) { } + public virtual void OnPointerUp(IGuiContext context, GuiPointerEventArgs args) { } - public virtual void OnPointerEnter(GuiPointerEventArgs args) + public virtual void OnPointerEnter(IGuiContext context, GuiPointerEventArgs args) { if (IsEnabled) HoverStyle?.Apply(this); } - public virtual void OnPointerLeave(GuiPointerEventArgs args) + public virtual void OnPointerLeave(IGuiContext context, GuiPointerEventArgs args) { if (IsEnabled) HoverStyle?.Revert(this); } - public void Draw(IGuiRenderer renderer, float deltaSeconds) + public void Draw(IGuiContext context, IGuiRenderer renderer, float deltaSeconds) { - DrawBackground(renderer, deltaSeconds); - DrawText(renderer, deltaSeconds, GetTextInfo(renderer, Text)); + DrawBackground(context, renderer, deltaSeconds); + DrawText(context, renderer, deltaSeconds, GetTextInfo(context, Text)); } - protected TextInfo GetTextInfo(IGuiRenderer renderer, string text) + protected TextInfo GetTextInfo(IGuiContext context, string text) { - var font = Font ?? renderer.DefaultFont; + var font = Font ?? context.DefaultFont; var textSize = font.GetStringRectangle(text ?? string.Empty, Vector2.Zero).Size.ToVector2(); var textPosition = BoundingRectangle.Center.ToVector2() - textSize * 0.5f; var textInfo = new TextInfo(text, font, textPosition, textSize, TextColor, ClippingRectangle); return textInfo; } - protected virtual void DrawBackground(IGuiRenderer renderer, float deltaSeconds) + protected virtual void DrawBackground(IGuiContext context, IGuiRenderer renderer, float deltaSeconds) { renderer.DrawRegion(BackgroundRegion, BoundingRectangle, Color); } - protected virtual void DrawText(IGuiRenderer renderer, float deltaSeconds, TextInfo textInfo) + protected virtual void DrawText(IGuiContext context, IGuiRenderer renderer, float deltaSeconds, TextInfo textInfo) { if (!string.IsNullOrWhiteSpace(textInfo.Text)) renderer.DrawText(textInfo.Font, textInfo.Text, textInfo.Position + TextOffset, textInfo.Color, textInfo.ClippingRectangle); diff --git a/Source/MonoGame.Extended.Gui/Controls/GuiProgressBar.cs b/Source/MonoGame.Extended.Gui/Controls/GuiProgressBar.cs index 7a429f9b..95a87d75 100644 --- a/Source/MonoGame.Extended.Gui/Controls/GuiProgressBar.cs +++ b/Source/MonoGame.Extended.Gui/Controls/GuiProgressBar.cs @@ -34,9 +34,9 @@ namespace MonoGame.Extended.Gui.Controls public event EventHandler ProgressChanged; - protected override void DrawBackground(IGuiRenderer renderer, float deltaSeconds) + protected override void DrawBackground(IGuiContext context, IGuiRenderer renderer, float deltaSeconds) { - base.DrawBackground(renderer, deltaSeconds); + base.DrawBackground(context, renderer, deltaSeconds); var boundingRectangle = BoundingRectangle; var clippingRectangle = new Rectangle(boundingRectangle.X, boundingRectangle.Y, (int)(boundingRectangle.Width * Progress), boundingRectangle.Height); diff --git a/Source/MonoGame.Extended.Gui/Controls/GuiTextBox.cs b/Source/MonoGame.Extended.Gui/Controls/GuiTextBox.cs index 97f54a13..6cf30021 100644 --- a/Source/MonoGame.Extended.Gui/Controls/GuiTextBox.cs +++ b/Source/MonoGame.Extended.Gui/Controls/GuiTextBox.cs @@ -1,3 +1,5 @@ +using System.Linq; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using MonoGame.Extended.Input.InputListeners; using MonoGame.Extended.TextureAtlases; @@ -25,17 +27,37 @@ namespace MonoGame.Extended.Gui.Controls public int SelectionStart { get; set; } public char? PasswordCharacter { get; set; } - public override void OnPointerDown(GuiPointerEventArgs args) + public override void OnPointerDown(IGuiContext context, GuiPointerEventArgs args) { - base.OnPointerDown(args); - - SelectionStart = Text.Length; + base.OnPointerDown(context, args); + + SelectionStart = FindNearestGlyphIndex(context, args.Position); _isCaretVisible = true; } - public override void OnKeyPressed(KeyboardEventArgs args) + private int FindNearestGlyphIndex(IGuiContext context, Point position) { - base.OnKeyPressed(args); + var font = Font ?? context.DefaultFont; + var textInfo = GetTextInfo(context, Text); + var glyphs = font.GetGlyphs(textInfo.Text, textInfo.Position); + + for (var i = 0; i < glyphs.Length; i++) + { + var glyph = glyphs[i]; + var glyphMiddle = (int)(glyph.Position.X + glyph.FontRegion.Width * 0.5f); + + if (position.X >= glyphMiddle) + continue; + + return i; + } + + return glyphs.Length; + } + + public override void OnKeyPressed(IGuiContext context, KeyboardEventArgs args) + { + base.OnKeyPressed(context, args); switch (args.Key) { @@ -74,10 +96,10 @@ namespace MonoGame.Extended.Gui.Controls private float _nextCaretBlink = _caretBlinkRate; private bool _isCaretVisible = true; - protected override void DrawText(IGuiRenderer renderer, float deltaSeconds, TextInfo textInfo) + protected override void DrawText(IGuiContext context, IGuiRenderer renderer, float deltaSeconds, TextInfo textInfo) { if (PasswordCharacter.HasValue) - textInfo = GetTextInfo(renderer, new string(PasswordCharacter.Value, textInfo.Text.Length)); + textInfo = GetTextInfo(context, new string(PasswordCharacter.Value, textInfo.Text.Length)); var caretRectangle = textInfo.Font.GetStringRectangle(textInfo.Text.Substring(0, SelectionStart), textInfo.Position); @@ -91,7 +113,7 @@ namespace MonoGame.Extended.Gui.Controls caretRectangle.X = caretRectangle.Right < ClippingRectangle.Right ? caretRectangle.Right : ClippingRectangle.Right; caretRectangle.Width = 1; - base.DrawText(renderer, deltaSeconds, textInfo); + base.DrawText(context, renderer, deltaSeconds, textInfo); if (IsFocused) { diff --git a/Source/MonoGame.Extended.Gui/GuiSpriteBatchRenderer.cs b/Source/MonoGame.Extended.Gui/GuiSpriteBatchRenderer.cs index 137e27ea..ab82f610 100644 --- a/Source/MonoGame.Extended.Gui/GuiSpriteBatchRenderer.cs +++ b/Source/MonoGame.Extended.Gui/GuiSpriteBatchRenderer.cs @@ -9,7 +9,6 @@ namespace MonoGame.Extended.Gui { public interface IGuiRenderer { - BitmapFont DefaultFont { get; } void Begin(); void DrawRegion(TextureRegion2D textureRegion, Rectangle rectangle, Color color, Rectangle? clippingRectangle = null); void DrawRegion(TextureRegion2D textureRegion, Vector2 position, Color color, Rectangle? clippingRectangle = null); @@ -26,11 +25,9 @@ namespace MonoGame.Extended.Gui public GuiSpriteBatchRenderer(GraphicsDevice graphicsDevice, BitmapFont defaultFont, Func getTransformMatrix) { _getTransformMatrix = getTransformMatrix; - DefaultFont = defaultFont; _spriteBatch = new SpriteBatch(graphicsDevice); } - public BitmapFont DefaultFont { get; } public SpriteSortMode SortMode { get; set; } public BlendState BlendState { get; set; } = BlendState.AlphaBlend; public SamplerState SamplerState { get; set; } = SamplerState.PointClamp; @@ -62,7 +59,7 @@ namespace MonoGame.Extended.Gui public void DrawText(BitmapFont font, string text, Vector2 position, Color color, Rectangle? clippingRectangle = null) { - _spriteBatch.DrawString(font ?? DefaultFont, text, position, color, clippingRectangle); + _spriteBatch.DrawString(font, text, position, color, clippingRectangle); } public void DrawRectangle(Rectangle rectangle, Color color, float thickness = 1f) diff --git a/Source/MonoGame.Extended.Gui/GuiSystem.cs b/Source/MonoGame.Extended.Gui/GuiSystem.cs index cc1a69eb..1a30c549 100644 --- a/Source/MonoGame.Extended.Gui/GuiSystem.cs +++ b/Source/MonoGame.Extended.Gui/GuiSystem.cs @@ -1,12 +1,19 @@ using System.Linq; using Microsoft.Xna.Framework; +using MonoGame.Extended.BitmapFonts; using MonoGame.Extended.Gui.Controls; using MonoGame.Extended.Input.InputListeners; using MonoGame.Extended.ViewportAdapters; namespace MonoGame.Extended.Gui { - public class GuiSystem + public interface IGuiContext + { + BitmapFont DefaultFont { get; } + Vector2 CursorPosition { get; } + } + + public class GuiSystem : IGuiContext { private readonly IGuiRenderer _renderer; private readonly MouseListener _mouseListener; @@ -32,12 +39,13 @@ namespace MonoGame.Extended.Gui _touchListener.TouchEnded += (s, e) => OnPointerUp(GuiPointerEventArgs.FromTouchArgs(e)); _keyboardListener = new KeyboardListener(); - _keyboardListener.KeyTyped += (sender, args) => _focusedControl?.OnKeyTyped(args); - _keyboardListener.KeyPressed += (sender, args) => _focusedControl?.OnKeyPressed(args); + _keyboardListener.KeyTyped += (sender, args) => _focusedControl?.OnKeyTyped(this, args); + _keyboardListener.KeyPressed += (sender, args) => _focusedControl?.OnKeyPressed(this, args); } public GuiScreen Screen { get; set; } public Vector2 CursorPosition { get; set; } + public BitmapFont DefaultFont => Screen?.Skin?.DefaultFont; public void Update(GameTime gameTime) { @@ -68,7 +76,7 @@ namespace MonoGame.Extended.Gui private void DrawChildren(GuiControlCollection controls, float deltaSeconds) { foreach (var control in controls.Where(c => c.IsVisible)) - control.Draw(_renderer, deltaSeconds); + control.Draw(this, _renderer, deltaSeconds); foreach (var childControl in controls.Where(c => c.IsVisible)) DrawChildren(childControl.Controls, deltaSeconds); @@ -80,7 +88,7 @@ namespace MonoGame.Extended.Gui return; _preFocusedControl = FindControlAtPoint(Screen.Controls, args.Position); - _hoveredControl?.OnPointerDown(args); + _hoveredControl?.OnPointerDown(this, args); } private void OnPointerUp(GuiPointerEventArgs args) @@ -107,7 +115,7 @@ namespace MonoGame.Extended.Gui } _preFocusedControl = null; - _hoveredControl?.OnPointerUp(args); + _hoveredControl?.OnPointerUp(this, args); } private void OnPointerMoved(GuiPointerEventArgs args) @@ -121,9 +129,9 @@ namespace MonoGame.Extended.Gui if (_hoveredControl != hoveredControl) { - _hoveredControl?.OnPointerLeave(args); + _hoveredControl?.OnPointerLeave(this, args); _hoveredControl = hoveredControl; - _hoveredControl?.OnPointerEnter(args); + _hoveredControl?.OnPointerEnter(this, args); } }