Microwave UX enhancements (#24547)

* Facelift Microwave UI

Includes new background light in UI, Uses predictive input, UI now properly disables buttons when microwave is active

* Microwave now shows Elapsed time

* Fixed bad formatting

* Added new term for "BottomMargin"

* Change yellow color

* Update StyleNano.cs

just spacing fixed

* Cook time countdown now detached from server


Instead of the server constantly sending out messages for the cook countdown, it is now predicted client side using TimeSpan

* Update MicrowaveMenu.xaml

forgot to re-add item space
This commit is contained in:
James Simonson
2024-02-14 06:16:00 +08:00
committed by GitHub
parent 40823416f0
commit 25f73f6406
8 changed files with 241 additions and 92 deletions

View File

@@ -4,6 +4,7 @@ using JetBrains.Annotations;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
namespace Content.Client.Kitchen.UI namespace Content.Client.Kitchen.UI
{ {
@@ -18,6 +19,9 @@ namespace Content.Client.Kitchen.UI
[ViewVariables] [ViewVariables]
private readonly Dictionary<int, ReagentQuantity> _reagents = new(); private readonly Dictionary<int, ReagentQuantity> _reagents = new();
[Dependency] private readonly IGameTiming _gameTiming = default!;
public MicrowaveUpdateUserInterfaceState currentState = default!;
private IEntityManager _entManager; private IEntityManager _entManager;
@@ -26,23 +30,47 @@ namespace Content.Client.Kitchen.UI
_entManager = IoCManager.Resolve<IEntityManager>(); _entManager = IoCManager.Resolve<IEntityManager>();
} }
public TimeSpan GetCurrentTime()
{
return _gameTiming.CurTime;
}
protected override void Open() protected override void Open()
{ {
base.Open(); base.Open();
_menu = new MicrowaveMenu(this); _menu = new MicrowaveMenu(this);
_menu.OpenCentered(); _menu.OpenCentered();
_menu.OnClose += Close; _menu.OnClose += Close;
_menu.StartButton.OnPressed += _ => SendMessage(new MicrowaveStartCookMessage()); _menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage());
_menu.EjectButton.OnPressed += _ => SendMessage(new MicrowaveEjectMessage()); _menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage());
_menu.IngredientsList.OnItemSelected += args => _menu.IngredientsList.OnItemSelected += args =>
{ {
SendMessage(new MicrowaveEjectSolidIndexedMessage(EntMan.GetNetEntity(_solids[args.ItemIndex]))); SendPredictedMessage(new MicrowaveEjectSolidIndexedMessage(EntMan.GetNetEntity(_solids[args.ItemIndex])));
}; };
_menu.OnCookTimeSelected += (args, buttonIndex) => _menu.OnCookTimeSelected += (args, buttonIndex) =>
{ {
var selectedCookTime = (uint) 0;
if (args.Button is MicrowaveMenu.MicrowaveCookTimeButton microwaveCookTimeButton)
{
// args.Button is a MicrowaveCookTimeButton
var actualButton = (MicrowaveMenu.MicrowaveCookTimeButton) args.Button; var actualButton = (MicrowaveMenu.MicrowaveCookTimeButton) args.Button;
SendMessage(new MicrowaveSelectCookTimeMessage(buttonIndex, actualButton.CookTime)); selectedCookTime = actualButton.CookTime == 0 ? 0 : actualButton.CookTime;
// SendMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime / 5, actualButton.CookTime));
SendPredictedMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime / 5, actualButton.CookTime));
_menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", selectedCookTime));
}
else
{
// args.Button is a normal button aka instant cook button
SendPredictedMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime, 0));
_menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", Loc.GetString("microwave-menu-instant-button")));
}
}; };
} }
@@ -67,20 +95,47 @@ namespace Content.Client.Kitchen.UI
return; return;
} }
_menu?.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy);
_menu?.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0);
currentState = cState;
// TODO move this to a component state and ensure the net ids. // TODO move this to a component state and ensure the net ids.
RefreshContentsDisplay(_entManager.GetEntityArray(cState.ContainedSolids)); RefreshContentsDisplay(_entManager.GetEntityArray(cState.ContainedSolids));
if (_menu == null) return; if (_menu == null) return;
var currentlySelectedTimeButton = (Button) _menu.CookTimeButtonVbox.GetChild(cState.ActiveButtonIndex); //Set the cook time info label
currentlySelectedTimeButton.Pressed = true;
var cookTime = cState.ActiveButtonIndex == 0 var cookTime = cState.ActiveButtonIndex == 0
? Loc.GetString("microwave-menu-instant-button") ? Loc.GetString("microwave-menu-instant-button")
: cState.CurrentCookTime.ToString(); : cState.CurrentCookTime.ToString();
_menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", _menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time", cookTime)); ("time", cookTime));
_menu.StartButton.Disabled = cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0;
_menu.EjectButton.Disabled = cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0;
//Set the correct button active button
if (cState.ActiveButtonIndex == 0)
{
_menu.InstantCookButton.Pressed = true;
}
else
{
var currentlySelectedTimeButton = (Button) _menu.CookTimeButtonVbox.GetChild(cState.ActiveButtonIndex - 1);
currentlySelectedTimeButton.Pressed = true;
}
//Set the "micowave light" ui color to indicate if the microwave is busy or not
if (cState.IsMicrowaveBusy && cState.ContainedSolids.Length > 0)
{
_menu.IngredientsPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#947300") };
}
else
{
_menu.IngredientsPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#1B1B1E") };
}
} }
private void RefreshContentsDisplay(EntityUid[] containedSolids) private void RefreshContentsDisplay(EntityUid[] containedSolids)

