diff --git a/Intersect.Client.Core/Core/Input.cs b/Intersect.Client.Core/Core/Input.cs index 6920bea7b8..9371c1c192 100644 --- a/Intersect.Client.Core/Core/Input.cs +++ b/Intersect.Client.Core/Core/Input.cs @@ -2,6 +2,7 @@ using Intersect.Client.Entities; using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Graphics; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; using Intersect.Client.Framework.Input; using Intersect.Client.General; @@ -138,6 +139,11 @@ public static void OnKeyPressed(Keys modifier, Keys key) return; } + if (DragAndDrop.IsDragging) + { + return; + } + var gameUi = Interface.Interface.GameUi; // First try and unfocus chat then close all UI elements, then untarget our target.. and THEN open the escape menu. @@ -196,7 +202,7 @@ public static void OnKeyPressed(Keys modifier, Keys key) break; case Control.ToggleGui: - if (currentGameState == GameStates.InGame) + if (currentGameState == GameStates.InGame && !DragAndDrop.IsDragging) { Interface.Interface.HideUi = !Interface.Interface.HideUi; } @@ -249,6 +255,11 @@ public static void OnKeyPressed(Keys modifier, Keys key) break; } + if (DragAndDrop.IsDragging) + { + break; + } + switch (control) { case Control.Block: diff --git a/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs b/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs index 487a705fd2..35bd1a943e 100644 --- a/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs +++ b/Intersect.Client.Core/Interface/Game/Bag/BagItem.cs @@ -1,9 +1,9 @@ using Intersect.Client.Core; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.Control.EventArguments; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; using Intersect.Client.Framework.Input; using Intersect.Client.General; @@ -12,7 +12,6 @@ using Intersect.Client.Localization; using Intersect.Client.Networking; using Intersect.Configuration; -using Intersect.Framework.Core; using Intersect.Framework.Core.GameObjects.Items; namespace Intersect.Client.Interface.Game.Bag; @@ -22,19 +21,7 @@ public partial class BagItem : SlotItem // Controls private readonly Label _quantityLabel; private readonly BagWindow _bagWindow; - private Draggable? _dragIcon; - private ItemDescriptionWindow? _descWindow; - - // Drag Handling - public bool IsDragging; - private bool _canDrag; - private long _clickTime; - private bool _mouseOver; - private int _mouseX = -1; - private int _mouseY = -1; - - // Data control - private string? _textureLoaded; + private ItemDescriptionWindow? _descriptionWindow; // Context Menu Handling private readonly MenuItem _withdrawContextItem; @@ -45,10 +32,10 @@ public BagItem(BagWindow bagWindow, Base parent, int index, ContextMenu contextM _bagWindow = bagWindow; TextureFilename = "bagitem.png"; - _iconImage.HoverEnter += _iconImage_HoverEnter; - _iconImage.HoverLeave += _iconImage_HoverLeave; - _iconImage.Clicked += _iconImage_Clicked; - _iconImage.DoubleClicked += _iconImage_DoubleClicked; + Icon.HoverEnter += Icon_HoverEnter; + Icon.HoverLeave += Icon_HoverLeave; + Icon.Clicked += Icon_Clicked; + Icon.DoubleClicked += Icon_DoubleClicked; _quantityLabel = new Label(this, "Quantity") { @@ -100,26 +87,20 @@ private void _withdrawMenuItem_Clicked(Base sender, MouseButtonState arguments) #region Mouse Events - private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) + private void Icon_HoverEnter(Base? sender, EventArgs? arguments) { if (InputHandler.MouseFocus != default) { return; } - _mouseOver = true; - _canDrag = true; if (Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) { - _canDrag = false; return; } - if (_descWindow != default) - { - _descWindow.Dispose(); - _descWindow = default; - } + _descriptionWindow?.Dispose(); + _descriptionWindow = default; if (Globals.BagSlots is not { Length: > 0 } bagSlots) { @@ -132,7 +113,7 @@ private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) } var item = bagSlots[SlotIndex]; - _descWindow = new ItemDescriptionWindow( + _descriptionWindow = new ItemDescriptionWindow( item.Descriptor, item.Quantity, _bagWindow.X, @@ -141,47 +122,64 @@ private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) ); } - private void _iconImage_HoverLeave(Base sender, EventArgs arguments) + private void Icon_HoverLeave(Base sender, EventArgs arguments) { - _mouseOver = false; - _mouseX = -1; - _mouseY = -1; + _descriptionWindow?.Dispose(); + _descriptionWindow = default; + } - if (_descWindow != default) + private void Icon_Clicked(Base sender, MouseButtonState arguments) + { + if (arguments.MouseButton is MouseButton.Right) { - _descWindow.Dispose(); - _descWindow = default; + if (ClientConfiguration.Instance.EnableContextMenus) + { + OpenContextMenu(); + } + else + { + Icon_DoubleClicked(sender, arguments); + } } } - private void _iconImage_Clicked(Base sender, MouseButtonState arguments) + private void Icon_DoubleClicked(Base sender, MouseButtonState arguments) { - // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault - switch (arguments.MouseButton) + if (arguments.MouseButton is MouseButton.Left) { - case MouseButton.Right: - if (ClientConfiguration.Instance.EnableContextMenus) - { - OpenContextMenu(); - } - else - { - _iconImage_DoubleClicked(sender, arguments); - } - break; - - case MouseButton.Left: - _clickTime = Timing.Global.MillisecondsUtc + 500; - break; + Globals.Me?.TryRetrieveItemFromBag(SlotIndex, -1); } } - private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) + #endregion + + #region Drag and Drop + + public override bool DragAndDrop_HandleDrop(Package package, int x, int y) { - if (Globals.InBag) + var targetNode = Interface.FindComponentUnderCursor(); + + // Find the first parent acceptable in that tree that can accept the package + while (targetNode != default) { - Globals.Me?.TryRetrieveItemFromBag(SlotIndex, -1); + switch (targetNode) + { + case BagItem bagItem: + PacketSender.SendMoveBagItems(SlotIndex, bagItem.SlotIndex); + return true; + + case InventoryItem inventoryItem: + Globals.Me?.TryRetrieveItemFromBag(SlotIndex, inventoryItem.SlotIndex); + return true; + + default: + targetNode = targetNode.Parent; + break; + } } + + // If we've reached the top of the tree, we can't drop here, so cancel drop + return false; } #endregion @@ -201,194 +199,41 @@ public override void Update() if (bagSlots[SlotIndex] is not { Descriptor: not null } or { Quantity: <= 0 }) { _quantityLabel.IsVisibleInParent = false; - _iconImage.Texture = default; - _textureLoaded = default; + Icon.Texture = default; return; } var bagSlot = bagSlots[SlotIndex]; var descriptor = bagSlot.Descriptor; - _quantityLabel.IsVisibleInParent = !IsDragging && descriptor.IsStackable && bagSlot.Quantity > 1; + _quantityLabel.IsVisibleInParent = !Icon.IsDragging && descriptor.IsStackable && bagSlot.Quantity > 1; if (_quantityLabel.IsVisibleInParent) { _quantityLabel.Text = Strings.FormatQuantityAbbreviated(bagSlot.Quantity); } - if (_textureLoaded != descriptor.Icon) + if (Icon.TextureFilename == descriptor.Icon) { - var itemTex = Globals.ContentManager?.GetTexture(Framework.Content.TextureType.Item, descriptor.Icon); - if (itemTex != default) - { - _iconImage.Texture = itemTex; - _iconImage.RenderColor = descriptor.Color; - _iconImage.IsVisibleInParent = true; - } - else - { - if (_iconImage.Texture != default) - { - _iconImage.Texture = default; - _iconImage.IsVisibleInParent = false; - } - } - - _textureLoaded = descriptor.Icon; - - if (_descWindow != default) - { - _descWindow.Dispose(); - _descWindow = default; - _iconImage_HoverEnter(default, default); - } + return; } - if (!IsDragging) + var itemTexture = GameContentManager.Current.GetTexture(Framework.Content.TextureType.Item, descriptor.Icon); + if (itemTexture != default) { - if (_mouseOver) - { - if (!Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) - { - _canDrag = true; - _mouseX = -1; - _mouseY = -1; - if (Timing.Global.MillisecondsUtc < _clickTime) - { - _clickTime = 0; - } - } - else - { - if (_canDrag && Draggable.Active == default) - { - if (_mouseX == -1 || _mouseY == -1) - { - _mouseX = InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X; - _mouseY = InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y; - } - else - { - var xdiff = _mouseX - - (InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X); - - var ydiff = _mouseY - - (InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y); - - if (Math.Sqrt(Math.Pow(xdiff, 2) + Math.Pow(ydiff, 2)) > 5) - { - IsDragging = true; - _dragIcon = new Draggable( - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseX, - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseY, _iconImage.Texture, _iconImage.RenderColor - ); - } - } - } - } - } + Icon.Texture = itemTexture; + Icon.RenderColor = descriptor.Color; + Icon.IsVisibleInParent = true; } else { - if (_dragIcon?.Update() == true) + if (Icon.Texture != default) { - //Drug the item and now we stopped - IsDragging = false; - var dragRect = new FloatRect( - _dragIcon.X - (Padding.Left + Padding.Right) / 2f, - _dragIcon.Y - (Padding.Top + Padding.Bottom) / 2f, - (Padding.Left + Padding.Right) / 2f + _iconImage.Width, - (Padding.Top + Padding.Bottom) / 2f + _iconImage.Height - ); - - float bestIntersect = 0; - var bestIntersectIndex = -1; - - //So we picked up an item and then dropped it. Lets see where we dropped it to. - //Check inventory first. - if (_bagWindow.RenderBounds().IntersectsWith(dragRect)) - { - for (var i = 0; i < Globals.BagSlots.Length; i++) - { - var slot = _bagWindow.Items[i]; - if (slot is not BagItem bagItem) - { - continue; - } - - if (bagItem.RenderBounds().IntersectsWith(dragRect)) - { - if (FloatRect.Intersect(bagItem.RenderBounds(), dragRect).Width * - FloatRect.Intersect(bagItem.RenderBounds(), dragRect).Height > - bestIntersect) - { - bestIntersect = - FloatRect.Intersect(bagItem.RenderBounds(), dragRect).Width * - FloatRect.Intersect(bagItem.RenderBounds(), dragRect).Height; - - bestIntersectIndex = i; - } - } - } - - if (bestIntersectIndex > -1) - { - if (SlotIndex != bestIntersectIndex) - { - //Try to swap.... - PacketSender.SendMoveBagItems(SlotIndex, bestIntersectIndex); - } - } - } - else - { - var invWindow = Interface.GameUi.GameMenu.GetInventoryWindow(); - - if (invWindow.RenderBounds().IntersectsWith(dragRect)) - { - for (var i = 0; i < Options.Instance.Player.MaxInventory; i++) - { - if(invWindow.Items[i] is not InventoryItem inventoryItem) - { - continue; - } - - if (inventoryItem.RenderBounds().IntersectsWith(dragRect)) - { - if (FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Width * - FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Height > - bestIntersect) - { - bestIntersect = - FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Width * - FloatRect.Intersect(inventoryItem.RenderBounds(), dragRect).Height; - - bestIntersectIndex = i; - } - } - } - - if (bestIntersectIndex > -1) - { - Globals.Me.TryRetrieveItemFromBag(SlotIndex, bestIntersectIndex); - } - } - } - - _dragIcon.Dispose(); + Icon.Texture = default; + Icon.IsVisibleInParent = false; } } - } - - public FloatRect RenderBounds() - { - var rect = new FloatRect() - { - X = _iconImage.ToCanvas(new Point(0, 0)).X, - Y = _iconImage.ToCanvas(new Point(0, 0)).Y, - Width = _iconImage.Width, - Height = _iconImage.Height - }; - return rect; + _descriptionWindow?.Dispose(); + _descriptionWindow = default; } } diff --git a/Intersect.Client.Core/Interface/Game/Bag/BagWindow.cs b/Intersect.Client.Core/Interface/Game/Bag/BagWindow.cs index 35f95e6a85..7c88c48f93 100644 --- a/Intersect.Client.Core/Interface/Game/Bag/BagWindow.cs +++ b/Intersect.Client.Core/Interface/Game/Bag/BagWindow.cs @@ -1,6 +1,5 @@ using Intersect.Client.Core; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.General; @@ -65,12 +64,6 @@ private void InitItemContainer() PopulateSlotContainer.Populate(_slotContainer, Items); } - public override void Hide() - { - _contextMenu?.Close(); - base.Hide(); - } - public void Update() { if (IsVisibleInTree == false) @@ -87,16 +80,9 @@ public void Update() } } - public FloatRect RenderBounds() + public override void Hide() { - var rect = new FloatRect() - { - X = ToCanvas(new Point(0, 0)).X - 4 / 2, - Y = ToCanvas(new Point(0, 0)).Y - 4 / 2, - Width = Width + 4, - Height = Height + 4 - }; - - return rect; + _contextMenu?.Close(); + base.Hide(); } } diff --git a/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs b/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs index 954403f6db..5bd52ab8bb 100644 --- a/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs +++ b/Intersect.Client.Core/Interface/Game/Bank/BankItem.cs @@ -4,6 +4,7 @@ using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.Control.EventArguments; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; using Intersect.Client.Framework.Input; using Intersect.Client.General; @@ -14,7 +15,6 @@ using Intersect.Client.Networking; using Intersect.Configuration; using Intersect.Enums; -using Intersect.Framework.Core; using Intersect.Framework.Core.GameObjects.Items; namespace Intersect.Client.Interface.Game.Bank; @@ -24,19 +24,7 @@ public partial class BankItem : SlotItem // Controls private readonly Label _quantityLabel; private BankWindow _bankWindow; - private Draggable? _dragIcon; - private ItemDescriptionWindow? _descWindow; - - // Drag Handling - public bool IsDragging; - private bool _canDrag; - private long _clickTime; - private bool _mouseOver; - private int _mouseX = -1; - private int _mouseY = -1; - - // Data control - private string? _textureLoaded; + private ItemDescriptionWindow? _descriptionWindow; // Context Menu Handling private MenuItem _withdrawContextItem; @@ -47,10 +35,10 @@ public BankItem(BankWindow bankWindow, Base parent, int index, ContextMenu conte _bankWindow = bankWindow; TextureFilename = "bankitem.png"; - _iconImage.HoverEnter += _iconImage_HoverEnter; - _iconImage.HoverLeave += _iconImage_HoverLeave; - _iconImage.Clicked += _iconImage_Clicked; - _iconImage.DoubleClicked += _iconImage_DoubleClicked; + Icon.HoverEnter += Icon_HoverEnter; + Icon.HoverLeave += Icon_HoverLeave; + Icon.Clicked += Icon_Clicked; + Icon.DoubleClicked += Icon_DoubleClicked; _quantityLabel = new Label(this, "Quantity") { @@ -69,6 +57,8 @@ public BankItem(BankWindow bankWindow, Base parent, int index, ContextMenu conte contextMenu.LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer.GetResolutionString()); } + #region Context Menu + protected override void OnContextMenuOpening(ContextMenu contextMenu) { if (Globals.BankSlots is not { Length: > 0 } bankSlots) @@ -94,29 +84,25 @@ private void _withdrawMenuItem_Clicked(Base sender, MouseButtonState arguments) Globals.Me?.TryRetrieveItemFromBank(SlotIndex); } + #endregion + #region Mouse Events - private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) + private void Icon_HoverEnter(Base? sender, EventArgs? arguments) { if (InputHandler.MouseFocus != null) { return; } - _mouseOver = true; - _canDrag = true; - if (Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) { - _canDrag = false; return; } - if (_descWindow != null) - { - _descWindow.Dispose(); - _descWindow = null; - } + + _descriptionWindow?.Dispose(); + _descriptionWindow = null; if (Globals.BankSlots is not { Length: > 0 } bankSlots) { @@ -129,7 +115,7 @@ private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) } var item = bankSlots[SlotIndex]; - _descWindow = new ItemDescriptionWindow( + _descriptionWindow = new ItemDescriptionWindow( item.Descriptor, item.Quantity, _bankWindow.X, @@ -138,43 +124,30 @@ private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) ); } - private void _iconImage_HoverLeave(Base sender, EventArgs arguments) + private void Icon_HoverLeave(Base sender, EventArgs arguments) { - _mouseOver = false; - _mouseX = -1; - _mouseY = -1; - - if (_descWindow != null) - { - _descWindow.Dispose(); - _descWindow = null; - } + _descriptionWindow?.Dispose(); + _descriptionWindow = default; } - private void _iconImage_Clicked(Base sender, MouseButtonState arguments) + private void Icon_Clicked(Base sender, MouseButtonState arguments) { - switch (arguments.MouseButton) + if (arguments.MouseButton is MouseButton.Right) { - case MouseButton.Left: - _clickTime = Timing.Global.MillisecondsUtc + 500; - break; - - case MouseButton.Right: - if (ClientConfiguration.Instance.EnableContextMenus) - { - OpenContextMenu(); - } - else - { - _iconImage_DoubleClicked(sender, arguments); - } - break; + if (ClientConfiguration.Instance.EnableContextMenus) + { + OpenContextMenu(); + } + else + { + Icon_DoubleClicked(sender, arguments); + } } } - private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) + private void Icon_DoubleClicked(Base sender, MouseButtonState arguments) { - if (!Globals.InBank) + if (arguments.MouseButton is not MouseButton.Left) { return; } @@ -206,7 +179,78 @@ private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) #endregion - public new void Update() + #region Drag and Drop + + public override bool DragAndDrop_HandleDrop(Package package, int x, int y) + { + if (Globals.Me is not { } player) + { + return false; + } + + var rank = player.GuildRank; + var isInGuild = !string.IsNullOrWhiteSpace(player.Guild); + + if (Globals.IsGuildBank) + { + if (!isInGuild || (player.Rank != 0 && rank?.Permissions.BankDeposit == false)) + { + ChatboxMsg.AddMessage( + new ChatboxMsg( + Strings.Guilds.NotAllowedSwap.ToString(player.Guild), + CustomColors.Alerts.Error, + ChatMessageType.Bank + ) + ); + + return false; + } + } + + var targetNode = Interface.FindComponentUnderCursor(); + + // Find the first parent acceptable in that tree that can accept the package + while (targetNode != default) + { + switch (targetNode) + { + case BankItem bankItem: + PacketSender.SendMoveBankItems(SlotIndex, bankItem.SlotIndex); + return true; + + case InventoryItem inventoryItem: + + if (Globals.BankSlots is not { Length: > 0 } bankSlots) + { + return false; + } + + if (bankSlots[SlotIndex] is not { Quantity: > 0 } slot) + { + return false; + } + + player.TryRetrieveItemFromBank( + SlotIndex, + inventorySlotIndex: inventoryItem.SlotIndex, + quantityHint: slot.Quantity, + skipPrompt: true + ); + return true; + + default: + targetNode = targetNode.Parent; + break; + } + } + + // If we've reached the top of the tree, we can't drop here, so cancel drop + return false; + } + + #endregion + + public override void Update() { if (Globals.Me == default) { @@ -221,226 +265,41 @@ private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) if (bankSlots[SlotIndex] is not { Descriptor: not null } or { Quantity: <= 0 }) { _quantityLabel.IsVisibleInParent = false; - _iconImage.Texture = default; - _textureLoaded = default; + Icon.Texture = default; return; } var bankSlot = bankSlots[SlotIndex]; var descriptor = bankSlot.Descriptor; - _quantityLabel.IsVisibleInParent = !IsDragging && descriptor.IsStackable && bankSlot.Quantity > 1; + _quantityLabel.IsVisibleInParent = !Icon.IsDragging && descriptor.IsStackable && bankSlot.Quantity > 1; if (_quantityLabel.IsVisibleInParent) { _quantityLabel.Text = Strings.FormatQuantityAbbreviated(bankSlot.Quantity); } - if (_textureLoaded != descriptor.Icon) + if (Icon.TextureFilename == descriptor.Icon) { - var itemTex = Globals.ContentManager?.GetTexture(Framework.Content.TextureType.Item, descriptor.Icon); - if (itemTex != default) - { - _iconImage.Texture = itemTex; - _iconImage.RenderColor = descriptor.Color; - _iconImage.IsVisibleInParent = true; - } - else - { - if (_iconImage.Texture != default) - { - _iconImage.Texture = default; - _iconImage.IsVisibleInParent = false; - } - } - - _textureLoaded = descriptor.Icon; - - if (_descWindow != default) - { - _descWindow.Dispose(); - _descWindow = default; - _iconImage_HoverEnter(default, default); - } + return; } - if (!IsDragging) + var itemTexture = GameContentManager.Current.GetTexture(Framework.Content.TextureType.Item, descriptor.Icon); + if (itemTexture != default) { - if (_mouseOver) - { - if (!Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) - { - _canDrag = true; - _mouseX = -1; - _mouseY = -1; - if (Timing.Global.MillisecondsUtc < _clickTime) - { - //Globals.Me.TryUseItem(_mySlot); - _clickTime = 0; - } - } - else - { - if (_canDrag && Draggable.Active == null) - { - if (_mouseX == -1 || _mouseY == -1) - { - _mouseX = InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X; - _mouseY = InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y; - } - else - { - var xdiff = _mouseX - - (InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X); - - var ydiff = _mouseY - - (InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y); - - if (Math.Sqrt(Math.Pow(xdiff, 2) + Math.Pow(ydiff, 2)) > 5) - { - IsDragging = true; - _dragIcon = new Draggable( - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseX, - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseY, _iconImage.Texture, _iconImage.RenderColor - ); - } - } - } - } - } + Icon.Texture = itemTexture; + Icon.RenderColor = descriptor.Color; + Icon.IsVisibleInParent = true; } - else if (_dragIcon?.Update() == true) + else { - //Drug the item and now we stopped - IsDragging = false; - var dragRect = new FloatRect( - _dragIcon.X - (Padding.Left + Padding.Right) / 2f, - _dragIcon.Y - (Padding.Top + Padding.Bottom) / 2f, - (Padding.Left + Padding.Right) / 2f + _iconImage.Width, - (Padding.Top + Padding.Bottom) / 2f + _iconImage.Height - ); - - float bestIntersect = 0; - var bestIntersectIndex = -1; - - // So we picked up an item and then dropped it. Lets see where we dropped it to. - if (_bankWindow.RenderBounds().IntersectsWith(dragRect)) + if (Icon.Texture != default) { - var bankSlotComponents = _bankWindow.Items.ToArray(); - var bankSlotLimit = Math.Min(Globals.BankSlotCount, bankSlotComponents.Length); - for (var bankSlotIndex = 0; bankSlotIndex < bankSlotLimit; bankSlotIndex++) - { - if (bankSlotComponents[bankSlotIndex] is not BankItem bankSlotComponent) - { - continue; - } - - var bankSlotRenderBounds = bankSlotComponent.RenderBounds(); - if (!bankSlotRenderBounds.IntersectsWith(dragRect)) - { - continue; - } - - var intersection = FloatRect.Intersect(bankSlotRenderBounds, dragRect); - if (intersection.Width * intersection.Height <= bestIntersect) - { - continue; - } - - bestIntersect = intersection.Width * intersection.Height; - bestIntersectIndex = bankSlotIndex; - } - - if (bestIntersectIndex > -1) - { - if (SlotIndex != bestIntersectIndex) - { - var allowed = true; - - //Permission Check - if (Globals.IsGuildBank) - { - var rank = Globals.Me.GuildRank; - if (string.IsNullOrWhiteSpace(Globals.Me.Guild) || - (rank?.Permissions.BankDeposit == false && Globals.Me.Rank != 0)) - { - ChatboxMsg.AddMessage( - new ChatboxMsg( - Strings.Guilds.NotAllowedSwap.ToString(Globals.Me.Guild), - CustomColors.Alerts.Error, - ChatMessageType.Bank - ) - ); - allowed = false; - } - } - - if (allowed) - { - PacketSender.SendMoveBankItems(SlotIndex, bestIntersectIndex); - } - } - } + Icon.Texture = default; + Icon.IsVisibleInParent = false; } - else - { - var invWindow = Interface.GameUi.GameMenu.GetInventoryWindow(); - if (invWindow.RenderBounds().IntersectsWith(dragRect)) - { - var inventorySlots = invWindow.Items.ToArray(); - var inventorySlotLimit = Math.Min( - Globals.Me?.Inventory.Length ?? inventorySlots.Length, - inventorySlots.Length - ); - for (var inventoryIndex = 0; inventoryIndex < inventorySlotLimit; inventoryIndex++) - { - if (inventorySlots[inventoryIndex] is not InventoryItem inventorySlotComponent) - { - continue; - } - - var inventorySlotRenderBounds = inventorySlotComponent.RenderBounds(); - if (!inventorySlotRenderBounds.IntersectsWith(dragRect)) - { - continue; - } - - var intersection = FloatRect.Intersect(inventorySlotRenderBounds, dragRect); - if (intersection.Width * intersection.Height <= bestIntersect) - { - continue; - } - - bestIntersect = intersection.Width * intersection.Height; - bestIntersectIndex = inventoryIndex; - } - - if (bestIntersectIndex > -1) - { - var slot = Globals.BankSlots[SlotIndex]; - Globals.Me?.TryRetrieveItemFromBank( - SlotIndex, - inventorySlotIndex: bestIntersectIndex, - quantityHint: slot.Quantity, - skipPrompt: true - ); - } - } - } - - _dragIcon.Dispose(); } - } - - public FloatRect RenderBounds() - { - var rect = new FloatRect() - { - X = _iconImage.ToCanvas(new Point(0, 0)).X, - Y = _iconImage.ToCanvas(new Point(0, 0)).Y, - Width = _iconImage.Width, - Height = _iconImage.Height - }; - return rect; + _descriptionWindow?.Dispose(); + _descriptionWindow = default; } } diff --git a/Intersect.Client.Core/Interface/Game/Bank/BankWindow.cs b/Intersect.Client.Core/Interface/Game/Bank/BankWindow.cs index 8b77f1add4..a618f1e7a7 100644 --- a/Intersect.Client.Core/Interface/Game/Bank/BankWindow.cs +++ b/Intersect.Client.Core/Interface/Game/Bank/BankWindow.cs @@ -1,6 +1,5 @@ using Intersect.Client.Core; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.General; @@ -90,16 +89,9 @@ public void Update() } } - public FloatRect RenderBounds() + public override void Hide() { - var rect = new FloatRect() - { - X = ToCanvas(new Point(0, 0)).X - 4 / 2, - Y = ToCanvas(new Point(0, 0)).Y - 4 / 2, - Width = Width + 4, - Height = Height + 4 - }; - - return rect; + _contextMenu?.Close(); + base.Hide(); } } diff --git a/Intersect.Client.Core/Interface/Game/Draggable.cs b/Intersect.Client.Core/Interface/Game/Draggable.cs index 04d7b64810..1205e3a1c5 100644 --- a/Intersect.Client.Core/Interface/Game/Draggable.cs +++ b/Intersect.Client.Core/Interface/Game/Draggable.cs @@ -1,68 +1,42 @@ -using Intersect.Client.Core; -using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.Graphics; using Intersect.Client.Framework.Gwen.Control; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; -using Intersect.Client.Framework.Input; -using Intersect.Client.General; namespace Intersect.Client.Interface.Game; - -partial class Draggable +public partial class Draggable(Base parent, string name) : ImagePanel(parent, name) { + public bool IsDragging => DragAndDrop.CurrentPackage?.DrawControl == this; - public static Draggable Active = null; - - ImagePanel mPnl; - - public Draggable(int x, int y, IGameTexture tex, Color color) + // TODO: Fix drag and drop names + public override bool DragAndDrop_Draggable() { - mPnl = new ImagePanel(Interface.GameUi.GameCanvas, "Draggable"); - mPnl.LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer.GetResolutionString()); - mPnl.SetPosition( - InputHandler.MousePosition.X - mPnl.Width / 2, InputHandler.MousePosition.Y - mPnl.Height / 2 - ); - - mPnl.Texture = tex; - mPnl.RenderColor = color; - Active = this; + return true; } - public int X + public override bool DragAndDrop_CanAcceptPackage(Package package) { - get => mPnl.X; - set => mPnl.X = value; + return true; } - public int Y + public override Package? DragAndDrop_GetPackage(int x, int y) { - get => mPnl.Y; - set => mPnl.Y = value; + return new Package() + { + IsDraggable = true, + DrawControl = this, + Name = Name, + HoldOffset = ToLocal(InputHandler.MousePosition.X, InputHandler.MousePosition.Y), + }; } - public bool Update() + public override void DragAndDrop_StartDragging(Package package, int x, int y) { - mPnl.SetPosition( - InputHandler.MousePosition.X - mPnl.Width / 2, InputHandler.MousePosition.Y - mPnl.Height / 2 - ); - - if (!Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) - { - return true; - } - - return false; + IsVisibleInParent = false; } - public void Dispose() + public override void DragAndDrop_EndDragging(bool success, int x, int y) { - if (Active == this) - { - Active = null; - } - - Interface.GameUi.GameCanvas.RemoveChild(mPnl, false); + IsVisibleInParent = true; } - -} +} \ No newline at end of file diff --git a/Intersect.Client.Core/Interface/Game/Hotbar/HotBarWindow.cs b/Intersect.Client.Core/Interface/Game/Hotbar/HotBarWindow.cs index a528821e29..a5a8fc6059 100644 --- a/Intersect.Client.Core/Interface/Game/Hotbar/HotBarWindow.cs +++ b/Intersect.Client.Core/Interface/Game/Hotbar/HotBarWindow.cs @@ -1,6 +1,5 @@ using Intersect.Client.Core; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.General; @@ -49,17 +48,4 @@ public void Update() slot.Update(); } } - - public FloatRect RenderBounds() - { - var rect = new FloatRect - { - X = ToCanvas(default).X, - Y = ToCanvas(default).Y, - Width = Width, - Height = Height, - }; - - return rect; - } } diff --git a/Intersect.Client.Core/Interface/Game/Hotbar/HotbarItem.cs b/Intersect.Client.Core/Interface/Game/Hotbar/HotbarItem.cs index e19115505f..8a934f611d 100644 --- a/Intersect.Client.Core/Interface/Game/Hotbar/HotbarItem.cs +++ b/Intersect.Client.Core/Interface/Game/Hotbar/HotbarItem.cs @@ -4,6 +4,7 @@ using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.Control.EventArguments; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; using Intersect.Client.Framework.Input; using Intersect.Client.General; @@ -20,33 +21,23 @@ namespace Intersect.Client.Interface.Game.Hotbar; public partial class HotbarItem : SlotItem { - private const int ItemXPadding = 4; - private const int ItemYPadding = 4; - private readonly Label _cooldownLabel; private readonly Label _equipLabel; private readonly Label _keyLabel; - private bool _canDrag; - private long _clickTime; private Guid _currentId = Guid.Empty; private ItemDescriptor? _currentItem = null; private SpellDescriptor? _currentSpell = null; - private Draggable _dragIcon; - private bool _isDragging; private bool _isEquipped; private bool _isFaded; private readonly Base _hotbarWindow; private ControlBinding? _hotKey; private Item? _inventoryItem = null; private int _inventoryItemIndex = -1; - private ItemDescriptionWindow? _itemDescWindow; - private bool _mouseOver; - private int _mouseX = -1; - private int _mouseY = -1; + private ItemDescriptionWindow? _itemDescriptionWindow; private Label _quantityLabel; private Spell? _spellBookItem = null; - private SpellDescriptionWindow? _spellDescWindow; + private SpellDescriptionWindow? _spellDescriptionWindow; private bool _textureLoaded; public HotbarItem(int hotbarSlotIndex, Base hotbarWindow) @@ -65,12 +56,12 @@ public HotbarItem(int hotbarSlotIndex, Base hotbarWindow) RestrictToParent = true; TextureFilename = "hotbaritem.png"; - // _iconImage is layered on top of the container (shows the Item or Spell Icon). - _iconImage.Name = $"{nameof(HotbarItem)}{SlotIndex}"; - _iconImage.SetPosition(1, 1); - _iconImage.HoverEnter += _iconImage_HoverEnter; - _iconImage.HoverLeave += _iconImage_HoverLeave; - _iconImage.Clicked += _iconImage_Clicked; + Icon.Name = $"{nameof(HotbarItem)}{SlotIndex}"; + Icon.SetPosition(1, 1); + Icon.HoverEnter += Icon_HoverEnter; + Icon.HoverLeave += Icon_HoverLeave; + Icon.Clicked += Icon_Clicked; + Icon.DoubleClicked += Icon_DoubleClicked; var font = GameContentManager.Current.GetFont("sourcesansproblack"); @@ -143,6 +134,11 @@ public void Activate() return; } + if (DragAndDrop.IsDragging) + { + return; + } + if (_currentId != Guid.Empty && Globals.Me != null) { if (_currentItem != null) @@ -159,61 +155,47 @@ public void Activate() } } - private void _iconImage_Clicked(Base sender, MouseButtonState arguments) + private void Icon_Clicked(Base sender, MouseButtonState arguments) { - switch (arguments.MouseButton) + if (arguments.MouseButton is MouseButton.Right) { - case MouseButton.Left: - _clickTime = Timing.Global.MillisecondsUtc + 500; - break; - - case MouseButton.Right: - Globals.Me?.AddToHotbar(SlotIndex, -1, -1); - break; + Globals.Me?.AddToHotbar(SlotIndex, -1, -1); } } - private void _iconImage_HoverLeave(Base sender, EventArgs arguments) + private void Icon_DoubleClicked(Base sender, MouseButtonState arguments) { - _mouseOver = false; - _mouseX = -1; - _mouseY = -1; - if (_itemDescWindow != null) + if (arguments.MouseButton is MouseButton.Left) { - _itemDescWindow.Dispose(); - _itemDescWindow = null; + Activate(); } + } - if (_spellDescWindow != null) - { - _spellDescWindow.Dispose(); - _spellDescWindow = null; - } + private void Icon_HoverLeave(Base sender, EventArgs arguments) + { + _itemDescriptionWindow?.Dispose(); + _itemDescriptionWindow = null; + + _spellDescriptionWindow?.Dispose(); + _spellDescriptionWindow = null; } - private void _iconImage_HoverEnter(Base sender, EventArgs arguments) + private void Icon_HoverEnter(Base sender, EventArgs arguments) { if (InputHandler.MouseFocus != null || Globals.Me == null) { return; } - _mouseOver = true; - _canDrag = true; if (Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) { - _canDrag = false; - return; } if (_currentItem != null && _inventoryItem != null) { - if (_itemDescWindow != null) - { - _itemDescWindow.Dispose(); - _itemDescWindow = null; - } + _itemDescriptionWindow?.Dispose(); + _itemDescriptionWindow = null; var quantityOfItem = 1; @@ -222,39 +204,50 @@ private void _iconImage_HoverEnter(Base sender, EventArgs arguments) quantityOfItem = Globals.Me.GetQuantityOfItemInInventory(_currentItem.Id); } - _itemDescWindow = new ItemDescriptionWindow( + _itemDescriptionWindow = new ItemDescriptionWindow( _currentItem, quantityOfItem, _hotbarWindow.X + (_hotbarWindow.Width / 2), _hotbarWindow.Y + _hotbarWindow.Height + 2, _inventoryItem.ItemProperties, _currentItem.Name, "" ); } else if (_currentSpell != null) { - if (_spellDescWindow != null) - { - _spellDescWindow.Dispose(); - _spellDescWindow = null; - } + _spellDescriptionWindow?.Dispose(); + _spellDescriptionWindow = null; - _spellDescWindow = new SpellDescriptionWindow( + _spellDescriptionWindow = new SpellDescriptionWindow( _currentSpell.Id, _hotbarWindow.X + (_hotbarWindow.Width / 2), _hotbarWindow.Y + _hotbarWindow.Height + 2 ); } } - public FloatRect RenderBounds() + public override bool DragAndDrop_HandleDrop(Package package, int x, int y) { - var rect = new FloatRect() + if (Globals.Me is not { } player) { - X = ToCanvas(new Point(0, 0)).X, - Y = ToCanvas(new Point(0, 0)).Y, - Width = Width, - Height = Height - }; + return false; + } + + var targetNode = Interface.FindComponentUnderCursor(); - return rect; + // Find the first parent acceptable in that tree that can accept the package + while (targetNode != default) + { + if (targetNode is HotbarItem hotbarItem) + { + player.HotbarSwap(SlotIndex, hotbarItem.SlotIndex); + return true; + } + else + { + targetNode = targetNode.Parent; + } + } + + // If we've reached the top of the tree, we can't drop here, so cancel drop + return false; } - public void Update() + public override void Update() { if (Globals.Me == null || Controls.ActiveControls == null) { @@ -405,12 +398,27 @@ public void Update() } } + var isDragging = Icon.IsDragging; + var invalidInventoryIndex = _inventoryItemIndex < 0; + if (isDragging) + { + _equipLabel.IsHidden = true; + _quantityLabel.IsHidden = true; + _cooldownLabel.IsHidden = true; + } + else + { + _equipLabel.IsHidden = !_isEquipped || invalidInventoryIndex; + _quantityLabel.IsHidden = _currentItem?.Stackable == false || invalidInventoryIndex; + _cooldownLabel.IsHidden = !_isFaded || invalidInventoryIndex; + } + if (updateDisplay) //Item on cd and fade is incorrect { if (_currentItem != null) { - _iconImage.Show(); - _iconImage.Texture = Globals.ContentManager.GetTexture( + Icon.IsVisibleInTree = !isDragging; + Icon.Texture = GameContentManager.Current.GetTexture( Framework.Content.TextureType.Item, _currentItem.Icon ); @@ -418,12 +426,12 @@ public void Update() _quantityLabel.IsHidden = true; _cooldownLabel.IsHidden = true; - if (_inventoryItemIndex > -1) + if (!invalidInventoryIndex) { _isFaded = Globals.Me.IsItemOnCooldown(_inventoryItemIndex); _isEquipped = Globals.Me.IsEquipped(_inventoryItemIndex); - if (_isFaded) + if (_isFaded && !isDragging) { _cooldownLabel.IsHidden = false; _cooldownLabel.Text = TimeSpan @@ -440,16 +448,12 @@ public void Update() _isFaded = true; } - _equipLabel.IsHidden = !_isEquipped || _inventoryItemIndex < 0; - _quantityLabel.IsHidden = !_currentItem.Stackable || _inventoryItemIndex < 0; - _cooldownLabel.IsHidden = !_isFaded || _inventoryItemIndex < 0; - _textureLoaded = true; } else if (_currentSpell != null) { - _iconImage.Show(); - _iconImage.Texture = Globals.ContentManager.GetTexture( + Icon.IsVisibleInTree = !isDragging; + Icon.Texture = Globals.ContentManager.GetTexture( Framework.Content.TextureType.Spell, _currentSpell.Icon ); @@ -460,7 +464,7 @@ public void Update() { var spellSlot = Globals.Me.FindHotbarSpell(slot); _isFaded = Globals.Me.IsSpellOnCooldown(spellSlot); - if (_isFaded) + if (_isFaded && !isDragging) { _cooldownLabel.IsHidden = false; var remaining = Globals.Me.GetSpellRemainingCooldown(spellSlot); @@ -477,7 +481,7 @@ public void Update() } else { - _iconImage.Hide(); + Icon.Hide(); _textureLoaded = true; _isEquipped = false; _equipLabel.IsHidden = true; @@ -489,143 +493,26 @@ public void Update() { if (_currentSpell != null) { - _iconImage.RenderColor = new Color(60, 255, 255, 255); + Icon.RenderColor = new Color(60, 255, 255, 255); } if (_currentItem != null) { - _iconImage.RenderColor = new Color(60, _currentItem.Color.R, _currentItem.Color.G, _currentItem.Color.B); + Icon.RenderColor = new Color(60, _currentItem.Color.R, _currentItem.Color.G, _currentItem.Color.B); } } else { if (_currentSpell != null) { - _iconImage.RenderColor = Color.White; + Icon.RenderColor = Color.White; } if (_currentItem != null) { - _iconImage.RenderColor = _currentItem.Color; + Icon.RenderColor = _currentItem.Color; } } } - - if (_currentItem != null || _currentSpell != null) - { - if (!_isDragging) - { - _iconImage.IsHidden = false; - - var equipLabelIsHidden = _currentItem == null || !Globals.Me.IsEquipped(_inventoryItemIndex) || _inventoryItemIndex < 0; - _equipLabel.IsHidden = equipLabelIsHidden; - - var quantityLabelIsHidden = _currentItem is not { Stackable: true } || _inventoryItemIndex < 0; - _quantityLabel.IsHidden = quantityLabelIsHidden; - - if (_mouseOver) - { - if (!Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) - { - _canDrag = true; - _mouseX = -1; - _mouseY = -1; - if (Timing.Global.MillisecondsUtc < _clickTime) - { - Activate(); - _clickTime = 0; - } - } - else - { - if (_canDrag && Draggable.Active == null) - { - if (_mouseX == -1 || _mouseY == -1) - { - _mouseX = InputHandler.MousePosition.X - ToCanvas(new Point(0, 0)).X; - _mouseY = InputHandler.MousePosition.Y - ToCanvas(new Point(0, 0)).Y; - } - else - { - var xdiff = _mouseX - - (InputHandler.MousePosition.X - - ToCanvas(new Point(0, 0)).X); - - var ydiff = _mouseY - - (InputHandler.MousePosition.Y - - ToCanvas(new Point(0, 0)).Y); - - if (Math.Sqrt(Math.Pow(xdiff, 2) + Math.Pow(ydiff, 2)) > 5) - { - _isDragging = true; - _dragIcon = new Draggable( - ToCanvas(new Point(0, 0)).X + _mouseX, - ToCanvas(new Point(0, 0)).X + _mouseY, _iconImage.Texture, _iconImage.RenderColor - ); - - //SOMETHING SHOULD BE RENDERED HERE, RIGHT? - } - } - } - } - } - } - else if (_dragIcon.Update()) - { - //Drug the item and now we stopped - _isDragging = false; - FloatRect dragRect = new( - _dragIcon.X - ItemXPadding / 2f, - _dragIcon.Y - ItemYPadding / 2f, - ItemXPadding / 2f + 32, - ItemYPadding / 2f + 32 - ); - - float bestIntersect = 0; - var bestIntersectIndex = -1; - - if (Interface.GameUi.Hotbar.RenderBounds().IntersectsWith(dragRect)) - { - var hotbarSlotComponents = Interface.GameUi.Hotbar.Items.ToArray(); - var hotbarSlotLimit = Math.Min( - Options.Instance.Player.HotbarSlotCount, - hotbarSlotComponents.Length - ); - for (var hotbarSlotIndex = 0; hotbarSlotIndex < hotbarSlotLimit; hotbarSlotIndex++) - { - var hotbarSlotComponent = hotbarSlotComponents[hotbarSlotIndex]; - var hotbarSlotRenderBounds = hotbarSlotComponent.RenderBounds(); - if (!hotbarSlotRenderBounds.IntersectsWith(dragRect)) - { - continue; - } - - var intersection = FloatRect.Intersect(hotbarSlotRenderBounds, dragRect); - if (intersection.Width * intersection.Height <= bestIntersect) - { - continue; - } - - bestIntersect = intersection.Width * intersection.Height; - - bestIntersectIndex = hotbarSlotIndex; - } - - if (bestIntersectIndex > -1 && bestIntersectIndex != SlotIndex) - { - Globals.Me.HotbarSwap(SlotIndex, (byte)bestIntersectIndex); - } - } - - _dragIcon.Dispose(); - } - else - { - _iconImage.IsHidden = true; - _equipLabel.IsHidden = true; - _quantityLabel.IsHidden = true; - _cooldownLabel.IsHidden = true; - } - } } } diff --git a/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs b/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs index 966f3e776f..61e39b21a2 100644 --- a/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs +++ b/Intersect.Client.Core/Interface/Game/Inventory/InventoryItem.cs @@ -1,20 +1,21 @@ using Intersect.Client.Core; using Intersect.Client.Entities; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.Control.EventArguments; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; using Intersect.Client.Framework.Input; using Intersect.Client.General; using Intersect.Client.Interface.Game.Bag; using Intersect.Client.Interface.Game.Bank; using Intersect.Client.Interface.Game.DescriptionWindows; +using Intersect.Client.Interface.Game.Hotbar; +using Intersect.Client.Interface.Game.Shop; using Intersect.Client.Localization; using Intersect.Client.Networking; using Intersect.Configuration; -using Intersect.Framework.Core; using Intersect.Framework.Core.GameObjects.Items; using Intersect.GameObjects; using Intersect.Utilities; @@ -29,19 +30,7 @@ public partial class InventoryItem : SlotItem private readonly Label _cooldownLabel; private readonly ImagePanel _equipImageBackground; private readonly InventoryWindow _inventoryWindow; - private Draggable? _dragIcon; - private ItemDescriptionWindow? _descWindow; - - // Drag Handling - public bool IsDragging; - private bool _canDrag; - private long _clickTime; - private bool _mouseOver; - private int _mouseX = -1; - private int _mouseY = -1; - - // Data control - private string _textureLoaded = string.Empty; + private ItemDescriptionWindow? _descriptionWindow; // Context Menu Handling private readonly MenuItem _useItemMenuItem; @@ -54,10 +43,10 @@ public InventoryItem(InventoryWindow inventoryWindow, Base parent, int index, Co _inventoryWindow = inventoryWindow; TextureFilename = "inventoryitem.png"; - _iconImage.HoverEnter += _iconImage_HoverEnter; - _iconImage.HoverLeave += _iconImage_HoverLeave; - _iconImage.Clicked += _iconImage_Clicked; - _iconImage.DoubleClicked += _iconImage_DoubleClicked; + Icon.HoverEnter += Icon_HoverEnter; + Icon.HoverLeave += Icon_HoverLeave; + Icon.Clicked += Icon_Clicked; + Icon.DoubleClicked += Icon_DoubleClicked; _equipImageBackground = new ImagePanel(this, "EquippedIcon") { @@ -215,7 +204,7 @@ private void _actionItemContextItem_Clicked(Base sender, MouseButtonState argume } } - private void _dropItemContextItem_Clicked(Base sender, Framework.Gwen.Control.EventArguments.MouseButtonState arguments) + private void _dropItemContextItem_Clicked(Base sender, MouseButtonState arguments) { Globals.Me?.TryDropItem(SlotIndex); } @@ -224,7 +213,7 @@ private void _dropItemContextItem_Clicked(Base sender, Framework.Gwen.Control.Ev #region Mouse Events - private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) + private void Icon_DoubleClicked(Base sender, MouseButtonState arguments) { if (Globals.Me == default) { @@ -269,79 +258,68 @@ private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) } } - private void _iconImage_Clicked(Base sender, MouseButtonState arguments) + private void Icon_Clicked(Base sender, MouseButtonState arguments) { - switch (arguments.MouseButton) + if (arguments.MouseButton is not MouseButton.Right) { - case MouseButton.Left: - _clickTime = Timing.Global.MillisecondsUtc + 500; - break; + return; + } - case MouseButton.Right: - if (ClientConfiguration.Instance.EnableContextMenus) - { - OpenContextMenu(); - } - else - { - if (Globals.GameShop != null) - { - Globals.Me?.TrySellItem(SlotIndex); - } - else if (Globals.InBank) - { - Globals.Me?.TryStoreItemInBank(SlotIndex); - } - else if (Globals.InBag) - { - Globals.Me?.TryStoreItemInBag(SlotIndex, -1); - } - else if (Globals.InTrade) - { - Globals.Me?.TryOfferItemToTrade(SlotIndex); - } - else - { - Globals.Me?.TryDropItem(SlotIndex); - } - } - break; + if (ClientConfiguration.Instance.EnableContextMenus) + { + OpenContextMenu(); + return; } - } - private void _iconImage_HoverLeave(Base sender, EventArgs arguments) - { - _mouseOver = false; - _mouseX = -1; - _mouseY = -1; + if (Globals.Me is not { } player) + { + return; + } - if (_descWindow != null) + if (Globals.GameShop != null) + { + player.TrySellItem(SlotIndex); + } + else if (Globals.InBank) + { + player.TryStoreItemInBank(SlotIndex); + } + else if (Globals.InBag) + { + player.TryStoreItemInBag(SlotIndex, -1); + } + else if (Globals.InTrade) { - _descWindow.Dispose(); - _descWindow = null; + player.TryOfferItemToTrade(SlotIndex); + } + else + { + player.TryDropItem(SlotIndex); } } - void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) + private void Icon_HoverLeave(Base sender, EventArgs arguments) + { + _descriptionWindow?.Dispose(); + _descriptionWindow = null; + } + + void Icon_HoverEnter(Base? sender, EventArgs? arguments) { if (InputHandler.MouseFocus != null) { return; } - _mouseOver = true; - _canDrag = true; - if (Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) { - _canDrag = false; return; } - if (_descWindow != null) + if (_descriptionWindow != null) { - _descWindow.Dispose(); - _descWindow = null; + _descriptionWindow.Dispose(); + _descriptionWindow = null; } if (Globals.Me?.Inventory[SlotIndex] is not { } inventorySlot) @@ -357,7 +335,7 @@ void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) if (Globals.GameShop == null) { - _descWindow = new ItemDescriptionWindow( + _descriptionWindow = new ItemDescriptionWindow( inventorySlotDescriptor, inventorySlot.Quantity, _inventoryWindow.X, @@ -385,7 +363,7 @@ void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) return; } - _descWindow = new ItemDescriptionWindow( + _descriptionWindow = new ItemDescriptionWindow( inventorySlotDescriptor, inventorySlot.Quantity, _inventoryWindow.X, @@ -400,7 +378,7 @@ void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) var costItem = Globals.GameShop.DefaultCurrency; if (inventorySlotDescriptor != null && costItem != null) { - _descWindow = new ItemDescriptionWindow( + _descriptionWindow = new ItemDescriptionWindow( inventorySlotDescriptor, inventorySlot.Quantity, _inventoryWindow.X, @@ -413,7 +391,7 @@ void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) } else { - _descWindow = new ItemDescriptionWindow( + _descriptionWindow = new ItemDescriptionWindow( inventorySlotDescriptor, inventorySlot.Quantity, _inventoryWindow.X, @@ -428,6 +406,80 @@ void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) #endregion + #region Drag and Drop + + public override bool DragAndDrop_HandleDrop(Package package, int x, int y) + { + if (Globals.Me is not { } player) + { + return false; + } + + if (player.Inventory is not { } inventory) + { + return false; + } + + if (inventory[SlotIndex] is not { } inventorySlot) + { + return false; + } + + if (!Interface.DoesMouseHitInterface() && !player.IsBusy) + { + PacketSender.SendDropItem(SlotIndex, inventorySlot.Quantity); + return true; + } + + var targetNode = Interface.FindComponentUnderCursor(); + + // Find the first parent acceptable in that tree that can accept the package + while (targetNode != default) + { + switch (targetNode) + { + case InventoryItem inventoryItem: + if (inventoryItem.SlotIndex == SlotIndex) + { + return false; + } + + player.SwapItems(SlotIndex, inventoryItem.SlotIndex); + return true; + + case BagItem bagItem: + player.TryStoreItemInBag(SlotIndex, bagItem.SlotIndex); + return true; + + case BankItem bankItem: + player.TryStoreItemInBank( + SlotIndex, + bankSlotIndex: bankItem.SlotIndex, + quantityHint: inventorySlot.Quantity, + skipPrompt: true + ); + return true; + + case HotbarItem hotbarItem: + player.AddToHotbar(hotbarItem.SlotIndex, 0, SlotIndex); + return true; + + case ShopWindow: + player.TrySellItem(SlotIndex); + return true; + + default: + targetNode = targetNode.Parent; + break; + } + } + + // If we've reached the top of the tree, we can't drop here, so cancel drop + return false; + } + + #endregion + private void PlayerOnInventoryUpdated(Player player, int slotIndex) { if (player != Globals.Me) @@ -446,20 +498,7 @@ private void PlayerOnInventoryUpdated(Player player, int slotIndex) } // empty texture to reload on update - _textureLoaded = string.Empty; - } - - public FloatRect RenderBounds() - { - var rect = new FloatRect() - { - X = _iconImage.ToCanvas(new Point(0, 0)).X, - Y = _iconImage.ToCanvas(new Point(0, 0)).Y, - Width = _iconImage.Width, - Height = _iconImage.Height - }; - - return rect; + Icon.Texture = default; } public override void Update() @@ -481,299 +520,68 @@ public override void Update() } var equipped = Globals.Me.MyEquipment.Any(s => s == SlotIndex); - _equipImageBackground.IsVisibleInParent = !IsDragging && equipped; - _equipLabel.IsVisibleInParent = !IsDragging && equipped; + var isDragging = Icon.IsDragging; + _equipImageBackground.IsVisibleInParent = !isDragging && equipped; + _equipLabel.IsVisibleInParent = !isDragging && equipped; - _quantityLabel.IsVisibleInParent = !IsDragging && descriptor.IsStackable && inventorySlot.Quantity > 1; + _quantityLabel.IsVisibleInParent = !isDragging && descriptor.IsStackable && inventorySlot.Quantity > 1; if (_quantityLabel.IsVisibleInParent) { _quantityLabel.Text = Strings.FormatQuantityAbbreviated(inventorySlot.Quantity); } - _cooldownLabel.IsVisibleInParent = !IsDragging && Globals.Me.IsItemOnCooldown(SlotIndex); + _cooldownLabel.IsVisibleInParent = !isDragging && Globals.Me.IsItemOnCooldown(SlotIndex); if (_cooldownLabel.IsVisibleInParent) { var itemCooldownRemaining = Globals.Me.GetItemRemainingCooldown(SlotIndex); _cooldownLabel.Text = TimeSpan.FromMilliseconds(itemCooldownRemaining).WithSuffix("0.0"); - _iconImage.RenderColor.A = 100; + Icon.RenderColor.A = 100; } else { - _iconImage.RenderColor.A = descriptor.Color.A; + Icon.RenderColor.A = descriptor.Color.A; } - if (_textureLoaded != descriptor.Icon) + if (Icon.TextureFilename == descriptor.Icon) { - var itemTex = Globals.ContentManager?.GetTexture(Framework.Content.TextureType.Item, descriptor.Icon); - if (itemTex != null) - { - _iconImage.Texture = itemTex; - _iconImage.RenderColor = Globals.Me.IsItemOnCooldown(SlotIndex) - ? new Color(100, descriptor.Color.R, descriptor.Color.G, descriptor.Color.B) - : descriptor.Color; - _iconImage.IsVisibleInParent = true; - } - else - { - if (_iconImage.Texture != null) - { - _iconImage.Texture = null; - _iconImage.IsVisibleInParent = false; - } - } - - _textureLoaded = descriptor.Icon; - - if (_descWindow != null) - { - _descWindow.Dispose(); - _descWindow = null; - _iconImage_HoverEnter(null, null); - } + return; } - if (!IsDragging) + var itemTexture = GameContentManager.Current.GetTexture(Framework.Content.TextureType.Item, descriptor.Icon); + if (itemTexture != null) { - if (_mouseOver) - { - if (!Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) - { - _canDrag = true; - _mouseX = -1; - _mouseY = -1; - - if (Timing.Global.MillisecondsUtc < _clickTime) - { - _clickTime = 0; - } - } - else - { - if (_canDrag && Draggable.Active == null) - { - if (_mouseX == -1 || _mouseY == -1) - { - _mouseX = InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X; - _mouseY = InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y; - } - else - { - var xdiff = _mouseX - - (InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X); - - var ydiff = _mouseY - - (InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y); - - if (Math.Sqrt(Math.Pow(xdiff, 2) + Math.Pow(ydiff, 2)) > 5) - { - IsDragging = true; - _iconImage.IsVisibleInParent = false; - - _dragIcon = new Draggable( - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseX, - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseY, _iconImage.Texture, _iconImage.RenderColor - ); - } - } - } - } - } + Icon.Texture = itemTexture; + Icon.RenderColor = Globals.Me.IsItemOnCooldown(SlotIndex) + ? new Color(100, descriptor.Color.R, descriptor.Color.G, descriptor.Color.B) + : descriptor.Color; + Icon.IsVisibleInParent = true; } - else if (_dragIcon?.Update() == true) + else { - //Drug the item and now we stopped - IsDragging = false; - _iconImage.IsVisibleInParent = true; - - var dragRect = new FloatRect( - _dragIcon.X - (Padding.Left + Padding.Right) / 2f, - _dragIcon.Y - (Padding.Top + Padding.Bottom) / 2f, - (Padding.Left + Padding.Right) / 2f + _iconImage.Width, - (Padding.Top + Padding.Bottom) / 2f + _iconImage.Height - ); - - float bestIntersect = 0; - var bestIntersectIndex = -1; - - //So we picked up an item and then dropped it. Lets see where we dropped it to. - //Check inventory first. - if (_inventoryWindow.RenderBounds().IntersectsWith(dragRect)) + if (Icon.Texture != null) { - var inventorySlotComponents = _inventoryWindow.Items.ToArray(); - var inventorySlotLimit = Math.Min(Options.Instance.Player.MaxInventory, inventorySlotComponents.Length); - for (var inventoryIndex = 0; inventoryIndex < inventorySlotLimit; inventoryIndex++) - { - var inventorySlotComponent = inventorySlotComponents[inventoryIndex]; - var inventoryRenderBounds = ((InventoryItem)inventorySlotComponent).RenderBounds(); - - if (!inventoryRenderBounds.IntersectsWith(dragRect)) - { - continue; - } - - var intersection = FloatRect.Intersect(inventoryRenderBounds, dragRect); - if (!(intersection.Width * intersection.Height > bestIntersect)) - { - continue; - } - - bestIntersect = intersection.Width * intersection.Height; - bestIntersectIndex = inventoryIndex; - } - - if (bestIntersectIndex > -1) - { - if (SlotIndex != bestIntersectIndex) - { - Globals.Me.SwapItems(SlotIndex, bestIntersectIndex); - } - } - } - else if (Interface.GameUi.Hotbar.RenderBounds().IntersectsWith(dragRect)) - { - var hotbarSlotComponents = Interface.GameUi.Hotbar.Items.ToArray(); - var hotbarSlotLimit = Math.Min( - Options.Instance.Player.HotbarSlotCount, - hotbarSlotComponents.Length - ); - for (var hotbarSlotIndex = 0; hotbarSlotIndex < hotbarSlotLimit; hotbarSlotIndex++) - { - var hotbarSlotComponent = hotbarSlotComponents[hotbarSlotIndex]; - var hotbarSlotRenderBounds = hotbarSlotComponent.RenderBounds(); - if (!hotbarSlotRenderBounds.IntersectsWith(dragRect)) - { - continue; - } - - var intersection = FloatRect.Intersect(hotbarSlotRenderBounds, dragRect); - if (intersection.Width * intersection.Height <= bestIntersect) - { - continue; - } - - bestIntersect = intersection.Width * intersection.Height; - bestIntersectIndex = hotbarSlotIndex; - } - - if (bestIntersectIndex > -1) - { - Globals.Me.AddToHotbar((byte)bestIntersectIndex, 0, SlotIndex); - } - } - else if (Globals.InBag && Globals.BagSlots != default) - { - var bagWindow = Interface.GameUi.GetBagWindow(); - if (bagWindow.RenderBounds().IntersectsWith(dragRect)) - { - var bagSlotComponents = bagWindow.Items.ToArray(); - var bagSlotLimit = Math.Min(Globals.BagSlots.Length, bagSlotComponents.Length); - for (var bagSlotIndex = 0; bagSlotIndex < bagSlotLimit; bagSlotIndex++) - { - if (bagSlotComponents[bagSlotIndex] is not BagItem bagSlotComponent) - { - continue; - } - - var bagSlotRenderBounds = bagSlotComponent.RenderBounds(); - if (!bagSlotRenderBounds.IntersectsWith(dragRect)) - { - continue; - } - - var intersection = FloatRect.Intersect(bagSlotRenderBounds, dragRect); - if (intersection.Width * intersection.Height <= bestIntersect) - { - continue; - } - - bestIntersect = intersection.Width * intersection.Height; - bestIntersectIndex = bagSlotIndex; - } - - if (bestIntersectIndex > -1) - { - Globals.Me.TryStoreItemInBag(SlotIndex, bestIntersectIndex); - } - } - } - else if (Globals.InBank && Globals.BankSlots != default) - { - if (Interface.GameUi.GetBankWindow() is not BankWindow bankWindow) - { - return; - } - - if (bankWindow.RenderBounds().IntersectsWith(dragRect)) - { - var bankSlotComponents = bankWindow.Items.ToArray(); - var bankSlotLimit = Math.Min( - Math.Min(Globals.BankSlots.Length, Globals.BankSlotCount), - bankSlotComponents.Length - ); - - for (var bankSlotIndex = 0; bankSlotIndex < bankSlotLimit; bankSlotIndex++) - { - if (bankSlotComponents[bankSlotIndex] is not BankItem bankSlotComponent) - { - continue; - } - - var bankSlotRenderBounds = bankSlotComponent.RenderBounds(); - if (!bankSlotRenderBounds.IntersectsWith(dragRect)) - { - continue; - } - - var intersection = FloatRect.Intersect(bankSlotRenderBounds, dragRect); - if (!(intersection.Width * intersection.Height > bestIntersect)) - { - continue; - } - - bestIntersect = intersection.Width * intersection.Height; - bestIntersectIndex = bankSlotIndex; - } - - if (bestIntersectIndex > -1) - { - var slot = Globals.Me.Inventory[SlotIndex]; - Globals.Me.TryStoreItemInBank( - SlotIndex, - bankSlotIndex: bestIntersectIndex, - quantityHint: slot.Quantity, - skipPrompt: true - ); - } - } - } - else if (!Globals.Me.IsBusy) - { - PacketSender.SendDropItem(SlotIndex, Globals.Me.Inventory[SlotIndex].Quantity); + Icon.Texture = null; + Icon.IsVisibleInParent = false; } + } - _dragIcon.Dispose(); + if (_descriptionWindow != null) + { + _descriptionWindow.Dispose(); + _descriptionWindow = null; + Icon_HoverEnter(null, null); } } private void _reset() { - _iconImage.IsVisibleInParent = false; + Icon.IsVisibleInParent = false; + Icon.Texture = default; _equipImageBackground.IsVisibleInParent = false; _quantityLabel.IsVisibleInParent = false; _equipLabel.IsVisibleInParent = false; _cooldownLabel.IsVisibleInParent = false; - _textureLoaded = string.Empty; - - if (_dragIcon != default) - { - _dragIcon.Dispose(); - _dragIcon = default; - } - - if (_descWindow != default) - { - _descWindow.Dispose(); - _descWindow = default; - } + _descriptionWindow?.Dispose(); + _descriptionWindow = default; } } diff --git a/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs b/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs index 8075650794..10a7a8725b 100644 --- a/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs +++ b/Intersect.Client.Core/Interface/Game/Inventory/InventoryWindow.cs @@ -1,6 +1,5 @@ using Intersect.Client.Core; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.General; @@ -99,19 +98,4 @@ public override void Hide() _contextMenu?.Close(); base.Hide(); } - - // TODO: Window has RenderBounds as property, but InventoryWindow has it as a method. This should be consistent. - public FloatRect RenderBounds() - { - var tempSlot = Items[0]; - var rect = new FloatRect() - { - X = ToCanvas(new Point(0, 0)).X - (tempSlot.Padding.Left + tempSlot.Padding.Right) / 2, - Y = ToCanvas(new Point(0, 0)).Y - (tempSlot.Padding.Top + tempSlot.Padding.Bottom) / 2, - Width = Width + tempSlot.Padding.Left + tempSlot.Padding.Right, - Height = Height + tempSlot.Padding.Top + tempSlot.Padding.Bottom - }; - - return rect; - } } diff --git a/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs b/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs index 235eedf673..18332db7fe 100644 --- a/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs +++ b/Intersect.Client.Core/Interface/Game/Shop/ShopItem.cs @@ -2,10 +2,12 @@ using Intersect.Client.Framework.File_Management; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.Control.EventArguments; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; using Intersect.Client.Framework.Input; using Intersect.Client.General; using Intersect.Client.Interface.Game.DescriptionWindows; +using Intersect.Client.Interface.Game.Inventory; using Intersect.Client.Localization; using Intersect.Configuration; using Intersect.Framework.Core.GameObjects.Items; @@ -17,7 +19,7 @@ public partial class ShopItem : SlotItem private readonly int _mySlot; private readonly ShopWindow _shopWindow; private readonly MenuItem _buyMenuItem; - private ItemDescriptionWindow? _itemDescWindow; + private ItemDescriptionWindow? _descriptionWindow; public ShopItem(ShopWindow shopWindow, Base parent, int index, ContextMenu contextMenu) : base(parent, nameof(ShopItem), index, contextMenu) @@ -26,10 +28,10 @@ public ShopItem(ShopWindow shopWindow, Base parent, int index, ContextMenu conte _mySlot = index; TextureFilename = "shopitem.png"; - _iconImage.HoverEnter += _iconImage_HoverEnter; - _iconImage.HoverLeave += _iconImage_HoverLeave; - _iconImage.Clicked += _iconImage_RightClicked; - _iconImage.DoubleClicked += _iconImage_DoubleClicked; + Icon.HoverEnter += Icon_HoverEnter; + Icon.HoverLeave += Icon_HoverLeave; + Icon.Clicked += Icon_RightClicked; + Icon.DoubleClicked += Icon_DoubleClicked; LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer.GetResolutionString()); @@ -41,7 +43,7 @@ public ShopItem(ShopWindow shopWindow, Base parent, int index, ContextMenu conte LoadItem(); } - private void _iconImage_HoverEnter(Base sender, EventArgs arguments) + private void Icon_HoverEnter(Base sender, EventArgs arguments) { if (InputHandler.MouseFocus != null) { @@ -53,10 +55,10 @@ private void _iconImage_HoverEnter(Base sender, EventArgs arguments) return; } - if (_itemDescWindow != default) + if (_descriptionWindow != default) { - _itemDescWindow.Dispose(); - _itemDescWindow = default; + _descriptionWindow.Dispose(); + _descriptionWindow = default; } if (Globals.GameShop is not { SellingItems.Count: > 0 } gameShop) @@ -76,7 +78,7 @@ private void _iconImage_HoverEnter(Base sender, EventArgs arguments) StatModifiers = item.StatsGiven, }; - _itemDescWindow = new ItemDescriptionWindow( + _descriptionWindow = new ItemDescriptionWindow( item: gameShop.SellingItems[_mySlot].Item, amount: 1, x: _shopWindow.X, @@ -87,16 +89,16 @@ private void _iconImage_HoverEnter(Base sender, EventArgs arguments) } } - private void _iconImage_HoverLeave(Base sender, EventArgs arguments) + private void Icon_HoverLeave(Base sender, EventArgs arguments) { - if (_itemDescWindow != null) + if (_descriptionWindow != null) { - _itemDescWindow.Dispose(); - _itemDescWindow = null; + _descriptionWindow.Dispose(); + _descriptionWindow = null; } } - private void _iconImage_RightClicked(Base sender, MouseButtonState arguments) + private void Icon_RightClicked(Base sender, MouseButtonState arguments) { if (arguments.MouseButton != MouseButton.Right) { @@ -109,11 +111,11 @@ private void _iconImage_RightClicked(Base sender, MouseButtonState arguments) } else { - _iconImage_DoubleClicked(sender, arguments); + Icon_DoubleClicked(sender, arguments); } } - private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) + private void Icon_DoubleClicked(Base sender, MouseButtonState arguments) { Globals.Me?.TryBuyItem(_mySlot); } @@ -156,8 +158,29 @@ public void LoadItem() var itemTex = Globals.ContentManager?.GetTexture(Framework.Content.TextureType.Item, itemDescriptor.Icon); if (itemTex != null) { - _iconImage.Texture = itemTex; - _iconImage.RenderColor = itemDescriptor.Color; + Icon.Texture = itemTex; + Icon.RenderColor = itemDescriptor.Color; } } + + public override bool DragAndDrop_HandleDrop(Package package, int x, int y) + { + var targetNode = Interface.FindComponentUnderCursor(); + + // Find the first parent acceptable in that tree that can accept the package + while (targetNode != default) + { + if (targetNode is not InventoryWindow) + { + targetNode = targetNode.Parent; + continue; + } + + Globals.Me?.TryBuyItem(_mySlot); + return true; + } + + // If we've reached the top of the tree, we can't drop here, so cancel drop + return false; + } } diff --git a/Intersect.Client.Core/Interface/Game/SlotItem.cs b/Intersect.Client.Core/Interface/Game/SlotItem.cs index fd47cfa32f..f0ddb79f30 100644 --- a/Intersect.Client.Core/Interface/Game/SlotItem.cs +++ b/Intersect.Client.Core/Interface/Game/SlotItem.cs @@ -1,12 +1,13 @@ using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; +using Intersect.Client.Framework.Gwen.DragDrop; namespace Intersect.Client.Interface.Game; public partial class SlotItem : ImagePanel { public readonly int SlotIndex; - protected readonly ImagePanel _iconImage; + public readonly Draggable Icon; protected readonly ContextMenu? _contextMenu; public SlotItem(Base parent, string name, int index, ContextMenu? contextMenu) : base(parent, name) @@ -17,7 +18,7 @@ public SlotItem(Base parent, string name, int index, ContextMenu? contextMenu) : Margin = new Margin(4); MouseInputEnabled = true; - _iconImage = new ImagePanel(this, "Icon") + Icon = new Draggable(this, nameof(Icon)) { MinimumSize = new Point(32, 32), MouseInputEnabled = true, @@ -42,6 +43,11 @@ public void OpenContextMenu() OnContextMenuOpening(contextMenu); } + public override bool DragAndDrop_CanAcceptPackage(Package package) + { + return true; + } + protected virtual void OnContextMenuOpening(ContextMenu contextMenu) { // Display our menu... If we have anything to display. diff --git a/Intersect.Client.Core/Interface/Game/Spells/SpellItem.cs b/Intersect.Client.Core/Interface/Game/Spells/SpellItem.cs index 67a1c75c87..65bb84869a 100644 --- a/Intersect.Client.Core/Interface/Game/Spells/SpellItem.cs +++ b/Intersect.Client.Core/Interface/Game/Spells/SpellItem.cs @@ -1,17 +1,17 @@ using Intersect.Client.Core; using Intersect.Client.Framework.Content; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.Control.EventArguments; +using Intersect.Client.Framework.Gwen.DragDrop; using Intersect.Client.Framework.Gwen.Input; using Intersect.Client.Framework.Input; using Intersect.Client.General; using Intersect.Client.Interface.Game.DescriptionWindows; +using Intersect.Client.Interface.Game.Hotbar; using Intersect.Client.Localization; using Intersect.Configuration; -using Intersect.Framework.Core; using Intersect.GameObjects; using Intersect.Utilities; @@ -22,17 +22,8 @@ public partial class SpellItem : SlotItem // Controls private readonly Label _cooldownLabel; private readonly SpellsWindow _spellWindow; - private Draggable? _dragIcon; private SpellDescriptionWindow? _descriptionWindow; - // Drag Handling - public bool IsDragging; - private bool _canDrag; - private long _clickTime; - private bool _mouseOver; - private int _mouseX = -1; - private int _mouseY = -1; - // Context Menu Handling private readonly MenuItem _useSpellMenuItem; private readonly MenuItem _forgetSpellMenuItem; @@ -43,10 +34,10 @@ public SpellItem(SpellsWindow spellWindow, Base parent, int index, ContextMenu c _spellWindow = spellWindow; TextureFilename = "spellitem.png"; - _iconImage.HoverEnter += _iconImage_HoverEnter; - _iconImage.HoverLeave += _iconImage_HoverLeave; - _iconImage.Clicked += _iconImage_Clicked; - _iconImage.DoubleClicked += _iconImage_DoubleClicked; + Icon.HoverEnter += Icon_HoverEnter; + Icon.HoverLeave += Icon_HoverLeave; + Icon.Clicked += Icon_Clicked; + Icon.DoubleClicked += Icon_DoubleClicked; _cooldownLabel = new Label(this, "CooldownLabel") { @@ -115,27 +106,20 @@ private void _forgetSpellMenuItem_Clicked(Base sender, MouseButtonState argument #region Mouse Events - private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) + private void Icon_HoverEnter(Base? sender, EventArgs? arguments) { if (InputHandler.MouseFocus != null) { return; } - _mouseOver = true; - _canDrag = true; - if (Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) { - _canDrag = false; return; } - if (_descriptionWindow != null) - { - _descriptionWindow.Dispose(); - _descriptionWindow = null; - } + _descriptionWindow?.Dispose(); + _descriptionWindow = null; if (Globals.Me?.Spells is not { Length: > 0 } spellSlots) { @@ -145,43 +129,66 @@ private void _iconImage_HoverEnter(Base? sender, EventArgs? arguments) _descriptionWindow = new SpellDescriptionWindow(spellSlots[SlotIndex].Id, _spellWindow.X, _spellWindow.Y); } - private void _iconImage_HoverLeave(Base sender, EventArgs arguments) + private void Icon_HoverLeave(Base sender, EventArgs arguments) { - _mouseOver = false; - _mouseX = -1; - _mouseY = -1; + _descriptionWindow?.Dispose(); + _descriptionWindow = null; + } - if (_descriptionWindow != null) + private void Icon_Clicked(Base sender, MouseButtonState arguments) + { + if (arguments.MouseButton is MouseButton.Right) { - _descriptionWindow.Dispose(); - _descriptionWindow = null; + if (ClientConfiguration.Instance.EnableContextMenus) + { + OpenContextMenu(); + } + else + { + Globals.Me?.TryForgetSpell(SlotIndex); + } } } - private void _iconImage_Clicked(Base sender, MouseButtonState arguments) + private void Icon_DoubleClicked(Base sender, MouseButtonState arguments) + { + Globals.Me?.TryUseSpell(SlotIndex); + } + + #endregion + + #region Drag and Drop + + public override bool DragAndDrop_HandleDrop(Package package, int x, int y) { - switch (arguments.MouseButton) + if (Globals.Me is not { } player) { - case MouseButton.Left: - _clickTime = Timing.Global.MillisecondsUtc + 500; - break; + return false; + } - case MouseButton.Right: - if (ClientConfiguration.Instance.EnableContextMenus) - { - OpenContextMenu(); - } - else - { - Globals.Me?.TryForgetSpell(SlotIndex); - } - break; + var targetNode = Interface.FindComponentUnderCursor(); + + // Find the first parent acceptable in that tree that can accept the package + while (targetNode != default) + { + switch (targetNode) + { + case SpellItem spellItem: + player.SwapSpells(SlotIndex, spellItem.SlotIndex); + return true; + + case HotbarItem hotbarItem: + player.AddToHotbar(hotbarItem.SlotIndex, 1, SlotIndex); + return true; + + default: + targetNode = targetNode.Parent; + break; + } } - } - private void _iconImage_DoubleClicked(Base sender, MouseButtonState arguments) - { - Globals.Me?.TryUseSpell(SlotIndex); + // If we've reached the top of the tree, we can't drop here, so cancel drop + return false; } #endregion @@ -200,190 +207,44 @@ public override void Update() if (!SpellDescriptor.TryGet(spellSlots[SlotIndex].Id, out var spell)) { - _iconImage.Hide(); - _iconImage.Texture = null; + Icon.Hide(); + Icon.Texture = null; _cooldownLabel.Hide(); return; } - _cooldownLabel.IsVisibleInParent = !IsDragging && Globals.Me.IsSpellOnCooldown(SlotIndex); + _cooldownLabel.IsVisibleInParent = !Icon.IsDragging && Globals.Me.IsSpellOnCooldown(SlotIndex); if (_cooldownLabel.IsVisibleInParent) { var itemCooldownRemaining = Globals.Me.GetSpellRemainingCooldown(SlotIndex); _cooldownLabel.Text = TimeSpan.FromMilliseconds(itemCooldownRemaining).WithSuffix("0.0"); - _iconImage.RenderColor.A = 100; + Icon.RenderColor.A = 100; } else { - _iconImage.RenderColor.A = 255; + Icon.RenderColor.A = 255; } - if (Path.GetFileName(_iconImage.Texture?.Name) != spell.Icon) + if (Path.GetFileName(Icon.Texture?.Name) != spell.Icon) { - var spellIconTexture = Globals.ContentManager?.GetTexture(TextureType.Spell, spell.Icon); + var spellIconTexture = GameContentManager.Current.GetTexture(TextureType.Spell, spell.Icon); if (spellIconTexture != null) { - _iconImage.Texture = spellIconTexture; - _iconImage.RenderColor.A = (byte)(_cooldownLabel.IsVisibleInParent ? 100 : 255); - _iconImage.IsVisibleInParent = true; + Icon.Texture = spellIconTexture; + Icon.RenderColor.A = (byte)(_cooldownLabel.IsVisibleInParent ? 100 : 255); + Icon.IsVisibleInParent = true; } else { - if (_iconImage.Texture != null) + if (Icon.Texture != null) { - _iconImage.Texture = null; - _iconImage.IsVisibleInParent = false; + Icon.Texture = null; + Icon.IsVisibleInParent = false; } } _descriptionWindow?.Dispose(); _descriptionWindow = null; } - - if (!IsDragging) - { - if (_mouseOver) - { - if (!Globals.InputManager.IsMouseButtonDown(MouseButton.Left)) - { - _canDrag = true; - _mouseX = -1; - _mouseY = -1; - if (Timing.Global.MillisecondsUtc < _clickTime) - { - _clickTime = 0; - } - } - else - { - if (_canDrag && Draggable.Active == null) - { - if (_mouseX == -1 || _mouseY == -1) - { - _mouseX = InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X; - _mouseY = InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y; - } - else - { - var xdiff = _mouseX - - (InputHandler.MousePosition.X - _iconImage.ToCanvas(new Point(0, 0)).X); - - var ydiff = _mouseY - - (InputHandler.MousePosition.Y - _iconImage.ToCanvas(new Point(0, 0)).Y); - - if (Math.Sqrt(Math.Pow(xdiff, 2) + Math.Pow(ydiff, 2)) > 5) - { - IsDragging = true; - _iconImage.IsVisibleInParent = false; - _dragIcon = new Draggable( - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseX, - _iconImage.ToCanvas(new Point(0, 0)).X + _mouseY, _iconImage.Texture, _iconImage.RenderColor - ); - } - } - } - } - } - } - else - { - if (_dragIcon?.Update() == true) - { - //Drug the item and now we stopped - IsDragging = false; - _iconImage.IsVisibleInParent = true; - - var dragRect = new FloatRect( - _dragIcon.X - (Padding.Left + Padding.Right) / 2f, - _dragIcon.Y - (Padding.Top + Padding.Bottom) / 2f, - (Padding.Left + Padding.Right) / 2f + _iconImage.Width, - (Padding.Top + Padding.Bottom) / 2f + _iconImage.Height - ); - - float bestIntersect = 0; - var bestIntersectIndex = -1; - - //So we picked up an item and then dropped it. Lets see where we dropped it to. - //Check spell first. - if (_spellWindow.RenderBounds().IntersectsWith(dragRect)) - { - for (var i = 0; i < Options.Instance.Player.MaxSpells; i++) - { - if (_spellWindow.Items[i] is not SpellItem spellSlot) - { - continue; - } - - if (i < _spellWindow.Items.Count && - spellSlot.RenderBounds().IntersectsWith(dragRect)) - { - if (FloatRect.Intersect(spellSlot.RenderBounds(), dragRect).Width * - FloatRect.Intersect(spellSlot.RenderBounds(), dragRect).Height > - bestIntersect) - { - bestIntersect = - FloatRect.Intersect(spellSlot.RenderBounds(), dragRect).Width * - FloatRect.Intersect(spellSlot.RenderBounds(), dragRect).Height; - - bestIntersectIndex = i; - } - } - } - - if (bestIntersectIndex > -1) - { - if (SlotIndex != bestIntersectIndex && !Globals.Me.IsCasting) - { - Globals.Me.SwapSpells(bestIntersectIndex, SlotIndex); - } - } - } - else if (Interface.GameUi.Hotbar.RenderBounds().IntersectsWith(dragRect)) - { - for (var i = 0; i < Options.Instance.Player.HotbarSlotCount; i++) - { - if (Interface.GameUi.Hotbar.Items[i].RenderBounds().IntersectsWith(dragRect)) - { - if (FloatRect.Intersect( - Interface.GameUi.Hotbar.Items[i].RenderBounds(), dragRect - ) - .Width * - FloatRect.Intersect(Interface.GameUi.Hotbar.Items[i].RenderBounds(), dragRect) - .Height > - bestIntersect) - { - bestIntersect = - FloatRect.Intersect(Interface.GameUi.Hotbar.Items[i].RenderBounds(), dragRect) - .Width * - FloatRect.Intersect(Interface.GameUi.Hotbar.Items[i].RenderBounds(), dragRect) - .Height; - - bestIntersectIndex = i; - } - } - } - - if (bestIntersectIndex > -1) - { - Globals.Me.AddToHotbar((byte) bestIntersectIndex, 1, SlotIndex); - } - } - - _dragIcon.Dispose(); - } - } - } - - public FloatRect RenderBounds() - { - var rect = new FloatRect() - { - X = _iconImage.ToCanvas(new Point(0, 0)).X, - Y = _iconImage.ToCanvas(new Point(0, 0)).Y, - Width = _iconImage.Width, - Height = _iconImage.Height - }; - - return rect; } } diff --git a/Intersect.Client.Core/Interface/Game/Spells/SpellsWindow.cs b/Intersect.Client.Core/Interface/Game/Spells/SpellsWindow.cs index a0c9500dcb..5aa172d8fb 100644 --- a/Intersect.Client.Core/Interface/Game/Spells/SpellsWindow.cs +++ b/Intersect.Client.Core/Interface/Game/Spells/SpellsWindow.cs @@ -1,6 +1,5 @@ using Intersect.Client.Core; using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Localization; @@ -76,19 +75,4 @@ public override void Hide() _contextMenu?.Close(); base.Hide(); } - - public FloatRect RenderBounds() - { - var rect = new FloatRect() - { - X = ToCanvas(new Point(0, 0)).X - - (Items[0].Padding.Left + Items[0].Padding.Right) / 2, - Y = ToCanvas(new Point(0, 0)).Y - - (Items[0].Padding.Top + Items[0].Padding.Bottom) / 2, - Width = Width + Items[0].Padding.Left + Items[0].Padding.Right, - Height = Height + Items[0].Padding.Top + Items[0].Padding.Bottom - }; - - return rect; - } } diff --git a/Intersect.Client.Framework/Gwen/Control/Base.cs b/Intersect.Client.Framework/Gwen/Control/Base.cs index 963cab2af3..1ac4e9d4c7 100644 --- a/Intersect.Client.Framework/Gwen/Control/Base.cs +++ b/Intersect.Client.Framework/Gwen/Control/Base.cs @@ -4258,12 +4258,13 @@ public virtual void UpdateCursor() } // giver - public virtual Package DragAndDrop_GetPackage(int x, int y) + public virtual Package? DragAndDrop_GetPackage(int x, int y) { return _dragPayload; } // giver + // TODO: Fix drag and drop names public virtual bool DragAndDrop_Draggable() { if (_dragPayload == null) diff --git a/Intersect.Client.Framework/Gwen/DragDrop/DragAndDrop.cs b/Intersect.Client.Framework/Gwen/DragDrop/DragAndDrop.cs index e978fccd1e..97f634e58b 100644 --- a/Intersect.Client.Framework/Gwen/DragDrop/DragAndDrop.cs +++ b/Intersect.Client.Framework/Gwen/DragDrop/DragAndDrop.cs @@ -1,4 +1,4 @@ -using Intersect.Client.Framework.GenericClasses; +using Intersect.Client.Framework.GenericClasses; using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.Input; @@ -27,6 +27,8 @@ public static partial class DragAndDrop public static Base SourceControl; + public static bool IsDragging => CurrentPackage != default; + private static bool OnDrop(int x, int y) { var success = false; @@ -78,7 +80,6 @@ private static bool ShouldStartDraggingControl(int x, int y) SourceControl = sLastPressedControl; InputHandler.MouseFocus = null; sLastPressedControl = null; - CurrentPackage.DrawControl = null; // Some controls will want to decide whether they should be dragged at that moment. // This function is for them (it defaults to true) diff --git a/Intersect.Client.Framework/Input/ControlBinding.cs b/Intersect.Client.Framework/Input/ControlBinding.cs index 1c4f05ab21..3914ab59e4 100644 --- a/Intersect.Client.Framework/Input/ControlBinding.cs +++ b/Intersect.Client.Framework/Input/ControlBinding.cs @@ -1,4 +1,5 @@ using Intersect.Client.Framework.GenericClasses; +using Intersect.Client.Framework.Gwen.DragDrop; using Newtonsoft.Json; namespace Intersect.Client.Framework.Input; @@ -34,7 +35,7 @@ public bool IsDown() if (IsMouseKey && Key.TryGetMouseButton(out var mouseButton)) { - return gameInput.IsMouseButtonDown(mouseButton); + return gameInput.IsMouseButtonDown(mouseButton) && !DragAndDrop.IsDragging; } return gameInput.IsKeyDown(Key); @@ -52,7 +53,7 @@ public bool WasDown() if (IsMouseKey && Key.TryGetMouseButton(out var mouseButton)) { - return gameInput.WasMouseButtonDown(mouseButton); + return gameInput.WasMouseButtonDown(mouseButton) && !DragAndDrop.IsDragging; } return gameInput.WasKeyDown(Key);