1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-16 04:25:23 +00:00

Added textbox. Added keyboard manager. Added name entry.

This commit is contained in:
Tim Sarbin 2018-11-23 20:51:32 -05:00
parent 4c020c13bc
commit 1983d0d40e
11 changed files with 221 additions and 9 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -8,6 +9,6 @@ namespace OpenDiablo2.Common.Interfaces
{
public interface IFont : IDisposable
{
Size CalculateSize(string text);
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenDiablo2.Common.Interfaces
{
public delegate void OnKeyPressed(char charcode);
public interface IKeyboardInfoProvider
{
OnKeyPressed KeyPressCallback { get; set; }
bool KeyIsPressed(int scancode);
}
}

View File

@ -74,6 +74,7 @@
<Compile Include="Enums\eMPQFormatVersion.cs" />
<Compile Include="Interfaces\IFont.cs" />
<Compile Include="Interfaces\IGameEngine.cs" />
<Compile Include="Interfaces\IKeyboardInfoProvider.cs" />
<Compile Include="Interfaces\ILabel.cs" />
<Compile Include="Interfaces\IMPQProvider.cs" />
<Compile Include="Interfaces\IMusicProvider.cs" />

View File

@ -93,6 +93,7 @@ namespace OpenDiablo2.Common
public static string WideButtonBlank = "data\\global\\ui\\FrontEnd\\WideButtonBlank.dc6";
public static string MediumButtonBlank = "data\\global\\ui\\FrontEnd\\MediumButtonBlank.dc6";
public static string CancelButton = "data\\global\\ui\\FrontEnd\\CancelButtonBlank.dc6";
public static string TextBox2 = "data\\global\\ui\\FrontEnd\\textbox2.dc6";
// --- Data ---
// TODO: Doesn't sound right :)

View File

@ -22,6 +22,8 @@ namespace OpenDiablo2.Core
builder.RegisterType<ResourceManager>().As<IResourceManager>().SingleInstance();
builder.RegisterType<TextDictionary>().As<ITextDictionary>().SingleInstance();
builder.RegisterType<Button>().AsSelf().InstancePerDependency();
builder.RegisterType<TextBox>().AsSelf().InstancePerDependency();
}
}
}

View File

@ -79,6 +79,7 @@
<Compile Include="ResourceManager.cs" />
<Compile Include="TextDictionary.cs" />
<Compile Include="UI\Button.cs" />
<Compile Include="UI\TextBox.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenDiablo2.Common\OpenDiablo2.Common.csproj">

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenDiablo2.Common;
using OpenDiablo2.Common.Interfaces;
namespace OpenDiablo2.Core.UI
{
public sealed class TextBox
{
private readonly IRenderWindow renderWindow;
private ISprite sprite;
private IFont font;
private ILabel label, linebar;
private float frameTime = 0f;
private Point location = new Point();
public Point Location
{
get => location;
set
{
if (location == value)
return;
location = value;
label.Location = new Point(value.X + 6, value.Y + 3);
linebar.Location = new Point(value.X + 6 + label.TextArea.Width, value.Y + 3);
sprite.Location = new Point(value.X, value.Y + sprite.LocalFrameSize.Height);
}
}
private string text = "";
public string Text
{
get => text;
set
{
if (text == value)
return;
text = value;
// Max width is 130
var newSize = font.CalculateSize(value);
if (newSize.Width < 130)
{
label.Text = value;
linebar.Location = new Point(location.X + 6 + newSize.Width, location.Y + 3);
return;
}
var newStr = value.Substring(1);
while(true)
{
newSize = font.CalculateSize(newStr);
if (newSize.Width >= 130)
{
newStr = newStr.Substring(1);
continue;
}
label.Text = newStr;
linebar.Location = new Point(location.X + 6 + newSize.Width, location.Y + 3);
break;
}
}
}
public TextBox(IRenderWindow renderWindow)
{
this.renderWindow = renderWindow;
sprite = renderWindow.LoadSprite(ResourcePaths.TextBox2, Palettes.Units);
font = renderWindow.LoadFont(ResourcePaths.FontFormal11, Palettes.Units);
label = renderWindow.CreateLabel(font);
linebar = renderWindow.CreateLabel(font);
linebar.Text = "_";
}
public void Update(long ms)
{
frameTime += ms / 500f;
while (frameTime >= 1f)
frameTime -= 1f;
}
public void Render()
{
renderWindow.Draw(sprite);
renderWindow.Draw(label);
if (frameTime < 0.5)
renderWindow.Draw(linebar);
}
}
}

View File