View File

@@ -1,73 +1,113 @@
<DefaultWindow xmlns="https://spacestation14.io" <controls:FancyWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client" xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:style="clr-namespace:Content.Client.Stylesheets"
Title="{Loc 'microwave-menu-title'}" Title="{Loc 'microwave-menu-title'}"
SetSize="512 256" MinWidth="512"
MinSize="512 256"> MinSize="512 256">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal" > <BoxContainer Orientation="Horizontal" >
<ItemList Name="IngredientsList" <PanelContainer
Name="IngredientsPanel"
Access="Public" Access="Public"
MinSize="300 128"
Margin="5 5">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1B1B1E" />
</PanelContainer.PanelOverride>
<ItemList
Name="IngredientsList"
Access="Public"
Margin="5 5"
VerticalExpand="True" VerticalExpand="True"
HorizontalExpand="True" HorizontalExpand="True"
StyleClasses="transparentBackgroundItemList"
SelectMode="Button" SelectMode="Button"
SizeFlagsStretchRatio="2" SizeFlagsStretchRatio="3"
ItemSeparation="5"
MinSize="100 128"> MinSize="100 128">
<!-- Ingredients are added here by code --> <!-- Ingredients are added here by code -->
</ItemList> </ItemList>
<BoxContainer Orientation="Vertical" </PanelContainer>
MinWidth="176" <BoxContainer
Orientation="Vertical"
MinWidth="170"
Margin="10 10"
VerticalExpand="True" VerticalExpand="True"
HorizontalExpand="True"> HorizontalExpand="True">
<BoxContainer Orientation="Vertical" <PanelContainer
Align="Center" VerticalExpand="True"
SizeFlagsStretchRatio="3">
<Button Name="StartButton"
Access="Public"
Text="{Loc 'microwave-menu-start-button'}"
TextAlign="Center" />
<Button Name="EjectButton"
Access="Public"
Text="{Loc 'microwave-menu-eject-all-text'}"
ToolTip="{Loc 'microwave-menu-eject-all-tooltip'}"
TextAlign="Center" />
</BoxContainer>
<Control MinSize="0 15" />
<PanelContainer VerticalExpand="True"
HorizontalExpand="True"> HorizontalExpand="True">
<PanelContainer VerticalExpand="True" <PanelContainer
VerticalExpand="True"
ModulateSelfOverride="#FF0000" ModulateSelfOverride="#FF0000"
MinSize="100 128"> MinSize="100 128">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#00000080" />
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Vertical"> <BoxContainer Orientation="Vertical">
<PanelContainer> <Label
<PanelContainer.PanelOverride> Name="CookTimeInfoLabel"
<gfx:StyleBoxFlat BackgroundColor="#80808032" />
</PanelContainer.PanelOverride>
<Label Name="CookTimeInfoLabel"
Access="Public" Access="Public"
Align="Center" Align="Center"
Modulate="#FFFFFF" Modulate="#FFFFFF"
VAlign="Center" /> VAlign="Center" />
</PanelContainer> <BoxContainer Orientation="Vertical">
<ScrollContainer VerticalExpand="True"> <Button
<BoxContainer Name="CookTimeButtonVbox" Name="InstantCookButton"
Access="Public" Access="Public"
Orientation="Vertical" Text="{Loc 'microwave-menu-instant-button'}"
VerticalExpand="True" StyleClasses="OpenLeft"
Align="Center"> ToggleMode="True"
Margin="0 0 2 0"
TextAlign="Center" />
<GridContainer
Name="CookTimeButtonVbox"
HSeparationOverride="1"
VSeparationOverride="1"
HorizontalExpand="True"
Columns="3"
Margin="0"
Access="Public">
<!-- Cook time buttons are added here by code --> <!-- Cook time buttons are added here by code -->
</GridContainer>
<BoxContainer
Orientation="Vertical"
Align="Center"
SizeFlagsStretchRatio="3">
<Control MinSize="0 15" />
<Button
Name="StartButton"
Access="Public"
Text="{Loc 'microwave-menu-start-button'}"
StyleClasses="ButtonColorGreen"
TextAlign="Center" />
<Button
Name="EjectButton"
Access="Public"
Text="{Loc 'microwave-menu-eject-all-text'}"
ToolTip="{Loc 'microwave-menu-eject-all-tooltip'}"
StyleClasses="ButtonColorRed"
TextAlign="Center" />
</BoxContainer>
</BoxContainer> </BoxContainer>
</ScrollContainer>
</BoxContainer> </BoxContainer>
</PanelContainer> </PanelContainer>
</PanelContainer> </PanelContainer>
</BoxContainer> </BoxContainer>
</BoxContainer> </BoxContainer>
<PanelContainer Name="DisableCookingPanelOverlay" <!-- Footer -->
MouseFilter="Stop"> <BoxContainer Orientation="Vertical">
<PanelContainer StyleClasses="LowDivider" />
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
<Label Text="{Loc 'microwave-menu-footer-flavor-left'}" StyleClasses="WindowFooterText" />
<Label Text="{Loc 'microwave-menu-footer-flavor-right'}" StyleClasses="WindowFooterText"
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered" VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
<PanelContainer Name="DisableCookingPanelOverlay" MouseFilter="Stop">
<PanelContainer.PanelOverride> <PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#00000099" /> <gfx:StyleBoxFlat BackgroundColor="#1B1B1E66" />
</PanelContainer.PanelOverride> </PanelContainer.PanelOverride>
</PanelContainer> </PanelContainer>
</DefaultWindow> </controls:FancyWindow>

