diff --git a/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs b/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs index 3c7fefed96..e2474b1846 100644 --- a/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs +++ b/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs @@ -5,6 +5,7 @@ using Intersect.Client.Framework.Input; using Intersect.Client.General; using Intersect.Client.Interface.Game.DescriptionWindows; +using Intersect.Client.Interface.Game.Inventory; using Intersect.Client.Networking; using Intersect.Configuration; using Intersect.Framework.Core; @@ -280,15 +281,20 @@ public void Update() { for (var i = 0; i < Options.Instance.Player.MaxInventory; i++) { - if (invWindow.Items[i].RenderBounds().IntersectsWith(dragRect)) + if(invWindow.Items[i] is not InventoryItem inventoryItem) { - if (FloatRect.Intersect(invWindow.Items[i].RenderBounds(), dragRect).Width * - FloatRect.Intersect(invWindow.Items[i].RenderBounds(), dragRect).Height > + continue; + } + + if (inventoryItem.RenderBounds().IntersectsWith(dragRect)) + { + if (FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Width * + FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Height > bestIntersect) { bestIntersect = - FloatRect.Intersect(invWindow.Items[i].RenderBounds(), dragRect).Width * - FloatRect.Intersect(invWindow.Items[i].RenderBounds(), dragRect).Height; + FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Width * + FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Height; bestIntersectIndex = i; } diff --git a/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs b/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs index 9f0dbf2f4e..7953e12fe1 100644 --- a/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs +++ b/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs @@ -6,6 +6,7 @@ using Intersect.Client.General; using Intersect.Client.Interface.Game.Chat; using Intersect.Client.Interface.Game.DescriptionWindows; +using Intersect.Client.Interface.Game.Inventory; using Intersect.Client.Localization; using Intersect.Client.Networking; using Intersect.Configuration; @@ -330,7 +331,11 @@ public void Update() ); for (var inventoryIndex = 0; inventoryIndex < inventorySlotLimit; inventoryIndex++) { - var inventorySlotComponent = inventorySlots[inventoryIndex]; + if (inventorySlots[inventoryIndex] is not InventoryItem inventorySlotComponent) + { + continue; + } + var inventorySlotRenderBounds = inventorySlotComponent.RenderBounds(); if (!inventorySlotRenderBounds.IntersectsWith(dragRect)) { diff --git a/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs b/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs index 021b7edead..2e68b70cca 100644 --- a/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs +++ b/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs @@ -16,14 +16,12 @@ using Intersect.Framework.Core.GameObjects.Items; using Intersect.GameObjects; using Intersect.Utilities; -using static Intersect.Client.Localization.Strings; namespace Intersect.Client.Interface.Game.Inventory; -public partial class InventoryItem : ImagePanel +public partial class InventoryItem : SlotItem { // Controls - private readonly ImagePanel _iconImage; private readonly Label _quantityLabel; private readonly Label _equipLabel; private readonly Label _cooldownLabel; @@ -41,32 +39,18 @@ public partial class InventoryItem : ImagePanel private int _mouseY = -1; // Data control - private readonly int _mySlot = -1; private string _textureLoaded = string.Empty; // Context Menu Handling - private readonly ContextMenu _contextMenu; private readonly MenuItem _useItemMenuItem; private readonly MenuItem _actionItemMenuItem; private readonly MenuItem _dropItemMenuItem; - public InventoryItem(InventoryWindow inventoryWindow, Base parent, int index) : base(parent, nameof(InventoryItem)) + public InventoryItem(InventoryWindow inventoryWindow, Base parent, int index, ContextMenu contextMenu) : base(parent, nameof(InventoryItem), index, contextMenu) { _inventoryWindow = inventoryWindow; - _mySlot = index; - - MinimumSize = new Point(34, 34); - Margin = new Margin(4); - MouseInputEnabled = true; TextureFilename = "inventoryitem.png"; - _iconImage = new ImagePanel(this, "Icon") - { - MinimumSize = new Point(32, 32), - MouseInputEnabled = true, - Alignment = [Alignments.Center], - HoverSound = "octave-tap-resonant.wav", - }; _iconImage.HoverEnter += _iconImage_HoverEnter; _iconImage.HoverLeave += _iconImage_HoverLeave; _iconImage.Clicked += _iconImage_Clicked; @@ -111,15 +95,6 @@ public InventoryItem(InventoryWindow inventoryWindow, Base parent, int index) : LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer.GetResolutionString()); - // Generate our context menu with basic options. - _contextMenu = new ContextMenu(Interface.CurrentInterface.Root, "InventoryContextMenu") - { - IsVisibleInParent = false, - IconMarginDisabled = true, - ItemFont = GameContentManager.Current.GetFont(name: "sourcesansproblack"), - ItemFontSize = 10, - }; - _contextMenu.ClearChildren(); _useItemMenuItem = _contextMenu.AddItem(Strings.ItemContextMenu.Use); _useItemMenuItem.Clicked += _useItemContextItem_Clicked; @@ -137,12 +112,12 @@ public InventoryItem(InventoryWindow inventoryWindow, Base parent, int index) : #region Context Menu - public void OpenContextMenu() + public override void OpenContextMenu() { // Clear out the old options since we might not show all of them _contextMenu.ClearChildren(); - if (Globals.Me?.Inventory[_mySlot] is not { } inventorySlot) + if (Globals.Me?.Inventory[SlotIndex] is not { } inventorySlot) { return; } @@ -175,7 +150,7 @@ public void OpenContextMenu() case ItemType.Equipment: _contextMenu.AddChild(_useItemMenuItem); - var equipItemLabel = Globals.Me.MyEquipment.Contains(_mySlot) ? Strings.ItemContextMenu.Unequip : Strings.ItemContextMenu.Equip; + var equipItemLabel = Globals.Me.MyEquipment.Contains(SlotIndex) ? Strings.ItemContextMenu.Unequip : Strings.ItemContextMenu.Equip; _useItemMenuItem.Text = equipItemLabel.ToString(descriptor.Name); break; } @@ -209,41 +184,37 @@ public void OpenContextMenu() _dropItemMenuItem.SetText(Strings.ItemContextMenu.Drop.ToString(descriptor.Name)); } - // Display our menu... If we have anything to display. - if (_contextMenu.Children.Count > 0) - { - _contextMenu.Open(Pos.None); - } + base.OpenContextMenu(); } private void _useItemContextItem_Clicked(Base sender, MouseButtonState arguments) { - Globals.Me?.TryUseItem(_mySlot); + Globals.Me?.TryUseItem(SlotIndex); } private void _actionItemContextItem_Clicked(Base sender, MouseButtonState arguments) { if (Globals.GameShop != null) { - Globals.Me?.TrySellItem(_mySlot); + Globals.Me?.TrySellItem(SlotIndex); } else if (Globals.InBank) { - Globals.Me?.TryStoreItemInBank(_mySlot); + Globals.Me?.TryStoreItemInBank(SlotIndex); } else if (Globals.InBag) { - Globals.Me?.TryStoreItemInBag(_mySlot, -1); + Globals.Me?.TryStoreItemInBag(SlotIndex, -1); } else if (Globals.InTrade) { - Globals.Me?.TryOfferItemToTrade(_mySlot); + Globals.Me?.TryOfferItemToTrade(SlotIndex); } } private void _dropItemContextItem_Clicked(Base sender, Framework.Gwen.Control.EventArguments.MouseButtonState arguments) { - Globals.Me?.TryDropItem(_mySlot); + Globals.Me?.TryDropItem(SlotIndex); } #endregion @@ -259,22 +230,22 @@ private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) if (Globals.GameShop != null) { - Globals.Me.TrySellItem(_mySlot); + Globals.Me.TrySellItem(SlotIndex); } else if (Globals.InBank) { if (Globals.InputManager.IsKeyDown(Framework.GenericClasses.Keys.Shift)) { Globals.Me.TryStoreItemInBank( - _mySlot, + SlotIndex, skipPrompt: true ); } else { - var slot = Globals.Me.Inventory[_mySlot]; + var slot = Globals.Me.Inventory[SlotIndex]; Globals.Me.TryStoreItemInBank( - _mySlot, + SlotIndex, slot, quantityHint: slot.Quantity, skipPrompt: false @@ -283,15 +254,15 @@ private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) } else if (Globals.InBag) { - Globals.Me.TryStoreItemInBag(_mySlot, -1); + Globals.Me.TryStoreItemInBag(SlotIndex, -1); } else if (Globals.InTrade) { - Globals.Me.TryOfferItemToTrade(_mySlot); + Globals.Me.TryOfferItemToTrade(SlotIndex); } else { - Globals.Me.TryUseItem(_mySlot); + Globals.Me.TryUseItem(SlotIndex); } } @@ -312,23 +283,23 @@ private void _iconImage_Clicked(Base sender, MouseButtonState arguments) { if (Globals.GameShop != null) { - Globals.Me?.TrySellItem(_mySlot); + Globals.Me?.TrySellItem(SlotIndex); } else if (Globals.InBank) { - Globals.Me?.TryStoreItemInBank(_mySlot); + Globals.Me?.TryStoreItemInBank(SlotIndex); } else if (Globals.InBag) { - Globals.Me?.TryStoreItemInBag(_mySlot, -1); + Globals.Me?.TryStoreItemInBag(SlotIndex, -1); } else if (Globals.InTrade) { - Globals.Me?.TryOfferItemToTrade(_mySlot); + Globals.Me?.TryOfferItemToTrade(SlotIndex); } else { - Globals.Me?.TryDropItem(_mySlot); + Globals.Me?.TryDropItem(SlotIndex); } } break; @@ -370,7 +341,7 @@ void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) _descWindow = null; } - if (Globals.Me?.Inventory[_mySlot] is not { } inventorySlot) + if (Globals.Me?.Inventory[SlotIndex] is not { } inventorySlot) { return; } @@ -461,12 +432,12 @@ private void PlayerOnInventoryUpdated(Player player, int slotIndex) return; } - if (slotIndex != _mySlot) + if (slotIndex != SlotIndex) { return; } - if (Globals.Me.Inventory[_mySlot] is not { } inventorySlot) + if (Globals.Me.Inventory[SlotIndex] == default) { return; } @@ -488,14 +459,14 @@ public FloatRect RenderBounds() return rect; } - public void Update() + public override void Update() { if (Globals.Me == default) { return; } - if (Globals.Me.Inventory[_mySlot] is not { } inventorySlot) + if (Globals.Me.Inventory[SlotIndex] is not { } inventorySlot) { return; } @@ -506,20 +477,20 @@ public void Update() return; } - var equipped = Globals.Me.MyEquipment.Any(s => s == _mySlot); + var equipped = Globals.Me.MyEquipment.Any(s => s == SlotIndex); _equipImageBackground.IsVisibleInParent = !IsDragging && equipped; _equipLabel.IsVisibleInParent = !IsDragging && equipped; _quantityLabel.IsVisibleInParent = !IsDragging && descriptor.IsStackable && inventorySlot.Quantity > 1; if (_quantityLabel.IsVisibleInParent) { - _quantityLabel.Text = FormatQuantityAbbreviated(inventorySlot.Quantity); + _quantityLabel.Text = Strings.FormatQuantityAbbreviated(inventorySlot.Quantity); } - _cooldownLabel.IsVisibleInParent = !IsDragging && Globals.Me.IsItemOnCooldown(_mySlot); + _cooldownLabel.IsVisibleInParent = !IsDragging && Globals.Me.IsItemOnCooldown(SlotIndex); if (_cooldownLabel.IsVisibleInParent) { - var itemCooldownRemaining = Globals.Me.GetItemRemainingCooldown(_mySlot); + var itemCooldownRemaining = Globals.Me.GetItemRemainingCooldown(SlotIndex); _cooldownLabel.Text = TimeSpan.FromMilliseconds(itemCooldownRemaining).WithSuffix("0.0"); _iconImage.RenderColor.A = 100; } @@ -534,7 +505,7 @@ public void Update() if (itemTex != null) { _iconImage.Texture = itemTex; - _iconImage.RenderColor = Globals.Me.IsItemOnCooldown(_mySlot) + _iconImage.RenderColor = Globals.Me.IsItemOnCooldown(SlotIndex) ? new Color(100, descriptor.Color.R, descriptor.Color.G, descriptor.Color.B) : descriptor.Color; _iconImage.IsVisibleInParent = true; @@ -630,7 +601,7 @@ public void Update() for (var inventoryIndex = 0; inventoryIndex < inventorySlotLimit; inventoryIndex++) { var inventorySlotComponent = inventorySlotComponents[inventoryIndex]; - var inventoryRenderBounds = inventorySlotComponent.RenderBounds(); + var inventoryRenderBounds = ((InventoryItem)inventorySlotComponent).RenderBounds(); if (!inventoryRenderBounds.IntersectsWith(dragRect)) { @@ -649,9 +620,9 @@ public void Update() if (bestIntersectIndex > -1) { - if (_mySlot != bestIntersectIndex) + if (SlotIndex != bestIntersectIndex) { - Globals.Me.SwapItems(_mySlot, bestIntersectIndex); + Globals.Me.SwapItems(SlotIndex, bestIntersectIndex); } } } @@ -683,10 +654,10 @@ public void Update() if (bestIntersectIndex > -1) { - Globals.Me.AddToHotbar((byte)bestIntersectIndex, 0, _mySlot); + Globals.Me.AddToHotbar((byte)bestIntersectIndex, 0, SlotIndex); } } - else if (Globals.InBag) + else if (Globals.InBag && Globals.BagSlots != default) { var bagWindow = Interface.GameUi.GetBagWindow(); if (bagWindow.RenderBounds().IntersectsWith(dragRect)) @@ -714,11 +685,11 @@ public void Update() if (bestIntersectIndex > -1) { - Globals.Me.TryStoreItemInBag(_mySlot, bestIntersectIndex); + Globals.Me.TryStoreItemInBag(SlotIndex, bestIntersectIndex); } } } - else if (Globals.InBank) + else if (Globals.InBank && Globals.BankSlots != default) { var bankWindow = Interface.GameUi.GetBankWindow(); if (bankWindow.RenderBounds().IntersectsWith(dragRect)) @@ -750,9 +721,9 @@ public void Update() if (bestIntersectIndex > -1) { - var slot = Globals.Me.Inventory[_mySlot]; + var slot = Globals.Me.Inventory[SlotIndex]; Globals.Me.TryStoreItemInBank( - _mySlot, + SlotIndex, bankSlotIndex: bestIntersectIndex, quantityHint: slot.Quantity, skipPrompt: true @@ -762,7 +733,7 @@ public void Update() } else if (!Globals.Me.IsBusy) { - PacketSender.SendDropItem(_mySlot, Globals.Me.Inventory[_mySlot].Quantity); + PacketSender.SendDropItem(SlotIndex, Globals.Me.Inventory[SlotIndex].Quantity); } _dragIcon.Dispose(); @@ -790,10 +761,4 @@ private void _reset() _descWindow = default; } } - - protected override void Dispose(bool disposing) - { - _contextMenu?.Close(); - base.Dispose(disposing); - } } diff --git a/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs b/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs index 793e7329e4..8075650794 100644 --- a/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs +++ b/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs @@ -5,14 +5,15 @@ using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.General; using Intersect.Client.Localization; +using Intersect.Client.Utilities; namespace Intersect.Client.Interface.Game.Inventory; public partial class InventoryWindow : Window { - public List Items { get; set; } = []; - + public List Items { get; set; } = []; private readonly ScrollControl _slotContainer; + private readonly ContextMenu _contextMenu; public InventoryWindow(Canvas gameCanvas) : base(gameCanvas, Strings.Inventory.Title, false, nameof(InventoryWindow)) { @@ -31,6 +32,14 @@ public InventoryWindow(Canvas gameCanvas) : base(gameCanvas, Strings.Inventory.T OverflowX = OverflowBehavior.Auto, OverflowY = OverflowBehavior.Scroll, }; + + _contextMenu = new ContextMenu(gameCanvas, "InventoryContextMenu") + { + IsVisibleInParent = false, + IconMarginDisabled = true, + ItemFont = GameContentManager.Current.GetFont(name: "sourcesansproblack"), + ItemFontSize = 10, + }; } protected override void EnsureInitialized() @@ -58,7 +67,7 @@ public void Update() IsClosable = Globals.CanCloseInventory; - if (Globals.Me?.Inventory is not { } inventory) + if (Globals.Me?.Inventory == default) { return; } @@ -72,23 +81,12 @@ public void Update() private void InitItemContainer() { - float containerInnerWidth = _slotContainer.InnerPanel.InnerWidth; for (var slotIndex = 0; slotIndex < Options.Instance.Player.MaxInventory; slotIndex++) { - var slotContainer = new InventoryItem(this, _slotContainer, slotIndex); - Items.Add(slotContainer); - - var outerSize = slotContainer.OuterBounds.Size; - var itemsPerRow = (int)(containerInnerWidth / outerSize.X); - - var column = slotIndex % itemsPerRow; - var row = slotIndex / itemsPerRow; - - var xPosition = column * outerSize.X + slotContainer.Margin.Left; - var yPosition = row * outerSize.Y + slotContainer.Margin.Top; - - slotContainer.SetPosition(xPosition, yPosition); + Items.Add(new InventoryItem(this, _slotContainer, slotIndex, _contextMenu)); } + + PopulateSlotContainer.Populate(_slotContainer, Items); } public override void Hide() @@ -98,6 +96,7 @@ public override void Hide() return; } + _contextMenu?.Close(); base.Hide(); } diff --git a/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs b/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs index 3304325458..5e776ad6f3 100644 --- a/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs +++ b/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs @@ -10,37 +10,22 @@ using Intersect.Client.Localization; using Intersect.Configuration; using Intersect.Framework.Core.GameObjects.Items; -using Intersect.GameObjects; -using Intersect.Network.Packets.Server; namespace Intersect.Client.Interface.Game.Shop; -public partial class ShopItem : ImagePanel +public partial class ShopItem : SlotItem { private readonly int _mySlot; private readonly ShopWindow _shopWindow; - public ImagePanel _iconImage; - private readonly ContextMenu _contextMenu; private readonly MenuItem _buyMenuItem; private ItemDescriptionWindow? _itemDescWindow; - public ShopItem(ShopWindow shopWindow, Base parent, int index) : base(parent, nameof(ShopItem)) + public ShopItem(ShopWindow shopWindow, Base parent, int index, ContextMenu contextMenu) : base(parent, nameof(ShopItem), index, contextMenu) { _shopWindow = shopWindow; _mySlot = index; - - MinimumSize = new Point(34, 34); - Margin = new Margin(4, 4, 4, 4); - MouseInputEnabled = true; TextureFilename = "shopitem.png"; - _iconImage = new ImagePanel(this, "ShopItemIcon") - { - MinimumSize = new Point(32, 32), - MouseInputEnabled = true, - Alignment = [Alignments.Center], - HoverSound = "octave-tap-resonant.wav", - }; _iconImage.HoverEnter += _iconImage_HoverEnter; _iconImage.HoverLeave += _iconImage_HoverLeave; _iconImage.Clicked += _iconImage_RightClicked; @@ -48,16 +33,6 @@ public ShopItem(ShopWindow shopWindow, Base parent, int index) : base(parent, na LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer.GetResolutionString()); - // Generate our context menu with basic options. - // TODO: Refactor so shop only has 1 context menu shared between all items - _contextMenu = new ContextMenu(Interface.CurrentInterface.Root, "ShopContextMenu") - { - IsVisibleInParent = false, - IconMarginDisabled = true, - ItemFont = GameContentManager.Current.GetFont(name: "sourcesansproblack"), - ItemFontSize = 10, - }; - //TODO: Is this a memory leak? _contextMenu.ClearChildren(); _buyMenuItem = _contextMenu.AddItem(Strings.ShopContextMenu.Buy); @@ -131,7 +106,7 @@ private void _iconImage_RightClicked(Base sender, MouseButtonState arguments) if (ClientConfiguration.Instance.EnableContextMenus) { - _openContextMenu(_mySlot); + OpenContextMenu(); } else { @@ -149,26 +124,20 @@ private void _buyMenuItem_Clicked(Base sender, Framework.Gwen.Control.EventArgum Globals.Me?.TryBuyItem(_mySlot); } - protected override void Dispose(bool disposing) - { - _contextMenu?.Close(); - base.Dispose(disposing); - } - - private void _openContextMenu(int slot) + public override void OpenContextMenu() { if (Globals.GameShop is not { SellingItems.Count: > 0 } gameShop) { return; } - if (!ItemDescriptor.TryGet(gameShop.SellingItems[slot].ItemId, out var item)) + if (!ItemDescriptor.TryGet(gameShop.SellingItems[SlotIndex].ItemId, out var item)) { return; } _buyMenuItem.SetText(Strings.ShopContextMenu.Buy.ToString(item.Name)); - _contextMenu.Open(Pos.None); + base.OpenContextMenu(); } public void LoadItem() diff --git a/Intersect.Client.Core/Interface/Game/Shop/ShopWindow.cs b/Intersect.Client.Core/Interface/Game/Shop/ShopWindow.cs index 0a863b2e3c..a5a0f538a3 100644 --- a/Intersect.Client.Core/Interface/Game/Shop/ShopWindow.cs +++ b/Intersect.Client.Core/Interface/Game/Shop/ShopWindow.cs @@ -4,13 +4,15 @@ using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.General; using Intersect.Client.Localization; +using Intersect.Client.Utilities; namespace Intersect.Client.Interface.Game.Shop; public partial class ShopWindow : Window { - private readonly List _items = []; + private readonly List _items = []; private readonly ScrollControl _slotContainer; + private readonly ContextMenu _contextMenu; public ShopWindow(Canvas gameCanvas) : base(gameCanvas, Globals.GameShop?.Name ?? Strings.Shop.Title, false, nameof(ShopWindow)) { @@ -31,6 +33,14 @@ public ShopWindow(Canvas gameCanvas) : base(gameCanvas, Globals.GameShop?.Name ? OverflowX = OverflowBehavior.Auto, OverflowY = OverflowBehavior.Scroll, }; + + _contextMenu = new ContextMenu(gameCanvas, "ShopContextMenu") + { + IsVisibleInParent = false, + IconMarginDisabled = true, + ItemFont = GameContentManager.Current.GetFont(name: "sourcesansproblack"), + ItemFontSize = 10, + }; } protected override void EnsureInitialized() @@ -46,22 +56,17 @@ private void InitItemContainer() return; } - float containerInnerWidth = _slotContainer.InnerPanel.InnerWidth; for (var slotIndex = 0; slotIndex < gameShop.SellingItems.Count; slotIndex++) { - var slotContainer = new ShopItem(this, _slotContainer, slotIndex); - _items.Add(slotContainer); - - var outerSize = slotContainer.OuterBounds.Size; - var itemsPerRow = (int)(containerInnerWidth / outerSize.X); - - var column = slotIndex % itemsPerRow; - var row = slotIndex / itemsPerRow; + _items.Add(new ShopItem(this, _slotContainer, slotIndex, _contextMenu)); + } - var xPosition = column * outerSize.X + slotContainer.Margin.Left; - var yPosition = row * outerSize.Y + slotContainer.Margin.Top; + PopulateSlotContainer.Populate(_slotContainer, _items); + } - slotContainer.SetPosition(xPosition, yPosition); - } + public override void Hide() + { + _contextMenu?.Close(); + base.Hide(); } } diff --git a/Intersect.Client.Core/Interface/Game/SlotItem.cs b/Intersect.Client.Core/Interface/Game/SlotItem.cs new file mode 100644 index 0000000000..afa7202fe1 --- /dev/null +++ b/Intersect.Client.Core/Interface/Game/SlotItem.cs @@ -0,0 +1,43 @@ +using Intersect.Client.Framework.Gwen; +using Intersect.Client.Framework.Gwen.Control; + +namespace Intersect.Client.Interface.Game; + +public partial class SlotItem : ImagePanel +{ + public readonly int SlotIndex; + protected readonly ImagePanel _iconImage; + protected readonly ContextMenu _contextMenu; + + public SlotItem(Base parent, string name, int index, ContextMenu contextMenu) : base(parent, name) + { + SlotIndex = index; + + MinimumSize = new Point(34, 34); + Margin = new Margin(4); + MouseInputEnabled = true; + + _iconImage = new ImagePanel(this, "Icon") + { + MinimumSize = new Point(32, 32), + MouseInputEnabled = true, + Alignment = [Alignments.Center], + HoverSound = "octave-tap-resonant.wav", + }; + + _contextMenu = contextMenu; + } + + public virtual void Update() + { + } + + public virtual void OpenContextMenu() + { + // Display our menu... If we have anything to display. + if (_contextMenu.Children.Count > 0) + { + _contextMenu.Open(Pos.None); + } + } +} diff --git a/Intersect.Client.Core/Utilities/PopulateSlotContainer.cs b/Intersect.Client.Core/Utilities/PopulateSlotContainer.cs new file mode 100644 index 0000000000..f08c8d74dd --- /dev/null +++ b/Intersect.Client.Core/Utilities/PopulateSlotContainer.cs @@ -0,0 +1,26 @@ +using Intersect.Client.Framework.Gwen.Control; +using Intersect.Client.Interface.Game; + +namespace Intersect.Client.Utilities; + +public static class PopulateSlotContainer +{ + public static void Populate(ScrollControl slotContainer, List items) + { + float containerInnerWidth = slotContainer.InnerPanel.InnerWidth; + for (var slotIndex = 0; slotIndex < items.Count; slotIndex++) + { + var slot = items[slotIndex]; + var outerSize = slot.OuterBounds.Size; + var itemsPerRow = (int)(containerInnerWidth / outerSize.X); + + var column = slotIndex % itemsPerRow; + var row = slotIndex / itemsPerRow; + + var xPosition = column * outerSize.X + slot.Margin.Left; + var yPosition = row * outerSize.Y + slot.Margin.Top; + + slot.SetPosition(xPosition, yPosition); + } + } +} \ No newline at end of file