diff --git a/EndlessClient/Dialogs/Extensions/EquipLocationExtensions.cs b/EndlessClient/Dialogs/Extensions/EquipLocationExtensions.cs new file mode 100644 index 000000000..b9e269763 --- /dev/null +++ b/EndlessClient/Dialogs/Extensions/EquipLocationExtensions.cs @@ -0,0 +1,32 @@ +using EOLib.IO; +using Microsoft.Xna.Framework; +using System; + +namespace EndlessClient.Dialogs.Extensions +{ + public static class EquipLocationExtensions + { + public static Rectangle GetEquipLocationRectangle(this EquipLocation loc) + { + switch (loc) + { + case EquipLocation.Boots: return new Rectangle(87, 220, 56, 54); + case EquipLocation.Accessory: return new Rectangle(55, 250, 23, 23); + case EquipLocation.Gloves: return new Rectangle(22, 188, 56, 54); + case EquipLocation.Belt: return new Rectangle(87, 188, 56, 23); + case EquipLocation.Armor: return new Rectangle(86, 82, 56, 98); + case EquipLocation.Necklace: return new Rectangle(152, 51, 56, 23); + case EquipLocation.Hat: return new Rectangle(87, 21, 56, 54); + case EquipLocation.Shield: return new Rectangle(152, 82, 56, 98); + case EquipLocation.Weapon: return new Rectangle(22, 82, 56, 98); + case EquipLocation.Ring1: return new Rectangle(152, 190, 23, 23); + case EquipLocation.Ring2: return new Rectangle(185, 190, 23, 23); + case EquipLocation.Armlet1: return new Rectangle(152, 220, 23, 23); + case EquipLocation.Armlet2: return new Rectangle(185, 220, 23, 23); + case EquipLocation.Bracer1: return new Rectangle(152, 250, 23, 23); + case EquipLocation.Bracer2: return new Rectangle(185, 250, 23, 23); + default: throw new ArgumentOutOfRangeException(nameof(loc), "That is not a valid equipment location"); + } + } + } +} diff --git a/EndlessClient/Dialogs/PaperdollDialog.cs b/EndlessClient/Dialogs/PaperdollDialog.cs index 393d341dc..b9ef8ea6f 100644 --- a/EndlessClient/Dialogs/PaperdollDialog.cs +++ b/EndlessClient/Dialogs/PaperdollDialog.cs @@ -1,9 +1,11 @@ using EndlessClient.Controllers; using EndlessClient.ControlSets; +using EndlessClient.Dialogs.Extensions; using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; using EndlessClient.HUD; +using EndlessClient.HUD.Controls; using EndlessClient.HUD.Inventory; using EndlessClient.HUD.Panels; using EOLib; @@ -19,6 +21,7 @@ using Optional; using Optional.Unsafe; using System; +using System.Collections.Generic; using System.Linq; using XNAControls; @@ -32,7 +35,6 @@ public class PaperdollDialog : BaseEODialog private readonly IInventoryController _inventoryController; private readonly IPaperdollProvider _paperdollProvider; private readonly IPubFileProvider _pubFileProvider; - private readonly IHudControlProvider _hudControlProvider; private readonly IInventorySpaceValidator _inventorySpaceValidator; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; private readonly IStatusLabelSetter _statusLabelSetter; @@ -40,9 +42,12 @@ public class PaperdollDialog : BaseEODialog private readonly Texture2D _characterIconSheet; private readonly Texture2D _background; private Option _characterIconSourceRect; + private readonly InventoryPanel _inventoryPanel; private Option _paperdollData; + private readonly List _childItems; + private readonly IXNALabel _name, _home, _class, @@ -68,7 +73,6 @@ public class PaperdollDialog : BaseEODialog { _paperdollProvider = paperdollProvider; _pubFileProvider = pubFileProvider; - _hudControlProvider = hudControlProvider; _inventorySpaceValidator = inventorySpaceValidator; _eoMessageBoxFactory = eoMessageBoxFactory; _statusLabelSetter = statusLabelSetter; @@ -79,6 +83,10 @@ public class PaperdollDialog : BaseEODialog _characterIconSheet = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 32, true); _characterIconSourceRect = Option.None(); + _inventoryPanel = hudControlProvider.GetComponent(HudControlIdentifier.InventoryPanel); + + _childItems = new List(); + _background = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 49); SetSize(_background.Width, _background.Height / 2); @@ -128,6 +136,8 @@ public class PaperdollDialog : BaseEODialog _paperdollData = Option.None(); } + public bool NoItemsDragging() => !_childItems.Any(x => x.IsBeingDragged); + protected override void OnUpdateControl(GameTime gameTime) { _paperdollData = _paperdollData.FlatMap(paperdollData => @@ -144,7 +154,7 @@ protected override void OnUpdateControl(GameTime gameTime) } }); - SuppressClickDragEvent(!_hudControlProvider.GetComponent(HUD.Controls.HudControlIdentifier.InventoryPanel).NoItemsDragging()); + SuppressClickDragEvent(!NoItemsDragging() || !_inventoryPanel.NoItemsDragging()); base.OnUpdateControl(gameTime); } @@ -191,9 +201,7 @@ private void UpdateDisplayedData(IPaperdollData paperdollData) _guild.Text = Capitalize(paperdollData.Guild); _rank.Text = Capitalize(paperdollData.Rank); - var paperdollDialogItems = ChildControls.OfType().ToList(); - - foreach (var control in paperdollDialogItems) + foreach (var control in _childItems) { control.SetControlUnparented(); control.Dispose(); @@ -206,9 +214,9 @@ private void UpdateDisplayedData(IPaperdollData paperdollData) var id = paperdollData.Paperdoll[equipLocation]; var eifRecord = id.SomeWhen(i => i > 0).Map(i => _pubFileProvider.EIFFile[i]); - var paperdollItem = new PaperdollDialogItem(_nativeGraphicsManager, _isMainCharacter, equipLocation, eifRecord) + var paperdollItem = new PaperdollDialogItem(_nativeGraphicsManager, _inventoryPanel, this, _isMainCharacter, equipLocation, eifRecord) { - DrawArea = GetEquipLocationRectangle(equipLocation) + DrawArea = equipLocation.GetEquipLocationRectangle() }; paperdollItem.OnMouseEnter += (_, _) => @@ -264,6 +272,8 @@ private void UpdateDisplayedData(IPaperdollData paperdollData) paperdollItem.SetParentControl(this); paperdollItem.Initialize(); + + _childItems.Add(paperdollItem); } _characterIconSourceRect = Option.Some(GetOnlineIconSourceRectangle(paperdollData.Icon)); @@ -277,28 +287,5 @@ private static Rectangle GetOnlineIconSourceRectangle(OnlineIcon icon) var (x, y, width, height) = icon.ToChatIcon().GetChatIconRectangleBounds().ValueOrDefault(); return new Rectangle(x, y, width, height); } - - private static Rectangle GetEquipLocationRectangle(EquipLocation loc) - { - switch (loc) - { - case EquipLocation.Boots: return new Rectangle(87, 220, 56, 54); - case EquipLocation.Accessory: return new Rectangle(55, 250, 23, 23); - case EquipLocation.Gloves: return new Rectangle(22, 188, 56, 54); - case EquipLocation.Belt: return new Rectangle(87, 188, 56, 23); - case EquipLocation.Armor: return new Rectangle(86, 82, 56, 98); - case EquipLocation.Necklace: return new Rectangle(152, 51, 56, 23); - case EquipLocation.Hat: return new Rectangle(87, 21, 56, 54); - case EquipLocation.Shield: return new Rectangle(152, 82, 56, 98); - case EquipLocation.Weapon: return new Rectangle(22, 82, 56, 98); - case EquipLocation.Ring1: return new Rectangle(152, 190, 23, 23); - case EquipLocation.Ring2: return new Rectangle(185, 190, 23, 23); - case EquipLocation.Armlet1: return new Rectangle(152, 220, 23, 23); - case EquipLocation.Armlet2: return new Rectangle(185, 220, 23, 23); - case EquipLocation.Bracer1: return new Rectangle(152, 250, 23, 23); - case EquipLocation.Bracer2: return new Rectangle(185, 250, 23, 23); - default: throw new ArgumentOutOfRangeException(nameof(loc), "That is not a valid equipment location"); - } - } } } diff --git a/EndlessClient/Dialogs/PaperdollDialogItem.cs b/EndlessClient/Dialogs/PaperdollDialogItem.cs index b1c52382e..9c0f8a08d 100644 --- a/EndlessClient/Dialogs/PaperdollDialogItem.cs +++ b/EndlessClient/Dialogs/PaperdollDialogItem.cs @@ -1,30 +1,48 @@ -using System; +using EndlessClient.Dialogs.Extensions; +using EndlessClient.HUD.Panels; using EOLib.Graphics; using EOLib.IO; using EOLib.IO.Pub; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Optional; +using System; using XNAControls; namespace EndlessClient.Dialogs { public class PaperdollDialogItem : XNAPictureBox { + private readonly InventoryPanel _inventoryPanel; + private readonly PaperdollDialog _paperdollDialog; private readonly bool _isMainCharacter; private readonly Option _itemInfo; + private bool _beingDragged; + public EquipLocation EquipLocation { get; } public short ItemID => (short)_itemInfo.Match(r => r.ID, () => 0); public event EventHandler RightClick; + public bool IsBeingDragged => _beingDragged; + + private bool LeftButtonReleased => CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState.LeftButton == ButtonState.Pressed; + + private bool RightButtonReleased => CurrentMouseState.RightButton == ButtonState.Released && PreviousMouseState.RightButton == ButtonState.Pressed; + + private bool LeftButtonHeld => CurrentMouseState.LeftButton == ButtonState.Pressed && PreviousMouseState.LeftButton == ButtonState.Pressed; + public PaperdollDialogItem(INativeGraphicsManager nativeGraphicsManager, + InventoryPanel inventoryPanel, + PaperdollDialog paperdollDialog, bool isMainCharacter, EquipLocation location, Option itemInfo) { + _inventoryPanel = inventoryPanel; + _paperdollDialog = paperdollDialog; _isMainCharacter = isMainCharacter; EquipLocation = location; _itemInfo = itemInfo; @@ -33,23 +51,60 @@ public class PaperdollDialogItem : XNAPictureBox StretchMode = StretchMode.CenterInFrame; } - protected override void OnUpdateControl(GameTime gameTime) + public void StartDragging() { - base.OnUpdateControl(gameTime); + _beingDragged = true; + SetControlUnparented(); + Game.Components.Add(this); - if (!_isMainCharacter) - return; + DrawOrder = 1000; + } - if (MouseOver && CurrentMouseState.RightButton == ButtonState.Released && PreviousMouseState.RightButton == ButtonState.Pressed) + protected override void OnUpdateControl(GameTime gameTime) + { + if (_isMainCharacter) { _itemInfo.MatchSome(itemInfo => { - if (_isMainCharacter) + if (!_beingDragged && MouseOver && MouseOverPreviously && LeftButtonHeld) + { + if (_inventoryPanel.NoItemsDragging() && _paperdollDialog.NoItemsDragging()) + { + StartDragging(); + } + } + else if (_beingDragged) + { + DrawPosition = new Vector2(CurrentMouseState.X - (DrawArea.Width / 2), CurrentMouseState.Y - (DrawArea.Height / 2)); + + if (LeftButtonReleased) + { + if (_inventoryPanel.MouseOver && _inventoryPanel.MouseOverPreviously) + { + StopDragging(); + RightClick?.Invoke(this, itemInfo); + } + } + else if (RightButtonReleased) + { + StopDragging(); + } + } + else if (!_beingDragged && MouseOver && RightButtonReleased) { RightClick?.Invoke(this, itemInfo); } }); } + + base.OnUpdateControl(gameTime); + } + + private void StopDragging() + { + _beingDragged = false; + SetParentControl(_paperdollDialog); + DrawArea = EquipLocation.GetEquipLocationRectangle(); } } } diff --git a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs index f91bdc04a..73c04645a 100644 --- a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs +++ b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs @@ -1,4 +1,5 @@ -using EndlessClient.HUD.Panels; +using EndlessClient.Dialogs; +using EndlessClient.HUD.Panels; using EOLib; using EOLib.Domain.Character; using EOLib.Graphics; @@ -30,6 +31,7 @@ public class ItemDragCompletedEventArgs private static readonly Rectangle InventoryGridArea = new Rectangle(114, 338, 363, 102); private readonly InventoryPanel _inventoryPanel; + private readonly IActiveDialogProvider _activeDialogProvider; private readonly Texture2D _itemGraphic; private readonly Texture2D _highlightBackground; private readonly XNALabel _nameLabel; @@ -58,7 +60,7 @@ public int Slot { _slot = value; DrawPosition = GetPosition(_slot); - DrawOrder = 102 - (_slot % InventoryPanel.InventoryRowSlots) * 2; + UpdateNameLabelPosition(); } } @@ -71,6 +73,7 @@ public string Text { _nameLabel.Text = value; _nameLabel.ResizeBasedOnText(16, 9); + UpdateNameLabelPosition(); } } @@ -81,9 +84,15 @@ public string Text public event EventHandler DoubleClick; public event EventHandler DoneDragging; - public InventoryPanelItem(IItemNameColorService itemNameColorService, InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) + public InventoryPanelItem(IItemNameColorService itemNameColorService, + InventoryPanel inventoryPanel, + IActiveDialogProvider activeDialogProvider, + int slot, + IInventoryItem inventoryItem, + EIFRecord data) { _inventoryPanel = inventoryPanel; + _activeDialogProvider = activeDialogProvider; Slot = slot; InventoryItem = inventoryItem; Data = data; @@ -102,7 +111,7 @@ public InventoryPanelItem(IItemNameColorService itemNameColorService, InventoryP Text = string.Empty }; - OnMouseEnter += (_, _) => _nameLabel.Visible = !_beingDragged; + OnMouseEnter += (_, _) => _nameLabel.Visible = _inventoryPanel.NoItemsDragging() && _activeDialogProvider.PaperdollDialog.Match(d => d.NoItemsDragging(), () => true); OnMouseLeave += (_, _) => _nameLabel.Visible = false; var (slotWidth, slotHeight) = Data.Size.GetDimensions(); @@ -136,7 +145,7 @@ public void StartDragging() public override void Initialize() { _nameLabel.Initialize(); - _nameLabel.SetParentControl(this); + _nameLabel.SetParentControl(_inventoryPanel); _nameLabel.ResizeBasedOnText(16, 9); base.Initialize(); @@ -173,7 +182,8 @@ protected override void OnUpdateControl(GameTime gameTime) } else if (++_updateTick % 8 == 0 && !_beingDragged && MouseOver && MouseOverPreviously && MouseHeld) { - if (_inventoryPanel.NoItemsDragging()) + if (_inventoryPanel.NoItemsDragging() && + _activeDialogProvider.PaperdollDialog.Match(dlg => dlg.NoItemsDragging(), () => true)) { StartDragging(); } @@ -245,6 +255,28 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + private void UpdateNameLabelPosition() + { + if (_nameLabel == null) + return; + + // the name label is parented to the inventory panel so that all name labels draw over all items (see draw orders below) + // the actual position of the name label needs to be set to this control's draw position + var actualPosition = DrawPosition; + + if (actualPosition.X + _nameLabel.DrawAreaWithParentOffset.Width + DrawArea.Width > InventoryGridArea.Width) + { + _nameLabel.DrawPosition = new Vector2(actualPosition.X -_nameLabel.DrawArea.Width, actualPosition.Y); + } + else + { + _nameLabel.DrawPosition = new Vector2(actualPosition.X + DrawArea.Width, actualPosition.Y); + } + + DrawOrder = 110; + _nameLabel.DrawOrder = 200; + } + private static Vector2 GetPosition(int slot) { return new Vector2(13 + 26 * (slot % InventoryPanel.InventoryRowSlots), 9 + 26 * (slot / InventoryPanel.InventoryRowSlots)); diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index 1a5193d03..188a38c8d 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -204,7 +204,7 @@ protected override void OnUpdateControl(GameTime gameTime) { _inventoryService.SetSlots(_inventorySlotRepository.FilledSlots, slot, itemData.Size); - var newItem = new InventoryPanelItem(_itemNameColorService, this, slot, item, itemData); + var newItem = new InventoryPanelItem(_itemNameColorService, this, _activeDialogProvider, slot, item, itemData); newItem.Initialize(); newItem.SetParentControl(this); newItem.Text = _itemStringService.GetStringForInventoryDisplay(itemData, item.Amount);