View File

@@ -1,14 +1,13 @@
using System; using Robust.Client.AutoGenerated;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization; using Robust.Shared.Timing;
namespace Content.Client.Kitchen.UI namespace Content.Client.Kitchen.UI
{ {
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class MicrowaveMenu : DefaultWindow public sealed partial class MicrowaveMenu : FancyWindow
{ {
public sealed class MicrowaveCookTimeButton : Button public sealed class MicrowaveCookTimeButton : Button
{ {
@@ -17,28 +16,43 @@ namespace Content.Client.Kitchen.UI
public event Action<BaseButton.ButtonEventArgs, int>? OnCookTimeSelected; public event Action<BaseButton.ButtonEventArgs, int>? OnCookTimeSelected;
private ButtonGroup CookTimeButtonGroup { get; } public ButtonGroup CookTimeButtonGroup { get; }
private readonly MicrowaveBoundUserInterface _owner;
public MicrowaveMenu(MicrowaveBoundUserInterface owner) public MicrowaveMenu(MicrowaveBoundUserInterface owner)
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
CookTimeButtonGroup = new ButtonGroup(); CookTimeButtonGroup = new ButtonGroup();
InstantCookButton.Group = CookTimeButtonGroup;
_owner = owner;
InstantCookButton.OnPressed += args =>
{
OnCookTimeSelected?.Invoke(args, 0);
};
for (var i = 0; i <= 30; i += 5) for (var i = 1; i <= 6; i++)
{ {
var newButton = new MicrowaveCookTimeButton var newButton = new MicrowaveCookTimeButton
{ {
Text = i == 0 ? Loc.GetString("microwave-menu-instant-button") : i.ToString(), Text = (i * 5).ToString(),
CookTime = (uint) i,
TextAlign = Label.AlignMode.Center, TextAlign = Label.AlignMode.Center,
ToggleMode = true, ToggleMode = true,
CookTime = (uint) (i * 5),
Group = CookTimeButtonGroup, Group = CookTimeButtonGroup,
HorizontalExpand = true,
}; };
CookTimeButtonVbox.AddChild(newButton); if (i == 4)
newButton.OnToggled += args =>
{ {
OnCookTimeSelected?.Invoke(args, newButton.GetPositionInParent()); newButton.StyleClasses.Add("OpenRight");
}
else
{
newButton.StyleClasses.Add("OpenBoth");
}
CookTimeButtonVbox.AddChild(newButton);
newButton.OnPressed += args =>
{
OnCookTimeSelected?.Invoke(args, i);
}; };
} }
} }
@@ -47,5 +61,18 @@ namespace Content.Client.Kitchen.UI
{ {
DisableCookingPanelOverlay.Visible = shouldDisable; DisableCookingPanelOverlay.Visible = shouldDisable;
} }
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if(!_owner.currentState.IsMicrowaveBusy)
return;
if(_owner.currentState.CurrentCookTimeEnd > _owner.GetCurrentTime())
{
CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time",_owner.currentState.CurrentCookTimeEnd.Subtract(_owner.GetCurrentTime()).Seconds));
}
}
} }
} }

