mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-01 09:37:03 +02:00
* [Dependency] source generator No more reflection, no more codegen at runtime Also various changes to Roslyn helpers to make this easier to write. Requires all types with dependencies to be partial and not have readonly dependency fields. An analyzer enforces this at warning level, the previous injection strategies have remained in the code *for now* as a fallback. No fallback is available for [field: Dependency] properties, due to a Roslyn bug. Code Fixes exist. We love Roslyn * Apply dependencies generator changes to all code * Release notes * Preprocessor got hands * Handle nullable dependencies These are bad but gotta deal with it. * Apply suggestions from code review Co-authored-by: Moony <moony@hellomouse.net> * Fine, let's not use collection expressions --------- Co-authored-by: Moony <moony@hellomouse.net>
225 lines
6.6 KiB
C#
225 lines
6.6 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.UserInterface.CustomControls;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Maths;
|
|
|
|
namespace Robust.Client.UserInterface.Controls
|
|
{
|
|
/// <summary>
|
|
/// Represents an operating system-based UI window.
|
|
/// </summary>
|
|
/// <seealso cref="BaseWindow"/>
|
|
[Virtual]
|
|
public partial class OSWindow : Control
|
|
{
|
|
[Dependency] private IClyde _clyde = default!;
|
|
|
|
private string _title = "Window";
|
|
private WindowRoot? _root;
|
|
|
|
/// <summary>
|
|
/// The window instance backing this window instance.
|
|
/// Not guaranteed to be available unless the window is currently open.
|
|
/// </summary>
|
|
public IClydeWindow? ClydeWindow { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The window that will "own" this window.
|
|
/// Owned windows always appear on top of their owners and have some other misc behavior depending on the OS.
|
|
/// </summary>
|
|
public IClydeWindow? Owner { get; set; }
|
|
|
|
/// <summary>
|
|
/// Whether the window is created and currently open.
|
|
/// </summary>
|
|
public bool IsOpen => ClydeWindow?.IsVisible ?? false;
|
|
|
|
/// <summary>
|
|
/// The title of the window.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Can be changed while the window is open.
|
|
/// </remarks>
|
|
public string Title
|
|
{
|
|
get => _title;
|
|
set
|
|
{
|
|
_title = value;
|
|
|
|
if (ClydeWindow != null)
|
|
ClydeWindow.Title = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The location to place the window at when it is opened.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Changing this while the window is open has no effect.
|
|
/// </remarks>
|
|
public WindowStartupLocation StartupLocation { get; set; }
|
|
|
|
/// <summary>
|
|
/// Controls whether to automatically size one or both axis of the window to fit the content.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Changing this while the window is open has no effect.
|
|
/// </remarks>
|
|
public WindowSizeToContent SizeToContent { get; set; }
|
|
|
|
/// <summary>
|
|
/// Specifies window styling options for the window.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Changing this while the window is open has no effect.
|
|
/// </remarks>
|
|
public OSWindowStyles WindowStyles { get; set; }
|
|
|
|
/// <summary>
|
|
/// Raised when the window is being closed
|
|
/// (via calling <see cref="Close"/> or the user clicking the close button).
|
|
/// Can be cancelled.
|
|
/// </summary>
|
|
public event Action<CancelEventArgs>? Closing;
|
|
|
|
/// <summary>
|
|
/// Raised when the window has been closed.
|
|
/// </summary>
|
|
public event Action? Closed;
|
|
|
|
public OSWindow()
|
|
{
|
|
IoCManager.InjectDependencies(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create the window if not already created.
|
|
/// This window is not visible by default, call <see cref="Show"/> to display it.
|
|
/// </summary>
|
|
public IClydeWindow Create()
|
|
{
|
|
if (ClydeWindow != null)
|
|
return ClydeWindow;
|
|
|
|
var parameters = new WindowCreateParameters();
|
|
|
|
if (!float.IsNaN(SetWidth))
|
|
parameters.Width = (int)SetWidth;
|
|
|
|
if (!float.IsNaN(SetHeight))
|
|
parameters.Height = (int)SetHeight;
|
|
|
|
if (SizeToContent != WindowSizeToContent.Manual)
|
|
{
|
|
Measure(Vector2Helpers.Infinity);
|
|
|
|
if ((SizeToContent & WindowSizeToContent.Width) != 0)
|
|
parameters.Width = (int)DesiredSize.X;
|
|
|
|
if ((SizeToContent & WindowSizeToContent.Height) != 0)
|
|
parameters.Height = (int)DesiredSize.Y;
|
|
}
|
|
|
|
parameters.Title = _title;
|
|
parameters.Styles = WindowStyles;
|
|
parameters.Owner = Owner;
|
|
parameters.StartupLocation = StartupLocation;
|
|
parameters.Visible = false;
|
|
|
|
ClydeWindow = _clyde.CreateWindow(parameters);
|
|
ClydeWindow.RequestClosed += OnWindowRequestClosed;
|
|
ClydeWindow.Destroyed += OnWindowDestroyed;
|
|
ClydeWindow.Resized += OnWindowResized;
|
|
|
|
_root = UserInterfaceManager.CreateWindowRoot(ClydeWindow);
|
|
_root.CreateRootControls();
|
|
|
|
// Add ourselves *after* creating the root.
|
|
// This way root controls are valid in EnteredTree().
|
|
// We have to re-organize the controls after, of course.
|
|
_root.AddChild(this);
|
|
SetPositionFirst();
|
|
|
|
// Resize the window by our UIScale
|
|
ClydeWindow.Size = new((int)(parameters.Width * UIScale), (int)(parameters.Height * UIScale));
|
|
return ClydeWindow;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Show the window to the user, creating it if necessary
|
|
/// </summary>
|
|
public void Show()
|
|
{
|
|
ClydeWindow = Create();
|
|
ClydeWindow.IsVisible = true;
|
|
|
|
Shown();
|
|
}
|
|
|
|
protected virtual void Shown()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Try to close the window.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This can be cancelled by anything handling <see cref="Closing"/>.
|
|
/// </remarks>
|
|
public void Close()
|
|
{
|
|
if (ClydeWindow == null)
|
|
return;
|
|
|
|
var eventArgs = new CancelEventArgs();
|
|
Closing?.Invoke(eventArgs);
|
|
if (eventArgs.Cancel)
|
|
return;
|
|
|
|
ClydeWindow.Dispose();
|
|
}
|
|
|
|
private void OnWindowRequestClosed(WindowRequestClosedEventArgs eventArgs)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
private void OnWindowDestroyed(WindowDestroyedEventArgs obj)
|
|
{
|
|
// I give it a 75% chance that some Linux user can force close the window,
|
|
// breaking GLFW,
|
|
// and forcing us to have a code path that ignores the RequestClosed code.
|
|
|
|
RealClosed();
|
|
}
|
|
|
|
private void OnWindowResized(WindowResizedEventArgs obj)
|
|
{
|
|
SetSize = obj.NewSize / UIScale;
|
|
}
|
|
|
|
private void RealClosed()
|
|
{
|
|
Orphan();
|
|
|
|
ClydeWindow = null;
|
|
_root = null;
|
|
|
|
Closed?.Invoke();
|
|
}
|
|
}
|
|
|
|
[Flags]
|
|
public enum WindowSizeToContent : byte
|
|
{
|
|
Manual = 0,
|
|
Width = 1 << 0,
|
|
Height = 1 << 1,
|
|
WidthAndHeight = Width | Height
|
|
}
|
|
}
|