add Gwen UI input processor and renderer implementations (ported)
This commit is contained in:
parent
6e13c6434e
commit
a5a83dd7dc
|
@ -177,6 +177,8 @@
|
|||
<Compile Include="Content\Types\ImageLoader.cs" />
|
||||
<Compile Include="Content\Types\TextureLoader.cs" />
|
||||
<Compile Include="Content\Types\SpriteFontLoader.cs" />
|
||||
<Compile Include="UI\GwenInputProcessor.cs" />
|
||||
<Compile Include="UI\GwenSpriteBatchRenderer.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -199,6 +201,7 @@
|
|||
<Folder Include="Processes\" />
|
||||
<Folder Include="Content\" />
|
||||
<Folder Include="Content\Types\" />
|
||||
<Folder Include="UI\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Fonts\Vera.ttf" />
|
||||
|
|
221
Blarg.GameFramework/UI/GwenInputProcessor.cs
Normal file
221
Blarg.GameFramework/UI/GwenInputProcessor.cs
Normal file
|
@ -0,0 +1,221 @@
|
|||
using System;
|
||||
using Blarg.GameFramework.Input;
|
||||
|
||||
namespace Blarg.GameFramework.UI
|
||||
{
|
||||
public class GwenInputProcessor : IKeyboardListener, IMouseListener, ITouchListener
|
||||
{
|
||||
Gwen.Control.Canvas _canvas;
|
||||
bool _isEnabled;
|
||||
|
||||
public GwenInputProcessor(Gwen.Control.Canvas canvas)
|
||||
{
|
||||
if (canvas == null)
|
||||
throw new ArgumentNullException("canvas");
|
||||
|
||||
_canvas = canvas;
|
||||
}
|
||||
|
||||
#region Enable / Disable
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get { return _isEnabled; }
|
||||
set { _isEnabled = Enable(value); }
|
||||
}
|
||||
|
||||
private bool Enable(bool enable)
|
||||
{
|
||||
if (_isEnabled != enable)
|
||||
{
|
||||
var keyboard = Framework.Keyboard;
|
||||
var mouse = Framework.Mouse;
|
||||
var touchscreen = Framework.TouchScreen;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
if (keyboard != null)
|
||||
keyboard.RegisterListener(this);
|
||||
if (mouse != null)
|
||||
mouse.RegisterListener(this);
|
||||
if (touchscreen != null)
|
||||
touchscreen.RegisterListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (keyboard != null)
|
||||
keyboard.UnregisterListener(this);
|
||||
if (mouse != null)
|
||||
mouse.UnregisterListener(this);
|
||||
if (touchscreen != null)
|
||||
touchscreen.UnregisterListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
return enable;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keyboard Events
|
||||
|
||||
public bool OnKeyDown(Key key)
|
||||
{
|
||||
char ch = ConvertKeyToChar(key);
|
||||
if (Gwen.Input.InputHandler.DoSpecialKeys(_canvas, ch))
|
||||
return false;
|
||||
|
||||
var gwenKey = ConvertToGwenKey(key);
|
||||
return _canvas.Input_Key(gwenKey, true);
|
||||
}
|
||||
|
||||
public bool OnKeyUp(Key key)
|
||||
{
|
||||
var gwenKey = ConvertToGwenKey(key);
|
||||
return _canvas.Input_Key(gwenKey, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mouse Events
|
||||
|
||||
public bool OnMouseButtonDown(MouseButton button, int x, int y)
|
||||
{
|
||||
int gwenButton = (int)button;
|
||||
|
||||
int scaledX = (int)((float)x / _canvas.Scale);
|
||||
int scaledY = (int)((float)y / _canvas.Scale);
|
||||
|
||||
// trigger mouse move event for button events to ensure GWEN
|
||||
// knows where the button event occured at
|
||||
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, 0, 0);
|
||||
bool clickResult = _canvas.Input_MouseButton(gwenButton, true);
|
||||
|
||||
// TODO: is this really the right way to do this .. ?
|
||||
return (movedResult || clickResult);
|
||||
}
|
||||
|
||||
public bool OnMouseButtonUp(MouseButton button, int x, int y)
|
||||
{
|
||||
int gwenButton = (int)button;
|
||||
|
||||
int scaledX = (int)((float)x / _canvas.Scale);
|
||||
int scaledY = (int)((float)y / _canvas.Scale);
|
||||
|
||||
// trigger mouse move event for button events to ensure GWEN
|
||||
// knows where the button event occured at
|
||||
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, 0, 0);
|
||||
bool clickResult = _canvas.Input_MouseButton(gwenButton, false);
|
||||
|
||||
// TODO: is this really the right way to do this .. ?
|
||||
return (movedResult || clickResult);
|
||||
}
|
||||
|
||||
public bool OnMouseMove(int x, int y, int deltaX, int deltaY)
|
||||
{
|
||||
// Gwen's input handling only processes coordinates in terms of scale = 1.0f
|
||||
int scaledX = (int)((float)x / _canvas.Scale);
|
||||
int scaledY = (int)((float)y / _canvas.Scale);
|
||||
int scaledDeltaX = (int)((float)deltaX / _canvas.Scale);
|
||||
int scaledDeltaY = (int)((float)deltaY / _canvas.Scale);
|
||||
|
||||
return _canvas.Input_MouseMoved(scaledX, scaledY, scaledDeltaX, scaledDeltaY);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Touchscreen Events
|
||||
|
||||
public bool OnTouchDown(int id, int x, int y, bool isPrimary)
|
||||
{
|
||||
if (!isPrimary)
|
||||
return false;
|
||||
|
||||
// Gwen's input handling only processes coordinates in terms of scale = 1.0f
|
||||
int scaledX = (int)((float)x / _canvas.Scale);
|
||||
int scaledY = (int)((float)y / _canvas.Scale);
|
||||
|
||||
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, 0, 0);
|
||||
bool clickResult = _canvas.Input_MouseButton(0, true);
|
||||
|
||||
// TODO: is this really the right way to do this .. ?
|
||||
return (movedResult || clickResult);
|
||||
}
|
||||
|
||||
public bool OnTouchUp(int id, bool isPrimary)
|
||||
{
|
||||
if (!isPrimary)
|
||||
return false;
|
||||
|
||||
bool clickResult = _canvas.Input_MouseButton(0, false);
|
||||
|
||||
// we do this so that GWEN isn't left thinking that the "mouse" is
|
||||
// hovering over whatever we were just clicking/touching. This is
|
||||
// done because obviously with a touchscreen, you don't hover over
|
||||
// anything unless you are clicking/touching...
|
||||
bool movedResult = _canvas.Input_MouseMoved(-1, -1, 0, 0);
|
||||
|
||||
// TODO: is this really the right way to do this .. ?
|
||||
return (movedResult || clickResult);
|
||||
}
|
||||
|
||||
public bool OnTouchMove(int id, int x, int y, int deltaX, int deltaY, bool isPrimary)
|
||||
{
|
||||
if (!isPrimary)
|
||||
return false;
|
||||
|
||||
// Gwen's input handling only processes coordinates in terms of scale = 1.0f
|
||||
int scaledX = (int)((float)x / _canvas.Scale);
|
||||
int scaledY = (int)((float)y / _canvas.Scale);
|
||||
int scaledDeltaX = (int)((float)deltaX / _canvas.Scale);
|
||||
int scaledDeltaY = (int)((float)deltaY / _canvas.Scale);
|
||||
|
||||
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, scaledDeltaX, scaledDeltaY);
|
||||
bool clickResult = _canvas.Input_MouseButton(0, true);
|
||||
|
||||
// TODO: is this really the right way to do this .. ?
|
||||
return (movedResult || clickResult);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc
|
||||
|
||||
private char ConvertKeyToChar(Key key)
|
||||
{
|
||||
if (key >= Key.A && key <= Key.Z)
|
||||
return (char)('a' + ((int)key - (int)Key.A));
|
||||
else
|
||||
return ' ';
|
||||
}
|
||||
|
||||
private Gwen.Key ConvertToGwenKey(Key key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case Key.Backspace: return Gwen.Key.Backspace;
|
||||
case Key.Enter: return Gwen.Key.Return;
|
||||
case Key.Escape: return Gwen.Key.Escape;
|
||||
case Key.Tab: return Gwen.Key.Tab;
|
||||
case Key.Space: return Gwen.Key.Space;
|
||||
case Key.Up: return Gwen.Key.Up;
|
||||
case Key.Down: return Gwen.Key.Down;
|
||||
case Key.Left: return Gwen.Key.Left;
|
||||
case Key.Right: return Gwen.Key.Right;
|
||||
case Key.Home: return Gwen.Key.Home;
|
||||
case Key.End: return Gwen.Key.End;
|
||||
case Key.Delete: return Gwen.Key.Delete;
|
||||
case Key.LeftCtrl: return Gwen.Key.Control;
|
||||
case Key.LeftAlt: return Gwen.Key.Alt;
|
||||
case Key.LeftShift: return Gwen.Key.Shift;
|
||||
case Key.RightCtrl: return Gwen.Key.Control;
|
||||
case Key.RightAlt: return Gwen.Key.Alt;
|
||||
case Key.RightShift: return Gwen.Key.Shift;
|
||||
}
|
||||
|
||||
return Gwen.Key.Invalid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
210
Blarg.GameFramework/UI/GwenSpriteBatchRenderer.cs
Normal file
210
Blarg.GameFramework/UI/GwenSpriteBatchRenderer.cs
Normal file
|
@ -0,0 +1,210 @@
|
|||
using System;
|
||||
using Blarg.GameFramework.Content;
|
||||
using Blarg.GameFramework.Graphics;
|
||||
|
||||
namespace Blarg.GameFramework.UI
|
||||
{
|
||||
public class GwenSpriteBatchRenderer : Gwen.Renderer.Base
|
||||
{
|
||||
const string LOG_TAG = "GWEN";
|
||||
|
||||
ContentManager _contentManager;
|
||||
GraphicsDevice _graphicsDevice;
|
||||
SpriteBatch _spriteBatch;
|
||||
|
||||
public GwenSpriteBatchRenderer(ContentManager contentManager, GraphicsDevice graphicsDevice)
|
||||
{
|
||||
if (contentManager == null)
|
||||
throw new ArgumentNullException("contentManager");
|
||||
if (graphicsDevice == null)
|
||||
throw new ArgumentNullException("graphicsDevice");
|
||||
|
||||
_contentManager = contentManager;
|
||||
_graphicsDevice = graphicsDevice;
|
||||
Alpha = Color.AlphaOpaque;
|
||||
}
|
||||
|
||||
#region Begin / End
|
||||
|
||||
public void PreRender(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (spriteBatch == null)
|
||||
throw new ArgumentNullException("spriteBatch");
|
||||
|
||||
_spriteBatch = spriteBatch;
|
||||
}
|
||||
|
||||
public void PostRender()
|
||||
{
|
||||
_spriteBatch = null;
|
||||
}
|
||||
|
||||
public override void Begin()
|
||||
{
|
||||
if (_spriteBatch == null)
|
||||
throw new InvalidOperationException();
|
||||
base.Begin();
|
||||
}
|
||||
|
||||
public override void End()
|
||||
{
|
||||
base.End();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rendering States / Properties
|
||||
|
||||
public float Alpha { get; set; }
|
||||
|
||||
public override void StartClip()
|
||||
{
|
||||
var rect = ClipRegion;
|
||||
|
||||
int left = (int)((float)rect.X * Scale);
|
||||
int top = (int)((float)rect.Y * Scale);
|
||||
int right = (int)((float)(rect.X + rect.Width) * Scale);
|
||||
int bottom = (int)((float)(rect.Y + rect.Height) * Scale);
|
||||
|
||||
_spriteBatch.BeginClipping(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public override void EndClip()
|
||||
{
|
||||
_spriteBatch.EndClipping();
|
||||
}
|
||||
|
||||
private void AdjustColorForAlpha(ref Color color)
|
||||
{
|
||||
color.A *= Alpha;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region General Rendering Operations
|
||||
|
||||
public override void DrawFilledRect(Gwen.Rectangle rect)
|
||||
{
|
||||
Translate(rect);
|
||||
|
||||
var renderColor = new Color((int)DrawColor.R, (int)DrawColor.G, (int)DrawColor.B, (int)DrawColor.A);
|
||||
AdjustColorForAlpha(ref renderColor);
|
||||
|
||||
// TODO: this solid color texture should probably be grabbed using a color
|
||||
// that has A = 1.0 always otherwise any kind of fading, etc. will
|
||||
// result in many different solid color's ending up in the solid color
|
||||
// texture cache (due to all the different A values!)
|
||||
var colorTexture = _graphicsDevice.GetSolidColorTexture(ref renderColor);
|
||||
|
||||
_spriteBatch.Render(colorTexture, rect.X, rect.Y, rect.Width, rect.Height);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Textured Rendering
|
||||
|
||||
public override void LoadTexture(Gwen.Texture t)
|
||||
{
|
||||
Framework.Logger.Info(LOG_TAG, "SpriteBatchRenderer loading texture \"{0}\".", t.Name);
|
||||
var texture = _contentManager.Get<Texture>(t.Name);
|
||||
|
||||
t.RendererData = texture;
|
||||
t.Width = texture.Width;
|
||||
t.Height = texture.Height;
|
||||
}
|
||||
|
||||
public override void FreeTexture(Gwen.Texture t)
|
||||
{
|
||||
// right now we don't care, ContentManager.RemoveAlLContent() can and will take care of this
|
||||
// (Gwen doesn't really load too many resources that I think we really need to care about this)
|
||||
}
|
||||
|
||||
public override void DrawTexturedRect(Gwen.Texture t, Gwen.Rectangle targetRect, float u1, float v1, float u2, float v2)
|
||||
{
|
||||
if (t.RendererData == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Translate(targetRect);
|
||||
var texture = (Texture)t.RendererData;
|
||||
|
||||
var renderColor = Color.White;
|
||||
AdjustColorForAlpha(ref renderColor);
|
||||
|
||||
_spriteBatch.Render(texture, targetRect.X, targetRect.Y, targetRect.Width, targetRect.Height, u1, v1, u2, v2, ref renderColor);
|
||||
}
|
||||
|
||||
public override Gwen.Color PixelColor(Gwen.Texture texture, uint x, uint y, Gwen.Color defaultColor)
|
||||
{
|
||||
if (texture.RendererData == null)
|
||||
return defaultColor;
|
||||
|
||||
// This method is really only used by Gwen to figure out various "system" colors
|
||||
// at initialization time. Pixel colors are read from the renderer skin texture
|
||||
// pretty sure no other textures are ever used with this method. Unless some
|
||||
// future custom control eventually is needed to read pixel colors...
|
||||
//
|
||||
// We load the image using ContentManager, but it won't be released... at least
|
||||
// not until the next ContentManager.RemoveAllContent() call (not done by this class)
|
||||
// I feel that this is fine given the above about only one texture (and therefore
|
||||
// only one image) being ever read by this method.
|
||||
|
||||
var image = _contentManager.Get<Image>(texture.Name);
|
||||
var pixelColor = image.GetColorAt((int)x, (int)y);
|
||||
|
||||
return Gwen.Color.FromArgb(pixelColor.IntA, pixelColor.IntR, pixelColor.IntG, pixelColor.IntB);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Font Rendering
|
||||
|
||||
public override bool LoadFont(Gwen.Font font)
|
||||
{
|
||||
Framework.Logger.Info(LOG_TAG, "SpriteBatchRenderer loading font \"{0}\".", font.FaceName);
|
||||
int size = font.Size;
|
||||
var spriteFont = _contentManager.Get<SpriteFont>(font.FaceName, size);
|
||||
|
||||
font.RendererData = spriteFont;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void FreeFont(Gwen.Font font)
|
||||
{
|
||||
// right now we don't care, ContentManager.RemoveAlLContent() can and will take care of this
|
||||
// (Gwen doesn't really load too many resources that I think we really need to care about this)
|
||||
}
|
||||
|
||||
public override void RenderText(Gwen.Font font, Gwen.Point position, string text)
|
||||
{
|
||||
Translate(position);
|
||||
var spriteFont = (SpriteFont)font.RendererData;
|
||||
|
||||
var renderColor = new Color((int)DrawColor.R, (int)DrawColor.G, (int)DrawColor.B, (int)DrawColor.A);
|
||||
AdjustColorForAlpha(ref renderColor);
|
||||
|
||||
_spriteBatch.Render(spriteFont, position.X, position.Y, ref renderColor, Scale, text);
|
||||
}
|
||||
|
||||
public override Gwen.Point MeasureText(Gwen.Font font, string text)
|
||||
{
|
||||
// HACK: is this supposed to work this way? seems that MeasureText
|
||||
// can (and will) get called from Gwen's classes before a call
|
||||
// to LoadFont is made...
|
||||
if (font.RendererData == null)
|
||||
LoadFont(font);
|
||||
|
||||
if (font.RendererData == null)
|
||||
throw new Exception("Failed to load font.");
|
||||
|
||||
var spriteFont = (SpriteFont)font.RendererData;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
spriteFont.MeasureString(out width, out height, text);
|
||||
|
||||
return new Gwen.Point(width, height);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Reference in a new issue