@ -2,6 +2,7 @@
using OpenDiablo2.Common.Models;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -30,5 +31,18 @@ namespace OpenDiablo2.SDL2_
{
sprite.Dispose();
}
public Size CalculateSize(string text)
{
int w = 0;
int h = 0;
foreach(byte ch in text)
{
w += font.CharacterMetric[ch].Width;
h = Math.Max(h, font.CharacterMetric[ch].Height);
}
return new Size(w, h);
}
}
}

View File

@ -9,10 +9,11 @@ using System.IO;
using System.Drawing;
using OpenDiablo2.Common.Models;
using Autofac;
using System.Runtime.InteropServices;
namespace OpenDiablo2.SDL2_
{
public sealed class SDL2RenderWindow : IRenderWindow, IRenderTarget, IMouseInfoProvider
public sealed class SDL2RenderWindow : IRenderWindow, IRenderTarget, IMouseInfoProvider, IKeyboardInfoProvider
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
@ -25,6 +26,8 @@ namespace OpenDiablo2.SDL2_
public bool RightMouseDown { get; internal set; } = false;
public bool ReserveMouse { get; set; } = false;
public OnKeyPressed KeyPressCallback { get; set; }
private readonly IMPQProvider mpqProvider;
private readonly IPaletteProvider paletteProvider;
private readonly IResourceManager resourceManager;
@ -51,8 +54,8 @@ namespace OpenDiablo2.SDL2_
if (renderer == IntPtr.Zero)
throw new ApplicationException($"Unable to create SDL Window: {SDL.SDL_GetError()}");
SDL.SDL_SetRenderDrawBlendMode(renderer, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
SDL.SDL_SetRenderDrawBlendMode(renderer, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
SDL.SDL_ShowCursor(0);
IsRunning = true;
@ -68,6 +71,14 @@ namespace OpenDiablo2.SDL2_
SDL.SDL_Quit();
}
public unsafe bool KeyIsPressed(int scancode)
{
int numKeys;
byte* keys = (byte*)SDL.SDL_GetKeyboardState(out numKeys);
return keys[scancode] > 0;
}
public void Clear()
{
SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero);
@ -81,7 +92,7 @@ namespace OpenDiablo2.SDL2_
SDL.SDL_RenderPresent(renderer);
}
public void Update()
public unsafe void Update()
{
while (SDL.SDL_PollEvent(out SDL.SDL_Event evt) != 0)
{
@ -117,6 +128,16 @@ namespace OpenDiablo2.SDL2_
break;
}
}
else if (evt.type == SDL.SDL_EventType.SDL_KEYDOWN)
{
if (evt.key.keysym.sym == SDL.SDL_Keycode.SDLK_BACKSPACE && KeyPressCallback != null)
KeyPressCallback('\b');
}
else if (evt.type == SDL.SDL_EventType.SDL_TEXTINPUT)
{
KeyPressCallback?.Invoke(Marshal.PtrToStringAnsi((IntPtr)evt.text.text)[0]);
continue;
}
else if (evt.type == SDL.SDL_EventType.SDL_QUIT)
{

View File

@ -53,14 +53,16 @@ namespace OpenDiablo2.Scenes
private readonly IMusicProvider musicProvider;
private readonly ISceneManager sceneManager;
private readonly ITextDictionary textDictionary;
private readonly IKeyboardInfoProvider keyboardInfoProvider;
private bool showEntryUi = false;
private eHero? selectedHero = null;
private float secondTimer;
private ISprite backgroundSprite, campfireSprite;
private IFont headingFont, heroDescFont;
private ILabel headingLabel, heroClassLabel, heroDesc1Label, heroDesc2Label, heroDesc3Label;
private IFont headingFont, heroDescFont, uiFont;
private ILabel headingLabel, heroClassLabel, heroDesc1Label, heroDesc2Label, heroDesc3Label, characterNameLabel;
private Button exitButton, okButton;
private TextBox characterNameTextBox;
private Dictionary<eHero, HeroRenderInfo> heroRenderInfo = new Dictionary<eHero, HeroRenderInfo>();
public SelectHeroClass(
@ -71,7 +73,9 @@ namespace OpenDiablo2.Scenes
IMusicProvider musicProvider,
ISceneManager sceneManager,
Func<eButtonType, Button> createButton,
ITextDictionary textDictionary
Func<TextBox> createTextBox,
ITextDictionary textDictionary,
IKeyboardInfoProvider keyboardInfoProvider
)
{
this.renderWindow = renderWindow;
@ -80,6 +84,7 @@ namespace OpenDiablo2.Scenes
this.mouseInfoProvider = mouseInfoProvider;
this.sceneManager = sceneManager;
this.textDictionary = textDictionary;
this.keyboardInfoProvider = keyboardInfoProvider;
backgroundSprite = renderWindow.LoadSprite(ResourcePaths.CharacterSelectBackground, Palettes.Fechar);
@ -195,6 +200,7 @@ namespace OpenDiablo2.Scenes
headingFont = renderWindow.LoadFont(ResourcePaths.Font30, Palettes.Units);
heroDescFont = renderWindow.LoadFont(ResourcePaths.Font16, Palettes.Units);
uiFont = renderWindow.LoadFont(ResourcePaths.Font16, Palettes.Units);
headingLabel = renderWindow.CreateLabel(headingFont);
headingLabel.Text = textDictionary.Translate("strSelectHeroClass");
@ -208,17 +214,26 @@ namespace OpenDiablo2.Scenes
heroDesc2Label = renderWindow.CreateLabel(heroDescFont);
heroDesc3Label = renderWindow.CreateLabel(heroDescFont);
characterNameLabel = renderWindow.CreateLabel(uiFont);
characterNameLabel.Text = "Character Name"; // TODO Translation table
characterNameLabel.Location = new Point(320, 475);
characterNameLabel.TextColor = Color.FromArgb(216, 196, 128);
exitButton = createButton(eButtonType.Medium);
exitButton.Text = "EXIT";
exitButton.Text = "EXIT"; // TODO Translation table
exitButton.Location = new Point(30, 540);
exitButton.OnActivate = OnExitClicked;
okButton = createButton(eButtonType.Medium);
okButton.Text = "OK";
okButton.Text = "OK"; // TODO Translation table
okButton.Location = new Point(630, 540);
okButton.OnActivate = OnOkclicked;
okButton.Enabled = false;
characterNameTextBox = createTextBox();
characterNameTextBox.Text = "";
characterNameTextBox.Location = new Point(320, 493);
}
private void OnOkclicked()
@ -235,6 +250,9 @@ namespace OpenDiablo2.Scenes
heroRenderInfo[hero].Stance = eHeroStance.Idle;
}
showEntryUi = false;
keyboardInfoProvider.KeyPressCallback = null;
characterNameTextBox.Text = "";
okButton.Enabled = false;
sceneManager.ChangeScene("Main Menu");
}
@ -258,7 +276,11 @@ namespace OpenDiablo2.Scenes
exitButton.Render();
if (showEntryUi)
{
renderWindow.Draw(characterNameLabel);
okButton.Render();
characterNameTextBox.Render();
}
}
private void RenderHeros()
@ -312,6 +334,27 @@ namespace OpenDiablo2.Scenes
}
private void OnKeyPressed(char charcode)
{
if (charcode == '\b')
{
if (characterNameTextBox.Text.Length == 0)
return;
characterNameTextBox.Text = characterNameTextBox.Text.Substring(0, characterNameTextBox.Text.Length - 1);
okButton.Enabled = characterNameTextBox.Text.Length >= 2;
return;
}
if (characterNameTextBox.Text.Length >= 15)
return;
if (!"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(charcode))
return;
characterNameTextBox.Text += charcode;
okButton.Enabled = characterNameTextBox.Text.Length >= 2;
}
public void Update(long ms)
{
float seconds = ((float)ms / 1500f);
@ -319,6 +362,9 @@ namespace OpenDiablo2.Scenes
while (secondTimer >= 1f)
secondTimer -= 1f;
if (keyboardInfoProvider.KeyPressCallback == null)
keyboardInfoProvider.KeyPressCallback = OnKeyPressed;
// Don't update hero selection if one of them is walking to or from the campfire
var canSelect = heroRenderInfo.All(x => x.Value.Stance == eHeroStance.Idle || x.Value.Stance == eHeroStance.IdleSelected || x.Value.Stance == eHeroStance.Selected);
@ -332,6 +378,7 @@ namespace OpenDiablo2.Scenes
exitButton.Update();
okButton.Update();
characterNameTextBox.Update(ms);
}
private void UpdateHeroSelectionHover(eHero hero, long ms, bool canSelect)

View File

@ -72,6 +72,13 @@ namespace OpenDiablo2
return (buttonType) => componentContext.Resolve<Button>(new NamedParameter("buttonLayout", ButtonLayout.Values[buttonType]));
});
/* Uncomment the below if we support multiple textbox types
containerBuilder.Register<Func<TextBox>>(c =>
{
var componentContext = c.Resolve<IComponentContext>();
return () => componentContext.Resolve<TextBox>();
});
*/
return containerBuilder;
}