mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
169 lines
5.2 KiB
C#
169 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.CustomControls;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Profiling;
|
|
|
|
namespace Robust.Client.UserInterface;
|
|
internal sealed partial class UserInterfaceManager
|
|
{
|
|
private readonly List<Control> _modalStack = new();
|
|
|
|
private void RunMeasure(Control control)
|
|
{
|
|
if (control.IsMeasureValid || !control.IsInsideTree)
|
|
return;
|
|
|
|
if (control.Parent != null)
|
|
{
|
|
RunMeasure(control.Parent);
|
|
}
|
|
|
|
if (control is WindowRoot root)
|
|
{
|
|
control.Measure(root.Window.RenderTarget.Size / root.UIScale);
|
|
}
|
|
else if (control.PreviousMeasure.HasValue)
|
|
{
|
|
control.Measure(control.PreviousMeasure.Value);
|
|
}
|
|
}
|
|
|
|
private void RunArrange(Control control)
|
|
{
|
|
if (control.IsArrangeValid || !control.IsInsideTree)
|
|
return;
|
|
|
|
if (control.Parent != null)
|
|
{
|
|
RunArrange(control.Parent);
|
|
}
|
|
|
|
if (control is WindowRoot root)
|
|
{
|
|
control.Arrange(UIBox2.FromDimensions(Vector2.Zero, root.Window.RenderTarget.Size / root.UIScale));
|
|
}
|
|
else if (control.PreviousArrange.HasValue)
|
|
{
|
|
control.Arrange(control.PreviousArrange.Value);
|
|
}
|
|
}
|
|
|
|
public void Popup(string contents, string title = "Alert!")
|
|
{
|
|
var popup = new DefaultWindow
|
|
{
|
|
Title = title
|
|
};
|
|
|
|
popup.Contents.AddChild(new Label {Text = contents});
|
|
popup.OpenCentered();
|
|
}
|
|
|
|
public void ControlHidden(Control control)
|
|
{
|
|
// Does the same thing but it could later be changed so..
|
|
ControlRemovedFromTree(control);
|
|
}
|
|
|
|
public void ControlRemovedFromTree(Control control)
|
|
{
|
|
if (control.Root?.StoredKeyboardFocus == control)
|
|
control.Root.StoredKeyboardFocus = null;
|
|
|
|
ReleaseKeyboardFocus(control);
|
|
RemoveModal(control);
|
|
|
|
if (control == ControlFocused)
|
|
ControlFocused = null;
|
|
|
|
if (control == CurrentlyHovered)
|
|
UpdateHovered();
|
|
}
|
|
|
|
public void PushModal(Control modal)
|
|
{
|
|
_modalStack.Add(modal);
|
|
}
|
|
|
|
public void RemoveModal(Control modal)
|
|
{
|
|
if (_modalStack.Remove(modal))
|
|
{
|
|
modal.ModalRemoved();
|
|
}
|
|
}
|
|
|
|
public void Render(IRenderHandle renderHandle)
|
|
{
|
|
// Render secondary windows LAST.
|
|
// This makes it so that (hopefully) the GPU will be done rendering secondary windows
|
|
// by the times we try to blit to them at the end of Clyde's render cycle,
|
|
// So that the GL driver doesn't have to block on glWaitSync.
|
|
|
|
foreach (var root in _roots)
|
|
{
|
|
if (root.Window != _clyde.MainWindow)
|
|
{
|
|
using var _ = _prof.Group("Window");
|
|
_prof.WriteValue("ID", ProfData.Int32((int) root.Window.Id));
|
|
|
|
renderHandle.RenderInRenderTarget(
|
|
root.Window.RenderTarget,
|
|
() => DoRender(root),
|
|
root.ActualBgColor);
|
|
}
|
|
}
|
|
|
|
using (_prof.Group("Main"))
|
|
{
|
|
DoRender(_windowsToRoot[_clyde.MainWindow.Id]);
|
|
}
|
|
|
|
void DoRender(WindowRoot root)
|
|
{
|
|
try
|
|
{
|
|
var total = 0;
|
|
var drawingHandle = renderHandle.DrawingHandleScreen;
|
|
drawingHandle.SetTransform(Matrix3.Identity);
|
|
RenderControl(renderHandle, ref total, root, Vector2i.Zero, Color.White, null, Matrix3.Identity);
|
|
drawingHandle.SetTransform(Matrix3.Identity);
|
|
OnPostDrawUIRoot?.Invoke(new PostDrawUIRootEventArgs(root, drawingHandle));
|
|
|
|
_prof.WriteValue("Controls rendered", ProfData.Int32(total));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_sawmillUI.Error($"Caught exception while trying to draw a UI element: {root}");
|
|
_runtime.LogException(e, nameof(UserInterfaceManager));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void QueueStyleUpdate(Control control)
|
|
{
|
|
_styleUpdateQueue.Enqueue(control);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queues a control so that it gets remeasured in the next frame update. Does not queue an arrange update.
|
|
/// </summary>
|
|
public void QueueMeasureUpdate(Control control)
|
|
{
|
|
_measureUpdateQueue.Enqueue(control);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queues a control so that it gets rearranged in the next frame update. Does not queue a measure update.
|
|
/// </summary>
|
|
public void QueueArrangeUpdate(Control control)
|
|
{
|
|
_arrangeUpdateQueue.Enqueue(control);
|
|
}
|
|
}
|