From 8a3490332636a5f97bf46434040a851e14c3017e Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Wed, 8 Apr 2026 11:42:46 -0600 Subject: [PATCH] feat: Consolidates staff gump layouts (#2404) ## Summary - Creates `PropsLayoutExtensions.cs` with reusable extension methods for both legacy `Gump` and `DynamicGumpBuilder` that encapsulate the repeating PropsConfig-style layout patterns (frame, header navigation, entry rows) - Converts all 12 standardized staff gumps to use the new extensions, reducing ~570 lines of duplicated layout code - Adds Type and Serial display to PropsGump and SkillsGump headers (e.g. `PlayerMobile (0x1)`) ### Extension methods provided | Method | Pattern | |--------|---------| | `AddPropsFrame` | Background + offset region + origin coordinates | | `AddPropsHeader` | 3-column: [Prev] [Title] [Next] | | `AddPropsHeaderWithBack` | 4-column: [Back] [Title] [Prev] [Next] | | `AddPropsEntryButton` | Label + action button | | `AddPropsEntryNameValue` | Name + Value + action button | | `AddPropsEntryTextInput` | Text input + action button | | `AddPropsEntryLabel` | Label only (no button) | | `AddPropsEntryType` | Full-width type label | | `AddPropsEntryBlank` | Separator row | ### Gumps converted PropsGump, GoGump, WhoGump, SkillsGump (frame+header), EditSkillGump, SetGump, SetObjectGump, SetPoint2DGump, SetPoint3DGump, SetTimeSpanGump (frame), SetListOptionGump (frame+header), CategorizedAddGump (frame+header) ## Test plan - [x] Verify `[props` gump displays correctly with type + serial in header - [x] Verify `[skills` gump displays correctly with type + serial in header - [x] Verify `[go` navigation gump works (prev/next/back) - [x] Verify property editing gumps (Set, SetObject, SetPoint2D, SetPoint3D, SetTimeSpan, SetListOption) - [x] Verify `[categorizedadd` gump works - [x] Verify `[who` gump works with pagination --- .../Object Creation/CategorizedAddGump.cs | 63 +- .../Engines/Spawners/SpawnPropsGump.cs | 28 +- Projects/UOContent/Gumps/Go/GoGump.cs | 64 +- Projects/UOContent/Gumps/Props/PropsGump.cs | 85 +-- .../Gumps/Props/PropsLayoutExtensions.cs | 677 ++++++++++++++++++ Projects/UOContent/Gumps/Props/SetGump.cs | 80 +-- .../Gumps/Props/SetListOptionGump.cs | 55 +- .../UOContent/Gumps/Props/SetObjectGump.cs | 84 +-- .../UOContent/Gumps/Props/SetPoint2DGump.cs | 56 +- .../UOContent/Gumps/Props/SetPoint3DGump.cs | 56 +- .../UOContent/Gumps/Props/SetTimeSpanGump.cs | 7 +- Projects/UOContent/Gumps/SkillsGump.cs | 60 +- Projects/UOContent/Gumps/WhoGump.cs | 41 +- 13 files changed, 786 insertions(+), 570 deletions(-) create mode 100644 Projects/UOContent/Gumps/Props/PropsLayoutExtensions.cs diff --git a/Projects/UOContent/Commands/Object Creation/CategorizedAddGump.cs b/Projects/UOContent/Commands/Object Creation/CategorizedAddGump.cs index 76b4b50af..57bb5d837 100644 --- a/Projects/UOContent/Commands/Object Creation/CategorizedAddGump.cs +++ b/Projects/UOContent/Commands/Object Creation/CategorizedAddGump.cs @@ -21,8 +21,6 @@ namespace Server.Gumps private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private readonly CAGCategory m_Category; private readonly Mobile m_Owner; @@ -50,64 +48,21 @@ namespace Server.Gumps var count = Math.Clamp(nodes.Length - page * EntryCount, 0, EntryCount); - var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); - AddPage(0); - AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); - AddImageTiled( - BorderSize, - BorderSize, - TotalWidth, - totalHeight, - OffsetGumpID + this.AddPropsFrame(TotalWidth, count + 1, out var x, out var y, EntryHeight); + this.AddPropsHeaderWithBack( + TotalWidth, ref x, ref y, m_Category.Title, + m_Category.Parent != null, 1, + page > 0, 2, + (page + 1) * EntryCount < nodes.Length, 3, + nextType: GumpButtonType.Reply, nextParam: 1, + entryHeight: EntryHeight ); - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); - - if (m_Category.Parent != null) - { - AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1); - } - - x += PrevWidth + OffsetSize; - - const int emptyWidth = TotalWidth - PrevWidth * 2 - NextWidth - OffsetSize * 5; - AddImageTiled(x, y, emptyWidth, EntryHeight, EntryGumpID); - - AddHtml( - x + TextOffsetX, - y + (EntryHeight - 20) / 2, - emptyWidth - TextOffsetX, - EntryHeight, - $"
{m_Category.Title}
" - ); - - x += emptyWidth + OffsetSize; - - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); - - if (page > 0) - { - AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 2); - } - - x += PrevWidth + OffsetSize; - - AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); - - if ((page + 1) * EntryCount < nodes.Length) - { - AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 3, GumpButtonType.Reply, 1); - } - for (int i = 0, index = page * EntryCount; i < EntryCount && index < nodes.Length; ++i, ++index) { - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; + PropsLayout.NextRow(ref x, ref y, EntryHeight); var node = nodes[index]; diff --git a/Projects/UOContent/Engines/Spawners/SpawnPropsGump.cs b/Projects/UOContent/Engines/Spawners/SpawnPropsGump.cs index ac06bf61f..4a6732ec9 100644 --- a/Projects/UOContent/Engines/Spawners/SpawnPropsGump.cs +++ b/Projects/UOContent/Engines/Spawners/SpawnPropsGump.cs @@ -41,24 +41,14 @@ public class SpawnPropsGump : PropertiesGump private List _spawners; - public SpawnPropsGump(Mobile mobile, object o, List spawners) : base(mobile, o) - { - _spawners = spawners; - } + public SpawnPropsGump(Mobile mobile, object o, List spawners) : base(mobile, o) => _spawners = spawners; - public SpawnPropsGump(Mobile mobile, object o, Stack stack, StackEntry parent, List spawners) : base( - mobile, o, stack, parent - ) - { - _spawners = spawners; - } + public SpawnPropsGump(Mobile mobile, object o, Stack stack, StackEntry parent, List spawners) + : base(mobile, o, stack, parent) => _spawners = spawners; - public SpawnPropsGump(Mobile mobile, object o, Stack stack, List list, int page, List spawners) : base( - mobile, o, stack, list, page - ) - { - _spawners = spawners; - } + public SpawnPropsGump( + Mobile mobile, object o, Stack stack, List list, int page, List spawners + ) : base(mobile, o, stack, list, page) => _spawners = spawners; protected override int TotalHeight => base.TotalHeight + PropsConfig.ApplySize; @@ -67,7 +57,7 @@ public class SpawnPropsGump : PropertiesGump base.Initialize(page); var totalHeight = TotalHeight - PropsConfig.ApplySize; - AddButton(BackWidth / 3, PropsConfig.BorderSize + totalHeight + PropsConfig.BorderSize, 5204, 5205, 3); + AddButton(BackWidth / 3, PropsConfig.BorderSize * 2 + totalHeight, 5204, 5205, 3); } public override void SendPropertiesGump() => @@ -111,9 +101,7 @@ public class SpawnPropsGump : PropertiesGump propsBuilder.Append(' '); } - propsBuilder.Append(attr); - propsBuilder.Append(' '); - propsBuilder.Append(prop.ToString()); // TODO: Replace with ZString, or IFormatter code + propsBuilder.Append($"{attr} {prop}"); } } diff --git a/Projects/UOContent/Gumps/Go/GoGump.cs b/Projects/UOContent/Gumps/Go/GoGump.cs index c658dadf8..95fe9f876 100644 --- a/Projects/UOContent/Gumps/Go/GoGump.cs +++ b/Projects/UOContent/Gumps/Go/GoGump.cs @@ -12,8 +12,6 @@ public class GoGump : Gump private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private readonly GoCategory _node; private readonly int _page; @@ -36,72 +34,30 @@ public class GoGump : Gump _tree = tree; _node = node; - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - var count = Math.Clamp(node.Categories.Length + node.Locations.Length - page * EntryCount, 0, EntryCount); - var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); - AddPage(0); - AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, totalHeight, OffsetGumpID); - - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); - - if (node.Parent != null) - { - AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1); - } - - x += PrevWidth + OffsetSize; - - const int emptyWidth = TotalWidth - PrevWidth * 2 - NextWidth - OffsetSize * 5; - AddImageTiled(x, y, emptyWidth, EntryHeight, EntryGumpID); - - AddHtml(x + TextOffsetX, y, emptyWidth - TextOffsetX, EntryHeight, $"
{node.Name}
"); - - x += emptyWidth + OffsetSize; - - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); - - if (page > 0) - { - AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 2); - } - - x += PrevWidth + OffsetSize; - - AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); - - if ((page + 1) * EntryCount < node.Categories.Length + node.Locations.Length) - { - AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 3, GumpButtonType.Reply, 1); - } + this.AddPropsFrame(TotalWidth, count + 1, out var x, out var y); + this.AddPropsHeaderWithBack( + TotalWidth, ref x, ref y, node.Name, + node.Parent != null, 1, + page > 0, 2, + (page + 1) * EntryCount < node.Categories.Length + node.Locations.Length, 3, + nextType: GumpButtonType.Reply, nextParam: 1 + ); var totalEntryCount = node.Categories.Length + node.Locations.Length; for (int i = 0, index = page * EntryCount; i < EntryCount && index < totalEntryCount; ++i, ++index) { - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; + PropsLayout.NextRow(ref x, ref y); var name = index >= node.Categories.Length ? node.Locations[index - node.Categories.Length].Name : node.Categories[index].Name; - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, name); - - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, index + 4); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, name, true, index + 4); } } diff --git a/Projects/UOContent/Gumps/Props/PropsGump.cs b/Projects/UOContent/Gumps/Props/PropsGump.cs index 0d8d656c1..eda11e287 100644 --- a/Projects/UOContent/Gumps/Props/PropsGump.cs +++ b/Projects/UOContent/Gumps/Props/PropsGump.cs @@ -106,90 +106,45 @@ namespace Server.Gumps --m_EntryCount; } - var totalHeight = TotalHeight; - AddPage(0); - AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); - AddImageTiled( - BorderSize, - BorderSize, - TotalWidth, - OffsetSize + (EntryHeight + OffsetSize) * (m_EntryCount + 1), - OffsetGumpID + this.AddPropsFrame(TotalWidth, m_EntryCount + 1, out var x, out var y); + var title = m_Type != null && m_Object is ISerializable serializable + ? $"{m_Type.Name} ({serializable.Serial})".Center(0xFAFAFA) + : m_Type?.Name.Center(0xFAFAFA); + + this.AddPropsHeader( + TotalWidth, ref x, ref y, + title, + page > 0, 1, + (page + 1) * MaxEntriesPerPage < m_List.Count, 2, + nextType: GumpButtonType.Reply, nextParam: 1 ); - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - - const int emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4; - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); - - if (page > 0) - { - AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1); - } - - x += PrevWidth + OffsetSize; - - AddImageTiled(x, y, emptyWidth, EntryHeight, HeaderGumpID); - - if (m_Type != null) - { - AddHtml(x, y, emptyWidth, EntryHeight, m_Type.Name.Center(0xFAFAFA)); - } - - x += emptyWidth + OffsetSize; - - AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); - - if ((page + 1) * MaxEntriesPerPage < m_List.Count) - { - AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1); - } - for (int i = 0, index = page * MaxEntriesPerPage; i < m_EntryCount && index < m_List.Count; ++i, ++index) { - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; + PropsLayout.NextRow(ref x, ref y); var o = m_List[index]; if (o == null) { - AddImageTiled(x - OffsetSize, y, TotalWidth, EntryHeight, BackGumpID + 4); + this.AddPropsEntryBlank(x, y, TotalWidth); } else if (o is Type type) { - AddImageTiled(x, y, TypeWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, type.Name); - x += TypeWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } + this.AddPropsEntryType(ref x, ref y, TypeWidth, type.Name); } else if (o is PropertyInfo prop) { - AddImageTiled(x, y, NameWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, NameWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); - x += NameWidth + OffsetSize; - AddImageTiled(x, y, ValueWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, TextHue, ValueToString(prop)); - x += ValueWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - var cpa = GetCPA(prop); + var canModify = cpa?.ReadOnly == false && m_Mobile.AccessLevel >= cpa.WriteLevel && (prop.CanWrite || cpa.CanModify); - if (cpa?.ReadOnly == false && m_Mobile.AccessLevel >= cpa.WriteLevel && (prop.CanWrite || cpa.CanModify)) - { - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3); - } + this.AddPropsEntryNameValue( + ref x, ref y, NameWidth, ValueWidth, + prop.Name, ValueToString(prop), + canModify, i + 3 + ); } } } diff --git a/Projects/UOContent/Gumps/Props/PropsLayoutExtensions.cs b/Projects/UOContent/Gumps/Props/PropsLayoutExtensions.cs new file mode 100644 index 000000000..f237ae581 --- /dev/null +++ b/Projects/UOContent/Gumps/Props/PropsLayoutExtensions.cs @@ -0,0 +1,677 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: PropsLayoutExtensions.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Runtime.CompilerServices; + +using static Server.Gumps.PropsConfig; + +namespace Server.Gumps; + +/// +/// Shared helper for advancing to the next row in PropsConfig-style layouts. +/// Resets x to content origin and advances y by one row height. +/// +public static class PropsLayout +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NextRow(ref int x, ref int y, int entryHeight = EntryHeight) + { + x = BorderSize + OffsetSize; + y += entryHeight + OffsetSize; + } +} + +/// +/// Extension methods for legacy Gump that provide PropsConfig-style layout building blocks. +/// Each method encapsulates a common row pattern used across staff gumps. +/// +public static class PropsLayoutExtensions +{ + extension(Gump gump) + { + /// + /// Adds the standard PropsConfig frame: outer background + inner offset region. + /// Outputs the content origin (x, y) for the first row. + /// Does NOT call AddPage — callers handle paging strategy. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsFrame( + int totalWidth, + int rowCount, + out int x, + out int y, + int entryHeight = EntryHeight + ) + { + var totalHeight = OffsetSize + (entryHeight + OffsetSize) * rowCount; + + gump.AddBackground(0, 0, BorderSize + totalWidth + BorderSize, BorderSize + totalHeight + BorderSize, BackGumpID); + gump.AddImageTiled(BorderSize, BorderSize, totalWidth, totalHeight, OffsetGumpID); + + x = BorderSize + OffsetSize; + y = BorderSize + OffsetSize; + } + + /// + /// Adds a 3-column navigation header: [Prev] [Title] [Next]. + /// All three columns use HeaderGumpID backgrounds. + /// + public void AddPropsHeader( + int totalWidth, + ref int x, + ref int y, + string title, + bool hasPrev, + int prevButtonId, + bool hasNext, + int nextButtonId, + GumpButtonType prevType = GumpButtonType.Reply, + int prevParam = 0, + GumpButtonType nextType = GumpButtonType.Reply, + int nextParam = 0, + int entryHeight = EntryHeight + ) + { + var emptyWidth = totalWidth - PrevWidth - NextWidth - OffsetSize * 4; + + gump.AddImageTiled(x, y, PrevWidth, entryHeight, HeaderGumpID); + + if (hasPrev) + { + gump.AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, prevButtonId, prevType, prevParam); + } + + x += PrevWidth + OffsetSize; + + gump.AddImageTiled(x, y, emptyWidth, entryHeight, HeaderGumpID); + + if (title != null) + { + gump.AddHtml(x, y, emptyWidth, entryHeight, title); + } + + x += emptyWidth + OffsetSize; + + gump.AddImageTiled(x, y, NextWidth, entryHeight, HeaderGumpID); + + if (hasNext) + { + gump.AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, nextButtonId, nextType, nextParam); + } + } + + /// + /// Adds a 4-column navigation header: [Back] [Title] [Prev] [Next]. + /// Back/Prev/Next use HeaderGumpID, Title uses EntryGumpID. + /// + public void AddPropsHeaderWithBack( + int totalWidth, + ref int x, + ref int y, + string title, + bool hasBack, + int backButtonId, + bool hasPrev, + int prevButtonId, + bool hasNext, + int nextButtonId, + GumpButtonType nextType = GumpButtonType.Reply, + int nextParam = 0, + int entryHeight = EntryHeight + ) + { + var emptyWidth = totalWidth - PrevWidth * 2 - NextWidth - OffsetSize * 5; + + gump.AddImageTiled(x, y, PrevWidth, entryHeight, HeaderGumpID); + + if (hasBack) + { + gump.AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, backButtonId); + } + + x += PrevWidth + OffsetSize; + + gump.AddImageTiled(x, y, emptyWidth, entryHeight, EntryGumpID); + + if (title != null) + { + gump.AddHtml( + x + TextOffsetX, + y + (entryHeight - EntryHeight) / 2, + emptyWidth - TextOffsetX, + entryHeight, + $"
{title}
" + ); + } + + x += emptyWidth + OffsetSize; + + gump.AddImageTiled(x, y, PrevWidth, entryHeight, HeaderGumpID); + + if (hasPrev) + { + gump.AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, prevButtonId); + } + + x += PrevWidth + OffsetSize; + + gump.AddImageTiled(x, y, NextWidth, entryHeight, HeaderGumpID); + + if (hasNext) + { + gump.AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, nextButtonId, nextType, nextParam); + } + } + + /// + /// Adds an entry row with a cropped label and optional action button. + /// Layout: [Label:EntryGumpID] [Button:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryButton( + ref int x, + ref int y, + int entryWidth, + string label, + bool hasButton, + int buttonId, + int textHue = TextHue, + int entryHeight = EntryHeight + ) + { + gump.AddImageTiled(x, y, entryWidth, entryHeight, EntryGumpID); + gump.AddLabelCropped(x + TextOffsetX, y, entryWidth - TextOffsetX, entryHeight, textHue, label); + x += entryWidth + OffsetSize; + + if (SetGumpID != 0) + { + gump.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + + if (hasButton) + { + gump.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, buttonId); + } + } + + /// + /// Adds a two-column entry row with name, value, and optional action button. + /// Layout: [Name:EntryGumpID] [Value:EntryGumpID] [Button:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryNameValue( + ref int x, + ref int y, + int nameWidth, + int valueWidth, + string name, + string value, + bool hasButton, + int buttonId, + int entryHeight = EntryHeight + ) + { + gump.AddImageTiled(x, y, nameWidth, entryHeight, EntryGumpID); + gump.AddLabelCropped(x + TextOffsetX, y, nameWidth - TextOffsetX, entryHeight, TextHue, name); + x += nameWidth + OffsetSize; + + gump.AddImageTiled(x, y, valueWidth, entryHeight, EntryGumpID); + gump.AddLabelCropped(x + TextOffsetX, y, valueWidth - TextOffsetX, entryHeight, TextHue, value); + x += valueWidth + OffsetSize; + + if (SetGumpID != 0) + { + gump.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + + if (hasButton) + { + gump.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, buttonId); + } + } + + /// + /// Adds an entry row with a text input field and optional action button. + /// Layout: [TextEntry:EntryGumpID] [Button:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryTextInput( + ref int x, + ref int y, + int entryWidth, + int entryId, + string initialText, + bool hasButton, + int buttonId, + int entryHeight = EntryHeight + ) + { + gump.AddImageTiled(x, y, entryWidth, entryHeight, EntryGumpID); + gump.AddTextEntry(x + TextOffsetX, y, entryWidth - TextOffsetX, entryHeight, TextHue, entryId, initialText); + x += entryWidth + OffsetSize; + + if (SetGumpID != 0) + { + gump.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + + if (hasButton) + { + gump.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, buttonId); + } + } + + /// + /// Adds an entry row with a cropped label and no action button. + /// Layout: [Label:EntryGumpID] [Empty:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryLabel( + ref int x, + ref int y, + int entryWidth, + string label, + int entryHeight = EntryHeight + ) + { + gump.AddImageTiled(x, y, entryWidth, entryHeight, EntryGumpID); + gump.AddLabelCropped(x + TextOffsetX, y, entryWidth - TextOffsetX, entryHeight, TextHue, label); + x += entryWidth + OffsetSize; + + if (SetGumpID != 0) + { + gump.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + } + + /// + /// Adds a full-width type label row (used for PropsGump type group headers). + /// Layout: [TypeName:EntryGumpID spanning typeWidth] [Empty:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryType( + ref int x, + ref int y, + int typeWidth, + string typeName, + int entryHeight = EntryHeight + ) + { + gump.AddImageTiled(x, y, typeWidth, entryHeight, EntryGumpID); + gump.AddLabelCropped(x + TextOffsetX, y, typeWidth - TextOffsetX, entryHeight, TextHue, typeName); + x += typeWidth + OffsetSize; + + if (SetGumpID != 0) + { + gump.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + } + + /// + /// Adds a blank separator row spanning the full width. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryBlank( + int x, + int y, + int totalWidth, + int entryHeight = EntryHeight + ) + { + gump.AddImageTiled(x - OffsetSize, y, totalWidth, entryHeight, BackGumpID + 4); + } + } +} + +/// +/// Extension methods for DynamicGumpBuilder that provide PropsConfig-style layout building blocks. +/// Mirrors PropsLayoutExtensions but uses ReadOnlySpan<char> for text parameters. +/// +public static class PropsLayoutBuilderExtensions +{ + extension(ref DynamicGumpBuilder builder) + { + /// + /// Adds the standard PropsConfig frame: outer background + inner offset region. + /// Outputs the content origin (x, y) for the first row. + /// Does NOT call AddPage — callers handle paging strategy. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsFrame( + int totalWidth, + int rowCount, + out int x, + out int y, + int entryHeight = EntryHeight + ) + { + var totalHeight = OffsetSize + (entryHeight + OffsetSize) * rowCount; + + builder.AddBackground( + 0, + 0, + BorderSize + totalWidth + BorderSize, + BorderSize + totalHeight + BorderSize, + BackGumpID + ); + builder.AddImageTiled(BorderSize, BorderSize, totalWidth, totalHeight, OffsetGumpID); + + x = BorderSize + OffsetSize; + y = BorderSize + OffsetSize; + } + + /// + /// Adds a 3-column navigation header: [Prev] [Title] [Next]. + /// All three columns use HeaderGumpID backgrounds. + /// + public void AddPropsHeader( + int totalWidth, + ref int x, + ref int y, + ReadOnlySpan title, + bool hasPrev, + int prevButtonId, + bool hasNext, + int nextButtonId, + GumpButtonType prevType = GumpButtonType.Reply, + int prevParam = 0, + GumpButtonType nextType = GumpButtonType.Reply, + int nextParam = 0, + int entryHeight = EntryHeight + ) + { + var emptyWidth = totalWidth - PrevWidth - NextWidth - OffsetSize * 4; + + builder.AddImageTiled(x, y, PrevWidth, entryHeight, HeaderGumpID); + + if (hasPrev) + { + builder.AddButton( + x + PrevOffsetX, + y + PrevOffsetY, + PrevButtonID1, + PrevButtonID2, + prevButtonId, + prevType, + prevParam + ); + } + + x += PrevWidth + OffsetSize; + + builder.AddImageTiled(x, y, emptyWidth, entryHeight, HeaderGumpID); + + if (title.Length > 0) + { + builder.AddHtml( + x + TextOffsetX, + y, + emptyWidth - TextOffsetX, + entryHeight, + title, + align: TextAlignment.Center + ); + } + + x += emptyWidth + OffsetSize; + + builder.AddImageTiled(x, y, NextWidth, entryHeight, HeaderGumpID); + + if (hasNext) + { + builder.AddButton( + x + NextOffsetX, + y + NextOffsetY, + NextButtonID1, + NextButtonID2, + nextButtonId, + nextType, + nextParam + ); + } + } + + /// + /// Adds a 4-column navigation header: [Back] [Title] [Prev] [Next]. + /// Back/Prev/Next use HeaderGumpID, Title uses EntryGumpID. + /// + public void AddPropsHeaderWithBack( + int totalWidth, + ref int x, + ref int y, + ReadOnlySpan title, + bool hasBack, + int backButtonId, + bool hasPrev, + int prevButtonId, + bool hasNext, + int nextButtonId, + GumpButtonType nextType = GumpButtonType.Reply, + int nextParam = 0, + int entryHeight = EntryHeight + ) + { + var emptyWidth = totalWidth - PrevWidth * 2 - NextWidth - OffsetSize * 5; + + builder.AddImageTiled(x, y, PrevWidth, entryHeight, HeaderGumpID); + + if (hasBack) + { + builder.AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, backButtonId); + } + + x += PrevWidth + OffsetSize; + + builder.AddImageTiled(x, y, emptyWidth, entryHeight, EntryGumpID); + + if (title.Length > 0) + { + builder.AddHtml( + x + TextOffsetX, + y + (entryHeight - EntryHeight) / 2, + emptyWidth - TextOffsetX, + entryHeight, + title, + align: TextAlignment.Center + ); + } + + x += emptyWidth + OffsetSize; + + builder.AddImageTiled(x, y, PrevWidth, entryHeight, HeaderGumpID); + + if (hasPrev) + { + builder.AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, prevButtonId); + } + + x += PrevWidth + OffsetSize; + + builder.AddImageTiled(x, y, NextWidth, entryHeight, HeaderGumpID); + + if (hasNext) + { + builder.AddButton( + x + NextOffsetX, + y + NextOffsetY, + NextButtonID1, + NextButtonID2, + nextButtonId, + nextType, + nextParam + ); + } + } + + /// + /// Adds an entry row with a cropped label and optional action button. + /// Layout: [Label:EntryGumpID] [Button:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryButton( + ref int x, + ref int y, + int entryWidth, + ReadOnlySpan label, + bool hasButton, + int buttonId, + int textHue = TextHue, + int entryHeight = EntryHeight + ) + { + builder.AddImageTiled(x, y, entryWidth, entryHeight, EntryGumpID); + builder.AddLabelCropped(x + TextOffsetX, y, entryWidth - TextOffsetX, entryHeight, textHue, label); + x += entryWidth + OffsetSize; + + if (SetGumpID != 0) + { + builder.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + + if (hasButton) + { + builder.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, buttonId); + } + } + + /// + /// Adds a two-column entry row with name, value, and optional action button. + /// Layout: [Name:EntryGumpID] [Value:EntryGumpID] [Button:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryNameValue( + ref int x, + ref int y, + int nameWidth, + int valueWidth, + ReadOnlySpan name, + ReadOnlySpan value, + bool hasButton, + int buttonId, + int entryHeight = EntryHeight + ) + { + builder.AddImageTiled(x, y, nameWidth, entryHeight, EntryGumpID); + builder.AddLabelCropped(x + TextOffsetX, y, nameWidth - TextOffsetX, entryHeight, TextHue, name); + x += nameWidth + OffsetSize; + + builder.AddImageTiled(x, y, valueWidth, entryHeight, EntryGumpID); + builder.AddLabelCropped(x + TextOffsetX, y, valueWidth - TextOffsetX, entryHeight, TextHue, value); + x += valueWidth + OffsetSize; + + if (SetGumpID != 0) + { + builder.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + + if (hasButton) + { + builder.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, buttonId); + } + } + + /// + /// Adds an entry row with a text input field and optional action button. + /// Layout: [TextEntry:EntryGumpID] [Button:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryTextInput( + ref int x, + ref int y, + int entryWidth, + int entryId, + ReadOnlySpan initialText, + bool hasButton, + int buttonId, + int entryHeight = EntryHeight + ) + { + builder.AddImageTiled(x, y, entryWidth, entryHeight, EntryGumpID); + builder.AddTextEntry(x + TextOffsetX, y, entryWidth - TextOffsetX, entryHeight, TextHue, entryId, initialText); + x += entryWidth + OffsetSize; + + if (SetGumpID != 0) + { + builder.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + + if (hasButton) + { + builder.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, buttonId); + } + } + + /// + /// Adds an entry row with a cropped label and no action button. + /// Layout: [Label:EntryGumpID] [Empty:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryLabel( + ref int x, + ref int y, + int entryWidth, + ReadOnlySpan label, + int entryHeight = EntryHeight + ) + { + builder.AddImageTiled(x, y, entryWidth, entryHeight, EntryGumpID); + builder.AddLabelCropped(x + TextOffsetX, y, entryWidth - TextOffsetX, entryHeight, TextHue, label); + x += entryWidth + OffsetSize; + + if (SetGumpID != 0) + { + builder.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + } + + /// + /// Adds a full-width type label row (used for PropsGump type group headers). + /// Layout: [TypeName:EntryGumpID spanning typeWidth] [Empty:SetGumpID] + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryType( + ref int x, + ref int y, + int typeWidth, + ReadOnlySpan typeName, + int entryHeight = EntryHeight + ) + { + builder.AddImageTiled(x, y, typeWidth, entryHeight, EntryGumpID); + builder.AddLabelCropped(x + TextOffsetX, y, typeWidth - TextOffsetX, entryHeight, TextHue, typeName); + x += typeWidth + OffsetSize; + + if (SetGumpID != 0) + { + builder.AddImageTiled(x, y, SetWidth, entryHeight, SetGumpID); + } + } + + /// + /// Adds a blank separator row spanning the full width. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddPropsEntryBlank( + int x, + int y, + int totalWidth, + int entryHeight = EntryHeight + ) + { + builder.AddImageTiled(x - OffsetSize, y, totalWidth, entryHeight, BackGumpID + 4); + } + } +} diff --git a/Projects/UOContent/Gumps/Props/SetGump.cs b/Projects/UOContent/Gumps/Props/SetGump.cs index 721019321..886ab28c3 100644 --- a/Projects/UOContent/Gumps/Props/SetGump.cs +++ b/Projects/UOContent/Gumps/Props/SetGump.cs @@ -12,10 +12,6 @@ namespace Server.Gumps private const int EntryWidth = 212; private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int TotalHeight = OffsetSize + 2 * (EntryHeight + OffsetSize); - - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private const int BackHeight = BorderSize + TotalHeight + BorderSize; private readonly Mobile m_Mobile; private readonly object m_Object; @@ -40,81 +36,25 @@ namespace Server.Gumps _ => val.ToString() }; + var rowCount = 2 + (canNull ? 1 : 0) + (canDye ? 1 : 0); + AddPage(0); - AddBackground( - 0, - 0, - BackWidth, - BackHeight + (canNull ? EntryHeight + OffsetSize : 0) + (canDye ? EntryHeight + OffsetSize : 0), - BackGumpID - ); - AddImageTiled( - BorderSize, - BorderSize, - TotalWidth, - TotalHeight + (canNull ? EntryHeight + OffsetSize : 0) + (canDye ? EntryHeight + OffsetSize : 0), - OffsetGumpID - ); - - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddTextEntry(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, 0, initialText); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); + this.AddPropsFrame(TotalWidth, rowCount, out var x, out var y); + this.AddPropsEntryLabel(ref x, ref y, EntryWidth, prop.Name); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryTextInput(ref x, ref y, EntryWidth, 0, initialText, true, 1); if (canNull) { - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Null"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Null", true, 2); } if (canDye) { - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Hue Picker"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Hue Picker", true, 3); } } diff --git a/Projects/UOContent/Gumps/Props/SetListOptionGump.cs b/Projects/UOContent/Gumps/Props/SetListOptionGump.cs index f65eb79d5..09a8060b9 100644 --- a/Projects/UOContent/Gumps/Props/SetListOptionGump.cs +++ b/Projects/UOContent/Gumps/Props/SetListOptionGump.cs @@ -14,8 +14,6 @@ namespace Server.Gumps private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private readonly object[] m_Values; protected Mobile m_Mobile; protected object m_Object; @@ -48,52 +46,13 @@ namespace Server.Gumps count = EntryCount; } - var totalHeight = OffsetSize + (count + 2) * (EntryHeight + OffsetSize); - var backHeight = BorderSize + totalHeight + BorderSize; - - AddBackground(0, 0, BackWidth, backHeight, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, totalHeight, OffsetGumpID); - - var x = BorderSize + OffsetSize; - const int y = BorderSize + OffsetSize; - - const int emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4; - - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); - - if (page > 1) - { - AddButton( - x + PrevOffsetX, - y + PrevOffsetY, - PrevButtonID1, - PrevButtonID2, - 0, - GumpButtonType.Page, - page - 1 - ); - } - - x += PrevWidth + OffsetSize; - - AddImageTiled(x, y, emptyWidth, EntryHeight, HeaderGumpID); - - x += emptyWidth + OffsetSize; - - AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); - - if (page < pages) - { - AddButton( - x + NextOffsetX, - y + NextOffsetY, - NextButtonID1, - NextButtonID2, - 0, - GumpButtonType.Page, - page + 1 - ); - } + this.AddPropsFrame(TotalWidth, count + 2, out var x, out var y); + this.AddPropsHeader( + TotalWidth, ref x, ref y, null, + page > 1, 0, page < pages, 0, + prevType: GumpButtonType.Page, prevParam: page - 1, + nextType: GumpButtonType.Page, nextParam: page + 1 + ); AddRect(0, prop.Name, 0); diff --git a/Projects/UOContent/Gumps/Props/SetObjectGump.cs b/Projects/UOContent/Gumps/Props/SetObjectGump.cs index d634d80e1..788ad79fe 100644 --- a/Projects/UOContent/Gumps/Props/SetObjectGump.cs +++ b/Projects/UOContent/Gumps/Props/SetObjectGump.cs @@ -14,10 +14,6 @@ namespace Server.Gumps private const int EntryWidth = 212; private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int TotalHeight = OffsetSize + 5 * (EntryHeight + OffsetSize); - - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private const int BackHeight = BorderSize + TotalHeight + BorderSize; private readonly Mobile m_Mobile; private readonly object m_Object; private readonly PropertyInfo m_Property; @@ -38,76 +34,16 @@ namespace Server.Gumps AddPage(0); - AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, TotalHeight, OffsetGumpID); - - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, initialText); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Change by Serial"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Nullify"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3); - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "View Properties"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 4); + this.AddPropsFrame(TotalWidth, 5, out var x, out var y); + this.AddPropsEntryLabel(ref x, ref y, EntryWidth, prop.Name); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, initialText, true, 1); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Change by Serial", true, 2); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Nullify", true, 3); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "View Properties", true, 4); } public override void OnResponse(NetState sender, in RelayInfo info) diff --git a/Projects/UOContent/Gumps/Props/SetPoint2DGump.cs b/Projects/UOContent/Gumps/Props/SetPoint2DGump.cs index 7ee4bb2c8..35fd70103 100644 --- a/Projects/UOContent/Gumps/Props/SetPoint2DGump.cs +++ b/Projects/UOContent/Gumps/Props/SetPoint2DGump.cs @@ -13,10 +13,6 @@ namespace Server.Gumps private const int EntryWidth = CoordWidth + OffsetSize + CoordWidth; private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int TotalHeight = OffsetSize + 4 * (EntryHeight + OffsetSize); - - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private const int BackHeight = BorderSize + TotalHeight + BorderSize; private readonly Mobile m_Mobile; private readonly object m_Object; private readonly PropertyInfo m_Property; @@ -34,51 +30,13 @@ namespace Server.Gumps AddPage(0); - AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, TotalHeight, OffsetGumpID); - - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop?.Name); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; + this.AddPropsFrame(TotalWidth, 4, out var x, out var y); + this.AddPropsEntryLabel(ref x, ref y, EntryWidth, prop?.Name); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Use your location", true, 1); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Target a location", true, 2); + PropsLayout.NextRow(ref x, ref y); AddImageTiled(x, y, CoordWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:"); diff --git a/Projects/UOContent/Gumps/Props/SetPoint3DGump.cs b/Projects/UOContent/Gumps/Props/SetPoint3DGump.cs index 297f4e36a..b0707bc3d 100644 --- a/Projects/UOContent/Gumps/Props/SetPoint3DGump.cs +++ b/Projects/UOContent/Gumps/Props/SetPoint3DGump.cs @@ -13,10 +13,6 @@ namespace Server.Gumps private const int EntryWidth = CoordWidth + OffsetSize + CoordWidth + OffsetSize + CoordWidth; private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int TotalHeight = OffsetSize + 4 * (EntryHeight + OffsetSize); - - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private const int BackHeight = BorderSize + TotalHeight + BorderSize; private readonly Mobile m_Mobile; private readonly object m_Object; @@ -35,51 +31,13 @@ namespace Server.Gumps AddPage(0); - AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, TotalHeight, OffsetGumpID); - - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop?.Name); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location"); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; + this.AddPropsFrame(TotalWidth, 4, out var x, out var y); + this.AddPropsEntryLabel(ref x, ref y, EntryWidth, prop?.Name); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Use your location", true, 1); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryButton(ref x, ref y, EntryWidth, "Target a location", true, 2); + PropsLayout.NextRow(ref x, ref y); AddImageTiled(x, y, CoordWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:"); diff --git a/Projects/UOContent/Gumps/Props/SetTimeSpanGump.cs b/Projects/UOContent/Gumps/Props/SetTimeSpanGump.cs index 19114f57b..fb7a5a137 100644 --- a/Projects/UOContent/Gumps/Props/SetTimeSpanGump.cs +++ b/Projects/UOContent/Gumps/Props/SetTimeSpanGump.cs @@ -12,10 +12,6 @@ namespace Server.Gumps private const int EntryWidth = 212; private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int TotalHeight = OffsetSize + 7 * (EntryHeight + OffsetSize); - - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private const int BackHeight = BorderSize + TotalHeight + BorderSize; private readonly Mobile m_Mobile; private readonly object m_Object; private readonly PropertyInfo m_Property; @@ -35,8 +31,7 @@ namespace Server.Gumps AddPage(0); - AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, TotalHeight, OffsetGumpID); + this.AddPropsFrame(TotalWidth, 7, out _, out _); AddRect(0, prop?.Name, 0, -1); AddRect(1, ts.ToString(), 0, -1); diff --git a/Projects/UOContent/Gumps/SkillsGump.cs b/Projects/UOContent/Gumps/SkillsGump.cs index c08df2948..d8efbb5e4 100644 --- a/Projects/UOContent/Gumps/SkillsGump.cs +++ b/Projects/UOContent/Gumps/SkillsGump.cs @@ -12,10 +12,6 @@ namespace Server.Gumps private const int EntryWidth = 160; private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int TotalHeight = OffsetSize + 2 * (EntryHeight + OffsetSize); - - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private const int BackHeight = BorderSize + TotalHeight + BorderSize; private readonly Mobile m_From; @@ -37,34 +33,10 @@ namespace Server.Gumps AddPage(0); - AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, TotalHeight, OffsetGumpID); - - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, skill.Name); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; - - AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - AddTextEntry(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, 0, initialText); - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); + this.AddPropsFrame(TotalWidth, 2, out var x, out var y); + this.AddPropsEntryLabel(ref x, ref y, EntryWidth, skill.Name); + PropsLayout.NextRow(ref x, ref y); + this.AddPropsEntryTextInput(ref x, ref y, EntryWidth, 0, initialText, true, 1); } public override void OnResponse(NetState sender, in RelayInfo info) @@ -110,8 +82,6 @@ namespace Server.Gumps private const int TotalWidth = OffsetSize + NameWidth + OffsetSize + ValueWidth + OffsetSize + SetWidth + OffsetSize; - private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; - private static readonly int IndentWidth = 12; private readonly Mobile m_From; @@ -135,26 +105,16 @@ namespace Server.Gumps count += selected.Skills.Length; } - var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); - AddPage(0); - AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); - AddImageTiled(BorderSize, BorderSize, TotalWidth, totalHeight, OffsetGumpID); - - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; + this.AddPropsFrame(TotalWidth, count + 1, out var x, out var y); + this.AddPropsHeader( + TotalWidth, ref x, ref y, + $"{target.GetType().Name} ({target.Serial})".Center(0xFAFAFA), + false, 0, false, 0 + ); const int emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4; - AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); - - x += PrevWidth + OffsetSize; - - AddImageTiled(x, y, emptyWidth, EntryHeight, HeaderGumpID); - - x += emptyWidth + OffsetSize; - - AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); for (var i = 0; i < m_Groups.Length; ++i) { diff --git a/Projects/UOContent/Gumps/WhoGump.cs b/Projects/UOContent/Gumps/WhoGump.cs index 405f5299d..f6d90fa1c 100644 --- a/Projects/UOContent/Gumps/WhoGump.cs +++ b/Projects/UOContent/Gumps/WhoGump.cs @@ -14,8 +14,6 @@ public class WhoGump : DynamicGump private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; - private const int BackWidth = BorderSize + TotalWidth + BorderSize; - private readonly List _mobiles; private readonly int _page; @@ -77,15 +75,9 @@ public class WhoGump : DynamicGump { var count = Math.Clamp(_mobiles.Count - _page * EntryCount, 0, EntryCount); - var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); - builder.AddPage(); - builder.AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); - builder.AddImageTiled(BorderSize, BorderSize, TotalWidth, totalHeight, OffsetGumpID); - - var x = BorderSize + OffsetSize; - var y = BorderSize + OffsetSize; + builder.AddPropsFrame(TotalWidth, count + 1, out var x, out var y); const int emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4; @@ -118,32 +110,19 @@ public class WhoGump : DynamicGump for (int i = 0, index = _page * EntryCount; i < EntryCount && index < _mobiles.Count; ++i, ++index) { - x = BorderSize + OffsetSize; - y += EntryHeight + OffsetSize; + PropsLayout.NextRow(ref x, ref y); var m = _mobiles[index]; - builder.AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); - builder.AddLabelCropped( - x + TextOffsetX, - y, - EntryWidth - TextOffsetX, - EntryHeight, - GetHueFor(m), - m.Deleted ? "(deleted)" : m.Name + builder.AddPropsEntryButton( + ref x, + ref y, + EntryWidth, + m.Deleted ? "(deleted)" : m.Name, + m.NetState != null && !m.Deleted, + i + 3, + textHue: GetHueFor(m) ); - - x += EntryWidth + OffsetSize; - - if (SetGumpID != 0) - { - builder.AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); - } - - if (m.NetState != null && !m.Deleted) - { - builder.AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3); - } } }