View File

@@ -998,6 +998,18 @@ namespace Content.Client.Stylesheets
itemListBackgroundSelected) itemListBackgroundSelected)
}), }),
new StyleRule(new SelectorElement(typeof(ItemList), new[] {"transparentBackgroundItemList"}, null, null), new[]
{
new StyleProperty(ItemList.StylePropertyBackground,
new StyleBoxFlat {BackgroundColor = Color.Transparent}),
new StyleProperty(ItemList.StylePropertyItemBackground,
itemListItemBackground),
new StyleProperty(ItemList.StylePropertyDisabledItemBackground,
itemListItemBackgroundDisabled),
new StyleProperty(ItemList.StylePropertySelectedItemBackground,
itemListBackgroundSelected)
}),
// Tree // Tree
new StyleRule(new SelectorElement(typeof(Tree), null, null, null), new[] new StyleRule(new SelectorElement(typeof(Tree), null, null, null), new[]
{ {

View File

@@ -56,6 +56,12 @@ namespace Content.Server.Kitchen.Components
[DataField("currentCookTimerTime"), ViewVariables(VVAccess.ReadWrite)] [DataField("currentCookTimerTime"), ViewVariables(VVAccess.ReadWrite)]
public uint CurrentCookTimerTime = 0; public uint CurrentCookTimerTime = 0;
/// <summary>
/// Tracks the elapsed time of the current cook timer.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan CurrentCookTimeEnd = TimeSpan.Zero;
/// <summary> /// <summary>
/// The maximum number of seconds a microwave can be set to. /// The maximum number of seconds a microwave can be set to.
/// This is currently only used for validation and the client does not check this. /// This is currently only used for validation and the client does not check this.

View File

@@ -369,7 +369,8 @@ namespace Content.Server.Kitchen.EntitySystems
GetNetEntityArray(component.Storage.ContainedEntities.ToArray()), GetNetEntityArray(component.Storage.ContainedEntities.ToArray()),
HasComp<ActiveMicrowaveComponent>(uid), HasComp<ActiveMicrowaveComponent>(uid),
component.CurrentCookTimeButtonIndex, component.CurrentCookTimeButtonIndex,
component.CurrentCookTimerTime component.CurrentCookTimerTime,
component.CurrentCookTimeEnd
)); ));
} }
@@ -492,6 +493,7 @@ namespace Content.Server.Kitchen.EntitySystems
activeComp.CookTimeRemaining = component.CurrentCookTimerTime * component.CookTimeMultiplier; activeComp.CookTimeRemaining = component.CurrentCookTimerTime * component.CookTimeMultiplier;
activeComp.TotalTime = component.CurrentCookTimerTime; //this doesn't scale so that we can have the "actual" time activeComp.TotalTime = component.CurrentCookTimerTime; //this doesn't scale so that we can have the "actual" time
activeComp.PortionedRecipe = portionedRecipe; activeComp.PortionedRecipe = portionedRecipe;
component.CurrentCookTimeEnd = _gameTiming.CurTime + TimeSpan.FromSeconds(component.CurrentCookTimerTime);
if (malfunctioning) if (malfunctioning)
activeComp.MalfunctionTime = _gameTiming.CurTime + TimeSpan.FromSeconds(component.MalfunctionInterval); activeComp.MalfunctionTime = _gameTiming.CurTime + TimeSpan.FromSeconds(component.MalfunctionInterval);
UpdateUserInterfaceState(uid, component); UpdateUserInterfaceState(uid, component);
@@ -580,6 +582,7 @@ namespace Content.Server.Kitchen.EntitySystems
} }
_container.EmptyContainer(microwave.Storage); _container.EmptyContainer(microwave.Storage);
microwave.CurrentCookTimeEnd = TimeSpan.Zero;
UpdateUserInterfaceState(uid, microwave); UpdateUserInterfaceState(uid, microwave);
_audio.PlayPvs(microwave.FoodDoneSound, uid); _audio.PlayPvs(microwave.FoodDoneSound, uid);
StopCooking((uid, microwave)); StopCooking((uid, microwave));
@@ -617,6 +620,7 @@ namespace Content.Server.Kitchen.EntitySystems
ent.Comp.CurrentCookTimeButtonIndex = args.ButtonIndex; ent.Comp.CurrentCookTimeButtonIndex = args.ButtonIndex;
ent.Comp.CurrentCookTimerTime = args.NewCookTime; ent.Comp.CurrentCookTimerTime = args.NewCookTime;
ent.Comp.CurrentCookTimeEnd = TimeSpan.Zero;
_audio.PlayPvs(ent.Comp.ClickSound, ent, AudioParams.Default.WithVolume(-2)); _audio.PlayPvs(ent.Comp.ClickSound, ent, AudioParams.Default.WithVolume(-2));
UpdateUserInterfaceState(ent, ent.Comp); UpdateUserInterfaceState(ent, ent.Comp);
} }

