diff --git a/Content.Client/Chemistry/UI/ButtonGrid.cs b/Content.Client/Chemistry/UI/ButtonGrid.cs
new file mode 100644
index 0000000000..0abd9ef8a4
--- /dev/null
+++ b/Content.Client/Chemistry/UI/ButtonGrid.cs
@@ -0,0 +1,119 @@
+using System;
+using Robust.Client.Graphics;
+using Robust.Client.UserInterface.Controls;
+
+namespace Content.Client.Chemistry.UI;
+
+///
+/// Creates a grid of buttons given a comma-seperated list of Text
+///
+public sealed class ButtonGrid : GridContainer
+{
+ private string _buttonList = "";
+
+ ///
+ /// A comma-seperated list of text to use for each button. These will be inserted sequentially.
+ ///
+ public string ButtonList
+ {
+ get => _buttonList;
+ set
+ {
+ _buttonList = value;
+ Update();
+ }
+ }
+
+ public bool RadioGroup { get; set; } = false;
+
+ private string? _selected;
+
+ ///
+ /// Which button is currently selected. Only matters when is true.
+ ///
+ public string? Selected
+ {
+ get => _selected;
+ set
+ {
+ _selected = value;
+ Update();
+ }
+ }
+
+ public Action? OnButtonPressed;
+
+ ///
+ ///
+ ///
+ public new int Columns
+ {
+ get => base.Columns;
+ set
+ {
+ base.Columns = value;
+ Update();
+ }
+ }
+
+ ///
+ ///
+ ///
+ public new int Rows
+ {
+ get => base.Rows;
+ set
+ {
+ base.Rows = value;
+ Update();
+ }
+ }
+
+ private void Update()
+ {
+ if (ButtonList == "")
+ return;
+
+ this.Children.Clear();
+ var i = 0;
+ var list = ButtonList.Split(",");
+
+ var group = new ButtonGroup();
+
+ foreach (var button in list)
+ {
+ var btn = new Button();
+ btn.Text = button;
+ btn.OnPressed += _ =>
+ {
+ if (RadioGroup)
+ btn.Pressed = true;
+ Selected = button;
+ OnButtonPressed?.Invoke(button);
+ };
+ if (button == Selected)
+ btn.Pressed = true;
+ var sep = HSeparationOverride ?? 0;
+ // ReSharper disable once PossibleLossOfFraction
+ // btn.SetWidth = (this.PixelWidth - sep * (Columns - 1)) / 3;
+ btn.Group = group;
+
+ var row = i / Columns;
+ var col = i % Columns;
+ var last = i == list.Length - 1;
+ var lastCol = i == Columns - 1;
+ var lastRow = row == list.Length / Columns - 1;
+
+ if (row == 0 && (lastCol || last))
+ btn.AddStyleClass("OpenLeft");
+ else if (col == 0 && lastRow)
+ btn.AddStyleClass("OpenRight");
+ else
+ btn.AddStyleClass("OpenBoth");
+
+ this.Children.Add(btn);
+
+ i++;
+ }
+ }
+}
diff --git a/Content.Client/Chemistry/UI/ReagentCardControl.xaml b/Content.Client/Chemistry/UI/ReagentCardControl.xaml
new file mode 100644
index 0000000000..966c730140
--- /dev/null
+++ b/Content.Client/Chemistry/UI/ReagentCardControl.xaml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
diff --git a/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs b/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs
new file mode 100644
index 0000000000..60336143fc
--- /dev/null
+++ b/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs
@@ -0,0 +1,30 @@
+using Content.Shared.Chemistry;
+using Robust.Client.AutoGenerated;
+using Robust.Client.Graphics;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Chemistry.UI;
+
+[GenerateTypedNameReferences]
+public sealed partial class ReagentCardControl : Control
+{
+ public string StorageSlotId { get; }
+ public Action? OnPressed;
+ public Action? OnEjectButtonPressed;
+
+ public ReagentCardControl(ReagentInventoryItem item)
+ {
+ RobustXamlLoader.Load(this);
+
+ StorageSlotId = item.StorageSlotId;
+ ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor };
+ ReagentNameLabel.Text = item.ReagentLabel;
+ ReagentNameLabel.FontColorOverride = Color.White;
+ FillLabel.Text = item.StoredAmount;
+ EjectButtonIcon.Text = Loc.GetString("reagent-dispenser-window-eject-container-button");
+
+ MainButton.OnPressed += args => OnPressed?.Invoke(StorageSlotId);
+ EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageSlotId);
+ }
+}
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs
index 8244e3e6ed..fce57a6ec5 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs
+++ b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs
@@ -42,38 +42,11 @@ namespace Content.Client.Chemistry.UI
// Setup static button actions.
_window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName));
_window.ClearButton.OnPressed += _ => SendMessage(new ReagentDispenserClearContainerSolutionMessage());
- _window.DispenseButton1.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U1));
- _window.DispenseButton5.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U5));
- _window.DispenseButton10.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U10));
- _window.DispenseButton15.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U15));
- _window.DispenseButton20.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U20));
- _window.DispenseButton25.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U25));
- _window.DispenseButton30.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U30));
- _window.DispenseButton50.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U50));
- _window.DispenseButton100.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U100));
- // Setup reagent button actions.
- _window.OnDispenseReagentButtonPressed += (args, button) => SendMessage(new ReagentDispenserDispenseReagentMessage(button.ReagentId));
- _window.OnDispenseReagentButtonMouseEntered += (args, button) =>
- {
- if (_lastState is not null)
- _window.UpdateContainerInfo(_lastState);
- };
- _window.OnDispenseReagentButtonMouseExited += (args, button) =>
- {
- if (_lastState is not null)
- _window.UpdateContainerInfo(_lastState);
- };
+ _window.AmountGrid.OnButtonPressed += s => SendMessage(new ReagentDispenserSetDispenseAmountMessage(s));
- _window.OnEjectJugButtonPressed += (args, button) => SendMessage(new ItemSlotButtonPressedEvent(button.ReagentId));
- _window.OnEjectJugButtonMouseEntered += (args, button) => {
- if (_lastState is not null)
- _window.UpdateContainerInfo(_lastState);
- };
- _window.OnEjectJugButtonMouseExited += (args, button) => {
- if (_lastState is not null)
- _window.UpdateContainerInfo(_lastState);
- };
+ _window.OnDispenseReagentButtonPressed += (id) => SendMessage(new ReagentDispenserDispenseReagentMessage(id));
+ _window.OnEjectJugButtonPressed += (id) => SendMessage(new ItemSlotButtonPressedEvent(id));
}
///
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml
index 3b812ba56b..c900d7ecf2 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml
+++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml
@@ -1,53 +1,77 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+ Orientation="Vertical"
+ HorizontalExpand="True"
+ VerticalExpand="True"
+ Margin="5">
+
-
+
-
+
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
index 7fcf0191f2..305d39cdeb 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
+++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
@@ -1,10 +1,9 @@
using Content.Client.Stylesheets;
+using Content.Client.UserInterface.Controls;
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;
@@ -15,17 +14,12 @@ namespace Content.Client.Chemistry.UI
/// Client-side UI used to control a .
///
[GenerateTypedNameReferences]
- public sealed partial class ReagentDispenserWindow : DefaultWindow
+ public sealed partial class ReagentDispenserWindow : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
- public event Action? OnDispenseReagentButtonPressed;
- public event Action? OnDispenseReagentButtonMouseEntered;
- public event Action? OnDispenseReagentButtonMouseExited;
-
- public event Action? OnEjectJugButtonPressed;
- public event Action? OnEjectJugButtonMouseEntered;
- public event Action? OnEjectJugButtonMouseExited;
+ public event Action? OnDispenseReagentButtonPressed;
+ public event Action? OnEjectJugButtonPressed;
///
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
@@ -35,44 +29,27 @@ namespace Content.Client.Chemistry.UI
{
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;
}
///
/// Update the button grid of reagents which can be dispensed.
///
/// Reagents which can be dispensed by this dispenser
- public void UpdateReagentsList(List>> inventory)
+ public void UpdateReagentsList(List inventory)
{
- if (ChemicalList == null)
+ if (ReagentList == null)
return;
- ChemicalList.Children.Clear();
+ ReagentList.Children.Clear();
//Sort inventory by reagentLabel
- inventory.Sort((x, y) => x.Value.Key.CompareTo(y.Value.Key));
+ inventory.Sort((x, y) => x.ReagentLabel.CompareTo(y.ReagentLabel));
- foreach (KeyValuePair> entry in inventory)
+ foreach (var item 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);
+ var card = new ReagentCardControl(item);
+ card.OnPressed += OnDispenseReagentButtonPressed;
+ card.OnEjectButtonPressed += OnEjectJugButtonPressed;
+ ReagentList.Children.Add(card);
}
}
@@ -93,36 +70,7 @@ namespace Content.Client.Chemistry.UI
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;
- }
+ AmountGrid.Selected = ((int)castState.SelectedDispenseAmount).ToString();
}
///
@@ -137,23 +85,15 @@ namespace Content.Client.Chemistry.UI
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;
}
- 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}
- }
- }
- });
+ // 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!)
{
diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
index 3bcdd4b964..c48bf086d3 100644
--- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
@@ -81,9 +81,9 @@ namespace Content.Server.Chemistry.EntitySystems
return null;
}
- private List>> GetInventory(Entity reagentDispenser)
+ private List GetInventory(Entity reagentDispenser)
{
- var inventory = new List>>();
+ var inventory = new List();
for (var i = 0; i < reagentDispenser.Comp.NumSlots; i++)
{
@@ -99,15 +99,17 @@ namespace Content.Server.Chemistry.EntitySystems
else
continue;
- // Add volume remaining label
+ // Get volume remaining and color of solution
FixedPoint2 quantity = 0f;
+ var reagentColor = Color.White;
if (storedContainer != null && _solutionContainerSystem.TryGetDrainableSolution(storedContainer.Value, out _, out var sol))
{
quantity = sol.Volume;
+ reagentColor = sol.GetColor(_prototypeManager);
}
var storedAmount = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity));
- inventory.Add(new KeyValuePair>(storageSlotId, new KeyValuePair(reagentLabel, storedAmount)));
+ inventory.Add(new ReagentInventoryItem(storageSlotId, reagentLabel, storedAmount, reagentColor));
}
return inventory;
diff --git a/Content.Shared/Chemistry/SharedReagentDispenser.cs b/Content.Shared/Chemistry/SharedReagentDispenser.cs
index 2b9c318c58..5de3f6cae3 100644
--- a/Content.Shared/Chemistry/SharedReagentDispenser.cs
+++ b/Content.Shared/Chemistry/SharedReagentDispenser.cs
@@ -20,6 +20,46 @@ namespace Content.Shared.Chemistry
{
ReagentDispenserDispenseAmount = amount;
}
+
+ ///
+ /// Create a new instance from interpreting a String as an integer,
+ /// throwing an exception if it is unable to parse.
+ ///
+ public ReagentDispenserSetDispenseAmountMessage(String s)
+ {
+ switch (s)
+ {
+ case "1":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U1;
+ break;
+ case "5":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U5;
+ break;
+ case "10":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U10;
+ break;
+ case "15":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U15;
+ break;
+ case "20":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U20;
+ break;
+ case "25":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U25;
+ break;
+ case "30":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U30;
+ break;
+ case "50":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U50;
+ break;
+ case "100":
+ ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U100;
+ break;
+ default:
+ throw new Exception($"Cannot convert the string `{s}` into a valid ReagentDispenser DispenseAmount");
+ }
+ }
}
[Serializable, NetSerializable]
@@ -52,20 +92,30 @@ namespace Content.Shared.Chemistry
U100 = 100,
}
+ [Serializable, NetSerializable]
+ public sealed class ReagentInventoryItem(string storageSlotId, string reagentLabel, string storedAmount, Color reagentColor)
+ {
+ public string StorageSlotId = storageSlotId;
+ public string ReagentLabel = reagentLabel;
+ public string StoredAmount = storedAmount;
+ public Color ReagentColor = reagentColor;
+ }
+
[Serializable, NetSerializable]
public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
{
public readonly ContainerInfo? OutputContainer;
public readonly NetEntity? OutputContainerEntity;
+
///
/// A list of the reagents which this dispenser can dispense.
///
- public readonly List>> Inventory;
+ public readonly List Inventory;
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
- public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List>> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
+ public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
{
OutputContainer = outputContainer;
OutputContainerEntity = outputContainerEntity;
diff --git a/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl b/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl
index 48ec8f5213..37697c4517 100644
--- a/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl
+++ b/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl
@@ -10,9 +10,9 @@ reagent-dispenser-bound-user-interface-title = Reagent dispenser
## UI
reagent-dispenser-window-amount-to-dispense-label = Amount
-reagent-dispenser-window-container-label = Container:
reagent-dispenser-window-clear-button = Clear
reagent-dispenser-window-eject-button = Eject
+reagent-dispenser-window-eject-container-button = ⏏
reagent-dispenser-window-no-container-loaded-text = No container loaded.
reagent-dispenser-window-reagent-name-not-found-text = Reagent name not found
reagent-dispenser-window-unknown-reagent-text = Unknown reagent