Skip to content

Commit

Permalink
Drag to/from inventory panel to equip/unequip. Follows semantics of o…
Browse files Browse the repository at this point in the history
…riginal client.

Fix inventory name labels to always render over everything else in the inventory
  • Loading branch information
ethanmoffat committed Apr 1, 2022
1 parent 86a0cf9 commit 2162c7d
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 45 deletions.
32 changes: 32 additions & 0 deletions 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");
}
}
}
}
49 changes: 18 additions & 31 deletions 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;
Expand All @@ -19,6 +21,7 @@
using Optional;
using Optional.Unsafe;
using System;
using System.Collections.Generic;
using System.Linq;
using XNAControls;

Expand All @@ -32,17 +35,19 @@ 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;
private readonly bool _isMainCharacter;
private readonly Texture2D _characterIconSheet;
private readonly Texture2D _background;
private Option<Rectangle> _characterIconSourceRect;
private readonly InventoryPanel _inventoryPanel;

private Option<IPaperdollData> _paperdollData;

private readonly List<PaperdollDialogItem> _childItems;

private readonly IXNALabel _name,
_home,
_class,
Expand All @@ -68,7 +73,6 @@ public class PaperdollDialog : BaseEODialog
{
_paperdollProvider = paperdollProvider;
_pubFileProvider = pubFileProvider;
_hudControlProvider = hudControlProvider;
_inventorySpaceValidator = inventorySpaceValidator;
_eoMessageBoxFactory = eoMessageBoxFactory;
_statusLabelSetter = statusLabelSetter;
Expand All @@ -79,6 +83,10 @@ public class PaperdollDialog : BaseEODialog
_characterIconSheet = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 32, true);
_characterIconSourceRect = Option.None<Rectangle>();

_inventoryPanel = hudControlProvider.GetComponent<InventoryPanel>(HudControlIdentifier.InventoryPanel);

_childItems = new List<PaperdollDialogItem>();

_background = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 49);
SetSize(_background.Width, _background.Height / 2);

Expand Down Expand Up @@ -128,6 +136,8 @@ public class PaperdollDialog : BaseEODialog
_paperdollData = Option.None<IPaperdollData>();
}

public bool NoItemsDragging() => !_childItems.Any(x => x.IsBeingDragged);

protected override void OnUpdateControl(GameTime gameTime)
{
_paperdollData = _paperdollData.FlatMap(paperdollData =>
Expand All @@ -144,7 +154,7 @@ protected override void OnUpdateControl(GameTime gameTime)
}
});

SuppressClickDragEvent(!_hudControlProvider.GetComponent<InventoryPanel>(HUD.Controls.HudControlIdentifier.InventoryPanel).NoItemsDragging());
SuppressClickDragEvent(!NoItemsDragging() || !_inventoryPanel.NoItemsDragging());

base.OnUpdateControl(gameTime);
}
Expand Down Expand Up @@ -191,9 +201,7 @@ private void UpdateDisplayedData(IPaperdollData paperdollData)
_guild.Text = Capitalize(paperdollData.Guild);
_rank.Text = Capitalize(paperdollData.Rank);

var paperdollDialogItems = ChildControls.OfType<PaperdollDialogItem>().ToList();

foreach (var control in paperdollDialogItems)
foreach (var control in _childItems)
{
control.SetControlUnparented();
control.Dispose();
Expand All @@ -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 += (_, _) =>
Expand Down Expand Up @@ -264,6 +272,8 @@ private void UpdateDisplayedData(IPaperdollData paperdollData)

paperdollItem.SetParentControl(this);
paperdollItem.Initialize();

_childItems.Add(paperdollItem);
}

_characterIconSourceRect = Option.Some(GetOnlineIconSourceRectangle(paperdollData.Icon));
Expand All @@ -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");
}
}
}
}
69 changes: 62 additions & 7 deletions 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<EIFRecord> _itemInfo;

private bool _beingDragged;

public EquipLocation EquipLocation { get; }

public short ItemID => (short)_itemInfo.Match(r => r.ID, () => 0);

public event EventHandler<EIFRecord> 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<EIFRecord> itemInfo)
{
_inventoryPanel = inventoryPanel;
_paperdollDialog = paperdollDialog;
_isMainCharacter = isMainCharacter;
EquipLocation = location;
_itemInfo = itemInfo;
Expand All @@ -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();
}
}
}
44 changes: 38 additions & 6 deletions 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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -58,7 +60,7 @@ public int Slot
{
_slot = value;
DrawPosition = GetPosition(_slot);
DrawOrder = 102 - (_slot % InventoryPanel.InventoryRowSlots) * 2;
UpdateNameLabelPosition();
}
}

Expand All @@ -71,6 +73,7 @@ public string Text
{
_nameLabel.Text = value;
_nameLabel.ResizeBasedOnText(16, 9);
UpdateNameLabelPosition();
}
}

Expand All @@ -81,9 +84,15 @@ public string Text
public event EventHandler<EIFRecord> DoubleClick;
public event EventHandler<ItemDragCompletedEventArgs> 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;
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit 2162c7d

Please sign in to comment.