View File

@@ -54,13 +54,16 @@ namespace Content.Shared.Kitchen.Components
public int ActiveButtonIndex; public int ActiveButtonIndex;
public uint CurrentCookTime; public uint CurrentCookTime;
public TimeSpan CurrentCookTimeEnd;
public MicrowaveUpdateUserInterfaceState(NetEntity[] containedSolids, public MicrowaveUpdateUserInterfaceState(NetEntity[] containedSolids,
bool isMicrowaveBusy, int activeButtonIndex, uint currentCookTime) bool isMicrowaveBusy, int activeButtonIndex, uint currentCookTime, TimeSpan currentCookTimeEnd)
{ {
ContainedSolids = containedSolids; ContainedSolids = containedSolids;
IsMicrowaveBusy = isMicrowaveBusy; IsMicrowaveBusy = isMicrowaveBusy;
ActiveButtonIndex = activeButtonIndex; ActiveButtonIndex = activeButtonIndex;
CurrentCookTime = currentCookTime; CurrentCookTime = currentCookTime;
CurrentCookTimeEnd = currentCookTimeEnd;
} }
} }

View File

@@ -24,3 +24,5 @@ microwave-menu-start-button = Start
microwave-menu-eject-all-text = Eject All Contents microwave-menu-eject-all-text = Eject All Contents
microwave-menu-eject-all-tooltip = This vaporizes all reagents, but ejects any solids. microwave-menu-eject-all-tooltip = This vaporizes all reagents, but ejects any solids.
microwave-menu-instant-button = INSTANT microwave-menu-instant-button = INSTANT
microwave-menu-footer-flavor-left = Do not insert any electronic, metallic or living objects.
microwave-menu-footer-flavor-right = v1.5