1
0

AlertsUI.xaml.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. using Content.Client.UserInterface.Systems.Alerts.Controls;
  2. using Content.Shared.Alert;
  3. using Robust.Client.AutoGenerated;
  4. using Robust.Client.UserInterface.Controls;
  5. using Robust.Client.UserInterface.XAML;
  6. using Robust.Shared.Input;
  7. using Robust.Shared.Prototypes;
  8. namespace Content.Client.UserInterface.Systems.Alerts.Widgets;
  9. /// <summary>
  10. /// The status effects display on the right side of the screen.
  11. /// </summary>
  12. [GenerateTypedNameReferences]
  13. public sealed partial class AlertsUI : UIWidget
  14. {
  15. // also known as Control.Children?
  16. private readonly Dictionary<AlertKey, AlertControl> _alertControls = new();
  17. public AlertsUI()
  18. {
  19. RobustXamlLoader.Load(this);
  20. }
  21. public void SyncControls(AlertsSystem alertsSystem,
  22. AlertOrderPrototype? alertOrderPrototype,
  23. IReadOnlyDictionary<AlertKey,
  24. AlertState> alertStates)
  25. {
  26. // remove any controls with keys no longer present
  27. if (SyncRemoveControls(alertStates))
  28. return;
  29. // now we know that alertControls contains alerts that should still exist but
  30. // may need to updated,
  31. // also there may be some new alerts we need to show.
  32. // further, we need to ensure they are ordered w.r.t their configured order
  33. SyncUpdateControls(alertsSystem, alertOrderPrototype, alertStates);
  34. }
  35. public void ClearAllControls()
  36. {
  37. foreach (var alertControl in _alertControls.Values)
  38. {
  39. alertControl.OnPressed -= AlertControlPressed;
  40. alertControl.Dispose();
  41. }
  42. _alertControls.Clear();
  43. }
  44. public event EventHandler<ProtoId<AlertPrototype>>? AlertPressed;
  45. private bool SyncRemoveControls(IReadOnlyDictionary<AlertKey, AlertState> alertStates)
  46. {
  47. var toRemove = new List<AlertKey>();
  48. foreach (var existingKey in _alertControls.Keys)
  49. {
  50. if (!alertStates.ContainsKey(existingKey))
  51. toRemove.Add(existingKey);
  52. }
  53. foreach (var alertKeyToRemove in toRemove)
  54. {
  55. _alertControls.Remove(alertKeyToRemove, out var control);
  56. if (control == null)
  57. return true;
  58. AlertContainer.Children.Remove(control);
  59. }
  60. return false;
  61. }
  62. private void SyncUpdateControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype,
  63. IReadOnlyDictionary<AlertKey, AlertState> alertStates)
  64. {
  65. foreach (var (alertKey, alertState) in alertStates)
  66. {
  67. if (!alertKey.AlertType.HasValue)
  68. {
  69. Logger.WarningS("alert", "found alertkey without alerttype," +
  70. " alert keys should never be stored without an alerttype set: {0}", alertKey);
  71. continue;
  72. }
  73. var alertType = alertKey.AlertType.Value;
  74. if (!alertsSystem.TryGet(alertType, out var newAlert))
  75. {
  76. Logger.ErrorS("alert", "Unrecognized alertType {0}", alertType);
  77. continue;
  78. }
  79. if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) &&
  80. existingAlertControl.Alert.ID == newAlert.ID)
  81. {
  82. // key is the same, simply update the existing control severity / cooldown
  83. existingAlertControl.SetSeverity(alertState.Severity);
  84. if (alertState.ShowCooldown)
  85. existingAlertControl.Cooldown = alertState.Cooldown;
  86. }
  87. else
  88. {
  89. if (existingAlertControl != null)
  90. AlertContainer.Children.Remove(existingAlertControl);
  91. // this is a new alert + alert key or just a different alert with the same
  92. // key, create the control and add it in the appropriate order
  93. var newAlertControl = CreateAlertControl(newAlert, alertState);
  94. //TODO: Can the presenter sort the states before giving it to us?
  95. if (alertOrderPrototype != null)
  96. {
  97. var added = false;
  98. foreach (var alertControl in AlertContainer.Children)
  99. {
  100. if (alertOrderPrototype.Compare(newAlert, ((AlertControl) alertControl).Alert) >= 0)
  101. continue;
  102. var idx = alertControl.GetPositionInParent();
  103. AlertContainer.Children.Add(newAlertControl);
  104. newAlertControl.SetPositionInParent(idx);
  105. added = true;
  106. break;
  107. }
  108. if (!added)
  109. AlertContainer.Children.Add(newAlertControl);
  110. }
  111. else
  112. {
  113. AlertContainer.Children.Add(newAlertControl);
  114. }
  115. _alertControls[newAlert.AlertKey] = newAlertControl;
  116. }
  117. }
  118. }
  119. private AlertControl CreateAlertControl(AlertPrototype alert, AlertState alertState)
  120. {
  121. (TimeSpan, TimeSpan)? cooldown = null;
  122. if (alertState.ShowCooldown)
  123. cooldown = alertState.Cooldown;
  124. var alertControl = new AlertControl(alert, alertState.Severity)
  125. {
  126. Cooldown = cooldown
  127. };
  128. alertControl.OnPressed += AlertControlPressed;
  129. return alertControl;
  130. }
  131. private void AlertControlPressed(BaseButton.ButtonEventArgs args)
  132. {
  133. if (args.Button is not AlertControl control)
  134. return;
  135. if (args.Event.Function != EngineKeyFunctions.UIClick)
  136. return;
  137. AlertPressed?.Invoke(this, control.Alert.ID);
  138. }
  139. }