mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 18:31:17 +03:00
Improve UX and visuals of communications console (#41899)
* Implment mockup of comms console UI * Fix broadcast broken by 31823 * Separate announce/broadcast functionality * Tweak resizing behaviour; make window wider by default * Split up comms console into different widgets Makes each section of the UI easier to understand Apply some cleanup, renames, make consistent with style guide, etc. * Polishing, todos, missing pieces * Consolidate button border images. Allow more accent colours with geometric_panel_border * Resolve some TODOs, small polish * Fix warning * Revert modification to StripeBack Old texture relied on two stripe colours, had to replicate with only styles. Split out a new version with tweakable modulation * Make UI more boring * Some element shuffling, style changing * Remove some leftover changes * Remove more leftovers * Fix warnings * Feedback; remove unused bits, dependencies, formatting, highlight
This commit is contained in:
parent
65f5f67cd5
commit
7c19a7d1de
11 changed files with 535 additions and 220 deletions
|
|
@ -0,0 +1,14 @@
|
|||
using Content.Shared.Communications;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Communications;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CommunicationsConsoleComponent : SharedCommunicationsConsoleComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// The prototype ID to use in the UI to show what entities a broadcast will display on
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId ScreenDisplayId = "Screen";
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using Content.Shared.CCVar;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.AlertLevel;
|
||||
using Content.Shared.Communications;
|
||||
|
|
@ -23,41 +23,36 @@ public sealed partial class CommunicationsConsoleBoundUserInterface(EntityUid ow
|
|||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<CommunicationsConsoleMenu>();
|
||||
_menu.OnAnnounce += AnnounceButtonPressed;
|
||||
_menu.OnBroadcast += BroadcastButtonPressed;
|
||||
_menu.OnAlertLevel += AlertLevelSelected;
|
||||
_menu.OnEmergencyLevel += EmergencyShuttleButtonPressed;
|
||||
_menu.OnRadioAnnounce += RadioAnnounceButtonPressed;
|
||||
_menu.OnScreenBroadcast += ScreenBroadcastButtonPressed;
|
||||
_menu.OnAlertLevelChanged += AlertLevelSelected;
|
||||
_menu.OnShuttleCalled += CallShuttle;
|
||||
_menu.OnShuttleRecalled += RecallShuttle;
|
||||
|
||||
if (EntMan.TryGetComponent<CommunicationsConsoleComponent>(Owner, out var console))
|
||||
{
|
||||
_menu.SetBroadcastDisplayEntity(console.ScreenDisplayId);
|
||||
}
|
||||
}
|
||||
|
||||
public void AlertLevelSelected(ProtoId<AlertLevelPrototype> level)
|
||||
{
|
||||
if (_menu!.AlertLevelSelectable)
|
||||
{
|
||||
// TODO: This does not work until the console UI is predicted and uses component states.
|
||||
// Also someone decided to send BUI states regularly in an update loop, so this just gets randomly bulldozed until the message reaches the server.
|
||||
// _menu.CurrentAlertLevel = level;
|
||||
// _menu.AlertLevelSelectable = false;
|
||||
// _menu.AlertLevelButton.Disabled = true;
|
||||
SendMessage(new CommunicationsConsoleSelectAlertLevelMessage(level));
|
||||
}
|
||||
// TODO: This does not work until the console UI is predicted and uses component states.
|
||||
// Also someone decided to send BUI states regularly in an update loop, so this just gets randomly bulldozed until the message reaches the server.
|
||||
// _menu.CurrentAlertLevel = level;
|
||||
// _menu.AlertLevelSelectable = false;
|
||||
// _menu.AlertLevelButton.Disabled = true;
|
||||
SendMessage(new CommunicationsConsoleSelectAlertLevelMessage(level));
|
||||
}
|
||||
|
||||
public void EmergencyShuttleButtonPressed()
|
||||
{
|
||||
if (_menu!.CountdownStarted)
|
||||
RecallShuttle();
|
||||
else
|
||||
CallShuttle();
|
||||
}
|
||||
|
||||
public void AnnounceButtonPressed(string message)
|
||||
public void RadioAnnounceButtonPressed(string message)
|
||||
{
|
||||
var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
|
||||
var msg = SharedChatSystem.SanitizeAnnouncement(message, maxLength);
|
||||
SendMessage(new CommunicationsConsoleAnnounceMessage(msg));
|
||||
}
|
||||
|
||||
public void BroadcastButtonPressed(string message)
|
||||
public void ScreenBroadcastButtonPressed(string message)
|
||||
{
|
||||
SendMessage(new CommunicationsConsoleBroadcastMessage(message));
|
||||
}
|
||||
|
|
@ -87,23 +82,11 @@ public sealed partial class CommunicationsConsoleBoundUserInterface(EntityUid ow
|
|||
|
||||
if (_menu != null)
|
||||
{
|
||||
_menu.CanAnnounce = commsState.CanAnnounce;
|
||||
_menu.CanBroadcast = commsState.CanBroadcast;
|
||||
_menu.CanCall = commsState.CanCall;
|
||||
_menu.CountdownStarted = commsState.CountdownStarted;
|
||||
_menu.CountdownEnd = commsState.ExpectedCountdownEnd;
|
||||
var currentAlertLevel = alertComp.CurrentAlertLevel;
|
||||
var selectableAlertLevels = _alertLevel.GetSelectableAlertLevels((stationUid.Value, alertComp));
|
||||
var canChangeAlertLevel = _alertLevel.CanChangeAlertLevel((stationUid.Value, alertComp));
|
||||
|
||||
_menu.CurrentAlertLevel = alertComp.CurrentAlertLevel;
|
||||
_menu.SelectableAlertLevels = _alertLevel.GetSelectableAlertLevels((stationUid.Value, alertComp));
|
||||
_menu.AlertLevelSelectable = _alertLevel.CanChangeAlertLevel((stationUid.Value, alertComp));
|
||||
|
||||
_menu.UpdateCountdown();
|
||||
_menu.UpdateAlertLevels();
|
||||
|
||||
_menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable;
|
||||
_menu.EmergencyShuttleButton.Disabled = !_menu.CanCall;
|
||||
_menu.AnnounceButton.Disabled = !_menu.CanAnnounce;
|
||||
_menu.BroadcastButton.Disabled = !_menu.CanBroadcast;
|
||||
_menu.UpdateState(commsState, currentAlertLevel, selectableAlertLevels, canChangeAlertLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +1,24 @@
|
|||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
<comms:CommunicationsConsoleMenu xmlns="https://spacestation14.io"
|
||||
xmlns:comms="clr-namespace:Content.Client.Communications.UI"
|
||||
xmlns:widgets="clr-namespace:Content.Client.Communications.UI.Widgets"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc 'comms-console-menu-title'}"
|
||||
MinSize="400 300">
|
||||
MinSize="400 654" SetWidth="450"
|
||||
Title="{Loc 'comms-console-menu-title'}">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="12">
|
||||
<PanelContainer StyleClasses="PanelDark" VerticalExpand="True">
|
||||
<widgets:MessagingControls Name="MessagingControls" VerticalExpand="True" />
|
||||
</PanelContainer>
|
||||
|
||||
<!-- Main Container -->
|
||||
<BoxContainer Orientation="Vertical"
|
||||
HorizontalExpand="False"
|
||||
VerticalExpand="True"
|
||||
Margin="6 6 6 5">
|
||||
<controls:HSpacer Spacing="12" />
|
||||
|
||||
<TextEdit Name="MessageInput"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
MinHeight="100"/>
|
||||
<PanelContainer StyleClasses="BackgroundPanelDark">
|
||||
<widgets:AlertLevelControls Name="AlertLevelControls" Margin="0 12 0 12" />
|
||||
</PanelContainer>
|
||||
|
||||
<!-- ButtonsPart -->
|
||||
<BoxContainer Orientation="Vertical"
|
||||
VerticalAlignment="Bottom"
|
||||
SeparationOverride="4">
|
||||
<controls:HSpacer Spacing="12" />
|
||||
|
||||
<!-- AnnouncePart -->
|
||||
<BoxContainer Orientation="Vertical"
|
||||
Margin="0 2">
|
||||
|
||||
<Button Name="AnnounceButton"
|
||||
Access="Public"
|
||||
Text="{Loc 'comms-console-menu-announcement-button'}"
|
||||
ToolTip="{Loc 'comms-console-menu-announcement-button-tooltip'}"
|
||||
StyleClasses="OpenLeft"
|
||||
Margin="0 0 1 0"
|
||||
Disabled="True"/>
|
||||
|
||||
<Button Name="BroadcastButton"
|
||||
Access="Public"
|
||||
Text="{Loc 'comms-console-menu-broadcast-button'}"
|
||||
ToolTip="{Loc 'comms-console-menu-broadcast-button-tooltip'}"
|
||||
StyleClasses="OpenBoth"/>
|
||||
|
||||
<OptionButton Name="AlertLevelButton"
|
||||
Access="Public"
|
||||
ToolTip="{Loc 'comms-console-menu-alert-level-button-tooltip'}"
|
||||
StyleClasses="OpenRight"/>
|
||||
|
||||
</BoxContainer>
|
||||
|
||||
<!-- EmergencyPart -->
|
||||
<BoxContainer Orientation="Vertical"
|
||||
SeparationOverride="6">
|
||||
|
||||
<RichTextLabel Name="CountdownLabel"/>
|
||||
|
||||
<Button Name="EmergencyShuttleButton"
|
||||
Access="Public"
|
||||
Text="Placeholder Text"
|
||||
ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<PanelContainer StyleClasses="BackgroundPanelDark">
|
||||
<widgets:ShuttleControls Name="ShuttleControls" Margin="0 12 0 12"/>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
</comms:CommunicationsConsoleMenu>
|
||||
|
|
|
|||
|
|
@ -1,133 +1,58 @@
|
|||
using System.Globalization;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.AlertLevel;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Communications;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Communications.UI
|
||||
namespace Content.Client.Communications.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CommunicationsConsoleMenu : FancyWindow
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CommunicationsConsoleMenu : FancyWindow
|
||||
public event Action? OnShuttleCalled;
|
||||
public event Action? OnShuttleRecalled;
|
||||
public event Action<ProtoId<AlertLevelPrototype>>? OnAlertLevelChanged;
|
||||
public event Action<string>? OnRadioAnnounce;
|
||||
public event Action<string>? OnScreenBroadcast;
|
||||
|
||||
public CommunicationsConsoleMenu()
|
||||
{
|
||||
[Dependency] private IConfigurationManager _cfg = default!;
|
||||
[Dependency] private IGameTiming _timing = default!;
|
||||
[Dependency] private ILocalizationManager _loc = default!;
|
||||
[Dependency] private IPrototypeManager _protoMan = default!;
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
public bool CanAnnounce;
|
||||
public bool CanBroadcast;
|
||||
public bool CanCall;
|
||||
public bool CountdownStarted;
|
||||
public TimeSpan? CountdownEnd;
|
||||
MessagingControls.OnRadioAnnounce += message => OnRadioAnnounce?.Invoke(message);
|
||||
MessagingControls.OnScreenBroadcast += message => OnScreenBroadcast?.Invoke(message);
|
||||
|
||||
public ProtoId<AlertLevelPrototype>? CurrentAlertLevel;
|
||||
public List<ProtoId<AlertLevelPrototype>> SelectableAlertLevels = new();
|
||||
public bool AlertLevelSelectable;
|
||||
AlertLevelControls.OnAlertLevelChanged += newLevel => OnAlertLevelChanged?.Invoke(newLevel);
|
||||
|
||||
public event Action? OnEmergencyLevel;
|
||||
public event Action<ProtoId<AlertLevelPrototype>>? OnAlertLevel;
|
||||
public event Action<string>? OnAnnounce;
|
||||
public event Action<string>? OnBroadcast;
|
||||
ShuttleControls.OnShuttleCalled += () => OnShuttleCalled?.Invoke();
|
||||
ShuttleControls.OnShuttleRecalled += () => OnShuttleRecalled?.Invoke();
|
||||
}
|
||||
|
||||
public CommunicationsConsoleMenu()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
/// <summary>
|
||||
/// Use the specified prototype ID as an example display in the
|
||||
/// UI subsection where users type broadcast messages
|
||||
/// </summary>
|
||||
public void SetBroadcastDisplayEntity(EntProtoId broadcastEntityId)
|
||||
{
|
||||
MessagingControls.SetBroadcastDisplayEntity(broadcastEntityId);
|
||||
}
|
||||
|
||||
MessageInput.Placeholder = new Rope.Leaf(_loc.GetString("comms-console-menu-announcement-placeholder"));
|
||||
/// <summary>
|
||||
/// Configure UI to be consistent with the input state
|
||||
/// </summary>
|
||||
public void UpdateState(CommunicationsConsoleInterfaceState commsState,
|
||||
ProtoId<AlertLevelPrototype> currentAlertLevel,
|
||||
List<ProtoId<AlertLevelPrototype>>? selectableAlertLevels,
|
||||
bool canChangeAlertLevel)
|
||||
{
|
||||
MessagingControls.CanRadioAnnounce = commsState.CanAnnounce;
|
||||
MessagingControls.CanScreenBroadcast = commsState.CanBroadcast;
|
||||
|
||||
var maxAnnounceLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
|
||||
MessageInput.OnTextChanged += (args) =>
|
||||
{
|
||||
if (args.Control.TextLength > maxAnnounceLength)
|
||||
{
|
||||
AnnounceButton.Disabled = true;
|
||||
AnnounceButton.ToolTip = Loc.GetString("comms-console-message-too-long");
|
||||
}
|
||||
else
|
||||
{
|
||||
AnnounceButton.Disabled = !CanAnnounce;
|
||||
AnnounceButton.ToolTip = null;
|
||||
var alertLevelSelectable = selectableAlertLevels != null && canChangeAlertLevel;
|
||||
AlertLevelControls.UpdateAlertLevels(selectableAlertLevels, currentAlertLevel, alertLevelSelectable);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
AnnounceButton.OnPressed += _ => OnAnnounce?.Invoke(Rope.Collapse(MessageInput.TextRope));
|
||||
AnnounceButton.Disabled = !CanAnnounce;
|
||||
|
||||
BroadcastButton.OnPressed += _ => OnBroadcast?.Invoke(Rope.Collapse(MessageInput.TextRope));
|
||||
BroadcastButton.Disabled = !CanBroadcast;
|
||||
|
||||
AlertLevelButton.OnItemSelected += args =>
|
||||
{
|
||||
var metadata = AlertLevelButton.GetItemMetadata(args.Id);
|
||||
if (metadata != null && metadata is ProtoId<AlertLevelPrototype> cast)
|
||||
{
|
||||
OnAlertLevel?.Invoke(cast);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
AlertLevelButton.Disabled = !AlertLevelSelectable;
|
||||
|
||||
EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke();
|
||||
EmergencyShuttleButton.Disabled = !CanCall;
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
UpdateCountdown();
|
||||
// TODO: Countdown for alert level delay
|
||||
}
|
||||
|
||||
public void UpdateAlertLevels()
|
||||
{
|
||||
AlertLevelButton.Clear();
|
||||
|
||||
if (CurrentAlertLevel == null)
|
||||
return;
|
||||
|
||||
if (!AlertLevelSelectable)
|
||||
{
|
||||
// selection is locked, only show the current alert
|
||||
var name = _protoMan.Index(CurrentAlertLevel).LocalizedName;
|
||||
AlertLevelButton.AddItem(name);
|
||||
AlertLevelButton.SetItemMetadata(AlertLevelButton.ItemCount - 1, CurrentAlertLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var alert in SelectableAlertLevels)
|
||||
{
|
||||
var name = _protoMan.Index(alert).LocalizedName;
|
||||
AlertLevelButton.AddItem(name);
|
||||
AlertLevelButton.SetItemMetadata(AlertLevelButton.ItemCount - 1, alert);
|
||||
if (alert == CurrentAlertLevel)
|
||||
AlertLevelButton.Select(AlertLevelButton.ItemCount - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCountdown()
|
||||
{
|
||||
if (!CountdownStarted)
|
||||
{
|
||||
CountdownLabel.SetMessage(string.Empty);
|
||||
EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-call-shuttle");
|
||||
return;
|
||||
}
|
||||
|
||||
var diff = MathHelper.Max((CountdownEnd - _timing.CurTime) ?? TimeSpan.Zero, TimeSpan.Zero);
|
||||
|
||||
EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle");
|
||||
var infoText = Loc.GetString($"comms-console-menu-time-remaining",
|
||||
("time", diff.ToString(@"hh\:mm\:ss", CultureInfo.CurrentCulture)));
|
||||
CountdownLabel.SetMessage(infoText);
|
||||
}
|
||||
ShuttleControls.UpdateState(commsState.CanCall, commsState.CountdownStarted, commsState.ExpectedCountdownEnd);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
Orientation="Vertical">
|
||||
<!-- Info about the current alert level -->
|
||||
<BoxContainer HorizontalAlignment="Center">
|
||||
<Label StyleClasses="StatusFieldTitle" Margin="0 0 9 0"
|
||||
Text="{Loc 'comms-console-alert-current-level-header'}" />
|
||||
<Label Name="CurrentAlertLevelLabel" Margin="9 0 0 0"/>
|
||||
</BoxContainer>
|
||||
|
||||
<Label Name="CurrentAlertLevelFlavorLabel" Align="Center" />
|
||||
|
||||
<!-- Controls for changing the alert level -->
|
||||
<BoxContainer Margin="9 12 9 6">
|
||||
<OptionButton Name="AlertLevelSelector" StyleClasses="OpenRight"
|
||||
ToolTip="{Loc 'comms-console-menu-alert-level-button-tooltip'}"
|
||||
HorizontalExpand="True" SizeFlagsStretchRatio="4" />
|
||||
<Button Name="ConfirmAlertLevelButton" StyleClasses="OpenLeft"
|
||||
HorizontalExpand="True" SizeFlagsStretchRatio="1"
|
||||
Text="{Loc 'comms-console-confirm-alert-level-button'}"
|
||||
Disabled="True" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
using Content.Shared.AlertLevel;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Communications.UI.Widgets;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AlertLevelControls : BoxContainer
|
||||
{
|
||||
[Dependency] private ILocalizationManager _loc = default!;
|
||||
[Dependency] private IPrototypeManager _protoman = default!;
|
||||
|
||||
private bool _alertLevelSelectable;
|
||||
private ProtoId<AlertLevelPrototype>? _currentAlertLevel = null;
|
||||
|
||||
public event Action<string>? OnAlertLevelChanged;
|
||||
|
||||
public AlertLevelControls()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
AlertLevelSelector.OnItemSelected += args =>
|
||||
{
|
||||
AlertLevelSelector.Select(args.Id);
|
||||
EnableDisableConfirmLevelChangeButton();
|
||||
};
|
||||
|
||||
ConfirmAlertLevelButton.OnPressed += _ =>
|
||||
{
|
||||
var metadata = AlertLevelSelector.GetItemMetadata(AlertLevelSelector.SelectedId);
|
||||
if (metadata is ProtoId<AlertLevelPrototype> cast)
|
||||
{
|
||||
OnAlertLevelChanged?.Invoke(cast);
|
||||
}
|
||||
};
|
||||
|
||||
AlertLevelSelector.Disabled = !_alertLevelSelectable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the UI components to display the current alert level and the
|
||||
/// selectable alert levels
|
||||
/// </summary>
|
||||
public void UpdateAlertLevels(List<ProtoId<AlertLevelPrototype>>? selectableAlertLevels, ProtoId<AlertLevelPrototype> currentAlertLevel, bool alertLevelSelectable)
|
||||
{
|
||||
_alertLevelSelectable = alertLevelSelectable;
|
||||
_currentAlertLevel = currentAlertLevel;
|
||||
CurrentAlertLevelLabel.Text = GetLocalizedAlertName(currentAlertLevel);
|
||||
if (_protoman.TryIndex(currentAlertLevel, out var alertData))
|
||||
{
|
||||
CurrentAlertLevelLabel.ModulateSelfOverride = alertData.Color;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentAlertLevelLabel.ModulateSelfOverride = Color.White;
|
||||
}
|
||||
|
||||
AlertLevelSelector.Disabled = selectableAlertLevels == null || !_alertLevelSelectable;
|
||||
|
||||
// If user had changed the selection, but hadn't pressed the confirm
|
||||
// button at the point we received an update message, we want to
|
||||
// remember what they had selected, so we can attempt to re-select it
|
||||
// if it's still an option in the new set of alert level possibilities.
|
||||
ProtoId<AlertLevelPrototype>? previousSelection = null;
|
||||
if (AlertLevelSelector.ItemCount > 1)
|
||||
{
|
||||
var metadata = AlertLevelSelector.GetItemMetadata(AlertLevelSelector.SelectedId);
|
||||
if (metadata is ProtoId<AlertLevelPrototype> cast)
|
||||
{
|
||||
previousSelection = cast;
|
||||
}
|
||||
}
|
||||
|
||||
// The server will only send alert levels which are selectable, but
|
||||
// unfortunately, for a short time after changing the alert level, no
|
||||
// level is selectable, so we won't have any levels to put into the
|
||||
// alert level list. Here, we make a dummy item to handle that; this
|
||||
// item also informs the user what this combo box is for.
|
||||
AlertLevelSelector.Clear();
|
||||
AlertLevelSelector.AddItem(Loc.GetString("comms-console-change-alert-level-button"));
|
||||
AlertLevelSelector.Select(0);
|
||||
|
||||
if (selectableAlertLevels != null)
|
||||
{
|
||||
foreach (var alert in selectableAlertLevels)
|
||||
{
|
||||
AlertLevelSelector.AddItem(GetLocalizedAlertName(alert));
|
||||
AlertLevelSelector.SetItemMetadata(AlertLevelSelector.ItemCount - 1, alert);
|
||||
|
||||
if (alert == previousSelection)
|
||||
{
|
||||
AlertLevelSelector.Select(AlertLevelSelector.ItemCount - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_loc.TryGetString($"comms-console-level-{currentAlertLevel}-flavour-label", out var flavour))
|
||||
{
|
||||
CurrentAlertLevelFlavorLabel.Text = flavour;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentAlertLevelFlavorLabel.Text = string.Empty;
|
||||
}
|
||||
|
||||
EnableDisableConfirmLevelChangeButton();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the "confirm alert level changed" button to be consistent with
|
||||
/// the server state and user interactions
|
||||
/// </summary>
|
||||
private void EnableDisableConfirmLevelChangeButton()
|
||||
{
|
||||
// Disable the button when:
|
||||
// 1. Server says we can't change level
|
||||
// 2. User selected special info option (id 0)
|
||||
// 3. User selected the same level the station is currently on
|
||||
var selectedId = AlertLevelSelector.SelectedId;
|
||||
ConfirmAlertLevelButton.Disabled = !_alertLevelSelectable || selectedId == 0;
|
||||
if (selectedId != 0)
|
||||
{
|
||||
var metadata = AlertLevelSelector.GetItemMetadata(selectedId);
|
||||
if (metadata is ProtoId<AlertLevelPrototype> selected)
|
||||
{
|
||||
ConfirmAlertLevelButton.Disabled |= selected == _currentAlertLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility function to convert an alert level identifier into a localized string
|
||||
/// </summary>
|
||||
private string GetLocalizedAlertName(ProtoId<AlertLevelPrototype> alertProto)
|
||||
{
|
||||
if (_protoman.TryIndex(alertProto, out var alertData))
|
||||
{
|
||||
return alertData.LocalizedName;
|
||||
}
|
||||
|
||||
return alertProto;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<TabContainer xmlns="https://spacestation14.io" >
|
||||
<!-- Controls for sending radio announcements -->
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True"
|
||||
TabContainer.TabTitle="{Loc 'comms-console-announce-tab-title'}">
|
||||
<Label StyleClasses="StatusFieldTitle" Align="Center"
|
||||
Text="{Loc 'comms-console-station-announcements-header'}" />
|
||||
<PanelContainer StyleClasses="BackgroundDark" Margin="10 6 6 6"
|
||||
HorizontalExpand="True" VerticalExpand="True">
|
||||
<TextEdit Name="RadioMessageInput" MinHeight="100"
|
||||
HorizontalExpand="True" VerticalExpand="True" />
|
||||
</PanelContainer>
|
||||
<Button Name="AnnounceButton" HorizontalExpand="True" Margin="10 6 6 6"
|
||||
Text="{Loc 'comms-console-menu-announcement-button'}"
|
||||
ToolTip="{Loc 'comms-console-menu-announcement-button-tooltip'}" />
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Controls for putting messages on station screens (aka broadcasting) -->
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True"
|
||||
TabContainer.TabTitle="{Loc 'comms-console-broadcast-tab-title'}">
|
||||
<Label StyleClasses="StatusFieldTitle" Align="Center" VAlign="Top"
|
||||
VerticalExpand="True" VerticalAlignment="Top"
|
||||
Text="{Loc 'comms-console-station-broadcast-header'}" />
|
||||
<SpriteView Name="BroadcastEntityDisplay" Scale="8 8" />
|
||||
<LineEdit Name="ScreenMessageInput" Margin="10 0 6 0"
|
||||
PlaceHolder="{Loc 'comms-console-menu-broadcast-placeholder'}" />
|
||||
<Button Name="BroadcastButton" HorizontalExpand="True" Margin="10 6 6 6"
|
||||
Text="{Loc 'comms-console-menu-broadcast-button'}"
|
||||
ToolTip="{Loc 'comms-console-menu-broadcast-button-tooltip'}" />
|
||||
</BoxContainer>
|
||||
</TabContainer>
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
using Content.Shared.CCVar;
|
||||
using Content.Shared.TextScreen;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Communications.UI.Widgets;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class MessagingControls : TabContainer
|
||||
{
|
||||
[Dependency] private IConfigurationManager _cfg = default!;
|
||||
[Dependency] private IEntityManager _entMan = default!;
|
||||
|
||||
// Entity temporarily created to display a screen preview
|
||||
private EntityUid _broadcastDisplayEntity = EntityUid.Invalid;
|
||||
|
||||
public event Action<string>? OnRadioAnnounce;
|
||||
public event Action<string>? OnScreenBroadcast;
|
||||
|
||||
private bool _canRadioAnnounce;
|
||||
public bool CanRadioAnnounce
|
||||
{
|
||||
set
|
||||
{
|
||||
_canRadioAnnounce = value;
|
||||
SyncButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _canScreenBroadcast;
|
||||
public bool CanScreenBroadcast
|
||||
{
|
||||
set
|
||||
{
|
||||
_canScreenBroadcast = value;
|
||||
SyncButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
public MessagingControls()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
RadioMessageInput.Placeholder = new Rope.Leaf(Loc.GetString("comms-console-menu-announcement-placeholder"));
|
||||
|
||||
RadioMessageInput.OnTextChanged += (_) => SyncButtonState();
|
||||
|
||||
AnnounceButton.OnPressed += _ =>
|
||||
{
|
||||
OnRadioAnnounce?.Invoke(Rope.Collapse(RadioMessageInput.TextRope));
|
||||
};
|
||||
|
||||
var appearanceSystem = _entMan.System<SharedAppearanceSystem>();
|
||||
ScreenMessageInput.OnTextChanged += args =>
|
||||
{
|
||||
if (_broadcastDisplayEntity.IsValid())
|
||||
{
|
||||
appearanceSystem.SetData(_broadcastDisplayEntity, TextScreenVisuals.ScreenText, args.Text);
|
||||
}
|
||||
};
|
||||
|
||||
BroadcastButton.OnPressed += _ =>
|
||||
{
|
||||
OnScreenBroadcast?.Invoke(ScreenMessageInput.Text);
|
||||
};
|
||||
|
||||
SyncButtonState();
|
||||
}
|
||||
|
||||
public void SetBroadcastDisplayEntity(EntProtoId broadcastEntityId)
|
||||
{
|
||||
_broadcastDisplayEntity = _entMan.Spawn(broadcastEntityId);
|
||||
if (_broadcastDisplayEntity.IsValid())
|
||||
{
|
||||
BroadcastEntityDisplay.SetEntity(_broadcastDisplayEntity);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
if (_broadcastDisplayEntity.IsValid())
|
||||
{
|
||||
_entMan.DeleteEntity(_broadcastDisplayEntity);
|
||||
}
|
||||
}
|
||||
|
||||
private void SyncButtonState()
|
||||
{
|
||||
if (_canRadioAnnounce)
|
||||
{
|
||||
var maxAnnounceLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
|
||||
if (RadioMessageInput.TextLength > maxAnnounceLength)
|
||||
{
|
||||
AnnounceButton.Disabled = true;
|
||||
AnnounceButton.ToolTip = Loc.GetString("comms-console-message-too-long");
|
||||
}
|
||||
else
|
||||
{
|
||||
AnnounceButton.Disabled = false;
|
||||
AnnounceButton.ToolTip = Loc.GetString("comms-console-menu-announcement-button-tooltip");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AnnounceButton.Disabled = true;
|
||||
AnnounceButton.ToolTip = Loc.GetString("comms-console-message-cannot-send");
|
||||
}
|
||||
|
||||
BroadcastButton.Disabled = !_canScreenBroadcast;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||
<!-- Controls for calling, recalling and displaying info for the emergency shuttle -->
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label StyleClasses="FancyWindowTitle" Align="Center"
|
||||
Text="{Loc 'comms-console-shuttle-controls-header'}" />
|
||||
|
||||
<!-- This contains some blank `Controls` to act as dummies. This is because the
|
||||
GridContainer will always left-align the children, while we want them centered.
|
||||
The dummy Controls will attempt to take an even amount of space each, which
|
||||
will re-center our real controls -->
|
||||
<BoxContainer>
|
||||
<!-- Row 1: the buttons themselves -->
|
||||
<Control HorizontalExpand="True" />
|
||||
<Button Name="EmergencyShuttleCallButton" VerticalAlignment="Center"
|
||||
Text="{Loc 'comms-console-call-button-label'}" />
|
||||
<Control HorizontalExpand="True" />
|
||||
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label StyleClasses="LabelSubText" Align="Center"
|
||||
Text="{Loc 'comms-console-shuttle-status-label'}" />
|
||||
<Label Name="CountdownLabel" ReservesSpace="True" Align="Center"/>
|
||||
</BoxContainer>
|
||||
<Control HorizontalExpand="True" />
|
||||
<Button Name="EmergencyShuttleRecallButton" VerticalAlignment="Center"
|
||||
Text="{Loc 'comms-console-recall-button-label'}" />
|
||||
<Control HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using Content.Shared.CCVar;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Communications.UI.Widgets;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ShuttleControls : Control
|
||||
{
|
||||
[Dependency] private IGameTiming _timing = default!;
|
||||
|
||||
private bool _canCall;
|
||||
private bool _countdownStarted;
|
||||
private TimeSpan? _countdownEnd;
|
||||
|
||||
public event Action? OnShuttleCalled;
|
||||
public event Action? OnShuttleRecalled;
|
||||
|
||||
public ShuttleControls()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
EmergencyShuttleCallButton.OnPressed += _ => OnShuttleCalled?.Invoke();
|
||||
EmergencyShuttleRecallButton.OnPressed += _ => OnShuttleRecalled?.Invoke();
|
||||
SyncButtonState();
|
||||
}
|
||||
|
||||
public void UpdateState(bool canCallShuttle, bool countdownStarted, TimeSpan? expectedCountdownEnd)
|
||||
{
|
||||
_canCall = canCallShuttle;
|
||||
_countdownStarted = countdownStarted;
|
||||
_countdownEnd = expectedCountdownEnd;
|
||||
SyncButtonState();
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
UpdateCountdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Syncs and animates the display of the time-to-shuttle-arrival label
|
||||
/// </summary>
|
||||
private void UpdateCountdown()
|
||||
{
|
||||
// Set the label on the LCD countdown
|
||||
var countdown = _countdownEnd == null ? 0.0f : (float)Math.Max(_countdownEnd.Value.Subtract(_timing.CurTime).TotalSeconds, 0);
|
||||
|
||||
var remainingWholeSeconds = _countdownStarted ? (int)Math.Ceiling(countdown) : 0;
|
||||
var message = (remainingWholeSeconds / 60).ToString("D2") + ":" + (remainingWholeSeconds % 60).ToString("D2");
|
||||
CountdownLabel.Text = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the shuttle call/recall buttons to have a consistent state
|
||||
/// </summary>
|
||||
private void SyncButtonState()
|
||||
{
|
||||
EmergencyShuttleCallButton.Disabled = !(_canCall && !_countdownStarted);
|
||||
EmergencyShuttleRecallButton.Disabled = !(_canCall && _countdownStarted);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,29 @@
|
|||
# User interface
|
||||
comms-console-menu-title = Communications Console
|
||||
comms-console-menu-announcement-placeholder = Announcement text...
|
||||
comms-console-menu-announcement-button = Announce
|
||||
comms-console-menu-broadcast-placeholder = Broadcast text...
|
||||
comms-console-menu-announcement-button = Announce over radio
|
||||
comms-console-menu-announcement-button-tooltip = Send your message as a station-wide radio announcement.
|
||||
comms-console-menu-broadcast-button = Broadcast
|
||||
comms-console-menu-broadcast-button = Display on screens
|
||||
comms-console-menu-broadcast-button-tooltip = Broadcast your message to wall-mounted screens around the station. Note: They fit only ten characters!
|
||||
comms-console-menu-alert-level-button-tooltip = Change the station alert level. Applies immediately on selecting.
|
||||
comms-console-menu-call-shuttle = Call emergency shuttle
|
||||
comms-console-menu-recall-shuttle = Recall emergency shuttle
|
||||
comms-console-menu-emergency-shuttle-button-tooltip = Calls or recalls the emergency shuttle. You can only recall when there's enough time left.
|
||||
comms-console-menu-time-remaining = Time remaining: {$time}
|
||||
comms-console-menu-alert-level-button-tooltip = Change the station alert level.
|
||||
comms-console-change-alert-level-button = Change status
|
||||
comms-console-confirm-alert-level-button = Confirm
|
||||
comms-console-call-button-label = Call
|
||||
comms-console-recall-button-label = Recall
|
||||
comms-console-shuttle-status-label = Arrival time
|
||||
comms-console-shuttle-controls-header = EMERGENCY SHUTTLE CONTROLS
|
||||
comms-console-alert-current-level-header = Alert level
|
||||
comms-console-station-announcements-header = Station Announcements
|
||||
comms-console-station-broadcast-header = Station Broadcast
|
||||
comms-console-announce-tab-title = Radio
|
||||
comms-console-broadcast-tab-title = Screen
|
||||
|
||||
# Popup
|
||||
comms-console-permission-denied = Permission denied
|
||||
comms-console-shuttle-unavailable = Shuttle is currently unavailable
|
||||
comms-console-message-too-long = Message is too long
|
||||
comms-console-message-cannot-send = Communications temporarily disabled
|
||||
|
||||
# Placeholder values
|
||||
comms-console-announcement-sent-by = Sent by
|
||||
|
|
@ -26,3 +35,13 @@ comms-console-announcement-title-centcom = Central Command
|
|||
comms-console-announcement-title-nukie = Syndicate Nuclear Operative
|
||||
comms-console-announcement-title-station-ai = Station AI
|
||||
comms-console-announcement-title-wizard = Wizard
|
||||
|
||||
# Flavor text for alert levels
|
||||
comms-console-level-Green-flavour-label = Work is to proceed as normal
|
||||
comms-console-level-Blue-flavour-label = Record suspicious activity with form NT-4772-b
|
||||
comms-console-level-Violet-flavour-label = Maintain social distancing
|
||||
comms-console-level-Yellow-flavour-label = Prepare to hold your breath
|
||||
comms-console-level-Red-flavour-label = Remain vigilant
|
||||
comms-console-level-Gamma-flavour-label = Suggest extreme caution
|
||||
comms-console-level-Delta-flavour-label = Good luck
|
||||
comms-console-level-Epsilon-flavour-label = You're fired
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue