* Keep reagent dispenser inventory ordered This way, reagents wont be "moving around" in the UI when juggling jugs. The reagent dispensers will also show what reagents their storage slots contain if jugs are not labelled. * Move sorting client-side * Revert "Keep reagent dispenser inventory ordered" This reverts commit 3a1fc2e36d593937d4ecc581ae5a617a273a9d1c.
206 lines
8.8 KiB
C#
206 lines
8.8 KiB
C#
using System.Linq;
|
|
using Content.Client.Stylesheets;
|
|
using Content.Shared.Chemistry;
|
|
using Content.Shared.Chemistry.Reagent;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.CustomControls;
|
|
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 : DefaultWindow
|
|
{
|
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
public event Action<BaseButton.ButtonEventArgs, DispenseReagentButton>? OnDispenseReagentButtonPressed;
|
|
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseEntered;
|
|
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseExited;
|
|
|
|
public event Action<BaseButton.ButtonEventArgs, EjectJugButton>? OnEjectJugButtonPressed;
|
|
public event Action<GUIMouseHoverEventArgs, EjectJugButton>? OnEjectJugButtonMouseEntered;
|
|
public event Action<GUIMouseHoverEventArgs, EjectJugButton>? OnEjectJugButtonMouseExited;
|
|
|
|
/// <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);
|
|
|
|
var dispenseAmountGroup = new ButtonGroup();
|
|
DispenseButton1.Group = dispenseAmountGroup;
|
|
DispenseButton5.Group = dispenseAmountGroup;
|
|
DispenseButton10.Group = dispenseAmountGroup;
|
|
DispenseButton15.Group = dispenseAmountGroup;
|
|
DispenseButton20.Group = dispenseAmountGroup;
|
|
DispenseButton25.Group = dispenseAmountGroup;
|
|
DispenseButton30.Group = dispenseAmountGroup;
|
|
DispenseButton50.Group = dispenseAmountGroup;
|
|
DispenseButton100.Group = dispenseAmountGroup;
|
|
}
|
|
|
|
/// <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<KeyValuePair<string, KeyValuePair<string,string>>> inventory)
|
|
{
|
|
if (ChemicalList == null)
|
|
return;
|
|
|
|
ChemicalList.Children.Clear();
|
|
//Sort inventory by reagentLabel
|
|
inventory.Sort((x, y) => x.Value.Key.CompareTo(y.Value.Key));
|
|
|
|
foreach (KeyValuePair<string, KeyValuePair<string, string>> entry in inventory)
|
|
{
|
|
var button = new DispenseReagentButton(entry.Key, entry.Value.Key, entry.Value.Value);
|
|
button.OnPressed += args => OnDispenseReagentButtonPressed?.Invoke(args, button);
|
|
button.OnMouseEntered += args => OnDispenseReagentButtonMouseEntered?.Invoke(args, button);
|
|
button.OnMouseExited += args => OnDispenseReagentButtonMouseExited?.Invoke(args, button);
|
|
ChemicalList.AddChild(button);
|
|
var ejectButton = new EjectJugButton(entry.Key);
|
|
ejectButton.OnPressed += args => OnEjectJugButtonPressed?.Invoke(args, ejectButton);
|
|
ejectButton.OnMouseEntered += args => OnEjectJugButtonMouseEntered?.Invoke(args, ejectButton);
|
|
ejectButton.OnMouseExited += args => OnEjectJugButtonMouseExited?.Invoke(args, ejectButton);
|
|
ChemicalList.AddChild(ejectButton);
|
|
}
|
|
}
|
|
|
|
/// <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);
|
|
|
|
// Disable the Clear & Eject button if no beaker
|
|
ClearButton.Disabled = castState.OutputContainer is null;
|
|
EjectButton.Disabled = castState.OutputContainer is null;
|
|
|
|
switch (castState.SelectedDispenseAmount)
|
|
{
|
|
case ReagentDispenserDispenseAmount.U1:
|
|
DispenseButton1.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U5:
|
|
DispenseButton5.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U10:
|
|
DispenseButton10.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U15:
|
|
DispenseButton15.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U20:
|
|
DispenseButton20.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U25:
|
|
DispenseButton25.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U30:
|
|
DispenseButton30.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U50:
|
|
DispenseButton50.Pressed = true;
|
|
break;
|
|
case ReagentDispenserDispenseAmount.U100:
|
|
DispenseButton100.Pressed = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <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)
|
|
{
|
|
ContainerInfo.Children.Add(new Label {Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") });
|
|
return;
|
|
}
|
|
|
|
ContainerInfo.Children.Add(new BoxContainer // Name of the container and its fill status (Ex: 44/100u)
|
|
{
|
|
Orientation = LayoutOrientation.Horizontal,
|
|
Children =
|
|
{
|
|
new Label {Text = $"{state.OutputContainer.DisplayName}: "},
|
|
new Label
|
|
{
|
|
Text = $"{state.OutputContainer.CurrentVolume}/{state.OutputContainer.MaxVolume}",
|
|
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
|
|
}
|
|
}
|
|
});
|
|
|
|
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,
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed class DispenseReagentButton : Button
|
|
{
|
|
public string ReagentId { get; }
|
|
|
|
public DispenseReagentButton(string reagentId, string text, string amount)
|
|
{
|
|
AddStyleClass("OpenRight");
|
|
ReagentId = reagentId;
|
|
Text = text + " " + amount;
|
|
}
|
|
}
|
|
|
|
public sealed class EjectJugButton : Button
|
|
{
|
|
public string ReagentId { get; }
|
|
|
|
public EjectJugButton(string reagentId)
|
|
{
|
|
AddStyleClass("OpenLeft");
|
|
ReagentId = reagentId;
|
|
Text = "⏏";
|
|
}
|
|
}
|
|
}
|