Files
tbd-station-14/Content.Client/UserInterface/Systems/Inventory/Controls/ItemStatusPanel.xaml.cs
pathetic meowmeow 39cb27fe21 Borg hands & hand whitelisting (#38668)
* Borg hands & hand whitelisting

* yaml linted

* yaml linted (x2)

* yaml linted (x3)

* my storage tests so pass

* no need for SetCount

* ok new stuff you can get fixed too

* oops

* staque

* what if we addressed feedback

* my place so holder

* what if we addresesd feedback

* what if i did it correctly

* terminating or deleted
2025-08-12 15:21:42 -07:00

194 lines
6.1 KiB
C#

using Content.Client.Items;
using Content.Shared.Hands.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Inventory.VirtualItem;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Inventory.Controls;
[GenerateTypedNameReferences]
public sealed partial class ItemStatusPanel : Control
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[ViewVariables] private EntityUid? _entity;
[ViewVariables] private Hand? _hand;
// Tracked so we can re-run SetSide() if the theme changes.
private HandUILocation _side;
public ItemStatusPanel()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
public void SetSide(HandUILocation location)
{
// AN IMPORTANT REMINDER ABOUT THIS CODE:
// In the UI, the RIGHT hand is on the LEFT on the screen.
// So that a character facing DOWN matches the hand positions.
Texture? texture;
Texture? textureHighlight;
StyleBox.Margin cutOut;
StyleBox.Margin flat;
Thickness contentMargin;
Thickness patchMargin;
switch (location)
{
case HandUILocation.Right:
texture = Theme.ResolveTexture("item_status_right");
textureHighlight = Theme.ResolveTexture("item_status_right_highlight");
cutOut = StyleBox.Margin.Left;
flat = StyleBox.Margin.Right;
contentMargin = MarginFromThemeColor("_itemstatus_content_margin_right");
break;
case HandUILocation.Left:
texture = Theme.ResolveTexture("item_status_left");
textureHighlight = Theme.ResolveTexture("item_status_left_highlight");
cutOut = StyleBox.Margin.Right;
flat = StyleBox.Margin.Left;
contentMargin = MarginFromThemeColor("_itemstatus_content_margin_left");
break;
default:
throw new ArgumentOutOfRangeException(nameof(location), location, null);
}
Contents.Margin = contentMargin;
//Important to note for patchMargin!
//Because of hand ui flipping, left and right instead correspond to outside and inside respectively.
patchMargin = MarginFromThemeColor("_itemstatus_patch_margin");
var panel = (StyleBoxTexture) Panel.PanelOverride!;
panel.Texture = texture;
panel.SetPatchMargin(cutOut, patchMargin.Left);
panel.SetPatchMargin(flat, patchMargin.Right);
panel.SetPatchMargin(StyleBox.Margin.Top, patchMargin.Top);
panel.SetPatchMargin(StyleBox.Margin.Bottom, patchMargin.Bottom);
var panelHighlight = (StyleBoxTexture) HighlightPanel.PanelOverride!;
panelHighlight.Texture = textureHighlight;
panelHighlight.SetPatchMargin(cutOut, patchMargin.Left);
panelHighlight.SetPatchMargin(flat, patchMargin.Right);
panelHighlight.SetPatchMargin(StyleBox.Margin.Top, patchMargin.Top);
panelHighlight.SetPatchMargin(StyleBox.Margin.Bottom, patchMargin.Bottom);
_side = location;
}
private Thickness MarginFromThemeColor(string itemName)
{
// This is the worst thing I've ever programmed
// (can you tell I'm a graphics programmer?)
// (the margin needs to change depending on the UI theme, so we use a fake color entry to store the value)
var color = Theme.ResolveColorOrSpecified(itemName);
return new Thickness(color.RByte, color.GByte, color.BByte, color.AByte);
}
protected override void OnThemeUpdated()
{
SetSide(_side);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateItemName(_hand);
}
public void Update(EntityUid? entity, Hand? hand)
{
if (entity == _entity && hand == _hand)
return;
_hand = hand;
if (entity == null)
{
ClearOldStatus();
_entity = null;
if (hand?.EmptyLabel is { } label)
{
ItemNameLabel.Visible = true;
NoItemLabel.Visible = false;
ItemNameLabel.Text = Loc.GetString(label);
}
else
{
ItemNameLabel.Visible = false;
NoItemLabel.Visible = true;
ItemNameLabel.Text = "";
}
return;
}
ItemNameLabel.Visible = true;
NoItemLabel.Visible = false;
_entity = entity.Value;
BuildNewEntityStatus();
UpdateItemName(hand);
}
public void UpdateHighlight(bool highlight)
{
HighlightPanel.Visible = highlight;
}
private void UpdateItemName(Hand? hand)
{
if (_entity == null)
return;
if (!_entityManager.TryGetComponent<MetaDataComponent>(_entity, out var meta) || meta.Deleted)
{
Update(null, hand);
return;
}
if (_entityManager.TryGetComponent(_entity, out VirtualItemComponent? virtualItem)
&& _entityManager.EntityExists(virtualItem.BlockingEntity))
{
// Uses identity because we can be blocked by pulling someone
ItemNameLabel.Text = Identity.Name(virtualItem.BlockingEntity, _entityManager);
}
else
{
ItemNameLabel.Text = Identity.Name(_entity.Value, _entityManager);
}
}
private void ClearOldStatus()
{
StatusContents.RemoveAllChildren();
}
private void BuildNewEntityStatus()
{
DebugTools.AssertNotNull(_entity);
ClearOldStatus();
var collectMsg = new ItemStatusCollectMessage();
_entityManager.EventBus.RaiseLocalEvent(_entity!.Value, collectMsg, true);
foreach (var control in collectMsg.Controls)
{
StatusContents.AddChild(control);
}
}
}