Files
tbd-station-14/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
pathetic meowmeow 5a0e0524ca Make reagent dispensers gridinv-based instead of pseudo-listinv (#34205)
This simplifies the code and makes the experience of examining contents
easier without the reagent dispenser UI, as well as adding the possibility
for dispensers to have items of heterogeneous sizes in them, which would
allow configuring reagent dispensers to accept smaller containers such
as beakers or vials in order to allow for more types of smaller quantities
of reagents, or other flexibilities brought by using a standard storage
component.
2025-05-09 23:49:05 -04:00

126 lines
5.2 KiB
C#

using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Storage;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Chemistry.UI
{
/// <summary>
/// Client-side UI used to control a <see cref="ReagentDispenserComponent"/>.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class ReagentDispenserWindow : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public event Action<ItemStorageLocation>? OnDispenseReagentButtonPressed;
public event Action<ItemStorageLocation>? OnEjectJugButtonPressed;
/// <summary>
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
/// actual data isn't filled in until the server sends data about the dispenser.
/// </summary>
public ReagentDispenserWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
/// <summary>
/// Update the button grid of reagents which can be dispensed.
/// </summary>
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
public void UpdateReagentsList(List<ReagentInventoryItem> inventory)
{
if (ReagentList == null)
return;
ReagentList.Children.Clear();
//Sort inventory by reagentLabel
inventory.Sort((x, y) => x.ReagentLabel.CompareTo(y.ReagentLabel));
foreach (var item in inventory)
{
var card = new ReagentCardControl(item);
card.OnPressed += OnDispenseReagentButtonPressed;
card.OnEjectButtonPressed += OnEjectJugButtonPressed;
ReagentList.Children.Add(card);
}
}
/// <summary>
/// Update the UI state when new state data is received from the server.
/// </summary>
/// <param name="state">State data sent by the server.</param>
public void UpdateState(BoundUserInterfaceState state)
{
var castState = (ReagentDispenserBoundUserInterfaceState) state;
UpdateContainerInfo(castState);
UpdateReagentsList(castState.Inventory);
_entityManager.TryGetEntity(castState.OutputContainerEntity, out var outputContainerEnt);
View.SetEntity(outputContainerEnt);
// Disable the Clear & Eject button if no beaker
ClearButton.Disabled = castState.OutputContainer is null;
EjectButton.Disabled = castState.OutputContainer is null;
AmountGrid.Selected = ((int)castState.SelectedDispenseAmount).ToString();
}
/// <summary>
/// Update the fill state and list of reagents held by the current reagent container, if applicable.
/// <para>Also highlights a reagent if it's dispense button is being mouse hovered.</para>
/// </summary>
/// <param name="state">State data for the dispenser.</param>
/// or null if no button is being hovered.</param>
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state)
{
ContainerInfo.Children.Clear();
if (state.OutputContainer is null)
{
ContainerInfoName.Text = "";
ContainerInfoFill.Text = "";
ContainerInfo.Children.Add(new Label { Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") });
return;
}
// Set Name of the container and its fill status (Ex: 44/100u)
ContainerInfoName.Text = state.OutputContainer.DisplayName;
ContainerInfoFill.Text = state.OutputContainer.CurrentVolume + "/" + state.OutputContainer.MaxVolume;
foreach (var (reagent, quantity) in state.OutputContainer.Reagents!)
{
// Try get to the prototype for the given reagent. This gives us its name.
var localizedName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? p)
? p.LocalizedName
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
var nameLabel = new Label { Text = $"{localizedName}: " };
var quantityLabel = new Label
{
Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity)),
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor },
};
ContainerInfo.Children.Add(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
nameLabel,
quantityLabel,
}
});
}
}
}
}