diff --git a/Craftimizer/ImGuiExtras.cs b/Craftimizer/ImGuiExtras.cs index fd710d2..a90ba0f 100644 --- a/Craftimizer/ImGuiExtras.cs +++ b/Craftimizer/ImGuiExtras.cs @@ -172,6 +172,36 @@ internal static unsafe class ImGuiExtras public static unsafe ImGuiItemFlags GetItemFlags() => igGetItemFlags(); + public static unsafe int? CalcWordWrapPositionA(this ImFontPtr font, float scale, ReadOnlySpan text, float wrap_width) + { + var utf8TextByteCount = Encoding.UTF8.GetByteCount(text); + byte* utf8TextBytes; + if (utf8TextByteCount > StackAllocationSizeLimit) + { + utf8TextBytes = Allocate(utf8TextByteCount + 1); + } + else + { + var stackPtr = stackalloc byte[utf8TextByteCount + 1]; + utf8TextBytes = stackPtr; + } + GetUtf8(text, utf8TextBytes, utf8TextByteCount); + + var ret = ImGuiNative.ImFont_CalcWordWrapPositionA(font.NativePtr, scale, utf8TextBytes, utf8TextBytes + utf8TextByteCount, wrap_width); + + int? retVal = null; + if (utf8TextBytes <= ret && ret <= utf8TextBytes + utf8TextByteCount) + { + var retIndex = (int)(ret - utf8TextBytes); + retVal = Encoding.UTF8.GetCharCount(utf8TextBytes, retIndex); + } + + if (utf8TextByteCount > StackAllocationSizeLimit) + Free(utf8TextBytes); + + return retVal; + } + public static unsafe bool SetDragDropPayload(string type, T data) where T : unmanaged => ImGui.SetDragDropPayload(type, (nint)(&data), (uint)sizeof(T)); diff --git a/Craftimizer/ImGuiUtils.cs b/Craftimizer/ImGuiUtils.cs index 30f3aec..7838d75 100644 --- a/Craftimizer/ImGuiUtils.cs +++ b/Craftimizer/ImGuiUtils.cs @@ -588,17 +588,51 @@ internal static class ImGuiUtils public static void Tooltip(string text) { + using var _font = ImRaii.PushFont(UiBuilder.DefaultFont); using var _tooltip = ImRaii.Tooltip(); ImGui.TextUnformatted(text); } public static void TooltipWrapped(string text, float width = 300) { + using var _font = ImRaii.PushFont(UiBuilder.DefaultFont); using var _tooltip = ImRaii.Tooltip(); using var _wrap = ImRaii2.TextWrapPos(width); ImGui.TextUnformatted(text); } + public static void TextWrappedTo(string text, float wrapPosX = default, float basePosX = default) + { + var font = ImGui.GetFont(); + + var currentPos = ImGui.GetCursorPosX(); + + if (basePosX == default) + basePosX = ImGui.GetCursorStartPos().X; + + float currentWrapWidth; + if (wrapPosX == default) + currentWrapWidth = ImGui.GetContentRegionAvail().X; + else + currentWrapWidth = wrapPosX - currentPos; + + var textBuf = text.AsSpan(); + var lineSize = font.CalcWordWrapPositionA(1, textBuf, currentWrapWidth) ?? textBuf.Length; + var lineBuf = textBuf[..lineSize]; + ImGui.Text(lineBuf.ToString()); + var remainingBuf = textBuf[lineSize..]; + + while (!remainingBuf.IsEmpty && char.IsWhiteSpace(remainingBuf[0])) + remainingBuf = remainingBuf[1..]; + + if (!remainingBuf.IsEmpty) + { + ImGui.SetCursorPosX(basePosX); + using (ImRaii2.TextWrapPos(wrapPosX)) + ImGui.TextWrapped(remainingBuf.ToString()); + } + } + public static void AlignCentered(float width, float availWidth = default) { if (availWidth == default) @@ -657,6 +691,12 @@ internal static class ImGuiUtils return ImGui.Button(text, buttonSize); } + public static float GetFontSize(this IFontHandle font) + { + using (font.Push()) + return ImGui.GetFontSize(); + } + public static Vector2 CalcTextSize(this IFontHandle font, string text) { using (font.Push()) diff --git a/Craftimizer/Windows/Settings.cs b/Craftimizer/Windows/Settings.cs index c40bd15..e1d2d92 100644 --- a/Craftimizer/Windows/Settings.cs +++ b/Craftimizer/Windows/Settings.cs @@ -1,6 +1,7 @@ using Craftimizer.Solver; using Dalamud.Interface; using Dalamud.Interface.Colors; +using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; @@ -23,10 +24,16 @@ public sealed class Settings : Window, IDisposable private string? SelectedTab { get; set; } + private IFontHandle HeaderFont { get; } + private IFontHandle SubheaderFont { get; } + public Settings() : base("Craftimizer Settings", WindowFlags) { Service.WindowSystem.AddWindow(this); + HeaderFont = Service.PluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePx * 2f))); + SubheaderFont = Service.PluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePx * 1.5f))); + SizeConstraints = new WindowSizeConstraints() { MinimumSize = new(450, 400), @@ -765,7 +772,18 @@ public sealed class Settings : Window, IDisposable ImGui.Image(icon.ImGuiHandle, new(icon.Width, icon.Height)); ImGui.TableNextColumn(); - ImGui.Text($"Craftimizer v{plugin.Version} {plugin.BuildConfiguration}"); + ImGuiUtils.AlignMiddle(new(float.PositiveInfinity, HeaderFont.GetFontSize() + SubheaderFont.GetFontSize() + ImGui.GetFontSize() + ImGui.GetStyle().ItemSpacing.Y * 2), new(0, icon.Height)); + + using (HeaderFont.Push()) + { + ImGuiUtils.AlignCentered(ImGui.CalcTextSize("Craftimizer").X); + ImGuiUtils.Hyperlink("Craftimizer", "https://github.com/WorkingRobot/craftimizer", false); + } + + using (SubheaderFont.Push()) + ImGuiUtils.TextCentered($"v{plugin.Version} {plugin.BuildConfiguration}"); + + ImGuiUtils.AlignCentered(ImGui.CalcTextSize($"By {plugin.Author} (WorkingRobot)").X); ImGui.Text($"By {plugin.Author} ("); ImGui.SameLine(0, 0); ImGuiUtils.Hyperlink("WorkingRobot", "https://github.com/WorkingRobot"); @@ -774,15 +792,34 @@ public sealed class Settings : Window, IDisposable } } - ImGui.Text("Credit to altosock's "); + ImGui.Separator(); + + using (SubheaderFont.Push()) + ImGuiUtils.TextCentered("Special Thanks"); + + var startPosX = ImGui.GetCursorPosX(); + + ImGuiUtils.TextWrappedTo("Thank you to "); + ImGui.SameLine(0, 0); + ImGuiUtils.Hyperlink("alostsock", "https://github.com/alostsock"); + ImGui.SameLine(0, 0); + ImGuiUtils.TextWrappedTo(" for making "); ImGui.SameLine(0, 0); ImGuiUtils.Hyperlink("Craftingway", "https://craftingway.app"); ImGui.SameLine(0, 0); - ImGui.Text(" for the original solver algorithm"); + ImGuiUtils.TextWrappedTo(" and the original solver algorithm"); + + ImGuiUtils.TextWrappedTo("Thank you to "); + ImGui.SameLine(0, 0); + ImGuiUtils.Hyperlink("FFXIV Teamcraft", "https://ffxivteamcraft.com"); + ImGui.SameLine(0, 0); + ImGuiUtils.TextWrappedTo(" and its users for their community rotations"); } public void Dispose() { Service.WindowSystem.RemoveWindow(this); + SubheaderFont?.Dispose(); + HeaderFont?.Dispose(); } }