1
0

CloseRecentWindowUIController.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using Content.Client.Gameplay;
  2. using Content.Client.Info;
  3. using Robust.Client.Input;
  4. using Robust.Client.UserInterface;
  5. using Robust.Client.UserInterface.Controllers;
  6. using Robust.Client.UserInterface.CustomControls;
  7. using Robust.Shared.Input;
  8. using Robust.Shared.Input.Binding;
  9. namespace Content.Client.UserInterface.Systems.Info;
  10. public sealed class CloseRecentWindowUIController : UIController
  11. {
  12. [Dependency] private readonly IInputManager _inputManager = default!;
  13. [Dependency] private readonly IUserInterfaceManager _uiManager = default!;
  14. /// <summary>
  15. /// A list of windows that have been interacted with recently. Windows should only
  16. /// be in this list once, with the most recent window at the end, and the oldest
  17. /// window at the start.
  18. /// </summary>
  19. List<BaseWindow> recentlyInteractedWindows = new List<BaseWindow>();
  20. public override void Initialize()
  21. {
  22. // Add listeners to be able to know when windows are opened.
  23. // (Does not need to be unlistened since UIControllers live forever)
  24. _uiManager.OnKeyBindDown += OnKeyBindDown;
  25. _uiManager.WindowRoot.OnChildAdded += OnRootChildAdded;
  26. _inputManager.SetInputCommand(EngineKeyFunctions.WindowCloseRecent,
  27. InputCmdHandler.FromDelegate(session => CloseMostRecentWindow()));
  28. }
  29. /// <summary>
  30. /// Closes the most recently focused window.
  31. /// </summary>
  32. public void CloseMostRecentWindow()
  33. {
  34. // Search backwards through the recency list to find a still open window and close it
  35. for (int i=recentlyInteractedWindows.Count-1; i>=0; i--)
  36. {
  37. var window = recentlyInteractedWindows[i];
  38. recentlyInteractedWindows.RemoveAt(i); // Should always be removed as either the reference is stale or we're closing it
  39. if (window.IsOpen)
  40. {
  41. window.Close();
  42. return;
  43. }
  44. // continue going down the list, hoping to find a still-open window
  45. }
  46. }
  47. private void OnKeyBindDown(Control control)
  48. {
  49. // On click, we should set the window that owns this control (if any) to the most recently
  50. // clicked window. By doing this, we can create an ordering of what windows have been
  51. // interacted with.
  52. // Something was clicked, so find the window corresponding to what was clicked
  53. var window = GetWindowForControl(control);
  54. // Find the window owning the control
  55. if (window != null)
  56. {
  57. // And move to top of recent stack
  58. //Logger.Debug("Most recent window is " + window.Name);
  59. SetMostRecentlyInteractedWindow(window);
  60. }
  61. }
  62. /// <summary>
  63. /// Sets the window as the one most recently interacted with. This function will update the
  64. /// internal recentlyInteractedWindows tracking.
  65. /// </summary>
  66. /// <param name="window"></param>
  67. public void SetMostRecentlyInteractedWindow(BaseWindow window)
  68. {
  69. // Search through the list and see if already added.
  70. // (This search is backwards since it's fairly common that the user is clicking the same
  71. // window multiple times in a row, and so that saves a tiny bit of perf doing it this way)
  72. for (int i=recentlyInteractedWindows.Count-1; i>=0; i--)
  73. {
  74. if (recentlyInteractedWindows[i] == window)
  75. {
  76. // Window already in the list
  77. // Is window the top most recent entry?
  78. if (i == recentlyInteractedWindows.Count-1)
  79. return; // Then there's nothing to do, it's already in the right spot
  80. else
  81. {
  82. // Need to remove the old entry so it can be readded (no duplicates in list allowed)
  83. recentlyInteractedWindows.RemoveAt(i);
  84. break;
  85. }
  86. }
  87. }
  88. // Now that the list has been checked for duplicates, okay to add new window at end of tracking
  89. recentlyInteractedWindows.Add(window);
  90. }
  91. private BaseWindow? GetWindowForControl(Control? control)
  92. {
  93. if (control == null)
  94. return null;
  95. if (control is BaseWindow)
  96. return (BaseWindow) control;
  97. // Go up the hierarchy until we find a window (or don't)
  98. return GetWindowForControl(control.Parent);
  99. }
  100. private void OnRootChildAdded(Control control)
  101. {
  102. if (control is BaseWindow)
  103. {
  104. // On new window open, add to tracking
  105. SetMostRecentlyInteractedWindow((BaseWindow) control);
  106. }
  107. }
  108. /// <summary>
  109. /// Checks whether there are any windows that can be closed.
  110. /// </summary>
  111. /// <returns></returns>
  112. public bool HasClosableWindow()
  113. {
  114. for (var i = recentlyInteractedWindows.Count - 1; i >= 0; i--)
  115. {
  116. var window = recentlyInteractedWindows[i];
  117. if (window.IsOpen)
  118. return true;
  119. // continue going down the list, hoping to find a still-open window
  120. }
  121. return false;
  122. }
  123. }