Adding sorting to chem master (#34763)

* Adding sorting to chem master

* Chem Master can now sort based on following categories
 - Alphabetical
 - Quantity
 - Time Added to Machine

* Sorting is disabled by default and persist in the machine for everyone

* Removed some pointless code from Chem Master's UI

* Changed None and Time Added's text to reflect what they do better

* Minor adjustments to the code requested by maintainers
This commit is contained in:
Dora
2025-02-27 13:19:52 +02:00
committed by GitHub
parent c20fb21ac1
commit 53dc27cb1e
7 changed files with 91 additions and 15 deletions

View File

@@ -46,6 +46,8 @@ namespace Content.Client.Chemistry.UI
_window.CreateBottleButton.OnPressed += _ => SendMessage( _window.CreateBottleButton.OnPressed += _ => SendMessage(
new ChemMasterOutputToBottleMessage( new ChemMasterOutputToBottleMessage(
(uint) _window.BottleDosage.Value, _window.LabelLine)); (uint) _window.BottleDosage.Value, _window.LabelLine));
_window.BufferSortButton.OnPressed += _ => SendMessage(
new ChemMasterSortingTypeCycleMessage());
for (uint i = 0; i < _window.PillTypeButtons.Length; i++) for (uint i = 0; i < _window.PillTypeButtons.Length; i++)
{ {

View File

@@ -34,6 +34,7 @@
<Label Text="{Loc 'chem-master-window-buffer-text'}" /> <Label Text="{Loc 'chem-master-window-buffer-text'}" />
<Control HorizontalExpand="True" /> <Control HorizontalExpand="True" />
<Button MinSize="80 0" Name="BufferTransferButton" Access="Public" Text="{Loc 'chem-master-window-transfer-button'}" ToggleMode="True" StyleClasses="OpenRight" /> <Button MinSize="80 0" Name="BufferTransferButton" Access="Public" Text="{Loc 'chem-master-window-transfer-button'}" ToggleMode="True" StyleClasses="OpenRight" />
<Button MinSize="80 0" Name="BufferSortButton" Access="Public" Text="{Loc 'chem-master-window-sort-type-none'}" StyleClasses="OpenBoth" />
<Button MinSize="80 0" Name="BufferDiscardButton" Access="Public" Text="{Loc 'chem-master-window-discard-button'}" ToggleMode="True" StyleClasses="OpenLeft" /> <Button MinSize="80 0" Name="BufferDiscardButton" Access="Public" Text="{Loc 'chem-master-window-discard-button'}" ToggleMode="True" StyleClasses="OpenLeft" />
</BoxContainer> </BoxContainer>

View File

@@ -140,17 +140,17 @@ namespace Content.Client.Chemistry.UI
// Ensure the Panel Info is updated, including UI elements for Buffer Volume, Output Container and so on // Ensure the Panel Info is updated, including UI elements for Buffer Volume, Output Container and so on
UpdatePanelInfo(castState); UpdatePanelInfo(castState);
BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u"; BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
InputEjectButton.Disabled = castState.InputContainerInfo is null; InputEjectButton.Disabled = castState.InputContainerInfo is null;
OutputEjectButton.Disabled = castState.OutputContainerInfo is null; OutputEjectButton.Disabled = castState.OutputContainerInfo is null;
CreateBottleButton.Disabled = castState.OutputContainerInfo?.Reagents == null; CreateBottleButton.Disabled = castState.OutputContainerInfo?.Reagents == null;
CreatePillButton.Disabled = castState.OutputContainerInfo?.Entities == null; CreatePillButton.Disabled = castState.OutputContainerInfo?.Entities == null;
UpdateDosageFields(castState); UpdateDosageFields(castState);
} }
//assign default values for pill and bottle fields. //assign default values for pill and bottle fields.
private void UpdateDosageFields(ChemMasterBoundUserInterfaceState castState) private void UpdateDosageFields(ChemMasterBoundUserInterfaceState castState)
{ {
@@ -162,8 +162,9 @@ namespace Content.Client.Chemistry.UI
var bufferVolume = castState.BufferCurrentVolume?.Int() ?? 0; var bufferVolume = castState.BufferCurrentVolume?.Int() ?? 0;
PillDosage.Value = (int)Math.Min(bufferVolume, castState.PillDosageLimit); PillDosage.Value = (int)Math.Min(bufferVolume, castState.PillDosageLimit);
PillTypeButtons[castState.SelectedPillType].Pressed = true; PillTypeButtons[castState.SelectedPillType].Pressed = true;
PillNumber.IsValid = x => x >= 0 && x <= pillNumberMax; PillNumber.IsValid = x => x >= 0 && x <= pillNumberMax;
PillDosage.IsValid = x => x > 0 && x <= castState.PillDosageLimit; PillDosage.IsValid = x => x > 0 && x <= castState.PillDosageLimit;
BottleDosage.IsValid = x => x >= 0 && x <= bottleAmountMax; BottleDosage.IsValid = x => x >= 0 && x <= bottleAmountMax;
@@ -213,6 +214,17 @@ namespace Content.Client.Chemistry.UI
BufferInfo.Children.Clear(); BufferInfo.Children.Clear();
// This has to happen here due to people possibly
// setting sorting before putting any chemicals
BufferSortButton.Text = state.SortingType switch
{
ChemMasterSortingType.Alphabetical => Loc.GetString("chem-master-window-sort-type-alphabetical"),
ChemMasterSortingType.Quantity => Loc.GetString("chem-master-window-sort-type-quantity"),
ChemMasterSortingType.Latest => Loc.GetString("chem-master-window-sort-type-latest"),
_ => Loc.GetString("chem-master-window-sort-type-none")
};
if (!state.BufferReagents.Any()) if (!state.BufferReagents.Any())
{ {
BufferInfo.Children.Add(new Label { Text = Loc.GetString("chem-master-window-buffer-empty-text") }); BufferInfo.Children.Add(new Label { Text = Loc.GetString("chem-master-window-buffer-empty-text") });
@@ -235,19 +247,48 @@ namespace Content.Client.Chemistry.UI
}; };
bufferHBox.AddChild(bufferVol); bufferHBox.AddChild(bufferVol);
// initialises rowCount to allow for striped rows // This sets up the needed data for sorting later in a list
// Its done this way to not repeat having to use same code twice (once for sorting
var rowCount = 0; // and once for displaying)
var reagentList = new List<(ReagentId reagentId, string name, Color color, FixedPoint2 quantity)>();
foreach (var (reagent, quantity) in state.BufferReagents) foreach (var (reagent, quantity) in state.BufferReagents)
{ {
var reagentId = reagent; var reagentId = reagent;
_prototypeManager.TryIndex(reagentId.Prototype, out ReagentPrototype? proto); _prototypeManager.TryIndex(reagentId.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text"); var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
var reagentColor = proto?.SubstanceColor ?? default(Color); var reagentColor = proto?.SubstanceColor ?? default(Color);
BufferInfo.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagentId, quantity, true, true)); reagentList.Add(new (reagentId, name, reagentColor, quantity));
}
// We sort here since we need sorted list to be filled first.
// You can easily add any new params you need to it.
switch (state.SortingType)
{
case ChemMasterSortingType.Alphabetical:
reagentList = reagentList.OrderBy(x => x.name).ToList();
break;
case ChemMasterSortingType.Quantity:
reagentList = reagentList.OrderByDescending(x => x.quantity).ToList();
break;
case ChemMasterSortingType.Latest:
reagentList = Enumerable.Reverse(reagentList).ToList();
break;
case ChemMasterSortingType.None:
default:
// This case is pointless but it is there for readability
break;
}
// initialises rowCount to allow for striped rows
var rowCount = 0;
foreach (var reagent in reagentList)
{
BufferInfo.Children.Add(BuildReagentRow(reagent.color, rowCount++, reagent.name, reagent.reagentId, reagent.quantity, true, true));
} }
} }
private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons) private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons)
{ {
control.Children.Clear(); control.Children.Clear();
@@ -295,7 +336,7 @@ namespace Content.Client.Chemistry.UI
_prototypeManager.TryIndex(reagent.Reagent.Prototype, out ReagentPrototype? proto); _prototypeManager.TryIndex(reagent.Reagent.Prototype, out ReagentPrototype? proto);
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text"); var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
var reagentColor = proto?.SubstanceColor ?? default(Color); var reagentColor = proto?.SubstanceColor ?? default(Color);
control.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagent.Reagent, reagent.Quantity, false, addReagentButtons)); control.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagent.Reagent, reagent.Quantity, false, addReagentButtons));
} }
} }
@@ -315,7 +356,7 @@ namespace Content.Client.Chemistry.UI
} }
//this calls the separated button builder, and stores the return to render after labels //this calls the separated button builder, and stores the return to render after labels
var reagentButtonConstructors = CreateReagentTransferButtons(reagent, isBuffer, addReagentButtons); var reagentButtonConstructors = CreateReagentTransferButtons(reagent, isBuffer, addReagentButtons);
// Create the row layout with the color panel // Create the row layout with the color panel
var rowContainer = new BoxContainer var rowContainer = new BoxContainer
{ {
@@ -358,7 +399,7 @@ namespace Content.Client.Chemistry.UI
Children = { rowContainer } Children = { rowContainer }
}; };
} }
public string LabelLine public string LabelLine
{ {
get => LabelLineEdit.Text; get => LabelLineEdit.Text;

View File

@@ -18,6 +18,9 @@ namespace Content.Server.Chemistry.Components
[DataField("mode"), ViewVariables(VVAccess.ReadWrite)] [DataField("mode"), ViewVariables(VVAccess.ReadWrite)]
public ChemMasterMode Mode = ChemMasterMode.Transfer; public ChemMasterMode Mode = ChemMasterMode.Transfer;
[DataField]
public ChemMasterSortingType SortingType = ChemMasterSortingType.None;
[DataField("pillDosageLimit", required: true), ViewVariables(VVAccess.ReadWrite)] [DataField("pillDosageLimit", required: true), ViewVariables(VVAccess.ReadWrite)]
public uint PillDosageLimit; public uint PillDosageLimit;

View File

@@ -53,6 +53,7 @@ namespace Content.Server.Chemistry.EntitySystems
SubscribeLocalEvent<ChemMasterComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState); SubscribeLocalEvent<ChemMasterComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetModeMessage>(OnSetModeMessage); SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetModeMessage>(OnSetModeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSortingTypeCycleMessage>(OnCycleSortingTypeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetPillTypeMessage>(OnSetPillTypeMessage); SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetPillTypeMessage>(OnSetPillTypeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterReagentAmountButtonMessage>(OnReagentButtonMessage); SubscribeLocalEvent<ChemMasterComponent, ChemMasterReagentAmountButtonMessage>(OnReagentButtonMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterCreatePillsMessage>(OnCreatePillsMessage); SubscribeLocalEvent<ChemMasterComponent, ChemMasterCreatePillsMessage>(OnCreatePillsMessage);
@@ -76,7 +77,7 @@ namespace Content.Server.Chemistry.EntitySystems
var bufferCurrentVolume = bufferSolution.Volume; var bufferCurrentVolume = bufferSolution.Volume;
var state = new ChemMasterBoundUserInterfaceState( var state = new ChemMasterBoundUserInterfaceState(
chemMaster.Mode, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer), chemMaster.Mode, chemMaster.SortingType, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer),
bufferReagents, bufferCurrentVolume, chemMaster.PillType, chemMaster.PillDosageLimit, updateLabel); bufferReagents, bufferCurrentVolume, chemMaster.PillType, chemMaster.PillDosageLimit, updateLabel);
_userInterfaceSystem.SetUiState(owner, ChemMasterUiKey.Key, state); _userInterfaceSystem.SetUiState(owner, ChemMasterUiKey.Key, state);
@@ -93,6 +94,15 @@ namespace Content.Server.Chemistry.EntitySystems
ClickSound(chemMaster); ClickSound(chemMaster);
} }
private void OnCycleSortingTypeMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterSortingTypeCycleMessage message)
{
chemMaster.Comp.SortingType++;
if (chemMaster.Comp.SortingType > ChemMasterSortingType.Latest)
chemMaster.Comp.SortingType = ChemMasterSortingType.None;
UpdateUiState(chemMaster);
ClickSound(chemMaster);
}
private void OnSetPillTypeMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterSetPillTypeMessage message) private void OnSetPillTypeMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterSetPillTypeMessage message)
{ {
// Ensure valid pill type. There are 20 pills selectable, 0-19. // Ensure valid pill type. There are 20 pills selectable, 0-19.

View File

@@ -89,6 +89,18 @@ namespace Content.Shared.Chemistry
Discard, Discard,
} }
public enum ChemMasterSortingType : byte
{
None = 0,
Alphabetical = 1,
Quantity = 2,
Latest = 3,
}
[Serializable, NetSerializable]
public sealed class ChemMasterSortingTypeCycleMessage : BoundUserInterfaceMessage;
public enum ChemMasterReagentAmount public enum ChemMasterReagentAmount
{ {
U1 = 1, U1 = 1,
@@ -160,6 +172,8 @@ namespace Content.Shared.Chemistry
public readonly ChemMasterMode Mode; public readonly ChemMasterMode Mode;
public readonly ChemMasterSortingType SortingType;
public readonly FixedPoint2? BufferCurrentVolume; public readonly FixedPoint2? BufferCurrentVolume;
public readonly uint SelectedPillType; public readonly uint SelectedPillType;
@@ -168,7 +182,7 @@ namespace Content.Shared.Chemistry
public readonly bool UpdateLabel; public readonly bool UpdateLabel;
public ChemMasterBoundUserInterfaceState( public ChemMasterBoundUserInterfaceState(
ChemMasterMode mode, ContainerInfo? inputContainerInfo, ContainerInfo? outputContainerInfo, ChemMasterMode mode, ChemMasterSortingType sortingType, ContainerInfo? inputContainerInfo, ContainerInfo? outputContainerInfo,
IReadOnlyList<ReagentQuantity> bufferReagents, FixedPoint2 bufferCurrentVolume, IReadOnlyList<ReagentQuantity> bufferReagents, FixedPoint2 bufferCurrentVolume,
uint selectedPillType, uint pillDosageLimit, bool updateLabel) uint selectedPillType, uint pillDosageLimit, bool updateLabel)
{ {
@@ -176,6 +190,7 @@ namespace Content.Shared.Chemistry
OutputContainerInfo = outputContainerInfo; OutputContainerInfo = outputContainerInfo;
BufferReagents = bufferReagents; BufferReagents = bufferReagents;
Mode = mode; Mode = mode;
SortingType = sortingType;
BufferCurrentVolume = bufferCurrentVolume; BufferCurrentVolume = bufferCurrentVolume;
SelectedPillType = selectedPillType; SelectedPillType = selectedPillType;
PillDosageLimit = pillDosageLimit; PillDosageLimit = pillDosageLimit;

View File

@@ -29,3 +29,7 @@ chem-master-window-dose-label = Dose (u):
chem-master-window-create-button = Create chem-master-window-create-button = Create
chem-master-window-bottles-label = Bottles: chem-master-window-bottles-label = Bottles:
chem-master-window-unknown-reagent-text = Unknown reagent chem-master-window-unknown-reagent-text = Unknown reagent
chem-master-window-sort-type-none = Sort by: Oldest First
chem-master-window-sort-type-alphabetical = Sort by: Alphabetical
chem-master-window-sort-type-quantity = Sort by: Quantity
chem-master-window-sort-type-latest = Sort by: Recent First