* Alert autoremove v0 * Code cleanup and timing * comment * Tritium, code compression * not resolving manually * reduced lookups, new comp * fix-fix yes * use RemCompDeferred, handle OnUnpaused * missed a todo * entitysystem resolve * remove unnecessary component updates * remove AlertState from comp, move EntityUnpausedEvent actions to AlertStateComponent's Timespan * Code cleanup * comments * combines AutoRemove input into Clear * minor logic adjustment that does not really change anything but is less ambiguous
160 lines
5.6 KiB
C#
160 lines
5.6 KiB
C#
using Content.Client.UserInterface.Systems.Alerts.Controls;
|
|
using Content.Shared.Alert;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Shared.Input;
|
|
|
|
namespace Content.Client.UserInterface.Systems.Alerts.Widgets;
|
|
|
|
/// <summary>
|
|
/// The status effects display on the right side of the screen.
|
|
/// </summary>
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class AlertsUI : UIWidget
|
|
{
|
|
// also known as Control.Children?
|
|
private readonly Dictionary<AlertKey, AlertControl> _alertControls = new();
|
|
|
|
public AlertsUI()
|
|
{
|
|
RobustXamlLoader.Load(this);
|
|
}
|
|
|
|
public void SyncControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype,
|
|
IReadOnlyDictionary<AlertKey, AlertState> alertStates)
|
|
{
|
|
// remove any controls with keys no longer present
|
|
if (SyncRemoveControls(alertStates))
|
|
return;
|
|
|
|
// now we know that alertControls contains alerts that should still exist but
|
|
// may need to updated,
|
|
// also there may be some new alerts we need to show.
|
|
// further, we need to ensure they are ordered w.r.t their configured order
|
|
SyncUpdateControls(alertsSystem, alertOrderPrototype, alertStates);
|
|
}
|
|
|
|
public void ClearAllControls()
|
|
{
|
|
foreach (var alertControl in _alertControls.Values)
|
|
{
|
|
alertControl.OnPressed -= AlertControlPressed;
|
|
alertControl.Dispose();
|
|
}
|
|
|
|
_alertControls.Clear();
|
|
}
|
|
|
|
public event EventHandler<AlertType>? AlertPressed;
|
|
|
|
private bool SyncRemoveControls(IReadOnlyDictionary<AlertKey, AlertState> alertStates)
|
|
{
|
|
var toRemove = new List<AlertKey>();
|
|
foreach (var existingKey in _alertControls.Keys)
|
|
{
|
|
if (!alertStates.ContainsKey(existingKey))
|
|
toRemove.Add(existingKey);
|
|
}
|
|
|
|
foreach (var alertKeyToRemove in toRemove)
|
|
{
|
|
_alertControls.Remove(alertKeyToRemove, out var control);
|
|
if (control == null)
|
|
return true;
|
|
AlertContainer.Children.Remove(control);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void SyncUpdateControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype,
|
|
IReadOnlyDictionary<AlertKey, AlertState> alertStates)
|
|
{
|
|
foreach (var (alertKey, alertState) in alertStates)
|
|
{
|
|
if (!alertKey.AlertType.HasValue)
|
|
{
|
|
Logger.WarningS("alert", "found alertkey without alerttype," +
|
|
" alert keys should never be stored without an alerttype set: {0}", alertKey);
|
|
continue;
|
|
}
|
|
|
|
var alertType = alertKey.AlertType.Value;
|
|
if (!alertsSystem.TryGet(alertType, out var newAlert))
|
|
{
|
|
Logger.ErrorS("alert", "Unrecognized alertType {0}", alertType);
|
|
continue;
|
|
}
|
|
|
|
if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) &&
|
|
existingAlertControl.Alert.AlertType == newAlert.AlertType)
|
|
{
|
|
// key is the same, simply update the existing control severity / cooldown
|
|
existingAlertControl.SetSeverity(alertState.Severity);
|
|
if (alertState.ShowCooldown)
|
|
existingAlertControl.Cooldown = alertState.Cooldown;
|
|
}
|
|
else
|
|
{
|
|
if (existingAlertControl != null) AlertContainer.Children.Remove(existingAlertControl);
|
|
|
|
// this is a new alert + alert key or just a different alert with the same
|
|
// key, create the control and add it in the appropriate order
|
|
var newAlertControl = CreateAlertControl(newAlert, alertState);
|
|
|
|
//TODO: Can the presenter sort the states before giving it to us?
|
|
if (alertOrderPrototype != null)
|
|
{
|
|
var added = false;
|
|
foreach (var alertControl in AlertContainer.Children)
|
|
{
|
|
if (alertOrderPrototype.Compare(newAlert, ((AlertControl) alertControl).Alert) >= 0)
|
|
continue;
|
|
|
|
var idx = alertControl.GetPositionInParent();
|
|
AlertContainer.Children.Add(newAlertControl);
|
|
newAlertControl.SetPositionInParent(idx);
|
|
added = true;
|
|
break;
|
|
}
|
|
|
|
if (!added)
|
|
AlertContainer.Children.Add(newAlertControl);
|
|
}
|
|
else
|
|
{
|
|
AlertContainer.Children.Add(newAlertControl);
|
|
}
|
|
|
|
_alertControls[newAlert.AlertKey] = newAlertControl;
|
|
}
|
|
}
|
|
}
|
|
|
|
private AlertControl CreateAlertControl(AlertPrototype alert, AlertState alertState)
|
|
{
|
|
(TimeSpan, TimeSpan)? cooldown = null;
|
|
if (alertState.ShowCooldown)
|
|
cooldown = alertState.Cooldown;
|
|
|
|
var alertControl = new AlertControl(alert, alertState.Severity)
|
|
{
|
|
Cooldown = cooldown
|
|
};
|
|
alertControl.OnPressed += AlertControlPressed;
|
|
return alertControl;
|
|
}
|
|
|
|
private void AlertControlPressed(BaseButton.ButtonEventArgs args)
|
|
{
|
|
if (args.Button is not AlertControl control)
|
|
return;
|
|
|
|
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
|
return;
|
|
|
|
AlertPressed?.Invoke(this, control.Alert.AlertType);
|
|
}
|
|
}
|