Files
wwdpublic/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs
NeLepus 1dd823f071 Label Rendering For Vending Machines and Item Preferences Menus (#1538)
# Description

This PR removes label duplicates from item names in order to make actual
labels work properly and make them visible in vending machines' menus as
well as loadout preferences.

As we can see in Fig 1, the aluminium jug is not only labelled as
"aluminium 10u" but contains "(aluminium 10u)" in the item name, which
drives chemists homicidal when it comes to labelling the jugs.
This issue also appears with other labelled items such as pill canisters
in item preferences (see Fig 2), which led to a row of nameless pill
canisters being present in our server's menu.

My solution is to fetch the item's LabelComponent in the menu so this
redundancy is no more needed.
See Fig 3 for an example.

The VendingMachineMenu.xaml.cs code fetches and localizes the text from
the LabelComponent from the prototype the same way it fetches sprites,
and in the LoadoutPreferenceSelector.xaml.cs the task is pretty
straightforward since the item is spawned in the Nullspace anyway.

---

- [x] Added label rendering for VendingMachineMenu.xaml.cs
- [x] Stripped reagent jugs' names off their fake labels
- [x] Added label rendering for LoadoutPreferenceSelector.xaml.cs
- [x] Stripped pill canisters' names off their fake labels
- [x] Reformatted pills *that do not have explicit descriptions* to
match "pill (label)" format

---

<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->

<details><summary><h1>Media</h1></summary>
<p>

Fig 1, the issue with ChemVend's reagent jugs:
![Fig
1](https://github.com/user-attachments/assets/05983f8d-1bc6-4352-b13c-194a6ea172e9)

Fig 2, the issue with pill canisters:
![Fig
2](https://github.com/user-attachments/assets/5afec42f-ef55-4b9d-af2f-2cef6174225d)

Fig 3, demonstration of the solution:
![Fig
3](https://github.com/user-attachments/assets/bbc2d1b3-e773-4654-a32a-ab5d7205e0e9)

</p>
</details>

---

# Changelog

🆑 NeLepus
- add: Added label rendering for vending machines & item preferences
- tweak: Formatted pill without descriptions to follow  "pill (label)"
- remove: Fake label duplicates in reagent jugs and pill canisters

(cherry picked from commit f0f9512b491fefa2416f661e8f6b20fab215fa2f)
2025-01-15 23:56:04 +03:00

125 lines
4.5 KiB
C#

using System.Numerics;
using Content.Shared.VendingMachines;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Content.Client.Stylesheets;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
using Content.Shared.Labels.Components;
using Content.Shared.Prototypes;
using System.Reflection.Emit;
using Content.Client.Labels;
namespace Content.Client.VendingMachines.UI
{
[GenerateTypedNameReferences]
public sealed partial class VendingMachineMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public event Action<ItemList.ItemListSelectedEventArgs>? OnItemSelected;
public event Action<string>? OnSearchChanged;
public VendingMachineMenu()
{
MinSize = SetSize = new Vector2(250, 150);
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
SearchBar.OnTextChanged += _ =>
{
OnSearchChanged?.Invoke(SearchBar.Text);
};
VendingContents.OnItemSelected += args =>
{
OnItemSelected?.Invoke(args);
};
}
/// <summary>
/// Populates the list of available items on the vending machine interface
/// and sets icons based on their prototypes
/// </summary>
public void Populate(List<VendingMachineInventoryEntry> inventory, out List<int> filteredInventory, string? filter = null)
{
filteredInventory = new();
if (inventory.Count == 0)
{
VendingContents.Clear();
var outOfStockText = Loc.GetString("vending-machine-component-try-eject-out-of-stock");
VendingContents.AddItem(outOfStockText);
SetSizeAfterUpdate(outOfStockText.Length, VendingContents.Count);
return;
}
while (inventory.Count != VendingContents.Count)
{
if (inventory.Count > VendingContents.Count)
VendingContents.AddItem(string.Empty);
else
VendingContents.RemoveAt(VendingContents.Count - 1);
}
var longestEntry = string.Empty;
var spriteSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>();
var filterCount = 0;
for (var i = 0; i < inventory.Count; i++)
{
var entry = inventory[i];
var vendingItem = VendingContents[i - filterCount];
vendingItem.Text = string.Empty;
vendingItem.Icon = null;
var itemName = entry.ID;
Texture? icon = null;
if (_prototypeManager.TryIndex<EntityPrototype>(entry.ID, out var prototype))
{
itemName = prototype.Name;
icon = spriteSystem.GetPrototypeIcon(prototype).Default;
const string labelCompName = "Label";
if (prototype.Components.TryGetValue(labelCompName, out var labelCompData)
&& labelCompData.Component is LabelComponent labelComponent)
{
var itemLabel = labelComponent.CurrentLabel;
if (!string.IsNullOrEmpty(itemLabel))
itemName += $" ({Loc.GetString(itemLabel)})";
}
}
// search filter
if (!string.IsNullOrEmpty(filter) &&
!itemName.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant()))
{
VendingContents.Remove(vendingItem);
filterCount++;
continue;
}
if (itemName.Length > longestEntry.Length)
longestEntry = itemName;
vendingItem.Text = $"{itemName} [{entry.Amount}]";
vendingItem.Icon = icon;
filteredInventory.Add(i);
}
SetSizeAfterUpdate(longestEntry.Length, inventory.Count);
}
private void SetSizeAfterUpdate(int longestEntryLength, int contentCount)
{
SetSize = new Vector2(Math.Clamp((longestEntryLength + 2) * 12, 250, 300),
Math.Clamp(contentCount * 50, 150, 350));
}
}
}