diff --git a/OpenDiablo2.Common/Enums/eTextAlign.cs b/OpenDiablo2.Common/Enums/eTextAlign.cs new file mode 100644 index 00000000..6201688e --- /dev/null +++ b/OpenDiablo2.Common/Enums/eTextAlign.cs @@ -0,0 +1,9 @@ +namespace OpenDiablo2.Common.Enums +{ + public enum eTextAlign + { + Centered = 0, + Left, + Right + } +} diff --git a/OpenDiablo2.Common/Interfaces/ILabel.cs b/OpenDiablo2.Common/Interfaces/ILabel.cs index 5739d5df..757dfd33 100644 --- a/OpenDiablo2.Common/Interfaces/ILabel.cs +++ b/OpenDiablo2.Common/Interfaces/ILabel.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using OpenDiablo2.Common.Enums; namespace OpenDiablo2.Common.Interfaces { @@ -9,5 +10,7 @@ namespace OpenDiablo2.Common.Interfaces Point Location { get; set; } Size TextArea { get; set; } Color TextColor { get; set; } + int MaxWidth { get; set; } + eTextAlign Alignment { get; set; } } } diff --git a/OpenDiablo2.Common/OpenDiablo2.Common.csproj b/OpenDiablo2.Common/OpenDiablo2.Common.csproj index aeb2f4c2..748279df 100644 --- a/OpenDiablo2.Common/OpenDiablo2.Common.csproj +++ b/OpenDiablo2.Common/OpenDiablo2.Common.csproj @@ -77,6 +77,7 @@ + diff --git a/OpenDiablo2.Core/UI/Button.cs b/OpenDiablo2.Core/UI/Button.cs index 7f8544df..998d9428 100644 --- a/OpenDiablo2.Core/UI/Button.cs +++ b/OpenDiablo2.Core/UI/Button.cs @@ -82,7 +82,6 @@ namespace OpenDiablo2.Core.UI font = renderWindow.LoadFont(ResourcePaths.FontExocet10, Palettes.Units); label = renderWindow.CreateLabel(font); - sprite = renderWindow.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName); // TODO: Less stupid way of doing this would be nice @@ -94,6 +93,9 @@ namespace OpenDiablo2.Core.UI buttonWidth += sprite.LocalFrameSize.Width; buttonHeight = Math.Max(buttonHeight, sprite.LocalFrameSize.Height); } + + label.MaxWidth = buttonWidth - 8; + label.Alignment = Common.Enums.eTextAlign.Centered; } public bool Toggle() @@ -201,7 +203,8 @@ namespace OpenDiablo2.Core.UI label.TextColor = Color.FromArgb(75, 75, 75); var offsetX = (buttonWidth / 2) - (label.TextArea.Width / 2); - labelOffset = new Point(offsetX, -5); + var offsetY = (buttonHeight / 2) - (label.TextArea.Height / 2); + labelOffset = new Point(offsetX, offsetY - 5); } public void Dispose() diff --git a/OpenDiablo2.SDL2/SDL2Label.cs b/OpenDiablo2.SDL2/SDL2Label.cs index cee260e3..ee7b4cd7 100644 --- a/OpenDiablo2.SDL2/SDL2Label.cs +++ b/OpenDiablo2.SDL2/SDL2Label.cs @@ -1,4 +1,5 @@ -using OpenDiablo2.Common.Interfaces; +using OpenDiablo2.Common.Enums; +using OpenDiablo2.Common.Interfaces; using SDL2; using System; using System.Collections.Generic; @@ -43,25 +44,59 @@ namespace OpenDiablo2.SDL2_ } } + public int MaxWidth { get; set; } + public eTextAlign Alignment { get; set; } + internal SDL2Label(IFont font, IntPtr renderer) { this.renderer = renderer; this.font = font as SDL2Font; this.texture = IntPtr.Zero; + this.MaxWidth = -1; } internal Size CalculateSize() { - int w = 0; - int h = 0; - foreach (var ch in text) + if (MaxWidth == -1) { - var metric = font.font.CharacterMetric[(byte)ch]; - w += metric.Width; - h = Math.Max(Math.Max(h, metric.Height), font.sprite.FrameSize.Height); + int w = 0; + int h = 0; + foreach (var ch in text) + { + var metric = font.font.CharacterMetric[(byte)ch]; + w += metric.Width; + h = Math.Max(Math.Max(h, metric.Height), font.sprite.FrameSize.Height); + } + + return new Size(w, h); } - return new Size(w, h); + if (MaxWidth < (font.sprite.FrameSize.Width)) + throw new ApplicationException("Max label width cannot be smaller than a single character."); + + var lastWordIndex = 0; + var width = 0; + var maxWidth = 0; + var height = font.sprite.FrameSize.Height; + for (int idx = 0; idx < text.Length; idx++) + { + width += font.font.CharacterMetric[(byte)text[idx]].Width; + + if (width >= MaxWidth) + { + idx = lastWordIndex; + height += font.font.CharacterMetric[(byte)'|'].Height + 6; + width = 0; + continue; + } + maxWidth = Math.Max(width, maxWidth); + + if (idx > 0 && (text[idx - 1] == ' ') && (text[idx] != ' ')) + lastWordIndex = idx; + } + + return new Size(maxWidth, height); + } internal int Pow2(int input) @@ -90,14 +125,65 @@ namespace OpenDiablo2.SDL2_ SDL.SDL_RenderClear(renderer); SDL.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - int cx = 0; - int cy = 0; - foreach (var ch in text) + if (MaxWidth == -1) { - WriteCharacter(cx, cy, (byte)ch); - cx += font.font.CharacterMetric[(byte)ch].Width; - } + int cx = 0; + int cy = 0; + foreach (var ch in text) + { + WriteCharacter(cx, cy, (byte)ch); + cx += font.font.CharacterMetric[(byte)ch].Width; + } + } + else + { + var linesToRender = new List(); + + var lastWordIndex = 0; + var width = 0; + var lastStartX = 0; + for (int idx = 0; idx < text.Length; idx++) + { + width += font.font.CharacterMetric[(byte)text[idx]].Width; + + if (width >= MaxWidth) + { + idx = lastWordIndex; + linesToRender.Add(text.Substring(lastStartX, lastWordIndex- lastStartX)); + lastStartX = idx; + width = 0; + continue; + } + + if (idx > 0 && text[idx - 1] == ' ' && text[idx] != ' ') + lastWordIndex = idx; + } + + var lastLine = text.Substring(lastStartX)?.Trim(); + if (!String.IsNullOrEmpty(lastLine)) + linesToRender.Add(lastLine); + + var y = 0; + foreach(var line in linesToRender) + { + var lineWidth = (line.Sum(c => font.font.CharacterMetric[(byte)c].Width)); + var x = 0; + + if (Alignment == eTextAlign.Centered) + x = (TextArea.Width / 2) - (lineWidth / 2); + else if (Alignment == eTextAlign.Right) + x = TextArea.Width - lineWidth; + + foreach (var ch in line) + { + WriteCharacter(x, y, (byte)ch); + x += font.font.CharacterMetric[(byte)ch].Width; + } + + y += font.font.CharacterMetric[(byte)'|'].Height + 6; + } + } SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero); } diff --git a/OpenDiablo2.Scenes/CharacterSelection.cs b/OpenDiablo2.Scenes/CharacterSelection.cs index ebea62a1..4bf53c9c 100644 --- a/OpenDiablo2.Scenes/CharacterSelection.cs +++ b/OpenDiablo2.Scenes/CharacterSelection.cs @@ -26,7 +26,7 @@ namespace OpenDiablo2.Scenes backgroundSprite = renderWindow.LoadSprite(ResourcePaths.CharacterSelectionBackground, Palettes.Sky); createNewCharacterButton = createButton(eButtonType.Tall); // TODO: use strCreateNewCharacter -- need to get the text to split after 10 chars though. - createNewCharacterButton.Text = "Create New".ToUpper(); + createNewCharacterButton.Text = textDictionary.Translate("strCreateNewCharacter");// "Create New".ToUpper(); createNewCharacterButton.Location = new Point(33, 467); createNewCharacterButton.OnActivate = () => sceneManager.ChangeScene("Select Hero Class");