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>
250 lines
7.5 KiB
C#
250 lines
7.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.Console.Commands;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.Input;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Shared.Input;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Maths;
|
|
|
|
namespace Robust.Client.UserInterface;
|
|
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class DevWindowTabUI : Control
|
|
{
|
|
[Dependency] private IClydeInternal _clyde = default!;
|
|
[Dependency] private IInputManager _input = default!;
|
|
|
|
public Control? SelectedControl { get; private set; }
|
|
private Dictionary<Control, DevWindowUITreeEntry> ControlMap { get; } = new();
|
|
private Control? LastHoveredControl { get; set; }
|
|
|
|
public event Action? SelectedControlChanged;
|
|
|
|
public DevWindowTabUI()
|
|
{
|
|
InitializeComponent();
|
|
|
|
TopbarButtons.PanelOverride = new StyleBoxFlat
|
|
{
|
|
BorderThickness = new Thickness(0, 0, 0, 1),
|
|
BorderColor = Color.Gray,
|
|
ContentMarginLeftOverride = 3,
|
|
ContentMarginRightOverride = 3,
|
|
ContentMarginBottomOverride = 1,
|
|
ContentMarginTopOverride = 3,
|
|
};
|
|
TreeRootBG.PanelOverride = new StyleBoxFlat
|
|
{
|
|
BorderThickness = new Thickness(0, 0, 1, 0),
|
|
BorderColor = Color.Gray,
|
|
ContentMarginLeftOverride = 3,
|
|
ContentMarginBottomOverride = 3,
|
|
};
|
|
}
|
|
|
|
private void InitializeComponent()
|
|
{
|
|
RobustXamlLoader.Load(this);
|
|
IoCManager.InjectDependencies(this);
|
|
|
|
ControlTreeRoot.OnKeyBindDown += ControlTreeRootOnKeyBindDown;
|
|
RefreshPropertiesButton.OnPressed += _ => Refresh();
|
|
}
|
|
|
|
private Control? GetControlUnderMouse()
|
|
{
|
|
return UserInterfaceManager.MouseGetControl(_input.MouseScreenPosition);
|
|
}
|
|
|
|
private void OnMouseMove(MouseMoveEventArgs obj)
|
|
{
|
|
if (!ControlPicker.Pressed)
|
|
return;
|
|
|
|
var controlUnderMouse = GetControlUnderMouse();
|
|
if (LastHoveredControl == controlUnderMouse)
|
|
return;
|
|
|
|
LastHoveredControl = controlUnderMouse;
|
|
|
|
Stack<Control> entryStack = new();
|
|
DevWindowUITreeEntry? entry = null;
|
|
var control = controlUnderMouse;
|
|
while (control != null)
|
|
{
|
|
if (ControlMap.TryGetValue(control, out entry))
|
|
break;
|
|
|
|
entryStack.Push(control);
|
|
control = control.Parent;
|
|
}
|
|
|
|
if (entry == null)
|
|
return;
|
|
|
|
if (entryStack.Count > 0)
|
|
entry.Open();
|
|
|
|
foreach (var subEntry in entryStack)
|
|
{
|
|
ControlMap[subEntry].Open();
|
|
}
|
|
|
|
SelectControl(controlUnderMouse);
|
|
}
|
|
|
|
private bool OnUIKeyBindStateChanged(BoundKeyEventArgs arg)
|
|
{
|
|
if (arg.Function != EngineKeyFunctions.UIClick)
|
|
return false;
|
|
|
|
if (!ControlPicker.Pressed)
|
|
return false;
|
|
|
|
var control = GetControlUnderMouse();
|
|
if (control == ControlPicker)
|
|
return false;
|
|
|
|
ControlPicker.Pressed = false;
|
|
return true;
|
|
}
|
|
|
|
private void ControlTreeRootOnKeyBindDown(GUIBoundKeyEventArgs obj)
|
|
{
|
|
if (obj.Function != EngineKeyFunctions.UIClick)
|
|
return;
|
|
|
|
obj.Handle();
|
|
SelectControl(null);
|
|
}
|
|
|
|
protected override void EnteredTree()
|
|
{
|
|
base.EnteredTree();
|
|
|
|
// Load tree roots.
|
|
foreach (var root in UserInterfaceManager.AllRoots)
|
|
{
|
|
var entry = new DevWindowUITreeEntry(this, root);
|
|
|
|
ControlTreeRoot.AddChild(entry);
|
|
}
|
|
|
|
UserInterfaceManager.OnPostDrawUIRoot += OnPostDrawUIRoot;
|
|
_clyde.MouseMove += OnMouseMove;
|
|
_input.UIKeyBindStateChanged += OnUIKeyBindStateChanged;
|
|
}
|
|
|
|
protected override void ExitedTree()
|
|
{
|
|
base.ExitedTree();
|
|
|
|
// Clear tree children.
|
|
ControlTreeRoot.RemoveAllChildren();
|
|
|
|
UserInterfaceManager.OnPostDrawUIRoot -= OnPostDrawUIRoot;
|
|
_clyde.MouseMove -= OnMouseMove;
|
|
_input.UIKeyBindStateChanged -= OnUIKeyBindStateChanged;
|
|
}
|
|
|
|
private void OnPostDrawUIRoot(PostDrawUIRootEventArgs eventArgs)
|
|
{
|
|
if (SelectedControl == null || eventArgs.Root != SelectedControl.Root)
|
|
return;
|
|
|
|
var rect = UIBox2i.FromDimensions(SelectedControl.GlobalPixelPosition, SelectedControl.PixelSize);
|
|
eventArgs.DrawingHandle.DrawRect(rect, Color.Cyan.WithAlpha(0.35f));
|
|
}
|
|
|
|
internal void EntryAdded(DevWindowUITreeEntry entry)
|
|
{
|
|
ControlMap[entry.VisControl] = entry;
|
|
}
|
|
|
|
public void EntryRemoved(DevWindowUITreeEntry entry)
|
|
{
|
|
if (SelectedControl == entry.VisControl)
|
|
SelectControl(null);
|
|
|
|
ControlMap.Remove(entry.VisControl);
|
|
}
|
|
|
|
public void SelectControl(Control? control)
|
|
{
|
|
SelectedControl = control;
|
|
|
|
SelectedControlChanged?.Invoke();
|
|
|
|
Refresh();
|
|
}
|
|
|
|
private void Refresh()
|
|
{
|
|
ControlProperties.RemoveAllChildren();
|
|
|
|
if (SelectedControl == null)
|
|
return;
|
|
|
|
var props = GuiDumpCommand.PropertyValuesForInheritance(SelectedControl);
|
|
foreach (var (classname, values) in props)
|
|
{
|
|
ControlProperties.AddChild(new PanelContainer
|
|
{
|
|
Children = { new Label
|
|
{
|
|
Text = classname,
|
|
Margin = new Thickness(3, 2)
|
|
}},
|
|
PanelOverride = new StyleBoxFlat
|
|
{
|
|
BorderThickness = new Thickness(0, 1),
|
|
BorderColor = Color.Gray,
|
|
BackgroundColor = Color.FromHex("#555555"),
|
|
}
|
|
});
|
|
foreach (var (prop, value) in values)
|
|
{
|
|
var button = new ContainerButton
|
|
{
|
|
Children =
|
|
{
|
|
new BoxContainer
|
|
{
|
|
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
|
SeparationOverride = 3,
|
|
Margin = new Thickness(3, 1),
|
|
Children =
|
|
{
|
|
new BoxContainer
|
|
{
|
|
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
|
Children =
|
|
{
|
|
new Label { Text = $"{prop}", FontColorOverride = Color.GreenYellow },
|
|
new Label { Text = ":" }, // this is for the non colored ":", intentional
|
|
}
|
|
},
|
|
new Label { Text = $"{value}" },
|
|
}
|
|
}
|
|
}
|
|
};
|
|
button.OnPressed += _ =>
|
|
{
|
|
// TODO replace with parenting to popup container on WindowRoot
|
|
UIPopup.Text = GuiDumpCommand.PropertyValuesString(SelectedControl, prop);
|
|
var box = UIBox2.FromDimensions(UserInterfaceManager.MousePositionScaled.Position
|
|
- GlobalPosition, Vector2.One);
|
|
UIPopup.Open(box);
|
|
};
|
|
ControlProperties.AddChild(button);
|
|
}
|
|
}
|
|
}
|
|
}
|