using Content.Client.Gameplay;
using Content.Client.Info;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
namespace Content.Client.UserInterface.Systems.Info;
public sealed class CloseRecentWindowUIController : UIController
{
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
///
/// A list of windows that have been interacted with recently. Windows should only
/// be in this list once, with the most recent window at the end, and the oldest
/// window at the start.
///
List recentlyInteractedWindows = new List();
public override void Initialize()
{
// Add listeners to be able to know when windows are opened.
// (Does not need to be unlistened since UIControllers live forever)
_uiManager.OnKeyBindDown += OnKeyBindDown;
_uiManager.WindowRoot.OnChildAdded += OnRootChildAdded;
_inputManager.SetInputCommand(EngineKeyFunctions.WindowCloseRecent,
InputCmdHandler.FromDelegate(session => CloseMostRecentWindow()));
}
///
/// Closes the most recently focused window.
///
public void CloseMostRecentWindow()
{
// Search backwards through the recency list to find a still open window and close it
for (int i=recentlyInteractedWindows.Count-1; i>=0; i--)
{
var window = recentlyInteractedWindows[i];
recentlyInteractedWindows.RemoveAt(i); // Should always be removed as either the reference is stale or we're closing it
if (window.IsOpen)
{
window.Close();
return;
}
// continue going down the list, hoping to find a still-open window
}
}
private void OnKeyBindDown(Control control)
{
// On click, we should set the window that owns this control (if any) to the most recently
// clicked window. By doing this, we can create an ordering of what windows have been
// interacted with.
// Something was clicked, so find the window corresponding to what was clicked
var window = GetWindowForControl(control);
// Find the window owning the control
if (window != null)
{
// And move to top of recent stack
//Logger.Debug("Most recent window is " + window.Name);
SetMostRecentlyInteractedWindow(window);
}
}
///
/// Sets the window as the one most recently interacted with. This function will update the
/// internal recentlyInteractedWindows tracking.
///
///
public void SetMostRecentlyInteractedWindow(BaseWindow window)
{
// Search through the list and see if already added.
// (This search is backwards since it's fairly common that the user is clicking the same
// window multiple times in a row, and so that saves a tiny bit of perf doing it this way)
for (int i=recentlyInteractedWindows.Count-1; i>=0; i--)
{
if (recentlyInteractedWindows[i] == window)
{
// Window already in the list
// Is window the top most recent entry?
if (i == recentlyInteractedWindows.Count-1)
return; // Then there's nothing to do, it's already in the right spot
else
{
// Need to remove the old entry so it can be readded (no duplicates in list allowed)
recentlyInteractedWindows.RemoveAt(i);
break;
}
}
}
// Now that the list has been checked for duplicates, okay to add new window at end of tracking
recentlyInteractedWindows.Add(window);
}
private BaseWindow? GetWindowForControl(Control? control)
{
if (control == null)
return null;
if (control is BaseWindow)
return (BaseWindow) control;
// Go up the hierarchy until we find a window (or don't)
return GetWindowForControl(control.Parent);
}
private void OnRootChildAdded(Control control)
{
if (control is BaseWindow)
{
// On new window open, add to tracking
SetMostRecentlyInteractedWindow((BaseWindow) control);
}
}
///
/// Checks whether there are any windows that can be closed.
///
///
public bool HasClosableWindow()
{
for (var i = recentlyInteractedWindows.Count - 1; i >= 0; i--)
{
var window = recentlyInteractedWindows[i];
if (window.IsOpen)
return true;
// continue going down the list, hoping to find a still-open window
}
return false;
}
}