Compare commits

...

27 Commits

Author SHA1 Message Date
Pieter-Jan Briers
583b7ebf38 WPF layout (#1581) 2021-02-21 12:28:13 +01:00
Acruid
771a256925 Fixes bug with an exception being throw when trying to overwrite a deleted Component. (#1587)
Entity now uses constructor injection instead of property injection.
2021-02-20 23:30:09 -08:00
Acruid
ae79e89347 Added a shared PointLightComponent interface. (#1585)
* Added a shared PointLightComponent interface.

* Fix unit tests.
2021-02-20 16:06:34 -08:00
Acruid
6c7eeb95eb Marks Register and RegisterReference obsolete in IComponentFactory. (#1582) 2021-02-20 12:18:37 -08:00
Acruid
de0bd1887f Sprite Rendering Bugfixes (#1551)
* Added documentation to Clyde on the sprite rendering calls.

* Added a rotation debug entity.

* Non-directional RSIs and raw textures are now rotated properly.

* Directional RSIs and Sprite Smoothing work.

* Remove the Directional flag usages.

* Supports layers with different numbers of directions.

* Fixes window rendering.
2021-02-20 11:06:08 -08:00
metalgearsloth
eb3a815d48 Remove AiLogicProcessor (#1568)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
2021-02-19 21:52:32 -08:00
DrSmugleaf
e2a4dcdff1 Fix comparing by name and not ID for entity prototype updates (#1578) 2021-02-20 02:41:51 +01:00
DrSmugleaf
68b0d7bf2e Fix not clearing the queue after hot reload (#1576) 2021-02-20 01:43:56 +01:00
DrSmugleaf
a9b163992b Fix and add test for PrototypeManager LoadString (#1574) 2021-02-20 01:43:43 +01:00
DrSmugleaf
2409965cf8 Fix build (#1575) 2021-02-20 00:15:43 +01:00
DrSmugleaf
eada37378a Add YAML hot reloading (#1571)
* Implement hot reloading for entity prototypes

* Implement automatic prototype hot-reloading

* Merge fixes

* Add yaml hot reloading and a message to notify the client

* Add reloading only changed files, remove cooldown, add retries and remove IPrototype

* Remove reload command

* Make the client listen for reloads instead and only when focused

* Fix errors

* Only queue a reload when the queue has items in it

* Make fails after 10 retries log instead of throw if reloading

Co-authored-by: Jackson Lewis <inquisitivepenguin@protonmail.com>
2021-02-20 00:02:04 +01:00
DrSmugleaf
0f1da1ba2a Add window focused callback to Clyde (#1573) 2021-02-19 22:10:03 +01:00
Acruid
e0cdcd228e Fixed Timer Namespace in unit tests. 2021-02-18 20:35:34 -08:00
Acruid
fdb5e014b5 PauseManager moved to Shared (#1553)
* Moved IPauseManager from server to shared.

* Moved ITimerManager from Timers to Timing.

* Added missing IConsoleHost to server/client RegisterIoC. Tests work again.
2021-02-18 20:12:26 -08:00
DrSmugleaf
cefcad775b Make addcomp and rmcomp give better feedback and case insensitive (#1570)
* Make addcomp and rmcomp case insensitive

* Fix up names

* Make addcomp and rmcomp give better feedback

* Make addcomp and rmcomp less fail happy
2021-02-18 20:01:14 -08:00
Vera Aguilera Puerto
e40feac1f1 Adds VV autorefresh when right-clicking the refresh button. (#1558)
* Adds VV autorefresh when right-clicking the refresh button.

* cancel token on close

* button tooltip
2021-02-18 00:14:11 -08:00
DrSmugleaf
3ef4ac7452 Make component states dependant on the player getting them (#1569) 2021-02-17 23:48:17 -08:00
Pieter-Jan Briers
93bf1b09e7 Fix disconnecting while connecting causes you to be locked out of the server. 2021-02-17 23:22:11 +01:00
DrSmugleaf
a1e557e870 Add IPrototypeManager method to load a string (#1567) 2021-02-17 13:20:39 -08:00
Pieter-Jan Briers
864adb7445 Add DateTimeStyles to sandbox. 2021-02-17 11:52:36 +01:00
mirrorcult
9e3f3f0c1c vec2i serializer (#1563)
Co-authored-by: cyclowns <cyclowns@protonmail.ch>
2021-02-16 12:19:45 -08:00
DrSmugleaf
a40c4a435c Fix file not found exceptions when starting up the game with a debugger (#1562)
* Fix exceptions when starting up the game

* Remove try catches
2021-02-16 20:05:22 +01:00
DrSmugleaf
17182dd0e8 Engine PR for enabling nullability in Content.Client (#1565) 2021-02-16 20:05:06 +01:00
DrSmugleaf
d8b50044a2 Add (de)serialization for immutable lists (#1549) 2021-02-16 20:04:28 +01:00
Pieter-Jan Briers
4dc396e73d Fixes warning in TypePropertySerialization_Test.cs 2021-02-16 09:20:06 +01:00
Pieter-Jan Briers
6ae0b0e892 Fix [GenerateTypedNameReferences] with sealed types.
Fixes #1546
2021-02-16 09:19:57 +01:00
Pieter-Jan Briers
7162ca3456 Probably fix the bug where people get locked out of the server due to duplicate connction attempts. 2021-02-16 09:02:14 +01:00
190 changed files with 3558 additions and 1625 deletions

View File

@@ -0,0 +1,40 @@
- type: entity
id: debugRotation1
name: dbg_rotation1
components:
- type: Clickable
- type: InteractionOutline
- type: Sprite
netsync: false
visible: true
sprite: debugRotation.rsi
state: direction1
placement:
mode: AlignTileAny
- type: entity
id: debugRotation4
name: dbg_rotation4
components:
- type: Clickable
- type: InteractionOutline
- type: Sprite
netsync: false
visible: true
sprite: debugRotation.rsi
state: direction4
placement:
mode: AlignTileAny
- type: entity
id: debugRotationTex
name: dbg_rotationTex
components:
- type: Clickable
- type: InteractionOutline
- type: Sprite
netsync: false
visible: true
texture: debugRotation.rsi/direction1.png
placement:
mode: AlignTileAny

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

View File

@@ -0,0 +1,17 @@
{
"version": 1,
"size": {
"x": 32,
"y": 32
},
"states": [{
"name": "direction1",
"directions": 1,
"delays": [[1.0]]
}, {
"name": "direction4",
"directions": 4,
"delays": [[1.0], [1.0], [1.0], [1.0]]
}
]
}

Binary file not shown.

View File

@@ -29,9 +29,9 @@ namespace Robust.Build.Tasks
public static Parser<char, float[]> Thickness { get; }
= SkipWhitespaces.Then(
OneOf(
Try(Single1.Select(c => new[] {c})),
Try(Single4.Select(c => new[] {c.Item1, c.Item2, c.Item3, c.Item4})),
Try(Single2.Select(c => new[] {c.Item1, c.Item2})),
Try(Single4.Select(c => new[] {c.Item1, c.Item2, c.Item3, c.Item4}))
Try(Single1.Select(c => new[] {c}))
));
}
}

View File

@@ -0,0 +1,32 @@
using System.Reflection.Emit;
using XamlX.Ast;
using XamlX.Emit;
using XamlX.IL;
using XamlX.TypeSystem;
namespace Robust.Build.Tasks
{
internal class RXamlColorAstNode
: XamlAstNode, IXamlAstValueNode, IXamlAstILEmitableNode
{
private readonly IXamlMethod _method;
private readonly string _color;
public RXamlColorAstNode(IXamlLineInfo lineInfo, RXamlWellKnownTypes types, string color) : base(lineInfo)
{
_color = color;
Type = new XamlAstClrTypeReference(lineInfo, types.Color, false);
_method = types.ColorFromXaml;
}
public IXamlAstTypeReference Type { get; }
public XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen)
{
codeGen.Ldstr(_color);
codeGen.EmitCall(_method);
return XamlILNodeEmitResult.Type(0, Type.GetClrType());
}
}
}

View File

@@ -13,6 +13,10 @@ namespace Robust.Build.Tasks
public IXamlConstructor Vector2ConstructorFull { get; }
public IXamlType Vector2i { get; }
public IXamlConstructor Vector2iConstructorFull { get; }
public IXamlType Thickness { get; }
public IXamlConstructor ThicknessConstructorFull { get; }
public IXamlType Color { get; }
public IXamlMethod ColorFromXaml { get; }
public RXamlWellKnownTypes(TransformerConfiguration cfg)
{
@@ -23,6 +27,7 @@ namespace Robust.Build.Tasks
(Vector2, Vector2ConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Vector2", Single, 2);
(Vector2i, Vector2iConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Vector2i", Int32, 2);
(Thickness, ThicknessConstructorFull) = GetNumericTypeInfo("Robust.Shared.Maths.Thickness", Single, 4);
(IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount)
{
@@ -31,6 +36,12 @@ namespace Robust.Build.Tasks
return (type, ctor);
}
Color = cfg.TypeSystem.GetType("Robust.Shared.Maths.Color");
ColorFromXaml = Color.GetMethod(new FindMethodMethodSignature("FromXaml", Color, XamlIlTypes.String)
{
IsStatic = true
});
}
}

View File

@@ -329,6 +329,77 @@ namespace Robust.Build.Tasks
return true;
}
if (type.Equals(types.Thickness))
{
var foo = MathParsing.Thickness.Parse(text);
if (!foo.Success)
throw new XamlLoadException($"Unable to parse \"{text}\" as a Thickness", node);
var val = foo.Value;
float[] full;
if (val.Length == 1)
{
var u = val[0];
full = new[] {u, u, u, u};
}
else if (val.Length == 2)
{
var h = val[0];
var v = val[1];
full = new[] {h, v, h, v};
}
else // 4
{
full = val;
}
result = new RXamlSingleVecLikeConstAstNode(
node,
types.Thickness, types.ThicknessConstructorFull,
types.Single, full);
return true;
}
if (type.Equals(types.Thickness))
{
var foo = MathParsing.Thickness.Parse(text);
if (!foo.Success)
throw new XamlLoadException($"Unable to parse \"{text}\" as a Thickness", node);
var val = foo.Value;
float[] full;
if (val.Length == 1)
{
var u = val[0];
full = new[] {u, u, u, u};
}
else if (val.Length == 2)
{
var h = val[0];
var v = val[1];
full = new[] {h, v, h, v};
}
else // 4
{
full = val;
}
result = new RXamlSingleVecLikeConstAstNode(
node,
types.Thickness, types.ThicknessConstructorFull,
types.Single, full);
return true;
}
if (type.Equals(types.Color))
{
// TODO: Interpret these colors at XAML compile time instead of at runtime.
result = new RXamlColorAstNode(node, types, text);
return true;
}
result = null;
return false;
}

View File

@@ -111,9 +111,10 @@ namespace Robust.Client.AutoGenerated
compiler.Transform(parsed);
var initialRoot = (XamlAstObjectNode) parsed.Root;
var names = NameVisitor.GetNames(initialRoot);
var fieldAccess = classSymbol.IsSealed ? "private" : "protected";
//var names = NameVisitor.GetNames((XamlAstObjectNode)XDocumentXamlParser.Parse(xamlFile).Root);
var namedControls = names.Select(info => " " +
$"protected global::{info.type} {info.name} => " +
$"{fieldAccess} global::{info.type} {info.name} => " +
$"this.FindControl<global::{info.type}>(\"{info.name}\");");
return $@"// <auto-generated />
using Robust.Client.UserInterface;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Robust.Client.Audio.Midi;
using Robust.Client.Console;
using Robust.Client.Debugging;
@@ -10,6 +10,7 @@ using Robust.Client.Input;
using Robust.Client.Map;
using Robust.Client.Placement;
using Robust.Client.Player;
using Robust.Client.Prototypes;
using Robust.Client.Reflection;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
@@ -17,6 +18,7 @@ using Robust.Client.UserInterface;
using Robust.Client.Utility;
using Robust.Client.ViewVariables;
using Robust.Shared;
using Robust.Shared.Console;
using Robust.Shared.ContentPack;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -33,7 +35,7 @@ namespace Robust.Client
{
SharedIoC.RegisterIoC();
IoCManager.Register<IPrototypeManager, PrototypeManager>();
IoCManager.Register<IPrototypeManager, ClientPrototypeManager>();
IoCManager.Register<IEntityManager, ClientEntityManager>();
IoCManager.Register<IComponentFactory, ClientComponentFactory>();
IoCManager.Register<ITileDefinitionManager, ClydeTileDefinitionManager>();
@@ -59,6 +61,7 @@ namespace Robust.Client
IoCManager.Register<ILightManager, LightManager>();
IoCManager.Register<IDiscordRichPresence, DiscordRichPresence>();
IoCManager.Register<IClientConsoleHost, ClientConsoleHost>();
IoCManager.Register<IConsoleHost, ClientConsoleHost>();
IoCManager.Register<IFontManager, FontManager>();
IoCManager.Register<IFontManagerInternal, FontManager>();
IoCManager.Register<IMidiManager, MidiManager>();

View File

@@ -481,6 +481,8 @@ namespace Robust.Client.Console.Commands
{
_writeNode(root, 0, writer);
}
shell.WriteLine("Saved guidump");
}
private static void _writeNode(Control control, int indents, TextWriter writer)
@@ -542,7 +544,7 @@ namespace Robust.Client.Console.Commands
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var window = new SS14Window { CustomMinimumSize = (500, 400)};
var window = new SS14Window { MinSize = (500, 400)};
var tabContainer = new TabContainer();
window.Contents.AddChild(tabContainer);
var scroll = new ScrollContainer();
@@ -562,7 +564,7 @@ namespace Robust.Client.Console.Commands
optionButton.OnItemSelected += eventArgs => optionButton.SelectId(eventArgs.Id);
vBox.AddChild(optionButton);
var tree = new Tree { SizeFlagsVertical = Control.SizeFlags.FillExpand };
var tree = new Tree { VerticalExpand = true };
var root = tree.CreateItem();
root.Text = "Honk!";
var child = tree.CreateItem();
@@ -599,7 +601,7 @@ namespace Robust.Client.Console.Commands
{
grid.AddChild(new Button
{
CustomMinimumSize = (50, 50),
MinSize = (50, 50),
Text = $"{x}, {y}"
});
}
@@ -631,6 +633,29 @@ namespace Robust.Client.Console.Commands
}
});
tabContainer.AddChild(new HSplitContainer
{
Children =
{
new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Red},
Children =
{
new Label{ Text = "FOOBARBAZ"},
}
},
new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Blue},
Children =
{
new Label{ Text = "FOOBARBAZ"},
}
},
}
});
window.OpenCentered();
}
}

View File

@@ -20,8 +20,6 @@ namespace Robust.Client.Console
{
private readonly IReflectionManager _reflectionManager;
protected override Vector2? CustomSize => (300, 300);
private readonly VBoxContainer _watchesVBox;
private readonly LineEdit _addWatchEdit;
private readonly Button _addWatchButton;
@@ -37,12 +35,12 @@ namespace Robust.Client.Console
var mainVBox = new VBoxContainer
{
CustomMinimumSize = (500, 300),
MinSize = (500, 300),
Children =
{
(_watchesVBox = new VBoxContainer
{
SizeFlagsVertical = SizeFlags.FillExpand
VerticalExpand = true
}),
new HBoxContainer
{
@@ -50,7 +48,7 @@ namespace Robust.Client.Console
{
(_addWatchEdit = new HistoryLineEdit
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = Loc.GetString("Add watch (C# interactive)")
}),
(_addWatchButton = new Button
@@ -66,6 +64,8 @@ namespace Robust.Client.Console
_addWatchEdit.OnTextEntered += _ => AddWatch();
Contents.AddChild(mainVBox);
SetSize = (300, 300);
}
private void AddWatch()
@@ -113,7 +113,7 @@ namespace Robust.Client.Console
{
(_outputLabel = new Label
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
ClipText = true
}),
(delButton = new Button
@@ -176,7 +176,7 @@ namespace Robust.Client.Console
{
Text = message,
ClipText = true,
SizeFlagsHorizontal = SizeFlags.FillExpand
HorizontalExpand = true
},
(delButton = new Button {Text = Loc.GetString("Remove")})
}

View File

@@ -26,7 +26,6 @@ using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Timers;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -163,6 +162,7 @@ namespace Robust.Client
_serializer.Initialize();
_inputManager.Initialize();
_consoleHost.Initialize();
_prototypeManager.Initialize();
_prototypeManager.LoadDirectory(new ResourcePath(@"/Prototypes/"));
_prototypeManager.Resync();
_mapManager.Initialize();

View File

@@ -1,4 +1,4 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Physics;
namespace Robust.Client.GameObjects
@@ -25,7 +25,6 @@ namespace Robust.Client.GameObjects
RegisterReference<PhysicsComponent, IPhysBody>();
RegisterReference<PhysicsComponent, IPhysicsComponent>();
RegisterIgnore("KeyBindingInput");
Register<PointLightComponent>();
Register<InputComponent>();

View File

@@ -1,11 +0,0 @@
using Robust.Shared.GameObjects;
namespace Robust.Client.GameObjects
{
[RegisterComponent]
[ComponentReference(typeof(SharedIgnorePauseComponent))]
public sealed class IgnorePauseComponent : SharedIgnorePauseComponent
{
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Animations;
@@ -11,8 +11,12 @@ using Robust.Shared.ViewVariables;
namespace Robust.Client.GameObjects
{
public class PointLightComponent : Component
[RegisterComponent]
[ComponentReference(typeof(IPointLightComponent))]
public class PointLightComponent : Component, IPointLightComponent
{
[Dependency] private readonly IResourceCache _resourceCache = default!;
public override string Name => "PointLight";
public override uint? NetID => NetIDs.POINT_LIGHT;
@@ -65,6 +69,21 @@ namespace Robust.Client.GameObjects
set => _rotation = value;
}
/// <inheritdoc />
/// <summary>
/// The resource path to the mask texture the light will use.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public string? MaskPath
{
get => _maskPath;
set
{
_maskPath = value;
UpdateMask();
}
}
/// <summary>
/// Set a mask texture that will be applied to the light while rendering.
/// The mask's red channel will be linearly multiplied.p
@@ -117,7 +136,7 @@ namespace Robust.Client.GameObjects
private float _radius = 5;
private bool _visibleNested = true;
private bool _lightOnParent = false;
private bool _lightOnParent;
private Color _color = Color.White;
private Vector2 _offset;
private bool _enabled = true;
@@ -125,6 +144,7 @@ namespace Robust.Client.GameObjects
private Angle _rotation;
private float _energy;
private float _softness;
private string? _maskPath;
/// <summary>
/// Radius, in meters.
@@ -141,6 +161,20 @@ namespace Robust.Client.GameObjects
}
}
private void UpdateMask()
{
if (_maskPath is not null)
Mask = _resourceCache.GetResource<TextureResource>(_maskPath);
else
Mask = null;
}
public override void Initialize()
{
base.Initialize();
UpdateMask();
}
/// <inheritdoc />
public override void HandleMessage(ComponentMessage message, IComponent? component)
{
@@ -180,11 +214,7 @@ namespace Robust.Client.GameObjects
serializer.DataFieldCached(ref _softness, "softness", 1f);
serializer.DataFieldCached(ref _maskAutoRotate, "autoRot", false);
serializer.DataFieldCached(ref _visibleNested, "nestedvisible", true);
if (serializer.Reading && serializer.TryReadDataField<string>("mask", out var value))
{
Mask = IoCManager.Resolve<IResourceCache>().GetResource<TextureResource>(value);
}
serializer.DataFieldCached(ref _maskPath, "mask", null);
}
public override void OnRemove()

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Shared.Animations;
@@ -49,8 +49,26 @@ namespace Robust.Client.GameObjects
/// Rotation transformations on individual layers still apply.
/// If false, all layers get locked to south and rotation is a transformation.
/// </summary>
[Obsolete("Use NoRotation and/or DirectionOverride")]
bool Directional { get; set; }
/// <summary>
/// All sprite rotation is locked, and will always be drawn upright on
/// the screen, regardless of world or view orientation.
/// </summary>
bool NoRotation {get; set; }
/// <summary>
/// Enables overriding the calculated directional RSI state for this sprite.
/// The state to use is defined in <see cref="DirectionOverride"/>.
/// </summary>
bool EnableDirectionOverride { get; set; }
/// <summary>
/// The directional RSI state that will always be displayed, regardless of orientation.
/// </summary>
Direction DirectionOverride { get; set; }
// NOTE: The below are ALL designed to NOT throw exceptions ever,
// instead making a bunch of noisy error logs.
@@ -203,4 +221,4 @@ namespace Robust.Client.GameObjects
IEnumerable<ISpriteLayer> AllLayers { get; }
}
}
}

View File

@@ -101,6 +101,7 @@ namespace Robust.Client.GameObjects
/// If false, all layers get locked to south and rotation is a transformation.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[Obsolete("Use NoRotation and/or DirectionOverride")]
public bool Directional
{
get => _directional;
@@ -965,41 +966,61 @@ namespace Robust.Client.GameObjects
public ISpriteLayer this[object layerKey] => this[LayerMap[layerKey]];
public IEnumerable<ISpriteLayer> AllLayers => Layers;
internal void Render(DrawingHandleWorld drawingHandle, in Matrix3 worldTransform, Angle worldRotation,
Direction? overrideDirection = null)
// Lobby SpriteView rendering path
internal void Render(DrawingHandleWorld drawingHandle, Angle worldRotation, Direction? overrideDirection = null)
{
var angle = Rotation;
if (Directional)
RenderInternal(drawingHandle, worldRotation, Vector2.Zero, overrideDirection);
}
private bool _screenLock = false;
private Direction _overrideDirection = Direction.South;
private bool _enableOverrideDirection = false;
/// <inheritdoc />
[ViewVariables(VVAccess.ReadWrite)]
public bool NoRotation { get => _screenLock; set => _screenLock = value; }
/// <inheritdoc />
[ViewVariables(VVAccess.ReadWrite)]
public Direction DirectionOverride { get => _overrideDirection; set => _overrideDirection = value; }
/// <inheritdoc />
[ViewVariables(VVAccess.ReadWrite)]
public bool EnableDirectionOverride { get => _enableOverrideDirection; set => _enableOverrideDirection = value; }
// Sprite rendering path
internal void Render(DrawingHandleWorld drawingHandle, in Angle worldRotation, in Vector2 worldPosition)
{
Direction? overrideDir = null;
if (_enableOverrideDirection)
{
angle -= worldRotation;
overrideDir = _overrideDirection;
}
RenderInternal(drawingHandle, worldRotation, worldPosition, overrideDir);
}
private void CalcModelMatrix(int numDirs, Angle worldRotation, Vector2 worldPosition, out Matrix3 modelMatrix)
{
Angle angle;
if (_screenLock)
{
angle = Angle.Zero;
}
else
{
angle -= new Angle(MathHelper.PiOver2);
angle = CalcRectWorldAngle(worldRotation, numDirs);
}
var mOffset = Matrix3.CreateTranslation(Offset);
var mRotation = Matrix3.CreateRotation(angle);
Matrix3.Multiply(ref mRotation, ref mOffset, out var transform);
// Only apply scale if needed.
if(!Scale.EqualsApprox(Vector2.One)) transform.Multiply(Matrix3.CreateScale(Scale));
transform.Multiply(worldTransform);
RenderInternal(drawingHandle, worldRotation, overrideDirection, transform);
var sWorldRotation = angle;
modelMatrix = Matrix3.CreateTransform(in worldPosition, in sWorldRotation);
}
internal void Render(DrawingHandleWorld drawingHandle, Angle worldRotation, Direction? overrideDirection = null)
private void RenderInternal(DrawingHandleWorld drawingHandle, Angle worldRotation, Vector2 worldPosition, Direction? overrideDirection)
{
RenderInternal(drawingHandle, worldRotation, overrideDirection, Matrix3.Identity);
}
private void RenderInternal(DrawingHandleWorld drawingHandle, Angle worldRotation, Direction? overrideDirection,
in Matrix3 transform)
{
drawingHandle.SetTransform(transform);
var localMatrix = Matrix3.CreateTransform(in offset, in rotation, in scale);
foreach (var layer in Layers)
{
if (!layer.Visible)
@@ -1007,26 +1028,87 @@ namespace Robust.Client.GameObjects
continue;
}
// TODO: Implement layer-specific rotation and scale.
// Oh and when you do update Layer.LocalToLayer so content doesn't break.
var dirType = GetLayerDirectionType(layer);
var texture = GetRenderTexture(layer, worldRotation, overrideDirection);
if (layer.Shader != null)
int numDirs;
switch (dirType)
{
drawingHandle.UseShader(layer.Shader);
case RSI.State.DirectionType.Dir1:
numDirs = 1;
break;
case RSI.State.DirectionType.Dir4:
numDirs = 4;
break;
case RSI.State.DirectionType.Dir8:
numDirs = 8;
break;
default:
throw new ArgumentOutOfRangeException();
}
drawingHandle.DrawTexture(texture, -(Vector2) texture.Size / (2f * EyeManager.PixelsPerMeter),
color * layer.Color);
CalcModelMatrix(numDirs, worldRotation, worldPosition, out var modelMatrix);
Matrix3.Multiply(ref localMatrix, ref modelMatrix, out var transformMatrix);
drawingHandle.SetTransform(in transformMatrix);
if (layer.Shader != null)
{
drawingHandle.UseShader(null);
}
RenderLayer(drawingHandle, layer, worldRotation, overrideDirection);
}
}
private void RenderLayer(DrawingHandleWorld drawingHandle, Layer layer, Angle worldRotation, Direction? overrideDirection)
{
var texture = GetRenderTexture(layer, worldRotation, overrideDirection);
if (layer.Shader != null)
{
drawingHandle.UseShader(layer.Shader);
}
var layerColor = color * layer.Color;
var position = -(Vector2) texture.Size / (2f * EyeManager.PixelsPerMeter);
var textureSize = texture.Size / (float) EyeManager.PixelsPerMeter;
var quad = Box2.FromDimensions(position, textureSize);
// TODO: Implement layer-specific rotation and scale.
// Apply these directly to the box.
// Oh and when you do update Layer.LocalToLayer so content doesn't break.
// handle.Modulate changes the color
// drawingHandle.SetTransform() is set above, turning the quad into local space vertices
drawingHandle.DrawTextureRectRegion(texture, quad, layerColor);
if (layer.Shader != null)
{
drawingHandle.UseShader(null);
}
}
private static Angle CalcRectWorldAngle(Angle worldAngle, int numDirections)
{
var theta = worldAngle.Theta;
var segSize = (MathF.PI*2) / (numDirections * 2);
var segments = (int)(theta / segSize);
var odd = segments % 2;
var result = theta - (segments * segSize) - (odd * segSize);
return result;
}
private RSI.State.DirectionType GetLayerDirectionType(Layer layer)
{
if (!layer.State.IsValid)
return RSI.State.DirectionType.Dir1;
// Pull texture from RSI state instead.
var rsi = layer.RSI ?? BaseRSI;
if (rsi == null || !rsi.TryGetState(layer.State, out var state))
{
state = GetFallbackState(resourceCache);
}
return state.Directions;
}
private Texture GetRenderTexture(Layer layer, Angle worldRotation, Direction? overrideDirection)
{
var texture = layer.Texture;
@@ -1039,7 +1121,7 @@ namespace Robust.Client.GameObjects
{
state = GetFallbackState(resourceCache);
}
var layerSpecificDir = layer.EffectiveDirection(state, worldRotation, overrideDirection);
texture = state.GetFrame(layerSpecificDir, layer.AnimationFrame);
}
@@ -1058,8 +1140,11 @@ namespace Robust.Client.GameObjects
serializer.DataFieldCached(ref drawDepth, "drawdepth", DrawDepthTag.Default,
WithFormat.Constants<DrawDepthTag>());
serializer.DataFieldCached(ref color, "color", Color.White);
serializer.DataFieldCached(ref _directional, "directional", true);
serializer.DataFieldCached(ref _visible, "visible", true);
serializer.DataFieldCached(ref _directional, "directional", true); //TODO: Kill ME
serializer.DataFieldCached(ref _screenLock, "noRot", false);
serializer.DataFieldCached(ref _enableOverrideDirection, "enableOverrideDir", false);
serializer.DataFieldCached(ref _overrideDirection, "overrideDir", Direction.East);
// TODO: Writing?
if (!serializer.Reading)
@@ -1314,7 +1399,6 @@ namespace Robust.Client.GameObjects
Rotation = thestate.Rotation;
Offset = thestate.Offset;
Color = thestate.Color;
Directional = thestate.Directional;
RenderOrder = thestate.RenderOrder;
if (thestate.BaseRsiPath != null && BaseRSI != null)
@@ -1371,16 +1455,28 @@ namespace Robust.Client.GameObjects
}
}
private RSI.State.Direction GetDir(RSI.State.DirectionType type, Angle worldRotation)
private RSI.State.Direction GetDir(RSI.State.DirectionType rsiDirectionType, Angle worldRotation)
{
if (!Directional)
var dir = rsiDirectionType switch
{
return RSI.State.Direction.South;
}
RSI.State.DirectionType.Dir1 => Direction.South,
RSI.State.DirectionType.Dir4 => worldRotation.GetCardinalDir(),
RSI.State.DirectionType.Dir8 => worldRotation.GetDir(),
_ => throw new ArgumentException($"Unknown RSI DirectionType: {rsiDirectionType}.", nameof(rsiDirectionType))
};
var angle = new Angle(worldRotation);
return angle.GetDir().Convert(type);
return dir switch
{
Direction.North => RSI.State.Direction.North,
Direction.South => RSI.State.Direction.South,
Direction.East => RSI.State.Direction.East,
Direction.West => RSI.State.Direction.West,
Direction.SouthEast => RSI.State.Direction.SouthEast,
Direction.SouthWest => RSI.State.Direction.SouthWest,
Direction.NorthEast => RSI.State.Direction.NorthEast,
Direction.NorthWest => RSI.State.Direction.NorthWest,
_ => throw new ArgumentOutOfRangeException(nameof(dir), dir, null)
};
}
private void UpdateIsInert()

View File

@@ -40,7 +40,7 @@ namespace Robust.Client.GameObjects
/// <param name="message">Arguments for this event.</param>
/// <param name="replay">if true, current cmd state will not be checked or updated - use this for "replaying" an
/// old input that was saved or buffered until further processing could be done</param>
public bool HandleInputCommand(ICommonSession session, BoundKeyFunction function, FullInputCmdMessage message, bool replay = false)
public bool HandleInputCommand(ICommonSession? session, BoundKeyFunction function, FullInputCmdMessage message, bool replay = false)
{
#if DEBUG

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Robust.Client.GameObjects;
using Robust.Client.Input;
using Robust.Shared.GameStates;
@@ -352,7 +353,10 @@ namespace Robust.Client.GameStates
foreach (var component in _componentManager.GetNetComponents(createdEntity))
{
var state = component.GetComponentState();
Debug.Assert(_players.LocalPlayer != null, "_players.LocalPlayer != null");
var player = _players.LocalPlayer.Session;
var state = component.GetComponentState(player);
if (state.GetType() == typeof(ComponentState))
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
@@ -199,7 +199,9 @@ namespace Robust.Client.Graphics.Clyde
_renderHandle.Viewport(Box2i.FromDimensions(-flippedPos, screenSize));
}
entry.sprite.Render(_renderHandle.DrawingHandleWorld, entry.worldMatrix, entry.worldRotation);
var matrix = entry.worldMatrix;
var worldPosition = new Vector2(matrix.R0C2, matrix.R1C2);
entry.sprite.Render(_renderHandle.DrawingHandleWorld, in entry.worldRotation, in worldPosition);
if (entry.sprite.PostShader != null)
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Runtime.InteropServices;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
@@ -37,28 +37,55 @@ namespace Robust.Client.Graphics.Clyde
_clyde.DrawSetProjViewTransform(proj, view);
}
/// <summary>
/// Draws a sprite to the screen. The coordinate system is left handed.
/// Make sure to set <see cref="DrawSetModelTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="bl">Bottom left vertex of the quad in object space.</param>
/// <param name="br">Bottom right vertex of the quad in object space.</param>
/// <param name="tl">Top left vertex of the quad in object space.</param>
/// <param name="tr">Top right vertex of the quad in object space.</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param
/// <param name="subRegion">The four corners of the texture sub region in px.</param>
public void DrawTextureScreen(Texture texture, Vector2 bl, Vector2 br, Vector2 tl, Vector2 tr,
in Color modulate, in UIBox2? subRegion)
{
var clydeTexture = ExtractTexture(texture, subRegion, out var csr);
var clydeTexture = ExtractTexture(texture, in subRegion, out var csr);
var (w, h) = clydeTexture.Size;
var sr = new Box2(csr.Left / w, (h - csr.Top) / h, csr.Right / w, (h - csr.Bottom) / h);
_clyde.DrawTexture(clydeTexture.TextureId, bl, br, tl, tr, modulate, sr);
_clyde.DrawTexture(clydeTexture.TextureId, bl, br, tl, tr, in modulate, in sr);
}
/// <summary>
/// Draws a sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawSetModelTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="bl">Bottom left vertex of the quad in object space.</param>
/// <param name="br">Bottom right vertex of the quad in object space.</param>
/// <param name="tl">Top left vertex of the quad in object space.</param>
/// <param name="tr">Top right vertex of the quad in object space.</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
/// <param name="subRegion">The four corners of the texture sub region in px.</param>
public void DrawTextureWorld(Texture texture, Vector2 bl, Vector2 br, Vector2 tl, Vector2 tr,
Color modulate, in UIBox2? subRegion)
{
var clydeTexture = ExtractTexture(texture, subRegion, out var csr);
var clydeTexture = ExtractTexture(texture, in subRegion, out var csr);
var (w, h) = clydeTexture.Size;
var sr = new Box2(csr.Left / w, (h - csr.Bottom) / h, csr.Right / w, (h - csr.Top) / h);
_clyde.DrawTexture(clydeTexture.TextureId, bl, br, tl, tr, modulate, sr);
_clyde.DrawTexture(clydeTexture.TextureId, bl, br, tl, tr, in modulate, in sr);
}
/// <summary>
/// Converts a subRegion (px) into texture coords (0-1) of a given texture (cells of the textureAtlas).
/// </summary>
private static ClydeTexture ExtractTexture(Texture texture, in UIBox2? subRegion, out UIBox2 sr)
{
if (texture is AtlasTexture atlas)
@@ -383,22 +410,40 @@ namespace Robust.Client.Graphics.Clyde
}
}
public override void DrawTextureRectRegion(Texture texture, Box2 rect, UIBox2? subRegion = null,
Color? modulate = null)
/// <summary>
/// Draws a sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawSetModelTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="quad">The four vertices of the quad in object space (or world if the transform is identity.).</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
/// <param name="subRegion">The four corners of the texture sub region in px.</param>
public override void DrawTextureRectRegion(Texture texture, Box2 quad,
Color? modulate = null, UIBox2? subRegion = null)
{
var color = (modulate ?? Color.White) * Modulate;
_renderHandle.DrawTextureWorld(texture, rect.BottomLeft, rect.BottomRight,
rect.TopLeft, rect.TopRight, color, subRegion);
_renderHandle.DrawTextureWorld(texture, quad.BottomLeft, quad.BottomRight,
quad.TopLeft, quad.TopRight, color, in subRegion);
}
public override void DrawTextureRectRegion(Texture texture, in Box2Rotated rect,
UIBox2? subRegion = null, Color? modulate = null)
/// <summary>
/// Draws a sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawSetModelTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="quad">The four vertices of the quad in object space (or world if the transform is identity.).</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
/// <param name="subRegion">The four corners of the texture sub region in px.</param>
public override void DrawTextureRectRegion(Texture texture, in Box2Rotated quad,
Color? modulate = null, UIBox2? subRegion = null)
{
var color = (modulate ?? Color.White) * Modulate;
_renderHandle.DrawTextureWorld(texture, rect.BottomLeft, rect.BottomRight,
rect.TopLeft, rect.TopRight, color, subRegion);
_renderHandle.DrawTextureWorld(texture, quad.BottomLeft, quad.BottomRight,
quad.TopLeft, quad.TopRight, color, in subRegion);
}
public override void DrawPrimitives(DrawPrimitiveTopology primitiveTopology,

View File

@@ -477,10 +477,20 @@ namespace Robust.Client.Graphics.Clyde
_currentMatrixView = view;
}
/// <summary>
/// Draws a texture quad to the screen.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="bl">Bottom left vertex of the quad in object space.</param>
/// <param name="br">Bottom right vertex of the quad in object space.</param>
/// <param name="tl">Top left vertex of the quad in object space.</param>
/// <param name="tr">Top right vertex of the quad in object space.</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
/// <param name="texCoords">The four corners of the texture coordinates, matching the four vertices.</param>
private void DrawTexture(ClydeHandle texture, Vector2 bl, Vector2 br, Vector2 tl, Vector2 tr, in Color modulate,
in Box2 sr)
in Box2 texCoords)
{
EnsureBatchState(texture, modulate, true, GetQuadBatchPrimitiveType(), _queuedShader);
EnsureBatchState(texture, in modulate, true, GetQuadBatchPrimitiveType(), _queuedShader);
bl = _currentMatrixModel.Transform(bl);
br = _currentMatrixModel.Transform(br);
@@ -489,10 +499,10 @@ namespace Robust.Client.Graphics.Clyde
// TODO: split batch if necessary.
var vIdx = BatchVertexIndex;
BatchVertexData[vIdx + 0] = new Vertex2D(bl, sr.BottomLeft);
BatchVertexData[vIdx + 1] = new Vertex2D(br, sr.BottomRight);
BatchVertexData[vIdx + 2] = new Vertex2D(tr, sr.TopRight);
BatchVertexData[vIdx + 3] = new Vertex2D(tl, sr.TopLeft);
BatchVertexData[vIdx + 0] = new Vertex2D(bl, texCoords.BottomLeft);
BatchVertexData[vIdx + 1] = new Vertex2D(br, texCoords.BottomRight);
BatchVertexData[vIdx + 2] = new Vertex2D(tr, texCoords.TopRight);
BatchVertexData[vIdx + 3] = new Vertex2D(tl, texCoords.TopLeft);
BatchVertexIndex += 4;
QuadBatchIndexWrite(BatchIndexData, ref BatchIndexIndex, (ushort) vIdx);

View File

@@ -55,6 +55,7 @@ namespace Robust.Client.Graphics.Clyde
private GLFWCallbacks.WindowSizeCallback _windowSizeCallback = default!;
private GLFWCallbacks.WindowContentScaleCallback _windowContentScaleCallback = default!;
private GLFWCallbacks.WindowIconifyCallback _windowIconifyCallback = default!;
private GLFWCallbacks.WindowFocusCallback _windowFocusCallback = default!;
private bool _glfwInitialized;
@@ -62,6 +63,7 @@ namespace Robust.Client.Graphics.Clyde
private Window* _glfwWindow;
private Vector2i _framebufferSize;
private bool _isFocused;
private Vector2i _windowSize;
private Vector2i _prevWindowSize;
private Vector2i _prevWindowPos;
@@ -74,6 +76,7 @@ namespace Robust.Client.Graphics.Clyde
// NOTE: in engine we pretend the framebuffer size is the screen size..
// For practical reasons like UI rendering.
public override Vector2i ScreenSize => _framebufferSize;
public override bool IsFocused => _isFocused;
public Vector2 DefaultWindowScale => _windowScale;
public Vector2 MouseScreenPosition => _lastMousePos;
@@ -231,6 +234,7 @@ namespace Robust.Client.Graphics.Clyde
GLFW.SetMouseButtonCallback(_glfwWindow, _mouseButtonCallback);
GLFW.SetWindowContentScaleCallback(_glfwWindow, _windowContentScaleCallback);
GLFW.SetWindowIconifyCallback(_glfwWindow, _windowIconifyCallback);
GLFW.SetWindowFocusCallback(_glfwWindow, _windowFocusCallback);
GLFW.MakeContextCurrent(_glfwWindow);
@@ -548,6 +552,19 @@ namespace Robust.Client.Graphics.Clyde
}
}
private void OnGlfwWindowFocus(Window* window, bool focused)
{
try
{
_isFocused = focused;
OnWindowFocused?.Invoke(new WindowFocusedEventArgs(focused));
}
catch (Exception e)
{
CatchCallbackException(e);
}
}
private void StoreCallbacks()
{
_errorCallback = OnGlfwError;
@@ -560,6 +577,7 @@ namespace Robust.Client.Graphics.Clyde
_windowSizeCallback = OnGlfwWindowSize;
_windowContentScaleCallback = OnGlfwWindownContentScale;
_windowIconifyCallback = OnGlfwWindowIconify;
_windowFocusCallback = OnGlfwWindowFocus;
}
public override void SetWindowTitle(string title)

View File

@@ -88,7 +88,7 @@ namespace Robust.Client.Graphics.Clyde
public override bool Initialize()
{
base.Initialize();
_configurationManager.OnValueChanged(CVars.DisplayOGLCheckErrors, b => _checkGLErrors = b, true);
if (!InitWindowing())
@@ -152,6 +152,8 @@ namespace Robust.Client.Graphics.Clyde
public override event Action<WindowResizedEventArgs>? OnWindowResized;
public override event Action<WindowFocusedEventArgs>? OnWindowFocused;
public void Screenshot(ScreenshotType type, Action<Image<Rgb24>> callback)
{
_queuedScreenshots.Add((type, callback));

View File

@@ -21,6 +21,7 @@ namespace Robust.Client.Graphics.Clyde
public IRenderWindow MainWindowRenderTarget { get; }
public override Vector2i ScreenSize { get; } = (1280, 720);
public Vector2 DefaultWindowScale => (1, 1);
public override bool IsFocused => true;
public ShaderInstance InstanceShader(ClydeHandle handle)
{
@@ -79,6 +80,12 @@ namespace Robust.Client.Graphics.Clyde
remove { }
}
public override event Action<WindowFocusedEventArgs> OnWindowFocused
{
add { }
remove { }
}
public void Render()
{
// Nada.

View File

@@ -25,6 +25,8 @@ namespace Robust.Client.Graphics
protected bool VSync { get; private set; } = true;
public abstract Vector2i ScreenSize { get; }
public abstract bool IsFocused { get; }
public abstract void SetWindowTitle(string title);
public virtual bool Initialize()
@@ -45,6 +47,8 @@ namespace Robust.Client.Graphics
public abstract event Action<WindowResizedEventArgs> OnWindowResized;
public abstract event Action<WindowFocusedEventArgs> OnWindowFocused;
protected virtual void ReadConfig()
{
WindowMode = (WindowMode) _configurationManager.GetCVar(CVars.DisplayWindowMode);

View File

@@ -19,17 +19,18 @@ namespace Robust.Client.Graphics
Disposed = true;
}
public void SetTransform(Vector2 position, Angle rotation, Vector2 scale)
public void SetTransform(in Vector2 position, in Angle rotation, in Vector2 scale)
{
CheckDisposed();
var matrix = Matrix3.Identity;
(matrix.R0C0, matrix.R1C1) = scale;
matrix.Rotate(rotation);
matrix.R0C2 += position.X;
matrix.R1C2 += position.Y;
var matrix = Matrix3.CreateTransform(in position, in rotation, in scale);
SetTransform(in matrix);
}
SetTransform(matrix);
public void SetTransform(in Vector2 position, in Angle rotation)
{
var matrix = Matrix3.CreateTransform(in position, in rotation);
SetTransform(in matrix);
}
public abstract void SetTransform(in Matrix3 matrix);

View File

@@ -6,15 +6,63 @@ namespace Robust.Client.Graphics
{
private const int Ppm = EyeManager.PixelsPerMeter;
/// <summary>
/// Draws an untextured colored rectangle to the world.The coordinate system is right handed.
/// Make sure to set <see cref="DrawingHandleBase.SetTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="rect">The four vertices of the quad in object space (or world if the transform is identity.).</param>
/// <param name="color">Color of the rectangle.</param>
/// <param name="filled">Is it filled with color, or just the border lines?</param>
public abstract void DrawRect(Box2 rect, Color color, bool filled = true);
/// <summary>
/// Draws an untextured colored rectangle to the world.The coordinate system is right handed.
/// Make sure to set <see cref="DrawingHandleBase.SetTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="rect">The four vertices of the quad in object space (or world if the transform is identity.).
/// The rotation of the rectangle is applied before the transform matrix.</param>
/// <param name="color">Color of the rectangle.</param>
/// <param name="filled">Is it filled with color, or just the border lines?</param>
public abstract void DrawRect(in Box2Rotated rect, Color color, bool filled = true);
public abstract void DrawTextureRectRegion(Texture texture, Box2 rect, UIBox2? subRegion = null,
Color? modulate = null);
/// <summary>
/// Draws a sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawingHandleBase.SetTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="quad">The four vertices of the quad in object space (or world if the transform is identity.).</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
/// <param name="subRegion">The four corners of the texture sub region in px.</param>
public abstract void DrawTextureRectRegion(Texture texture, Box2 quad,
Color? modulate = null, UIBox2? subRegion = null);
public abstract void DrawTextureRectRegion(Texture texture, in Box2Rotated rect, UIBox2? subRegion = null,
Color? modulate = null);
/// <summary>
/// Draws a sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawingHandleBase.SetTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="quad">The four vertices of the quad in object space (or world if the transform is identity.).
/// The rotation of the rectangle is applied before the transform matrix.</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
/// <param name="subRegion">The four corners of the texture sub region in px.</param>
public abstract void DrawTextureRectRegion(Texture texture, in Box2Rotated quad,
Color? modulate = null, UIBox2? subRegion = null);
/// <summary>
/// Draws a full texture sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawingHandleBase.SetTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="position">The coordinates of the quad in object space (or world if the transform is identity.).</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
/// <remarks>
/// The sprite will have it's local dimensions calculated so that it has <see cref="EyeManager.PixelsPerMeter"/> texels per meter in the world.
/// </remarks>
public void DrawTexture(Texture texture, Vector2 position, Color? modulate = null)
{
CheckDisposed();
@@ -22,18 +70,35 @@ namespace Robust.Client.Graphics
DrawTextureRect(texture, Box2.FromDimensions(position, texture.Size / (float) Ppm), modulate);
}
public void DrawTextureRect(Texture texture, Box2 rect, Color? modulate = null)
/// <summary>
/// Draws a full texture sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawingHandleBase.SetTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="quad">The four vertices of the quad in object space (or world if the transform is identity.).</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
public void DrawTextureRect(Texture texture, Box2 quad, Color? modulate = null)
{
CheckDisposed();
DrawTextureRectRegion(texture, rect, null, modulate);
DrawTextureRectRegion(texture, quad, modulate);
}
public void DrawTextureRect(Texture texture, in Box2Rotated rect, Color? modulate = null)
/// <summary>
/// Draws a full texture sprite to the world. The coordinate system is right handed.
/// Make sure to set <see cref="DrawingHandleBase.SetTransform"/>
/// to set the model matrix if needed.
/// </summary>
/// <param name="texture">Texture to draw.</param>
/// <param name="quad">The four vertices of the quad in object space (or world if the transform is identity.).
/// The rotation of the rectangle is applied before the transform matrix.</param>
/// <param name="modulate">A color to multiply the texture by when shading.</param>
public void DrawTextureRect(Texture texture, in Box2Rotated quad, Color? modulate = null)
{
CheckDisposed();
DrawTextureRectRegion(texture, rect, null, modulate);
DrawTextureRectRegion(texture, in quad, modulate);
}
}
}

View File

@@ -13,6 +13,8 @@ namespace Robust.Client.Graphics
Vector2i ScreenSize { get; }
bool IsFocused { get; }
/// <summary>
/// The default scale ratio for window contents, given to us by the OS.
/// </summary>
@@ -27,6 +29,8 @@ namespace Robust.Client.Graphics
event Action<WindowResizedEventArgs> OnWindowResized;
event Action<WindowFocusedEventArgs> OnWindowFocused;
Texture LoadTextureFromPNGStream(Stream stream, string? name = null,
TextureLoadParameters? loadParams = null);

View File

@@ -12,7 +12,7 @@ using YamlDotNet.RepresentationModel;
namespace Robust.Client.Graphics
{
[Prototype("shader")]
public sealed class ShaderPrototype : IPrototype, IIndexedPrototype
public sealed class ShaderPrototype : IPrototype
{
[Dependency] private readonly IClydeInternal _clyde = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;

View File

@@ -0,0 +1,14 @@
using System;
namespace Robust.Client.Graphics
{
public class WindowFocusedEventArgs : EventArgs
{
public WindowFocusedEventArgs(bool focused)
{
Focused = focused;
}
public bool Focused { get; }
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Robust.Client.Graphics;
using Robust.Shared.ContentPack;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Network.Messages;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using Timer = Robust.Shared.Timing.Timer;
namespace Robust.Client.Prototypes
{
public sealed class ClientPrototypeManager : PrototypeManager
{
[Dependency] private readonly IClyde _clyde = default!;
private readonly List<FileSystemWatcher> _watchers = new();
private readonly TimeSpan _reloadDelay = TimeSpan.FromMilliseconds(10);
private CancellationTokenSource _reloadToken = new();
private readonly HashSet<ResourcePath> _reloadQueue = new();
public override void Initialize()
{
base.Initialize();
NetManager.RegisterNetMessage<MsgReloadPrototypes>(MsgReloadPrototypes.NAME, accept: NetMessageAccept.Server);
_clyde.OnWindowFocused += WindowFocusedChanged;
WatchResources();
}
private void WindowFocusedChanged(WindowFocusedEventArgs args)
{
#if !FULL_RELEASE
if (args.Focused && _reloadQueue.Count > 0)
{
Timer.Spawn(_reloadDelay, ReloadPrototypeQueue, _reloadToken.Token);
}
else
{
_reloadToken.Cancel();
_reloadToken = new CancellationTokenSource();
}
#endif
}
private void ReloadPrototypeQueue()
{
#if !FULL_RELEASE
var then = DateTime.Now;
var msg = NetManager.CreateNetMessage<MsgReloadPrototypes>();
msg.Paths = _reloadQueue.ToArray();
NetManager.ClientSendMessage(msg);
foreach (var path in _reloadQueue)
{
ReloadPrototypes(path);
}
_reloadQueue.Clear();
Logger.Info($"Reloaded prototypes in {(int) (DateTime.Now - then).TotalMilliseconds} ms");
#endif
}
private void WatchResources()
{
#if !FULL_RELEASE
foreach (var path in Resources.GetContentRoots().Select(r => r.ToString())
.Where(r => Directory.Exists(r + "/Prototypes")).Select(p => p + "/Prototypes"))
{
var watcher = new FileSystemWatcher(path, "*.yml")
{
IncludeSubdirectories = true,
NotifyFilter = NotifyFilters.LastWrite
};
watcher.Changed += (_, args) =>
{
switch (args.ChangeType)
{
case WatcherChangeTypes.Renamed:
case WatcherChangeTypes.Deleted:
return;
case WatcherChangeTypes.Created:
// case WatcherChangeTypes.Deleted:
case WatcherChangeTypes.Changed:
case WatcherChangeTypes.All:
break;
default:
throw new ArgumentOutOfRangeException();
}
TaskManager.RunOnMainThread(() =>
{
var file = new ResourcePath(args.FullPath);
foreach (var root in IoCManager.Resolve<IResourceManager>().GetContentRoots())
{
if (!file.TryRelativeTo(root, out var relative))
{
continue;
}
_reloadQueue.Add(relative);
}
});
};
watcher.EnableRaisingEvents = true;
_watchers.Add(watcher);
}
#endif
}
}
}

View File

@@ -1,30 +1,54 @@
using System;
using JetBrains.Annotations;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Robust.Client.UserInterface
{
// Code and design heavily inspired by WPF/Avalonia.
public partial class Control
{
public event Action<Control>? OnMinimumSizeChanged;
private Vector2 _size;
[ViewVariables] internal Vector2? PreviousMeasure;
[ViewVariables] internal UIBox2? PreviousArrange;
private float _sizeFlagsStretchRatio = 1;
private Vector2? _calculatedMinimumSize;
private Vector2 _customMinimumSize;
private SizeFlags _sizeFlagsHorizontal = SizeFlags.Fill;
private SizeFlags _sizeFlagsVertical = SizeFlags.Fill;
private bool _layoutDirty;
private float _minWidth;
private float _minHeight;
private float _setWidth = float.NaN;
private float _setHeight = float.NaN;
private float _maxWidth = float.PositiveInfinity;
private float _maxHeight = float.PositiveInfinity;
private bool _horizontalExpand;
private bool _verticalExpand;
private HAlignment _horizontalAlignment;
private VAlignment _verticalAlignment;
private Thickness _margin;
private bool _isLayoutUpdateOverrideUsed;
private bool _measuring;
[ViewVariables] public Vector2 DesiredSize { get; private set; }
[ViewVariables] public Vector2i DesiredPixelSize => (Vector2i) (DesiredSize * UIScale);
[ViewVariables] public bool IsMeasureValid { get; private set; }
[ViewVariables] public bool IsArrangeValid { get; private set; }
[ViewVariables]
public Thickness Margin
{
get => _margin;
set => _margin = value;
}
/// <summary>
/// Called when the <see cref="UIScale"/> for this control changes.
/// </summary>
protected internal virtual void UIScaleChanged()
{
MinimumSizeChanged();
InvalidateMeasure();
}
/// <summary>
@@ -56,7 +80,6 @@ namespace Robust.Client.UserInterface
_size = value;
Resized();
UpdateLayout();
}
}
@@ -179,12 +202,36 @@ namespace Robust.Client.UserInterface
/// Horizontal size flags for container layout.
/// </summary>
[ViewVariables]
[Obsolete("Use HorizontalAlignment and HorizontalExpand instead.")]
public SizeFlags SizeFlagsHorizontal
{
get => _sizeFlagsHorizontal;
get
{
var flags = HorizontalAlignment switch
{
HAlignment.Stretch => SizeFlags.Fill,
HAlignment.Left => SizeFlags.None,
HAlignment.Center => SizeFlags.ShrinkCenter,
HAlignment.Right => SizeFlags.ShrinkEnd,
_ => throw new ArgumentOutOfRangeException()
};
if (_horizontalExpand)
flags |= SizeFlags.Expand;
return flags;
}
set
{
_sizeFlagsHorizontal = value;
HorizontalExpand = (value & SizeFlags.Expand) != 0;
HorizontalAlignment = (value & ~SizeFlags.Expand) switch
{
SizeFlags.None => HAlignment.Left,
SizeFlags.Fill => HAlignment.Stretch,
SizeFlags.ShrinkCenter => HAlignment.Center,
SizeFlags.ShrinkEnd => HAlignment.Right,
_ => throw new ArgumentOutOfRangeException()
};
Parent?.UpdateLayout();
}
@@ -193,18 +240,87 @@ namespace Robust.Client.UserInterface
/// <summary>
/// Vertical size flags for container layout.
/// </summary>
[Obsolete("Use VerticalAlignment and VerticalExpand instead.")]
[ViewVariables]
public SizeFlags SizeFlagsVertical
{
get => _sizeFlagsVertical;
get
{
var flags = _verticalAlignment switch
{
VAlignment.Stretch => SizeFlags.Fill,
VAlignment.Top => SizeFlags.None,
VAlignment.Center => SizeFlags.ShrinkCenter,
VAlignment.Bottom => SizeFlags.ShrinkEnd,
_ => throw new ArgumentOutOfRangeException()
};
if (_verticalExpand)
flags |= SizeFlags.Expand;
return flags;
}
set
{
_sizeFlagsVertical = value;
VerticalExpand = (value & SizeFlags.Expand) != 0;
VerticalAlignment = (value & ~SizeFlags.Expand) switch
{
SizeFlags.None => VAlignment.Top,
SizeFlags.Fill => VAlignment.Stretch,
SizeFlags.ShrinkCenter => VAlignment.Center,
SizeFlags.ShrinkEnd => VAlignment.Bottom,
_ => throw new ArgumentOutOfRangeException()
};
Parent?.UpdateLayout();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public HAlignment HorizontalAlignment
{
get => _horizontalAlignment;
set
{
_horizontalAlignment = value;
InvalidateArrange();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public VAlignment VerticalAlignment
{
get => _verticalAlignment;
set
{
_verticalAlignment = value;
InvalidateArrange();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public bool HorizontalExpand
{
get => _horizontalExpand;
set
{
_horizontalExpand = value;
Parent?.InvalidateMeasure();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public bool VerticalExpand
{
get => _verticalExpand;
set
{
_verticalExpand = value;
Parent?.InvalidateArrange();
}
}
/// <summary>
/// Stretch ratio used to give shared of the available space in case multiple siblings are set to expand
/// in a container
@@ -225,12 +341,12 @@ namespace Robust.Client.UserInterface
_sizeFlagsStretchRatio = value;
Parent?.UpdateLayout();
Parent?.InvalidateArrange();
}
}
/// <summary>
/// A combination of <see cref="CustomMinimumSize" /> and <see cref="CalculateMinimumSize" />,
/// A combination of <see cref="MinSize" /> and <see cref="CalculateMinimumSize" />,
/// Whichever is greater.
/// Use this for whenever you need the *actual* minimum size of something.
/// </summary>
@@ -238,24 +354,13 @@ namespace Robust.Client.UserInterface
/// This is in virtual pixels.
/// </remarks>
/// <seealso cref="CombinedPixelMinimumSize"/>
[ViewVariables]
public Vector2 CombinedMinimumSize
{
get
{
if (!_calculatedMinimumSize.HasValue)
{
_updateMinimumSize();
DebugTools.Assert(_calculatedMinimumSize.HasValue);
}
return Vector2.ComponentMax(CustomMinimumSize, _calculatedMinimumSize!.Value);
}
}
[Obsolete("Use DesiredSize and Measure()")]
public Vector2 CombinedMinimumSize => DesiredSize;
/// <summary>
/// The <see cref="CombinedMinimumSize"/>, in physical pixels.
/// </summary>
[Obsolete("Use DesiredSize and Measure()")]
public Vector2i CombinedPixelMinimumSize => (Vector2i) (CombinedMinimumSize * UIScale);
/// <summary>
@@ -264,24 +369,95 @@ namespace Robust.Client.UserInterface
/// <seealso cref="CalculateMinimumSize" />
/// <seealso cref="CombinedMinimumSize" />
[ViewVariables]
[Obsolete("Use MinSize instead.")]
public Vector2 CustomMinimumSize
{
get => _customMinimumSize;
get => (_minWidth, _minHeight);
set => (MinWidth, MinHeight) = Vector2.ComponentMax(Vector2.Zero, value);
}
public Vector2 MinSize
{
get => (_minWidth, _minHeight);
set => (MinWidth, MinHeight) = Vector2.ComponentMax(Vector2.Zero, value);
}
public Vector2 SetSize
{
get => (_setWidth, _setHeight);
set => (SetWidth, SetHeight) = value;
}
public Vector2 MaxSize
{
get => (_maxWidth, _maxHeight);
set => (MaxWidth, MaxHeight) = value;
}
[ViewVariables(VVAccess.ReadWrite)]
public float MinWidth
{
get => _minWidth;
set
{
_customMinimumSize = Vector2.ComponentMax(Vector2.Zero, value);
MinimumSizeChanged();
_minWidth = value;
InvalidateMeasure();
}
}
private void _updateMinimumSize()
[ViewVariables(VVAccess.ReadWrite)]
public float MinHeight
{
if (_stylingDirty)
get => _minHeight;
set
{
ForceRunStyleUpdate();
_minHeight = value;
InvalidateMeasure();
}
}
_calculatedMinimumSize = Vector2.ComponentMax(Vector2.Zero, CalculateMinimumSize());
[ViewVariables(VVAccess.ReadWrite)]
public float SetWidth
{
get => _setWidth;
set
{
_setWidth = value;
InvalidateMeasure();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public float SetHeight
{
get => _setHeight;
set
{
_setHeight = value;
InvalidateMeasure();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public float MaxWidth
{
get => _maxWidth;
set
{
_maxWidth = value;
InvalidateMeasure();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public float MaxHeight
{
get => _maxHeight;
set
{
_maxHeight = value;
InvalidateMeasure();
}
}
/// <summary>
@@ -289,27 +465,31 @@ namespace Robust.Client.UserInterface
/// Do NOT call this directly to get the minimum size for layout purposes!
/// Use <see cref="CombinedMinimumSize" /> for the ACTUAL minimum size.
/// </summary>
[Obsolete("Implement MeasureOverride instead")]
protected virtual Vector2 CalculateMinimumSize()
{
var min = Vector2.Zero;
foreach (var child in Children)
{
min = Vector2.ComponentMax(min, child.CombinedMinimumSize);
}
return min;
return Vector2.Zero;
}
/// <summary>
/// Tells the GUI system that the minimum size of this control may have changed,
/// so that say containers will re-sort it if necessary.
/// </summary>
[Obsolete("Use InvalidateMeasure()")]
public void MinimumSizeChanged()
{
_calculatedMinimumSize = null;
OnMinimumSizeChanged?.Invoke(this);
InvalidateMeasure();
}
Parent?.MinimumSizeChanged();
UpdateLayout();
public void InvalidateMeasure()
{
if (!IsMeasureValid)
return;
IsMeasureValid = false;
IsArrangeValid = false;
UserInterfaceManagerInternal.QueueMeasureUpdate(this);
}
/// <summary>
@@ -320,89 +500,241 @@ namespace Robust.Client.UserInterface
/// where running the deferred layout updating system in the UI manager can be annoying.
/// If you are forced to use this in regular code, you have found a bug.
/// </remarks>
[Obsolete("Call Arrange manually for unit tests or call Measure manually for early measures.")]
public void ForceRunLayoutUpdate()
{
DoLayoutUpdate();
foreach (var child in Children)
{
child.ForceRunLayoutUpdate();
}
// TODO: Fix or remove this
if (PreviousArrange.HasValue)
Arrange(PreviousArrange.Value);
}
protected void UpdateLayout()
public void InvalidateArrange()
{
if (_layoutDirty)
if (!IsArrangeValid)
{
// Already queued for a layout update, don't bother.
return;
}
_layoutDirty = true;
UserInterfaceManagerInternal.QueueLayoutUpdate(this);
IsArrangeValid = false;
UserInterfaceManagerInternal.QueueArrangeUpdate(this);
}
protected void FitChildInPixelBox(Control child, UIBox2i pixelBox)
[Obsolete("Use InvalidateArrange()")]
protected void UpdateLayout()
{
var topLeft = pixelBox.TopLeft / UIScale;
var bottomRight = pixelBox.BottomRight / UIScale;
FitChildInBox(child, new UIBox2(topLeft, bottomRight));
InvalidateArrange();
}
protected void FitChildInBox(Control child, UIBox2 box)
public void Measure(Vector2 availableSize)
{
DebugTools.Assert(child.Parent == this);
if (!IsMeasureValid || PreviousMeasure != availableSize)
{
IsMeasureValid = true;
var desired = MeasureCore(availableSize);
var (minX, minY) = child.CombinedMinimumSize;
var newPosX = box.Left;
var newSizeX = minX;
if (desired.X < 0 || desired.Y < 0 || !float.IsFinite(desired.X) || !float.IsFinite(desired.Y))
throw new InvalidOperationException("Invalid size returned from Measure()");
if ((child.SizeFlagsHorizontal & SizeFlags.ShrinkEnd) != 0)
{
newPosX += (box.Width - minX);
}
else if ((child.SizeFlagsHorizontal & SizeFlags.ShrinkCenter) != 0)
{
newPosX += (box.Width - minX) / 2;
}
else if ((child.SizeFlagsHorizontal & SizeFlags.Fill) != 0)
{
newSizeX = Math.Max(box.Width, newSizeX);
}
var prev = DesiredSize;
DesiredSize = desired;
PreviousMeasure = availableSize;
var newPosY = box.Top;
var newSizeY = minY;
if ((child.SizeFlagsVertical & SizeFlags.ShrinkEnd) != 0)
{
newPosY += (box.Height - minY);
if (prev != desired && Parent != null && !Parent._measuring)
Parent?.InvalidateMeasure();
}
else if ((child.SizeFlagsVertical & SizeFlags.ShrinkCenter) != 0)
{
newPosY += (box.Height - minY) / 2;
}
else if ((child.SizeFlagsVertical & SizeFlags.Fill) != 0)
{
newSizeY = Math.Max(box.Height, newSizeY);
}
child.Position = new Vector2(newPosX, newPosY);
child.Size = new Vector2(newSizeX, newSizeY);
}
internal void DoLayoutUpdate()
protected virtual Vector2 MeasureCore(Vector2 availableSize)
{
if (!Visible)
return default;
if (_stylingDirty)
ForceRunStyleUpdate();
var withoutMargin = _margin.Deflate(availableSize);
var constrained = ApplySizeConstraints(this, withoutMargin);
Vector2 measured;
try
{
_measuring = true;
measured = Vector2.ComponentMax(
MeasureOverride(constrained),
// For the time being keep the old CalculateMinimumSize around.
#pragma warning disable 618
CalculateMinimumSize());
#pragma warning restore 618
}
finally
{
_measuring = false;
}
if (!float.IsNaN(SetWidth))
{
measured.X = SetWidth;
}
measured.X = Math.Clamp(measured.X, MinWidth, MaxWidth);
if (!float.IsNaN(SetHeight))
{
measured.Y = SetHeight;
}
measured.Y = Math.Clamp(measured.Y, MinHeight, MaxHeight);
measured = _margin.Inflate(measured);
return Vector2.ComponentMin(measured, availableSize);
}
protected virtual Vector2 MeasureOverride(Vector2 availableSize)
{
var min = Vector2.Zero;
foreach (var child in Children)
{
child.Measure(availableSize);
min = Vector2.ComponentMax(min, child.DesiredSize);
}
return min;
}
public void ArrangePixel(UIBox2i finalRect)
{
var topLeft = finalRect.TopLeft / UIScale;
var bottomRight = finalRect.BottomRight / UIScale;
Arrange(new UIBox2(topLeft, bottomRight));
}
public void Arrange(UIBox2 finalRect)
{
if (!IsMeasureValid)
Measure(PreviousMeasure ?? finalRect.Size);
if (!IsArrangeValid || PreviousArrange != finalRect)
{
IsArrangeValid = true;
ArrangeCore(finalRect);
PreviousArrange = finalRect;
}
}
protected virtual void ArrangeCore(UIBox2 finalRect)
{
if (!Visible)
return;
var withoutMargins = _margin.Deflate(finalRect);
var availWithoutMargins = withoutMargins.Size;
var size = availWithoutMargins;
var origin = withoutMargins.TopLeft;
if (_horizontalAlignment != HAlignment.Stretch)
size.X = Math.Min(size.X, DesiredSize.X - _margin.SumHorizontal);
if (_verticalAlignment != VAlignment.Stretch)
size.Y = Math.Min(size.Y, DesiredSize.Y - _margin.SumVertical);
size = ApplySizeConstraints(this, size);
Size = size;
_isLayoutUpdateOverrideUsed = true;
#pragma warning disable 618
LayoutUpdateOverride();
_layoutDirty = false;
#pragma warning restore 618
if (!_isLayoutUpdateOverrideUsed)
{
var arranged = ArrangeOverride(size);
size = Vector2.ComponentMin(arranged, size);
}
switch (HorizontalAlignment)
{
case HAlignment.Stretch:
case HAlignment.Center:
origin.X += (availWithoutMargins.X - size.X) / 2;
break;
case HAlignment.Right:
origin.X += availWithoutMargins.X - size.X;
break;
}
switch (VerticalAlignment)
{
case VAlignment.Stretch:
case VAlignment.Center:
origin.Y += (availWithoutMargins.Y - size.Y) / 2;
break;
case VAlignment.Bottom:
origin.Y += availWithoutMargins.Y - size.Y;
break;
}
Position = origin;
Size = size;
}
protected virtual void LayoutUpdateOverride()
protected virtual Vector2 ArrangeOverride(Vector2 finalSize)
{
foreach (var child in Children)
{
FitChildInPixelBox(child, PixelSizeBox);
child.Arrange(UIBox2.FromDimensions(Vector2.Zero, finalSize));
}
return finalSize;
}
[Obsolete("Use Control.ArrangePixel")]
protected void FitChildInPixelBox(Control child, UIBox2i pixelBox)
{
child.ArrangePixel(pixelBox);
}
[Obsolete("Use Control.Arrange")]
protected void FitChildInBox(Control child, UIBox2 box)
{
child.Arrange(box);
}
[Obsolete("Implement ArrangeOverride instead.")]
protected virtual void LayoutUpdateOverride()
{
_isLayoutUpdateOverrideUsed = false;
}
private static Vector2 ApplySizeConstraints(Control control, Vector2 avail)
{
var minW = control._minWidth;
var setW = control._setWidth;
var maxW = control._maxWidth;
var maxConstraint = float.IsNaN(setW) ? float.PositiveInfinity : setW;
maxW = MathHelper.Clamp(maxConstraint, minW, maxW);
var minConstraint = float.IsNaN(setW) ? 0 : setW;
minW = MathHelper.Clamp(maxW, minConstraint, minW);
var minH = control._minHeight;
var setH = control._setHeight;
var maxH = control._maxHeight;
maxConstraint = float.IsNaN(setH) ? float.PositiveInfinity : setH;
maxH = MathHelper.Clamp(maxConstraint, minH, maxH);
minConstraint = float.IsNaN(setH) ? 0 : setH;
minH = MathHelper.Clamp(minW, minConstraint, minH);
return (
Math.Clamp(avail.X, minW, maxW),
Math.Clamp(avail.Y, minH, maxH));
}
/// <summary>
@@ -443,5 +775,21 @@ namespace Robust.Client.UserInterface
/// </summary>
ShrinkEnd = 8,
}
public enum HAlignment
{
Stretch,
Left,
Center,
Right
}
public enum VAlignment
{
Stretch,
Top,
Center,
Bottom
}
}
}

View File

@@ -233,7 +233,7 @@ namespace Robust.Client.UserInterface
protected virtual void StylePropertiesChanged()
{
MinimumSizeChanged();
InvalidateMeasure();
}
public void ForceRunStyleUpdate()

View File

@@ -154,7 +154,8 @@ namespace Robust.Client.UserInterface
_propagateVisibilityChanged(value);
// TODO: unhardcode this.
// Many containers ignore children if they're invisible, so that's why we're replicating that ehre.
Parent?.MinimumSizeChanged();
Parent?.InvalidateMeasure();
InvalidateMeasure();
}
}
@@ -594,7 +595,7 @@ namespace Robust.Client.UserInterface
/// <param name="newChild">The new child.</param>
protected virtual void ChildAdded(Control newChild)
{
MinimumSizeChanged();
InvalidateMeasure();
}
/// <summary>
@@ -604,7 +605,7 @@ namespace Robust.Client.UserInterface
protected virtual void Parented(Control newParent)
{
StylesheetUpdateRecursive();
UpdateLayout();
InvalidateMeasure();
}
/// <summary>
@@ -642,7 +643,7 @@ namespace Robust.Client.UserInterface
/// <param name="child">The former child.</param>
protected virtual void ChildRemoved(Control child)
{
MinimumSizeChanged();
InvalidateMeasure();
}
/// <summary>

View File

@@ -35,8 +35,60 @@ namespace Robust.Client.UserInterface.Controls
public int? SeparationOverride { get; set; }
protected override void LayoutUpdateOverride()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var separation = ActualSeparation;
var minSize = Vector2.Zero;
var first = true;
foreach (var child in Children)
{
if (!child.Visible)
{
continue;
}
child.Measure(availableSize);
var childSize = child.DesiredSize;
if (Vertical)
{
var taken = childSize.Y;
if (!first)
{
taken += separation;
}
minSize.Y += taken;
availableSize.Y = Math.Max(0, availableSize.Y - taken);
first = false;
minSize.X = Math.Max(minSize.X, childSize.X);
}
else
{
var taken = childSize.X;
if (!first)
{
taken += separation;
}
minSize.X += taken;
availableSize.X = Math.Max(0, availableSize.X - taken);
first = false;
minSize.Y = Math.Max(minSize.Y, childSize.Y);
}
}
return minSize;
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var finalPixel = (Vector2i) (finalSize * UIScale);
var separation = (int) (ActualSeparation * UIScale);
// Step one: figure out the sizes of all our children and whether they want to stretch.
@@ -51,19 +103,20 @@ namespace Robust.Client.UserInterface.Controls
{
continue;
}
var (minX, minY) = child.CombinedPixelMinimumSize;
var (minX, minY) = child.DesiredPixelSize;
int minSize;
bool stretch;
if (Vertical)
{
minSize = minY;
stretch = (child.SizeFlagsVertical & SizeFlags.Expand) == SizeFlags.Expand;
stretch = child.VerticalExpand;
}
else
{
minSize = minX;
stretch = (child.SizeFlagsHorizontal & SizeFlags.Expand) == SizeFlags.Expand;
stretch = child.HorizontalExpand;
}
if (!stretch)
@@ -78,7 +131,7 @@ namespace Robust.Client.UserInterface.Controls
sizeList.Add((child, minSize, minSize, stretch));
}
var stretchMax = Vertical ? PixelHeight : PixelWidth;
var stretchMax = Vertical ? finalPixel.Y : finalPixel.X;
stretchMax -= separation * (ChildCount - 1);
// This is the amount of space allocated for stretchable children.
@@ -152,62 +205,19 @@ namespace Robust.Client.UserInterface.Controls
UIBox2i targetBox;
if (Vertical)
{
targetBox = new UIBox2i(0, offset, PixelWidth, offset+size);
targetBox = new UIBox2i(0, offset, finalPixel.X, offset + size);
}
else
{
targetBox = new UIBox2i(offset, 0, offset+size, PixelHeight);
targetBox = new UIBox2i(offset, 0, offset + size, finalPixel.Y);
}
FitChildInPixelBox(control, targetBox);
control.ArrangePixel(targetBox);
offset += size;
}
}
protected override Vector2 CalculateMinimumSize()
{
var separation = ActualSeparation;
var minWidth = 0f;
var minHeight = 0f;
var first = true;
foreach (var child in Children)
{
if (!child.Visible)
{
continue;
}
var (childWidth, childHeight) = child.CombinedMinimumSize;
if (Vertical)
{
minHeight += childHeight;
if (!first)
{
minHeight += separation;
}
first = false;
minWidth = MathF.Max(minWidth, childWidth);
}
else
{
minWidth += childWidth;
if (!first)
{
minWidth += separation;
}
first = false;
minHeight = MathF.Max(minHeight, childHeight);
}
}
return new Vector2(minWidth, minHeight);
return finalSize;
}
public enum AlignMode : byte

View File

@@ -7,15 +7,19 @@ namespace Robust.Client.UserInterface.Controls
/// </summary>
public class CenterContainer : Container
{
protected override void LayoutUpdateOverride()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var max = Vector2.Zero;
foreach (var child in Children)
{
var childSize = child.CombinedMinimumSize;
var childPos = (Size - childSize) / 2;
var childSize = child.DesiredSize;
var childPos = (finalSize - childSize) / 2;
FitChildInBox(child, UIBox2.FromDimensions(childPos, childSize));
child.Arrange(UIBox2.FromDimensions(childPos, childSize));
max = Vector2.ComponentMax(max, childSize);
}
return max;
}
}
}

View File

@@ -31,13 +31,30 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override void LayoutUpdateOverride()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var contentBox = ActualStyleBox.GetContentBox(PixelSizeBox);
var boxSize = ActualStyleBox.MinimumSize / UIScale;
var childBox = Vector2.ComponentMax(availableSize - boxSize, Vector2.Zero);
var min = Vector2.Zero;
foreach (var child in Children)
{
FitChildInPixelBox(child, (UIBox2i) contentBox);
child.Measure(childBox);
min = Vector2.ComponentMax(min, child.DesiredSize);
}
return min + boxSize;
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var contentBox = ActualStyleBox.GetContentBox(UIBox2.FromDimensions(Vector2.Zero, finalSize * UIScale));
foreach (var child in Children)
{
child.ArrangePixel((UIBox2i) contentBox);
}
return finalSize;
}
protected internal override void Draw(DrawingHandleScreen handle)
@@ -49,17 +66,6 @@ namespace Robust.Client.UserInterface.Controls
style.Draw(handle, drawBox);
}
protected override Vector2 CalculateMinimumSize()
{
var min = Vector2.Zero;
foreach (var child in Children)
{
min = Vector2.ComponentMax(min, child.CombinedMinimumSize);
}
return min + ActualStyleBox.MinimumSize / UIScale;
}
protected override void DrawModeChanged()
{
switch (DrawMode)

View File

@@ -49,8 +49,8 @@ namespace Robust.Client.UserInterface.Controls
_lineEdit = new LineEdit
{
CustomMinimumSize = new Vector2(40, 0),
SizeFlagsHorizontal = SizeFlags.FillExpand
MinSize = new Vector2(40, 0),
HorizontalExpand = true,
};
AddChild(_lineEdit);

View File

@@ -48,7 +48,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_expandBackwards = value;
UpdateLayout();
InvalidateArrange();
}
}
private bool _expandBackwards;
@@ -100,10 +100,17 @@ namespace Robust.Client.UserInterface.Controls
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the value assigned is less than or equal to 0.
/// </exception>
public float MaxWidth
[Obsolete("Use MaxGridWidth")]
public new float MaxWidth
{
set => MaxGridWidth = value;
}
public float MaxGridWidth
{
set => SetMaxSize(Dimension.Column, value);
}
/// <summary>
/// The max height (in virtual pixels) the grid of elements can have. This dynamically determines
/// the number of rows based on the size of the elements. Setting this puts this grid
@@ -120,12 +127,17 @@ namespace Robust.Client.UserInterface.Controls
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the value assigned is less than or equal to 0.
/// </exception>
public float MaxHeight
[Obsolete("Use MaxGridHeight")]
public new float MaxHeight
{
set => MaxGridHeight = value;
}
public float MaxGridHeight
{
set => SetMaxSize(Dimension.Row, value);
}
private int? _vSeparationOverride;
[SuppressMessage("ReSharper", "StringLiteralTypo")]
@@ -199,8 +211,7 @@ namespace Robust.Client.UserInterface.Controls
_limitType = LimitType.Count;
_limitedDimensionCount = value;
MinimumSizeChanged();
UpdateLayout();
InvalidateMeasure();
}
private void SetMaxSize(Dimension forDimension, float value)
@@ -214,8 +225,7 @@ namespace Robust.Client.UserInterface.Controls
_limitType = LimitType.Size;
_limitSize = value;
MinimumSizeChanged();
UpdateLayout();
InvalidateMeasure();
}
/// <summary>
@@ -263,7 +273,7 @@ namespace Robust.Client.UserInterface.Controls
int maxMinHeight = -1;
foreach (var child in Children)
{
var (minSizeX, minSizeY) = child.CombinedPixelMinimumSize;
var (minSizeX, minSizeY) = child.DesiredPixelSize;
maxMinWidth = Math.Max(maxMinWidth, minSizeX);
maxMinHeight = Math.Max(maxMinHeight, minSizeY);
}
@@ -271,7 +281,7 @@ namespace Robust.Client.UserInterface.Controls
return new Vector2i(maxMinWidth, maxMinHeight);
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
// to make it easier to read and visualize, we're just going to use the terms "x" and "y", width, and height,
// rows and cols,
@@ -280,6 +290,12 @@ namespace Robust.Client.UserInterface.Controls
// For the below convention, we pretend that columns have a limit defined, thus
// the amount of rows is not limited (unlimited).
foreach (var child in Children)
{
// TODO: This is not really correct in any fucking way but I CBA to fix this properly.
child.Measure(availableSize);
}
var rows = GetCount(UnlimitedDimension);
var cols = GetCount(LimitedDimension);
var cellSize = CellSize();
@@ -304,7 +320,7 @@ namespace Robust.Client.UserInterface.Controls
// also converting here to our "pretend" scenario where columns have a limit defined.
// note if we are limiting by size rather than count, the size of each child is constant (cell size)
var (minSizeXActual, minSizeYActual) = _limitType == LimitType.Count ? child.CombinedPixelMinimumSize : cellSize;
var (minSizeXActual, minSizeYActual) = _limitType == LimitType.Count ? child.DesiredPixelSize : cellSize;
var minSizeX = _limitDimension == Dimension.Column ? minSizeXActual : minSizeYActual;
var minSizeY = _limitDimension == Dimension.Column ? minSizeYActual : minSizeXActual;
minColWidth[column] = Math.Max(minSizeX, minColWidth[column]);
@@ -348,9 +364,9 @@ namespace Robust.Client.UserInterface.Controls
return totalSize;
}
protected override void LayoutUpdateOverride()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
// to make it easier to read and visualize, we're just going to use the terms "x" and "y", width, and height,
// to make it easier to read and visualize, we're just going to use the terms "x" and "y", width, and height,
// rows and cols,
// but at the start of the method here we'll set those to what they actually are based
// on the limited dimension, which might involve swapping them.
@@ -390,19 +406,19 @@ namespace Robust.Client.UserInterface.Controls
// converting here to our "pretend" scenario where columns have a limit defined
// note if we are limiting by size rather than count, the size of each child is constant (cell size)
var (minSizeXActual, minSizeYActual) = _limitType == LimitType.Count ? child.CombinedPixelMinimumSize : cellSize;
var (minSizeXActual, minSizeYActual) = _limitType == LimitType.Count ? child.DesiredPixelSize : cellSize;
var minSizeX = _limitDimension == Dimension.Column ? minSizeXActual : minSizeYActual;
var minSizeY = _limitDimension == Dimension.Column ? minSizeYActual : minSizeXActual;
minColWidth[column] = Math.Max(minSizeX, minColWidth[column]);
minRowHeight[row] = Math.Max(minSizeY, minRowHeight[row]);
var colSizeFlag = _limitDimension == Dimension.Column
? child.SizeFlagsHorizontal
: child.SizeFlagsVertical;
var rowSizeFlag = UnlimitedDimension == Dimension.Column
? child.SizeFlagsHorizontal
: child.SizeFlagsVertical;
colExpand[column] = colExpand[column] || (colSizeFlag & SizeFlags.Expand) != 0;
rowExpand[row] = rowExpand[row] || (rowSizeFlag & SizeFlags.Expand) != 0;
var colExpandFlag = _limitDimension == Dimension.Column
? child.HorizontalExpand
: child.VerticalExpand;
var rowExpandFlag = UnlimitedDimension == Dimension.Column
? child.HorizontalExpand
: child.VerticalExpand;
colExpand[column] = colExpand[column] || colExpandFlag;
rowExpand[row] = rowExpand[row] || rowExpandFlag;
index += 1;
}
@@ -550,10 +566,12 @@ namespace Robust.Client.UserInterface.Controls
var boxHeight = _limitDimension == Dimension.Column ? minRowHeight[row] : minColWidth[column];
var box = UIBox2i.FromDimensions(left, top, boxWidth, boxHeight);
FitChildInPixelBox(child, box);
child.ArrangePixel(box);
hOffset += minColWidth[column] + hSep;
}
return finalSize;
}
}

View File

@@ -5,7 +5,7 @@ using System.Diagnostics.Contracts;
using Robust.Client.Graphics;
using Robust.Shared.Input;
using Robust.Shared.Maths;
using Timer = Robust.Shared.Timers.Timer;
using Timer = Robust.Shared.Timing.Timer;
namespace Robust.Client.UserInterface.Controls
{
@@ -43,9 +43,7 @@ namespace Robust.Client.UserInterface.Controls
{
Name = "_v_scroll",
SizeFlagsVertical = SizeFlags.Fill,
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
HorizontalAlignment = HAlignment.Right
};
AddChild(_scrollBar);
_scrollBar.OnValueChanged += _ => _isAtBottom = _scrollBar.IsAtEnd;
@@ -403,7 +401,7 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var size = Vector2.Zero;
if (ActualBackground != null)

View File

@@ -26,7 +26,7 @@ namespace Robust.Client.UserInterface.Controls
public Label()
{
SizeFlagsVertical = SizeFlags.ShrinkCenter;
VerticalAlignment = VAlignment.Center;
}
/// <summary>
@@ -40,7 +40,7 @@ namespace Robust.Client.UserInterface.Controls
{
_text = value;
_textDimensionCacheValid = false;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -52,7 +52,7 @@ namespace Robust.Client.UserInterface.Controls
{
_clipText = value;
RectClipContent = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -209,7 +209,7 @@ namespace Robust.Client.UserInterface.Controls
Fill = 3
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
if (!_textDimensionCacheValid)
{
@@ -267,7 +267,7 @@ namespace Robust.Client.UserInterface.Controls
continue;
}
_cachedTextWidths[_cachedTextWidths.Count-1] += metrics.Value.Advance;
_cachedTextWidths[^1] += metrics.Value.Advance;
}
}

View File

@@ -27,7 +27,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_textures = value;
CalculateMinimumSize();
InvalidateMeasure();
}
}
@@ -43,7 +43,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_textureScale = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -60,7 +60,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_canShrink = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -148,7 +148,7 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
if (_textures.Count == 0 || CanShrink)
{

View File

@@ -1,6 +1,8 @@
using System;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;
namespace Robust.Client.UserInterface.Controls
{
@@ -17,6 +19,8 @@ namespace Robust.Client.UserInterface.Controls
/// </summary>
public const float AnchorEnd = 1;
[ViewVariables(VVAccess.ReadWrite)] public bool Debug { get; set; }
public static readonly AttachedProperty MarginLeftProperty = AttachedProperty.Create("MarginLeft",
typeof(LayoutContainer), typeof(float), changed: LayoutPropertyChangedCallback);
@@ -47,6 +51,9 @@ namespace Robust.Client.UserInterface.Controls
public static readonly AttachedProperty GrowVerticalProperty = AttachedProperty.Create("GrowVertical",
typeof(LayoutContainer), typeof(GrowDirection), changed: LayoutPropertyChangedCallback);
public static readonly AttachedProperty<bool> DebugProperty = AttachedProperty<bool>.Create("Debug",
typeof(LayoutContainer));
public static void SetMarginLeft(Control control, float value)
{
@@ -112,16 +119,10 @@ namespace Robust.Client.UserInterface.Controls
SetMarginBottom(control, diffY + control.GetValue<float>(MarginBottomProperty));
}
public static void SetSize(Control control, Vector2 size)
[Obsolete("Change SetSize on the control instead.")]
public new static void SetSize(Control control, Vector2 size)
{
var (diffX, diffY) = size - control.Size;
// This is just to make subsequent set calls work correctly.
// It should get reset to this exact value next update either way.
control.Size = size;
SetMarginRight(control, diffX + control.GetValue<float>(MarginRightProperty));
SetMarginBottom(control, diffY + control.GetValue<float>(MarginBottomProperty));
control.SetSize = size;
}
/// <summary>
@@ -297,8 +298,9 @@ namespace Robust.Client.UserInterface.Controls
LayoutPresetMode resizeMode = LayoutPresetMode.MinSize,
int margin = 0)
{
control.Measure(Vector2.Infinity);
var newSize = control.Size;
var minSize = control.CombinedMinimumSize;
var minSize = control.DesiredSize;
if ((resizeMode & LayoutPresetMode.KeepWidth) == 0)
{
newSize = new Vector2(minSize.X, newSize.Y);
@@ -445,39 +447,131 @@ namespace Robust.Client.UserInterface.Controls
control.SetValue(MarginBottomProperty, marginBottom);
}
protected override void LayoutUpdateOverride()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var min = Vector2.Zero;
var uiScale = UIScale;
foreach (var child in Children)
{
var growH = child.GetValue<GrowDirection>(GrowHorizontalProperty);
var growV = child.GetValue<GrowDirection>(GrowVerticalProperty);
var anchorMargins = CalcAnchorMargins(availableSize, uiScale, child);
var size = availableSize;
if (growH == GrowDirection.Constrain)
size.X = anchorMargins.Width / uiScale;
if (growV == GrowDirection.Constrain)
size.Y = anchorMargins.Height / uiScale;
child.Measure(size);
min = Vector2.ComponentMax(min, child.DesiredSize);
}
return min;
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
foreach (var child in Children)
{
child.Arrange(CalcChildRect(finalSize, UIScale, child, out _));
}
return finalSize;
}
protected internal override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (!Debug)
return;
var (pSizeX, pSizeY) = PixelSize;
foreach (var child in Children)
{
var anchorLeft = child.GetValue<float>(AnchorLeftProperty);
var anchorTop = child.GetValue<float>(AnchorTopProperty);
var anchorRight = child.GetValue<float>(AnchorRightProperty);
var anchorBottom = child.GetValue<float>(AnchorBottomProperty);
if (!child.GetValue(DebugProperty))
{
continue;
}
var marginLeft = child.GetValue<float>(MarginLeftProperty) * UIScale;
var marginTop = child.GetValue<float>(MarginTopProperty) * UIScale;
var marginRight = child.GetValue<float>(MarginRightProperty) * UIScale;
var marginBottom = child.GetValue<float>(MarginBottomProperty) * UIScale;
var rect = CalcChildRect(Size, UIScale, child, out var anchorSize);
var growHorizontal = child.GetValue<GrowDirection>(GrowHorizontalProperty);
var growVertical = child.GetValue<GrowDirection>(GrowVerticalProperty);
var left = rect.Left * UIScale;
var right = rect.Right * UIScale;
var top = rect.Top * UIScale;
var bottom = rect.Bottom * UIScale;
// Calculate where the control "wants" to be by its anchors/margins.
var left = anchorLeft * pSizeX + marginLeft;
var top = anchorTop * pSizeY + marginTop;
var right = anchorRight * pSizeX + marginRight;
var bottom = anchorBottom * pSizeY + marginBottom;
DrawVLine(anchorSize.Left, Color.Pink);
DrawVLine(anchorSize.Right, Color.Green);
DrawHLine(anchorSize.Top, Color.Pink);
DrawHLine(anchorSize.Bottom, Color.Green);
var (wSizeX, wSizeY) = (right - left, bottom - top);
var (minSizeX, minSizeY) = child.CombinedPixelMinimumSize;
/*
DrawVLine(left, Color.Orange);
DrawVLine(right, Color.Blue);
DrawHLine(top, Color.Orange);
DrawHLine(bottom, Color.Blue);
*/
HandleLayoutOverflow(growHorizontal, minSizeX, left, wSizeX, out var posX, out var sizeX);
HandleLayoutOverflow(growVertical, minSizeY, top, wSizeY, out var posY, out var sizeY);
child.Position = new Vector2(posX, posY) / UserInterfaceManager.UIScale;
child.Size = new Vector2(sizeX, sizeY) / UserInterfaceManager.UIScale;
handle.DrawRect(new UIBox2(left, top, right, bottom), Color.Red, false);
}
void DrawVLine(float x, Color color)
{
handle.DrawLine((x, 0), (x, pSizeY), color);
}
void DrawHLine(float y, Color color)
{
handle.DrawLine((0, y), (pSizeX, y), color);
}
}
private static UIBox2 CalcAnchorMargins(Vector2 ourSize, float uiScale, Control child)
{
var (pSizeX, pSizeY) = ourSize * uiScale;
var anchorLeft = child.GetValue<float>(AnchorLeftProperty);
var anchorTop = child.GetValue<float>(AnchorTopProperty);
var anchorRight = child.GetValue<float>(AnchorRightProperty);
var anchorBottom = child.GetValue<float>(AnchorBottomProperty);
var marginLeft = child.GetValue<float>(MarginLeftProperty) * uiScale;
var marginTop = child.GetValue<float>(MarginTopProperty) * uiScale;
var marginRight = child.GetValue<float>(MarginRightProperty) * uiScale;
var marginBottom = child.GetValue<float>(MarginBottomProperty) * uiScale;
var left = anchorLeft * pSizeX + marginLeft;
var top = anchorTop * pSizeY + marginTop;
var right = anchorRight * pSizeX + marginRight;
var bottom = anchorBottom * pSizeY + marginBottom;
// Yes, this can return boxes with left > right (and top > bottom).
// This is "intentional", see comment in CalcChildRect.
return new UIBox2(left, top, right, bottom);
}
private static UIBox2 CalcChildRect(Vector2 ourSize, float uiScale, Control child, out UIBox2 anchorSize)
{
// Calculate where the control "wants" to be by its anchors/margins.
var growHorizontal = child.GetValue<GrowDirection>(GrowHorizontalProperty);
var growVertical = child.GetValue<GrowDirection>(GrowVerticalProperty);
anchorSize = CalcAnchorMargins(ourSize, uiScale, child);
// This intentionally results in negatives if the right bound is < the left bound.
// Which then causes HandleLayoutOverflow to CORRECTLY work from the right bound instead.
var (wSizeX, wSizeY) = (anchorSize.Right - anchorSize.Left, anchorSize.Bottom - anchorSize.Top);
var (minSizeX, minSizeY) = child.DesiredPixelSize;
HandleLayoutOverflow(growHorizontal, minSizeX, anchorSize.Left, wSizeX, out var posX, out var sizeX);
HandleLayoutOverflow(growVertical, minSizeY, anchorSize.Top, wSizeY, out var posY, out var sizeY);
return UIBox2.FromDimensions(posX / uiScale, posY / uiScale, sizeX / uiScale, sizeY / uiScale);
}
private static void HandleLayoutOverflow(GrowDirection direction, float minSize, float wPos, float wSize,
@@ -485,7 +579,7 @@ namespace Robust.Client.UserInterface.Controls
out float size)
{
var overflow = minSize - wSize;
if (overflow <= 0)
if (overflow <= 0 || direction == GrowDirection.Constrain)
{
pos = wPos;
size = wSize;
@@ -514,7 +608,7 @@ namespace Robust.Client.UserInterface.Controls
{
if (owner.Parent is LayoutContainer container)
{
container.UpdateLayout();
container.InvalidateArrange();
}
}
@@ -537,7 +631,12 @@ namespace Robust.Client.UserInterface.Controls
/// <summary>
/// The control will expand on all axes equally to reach its minimum size.
/// </summary>
Both
Both,
/// <summary>
/// The control will not be allowed to grow on this axis.
/// </summary>
Constrain,
}
/// <seealso cref="Control.SetMarginsPreset" />

View File

@@ -242,18 +242,22 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var font = _getFont();
var style = _getStyleBox();
return new Vector2(0, font.GetHeight(UIScale) / UIScale) + style.MinimumSize / UIScale;
}
protected override void LayoutUpdateOverride()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var style = _getStyleBox();
FitChildInPixelBox(_renderBox, (UIBox2i) style.GetContentBox(PixelSizeBox));
_renderBox.ArrangePixel(
(UIBox2i) style.GetContentBox(
UIBox2.FromDimensions(Vector2.Zero, finalSize * UIScale)));
return finalSize;
}
protected internal override void TextEntered(GUITextEventArgs args)

View File

@@ -1,7 +1,9 @@
using System;
using Robust.Shared.Maths;
namespace Robust.Client.UserInterface.Controls
{
[Obsolete("Set Margin directly")]
public class MarginContainer : Container
{
public int? MarginBottomOverride { get; set; }
@@ -9,36 +11,41 @@ namespace Robust.Client.UserInterface.Controls
public int? MarginRightOverride { get; set; }
public int? MarginLeftOverride { get; set; }
protected override void LayoutUpdateOverride()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var top = MarginTopOverride ?? 0;
var bottom = MarginBottomOverride ?? 0;
var left = MarginLeftOverride ?? 0;
var right = MarginRightOverride ?? 0;
var box = UIBox2.FromDimensions(left, top, Width - right - left, Height - bottom - top);
var margin = GetMargin();
var availWithoutMargin = margin.Deflate(availableSize);
var max = Vector2.Zero;
foreach (var child in Children)
{
FitChildInBox(child, box);
child.Measure(availWithoutMargin);
max = Vector2.ComponentMax(max, child.DesiredSize);
}
return margin.Inflate(max);
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var box = GetMargin().Deflate(UIBox2.FromDimensions(Vector2.Zero, finalSize));
foreach (var child in Children)
{
child.Arrange(box);
}
return finalSize;
}
private Thickness GetMargin()
{
var top = MarginTopOverride ?? 0;
var bottom = MarginBottomOverride ?? 0;
var left = MarginLeftOverride ?? 0;
var right = MarginRightOverride ?? 0;
var childMinSize = Vector2.Zero;
foreach (var child in Children)
{
childMinSize = Vector2.ComponentMax(child.CombinedMinimumSize, childMinSize);
}
return childMinSize + (left + right, top + bottom);
var margin = new Thickness(left, top, right, bottom);
return margin;
}
}
}

View File

@@ -26,7 +26,7 @@ namespace Robust.Client.UserInterface.Controls
{
Children =
{
(_popupVBox = new VBoxContainer {CustomMinimumSize = (300, 0)})
(_popupVBox = new VBoxContainer {MinSize = (300, 0)})
}
};
_popup.OnPopupHide += PopupHidden;
@@ -113,7 +113,7 @@ namespace Robust.Client.UserInterface.Controls
break;
case MenuSeparator _:
var control = new Control {CustomMinimumSize = (0, 6)};
var control = new Control {MinSize = (0, 6)};
container.AddChild(control);
break;
}

View File

@@ -71,14 +71,14 @@ namespace Robust.Client.UserInterface.Controls
_label = new Label
{
StyleClasses = { StyleClassOptionButton },
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
};
hBox.AddChild(_label);
var textureRect = new TextureRect
{
StyleClasses = { StyleClassOptionTriangle },
SizeFlagsVertical = SizeFlags.ShrinkCenter,
VerticalAlignment = VAlignment.Center,
};
hBox.AddChild(textureRect);
}
@@ -112,7 +112,8 @@ namespace Robust.Client.UserInterface.Controls
if (show)
{
var globalPos = GlobalPosition;
var (minX, minY) = _popupVBox.CombinedMinimumSize;
_popupVBox.Measure(Vector2.Infinity);
var (minX, minY) = _popupVBox.DesiredSize;
var box = UIBox2.FromDimensions(globalPos, (Math.Max(minX, Width), minY));
UserInterfaceManager.ModalRoot.AddChild(_popup);
_popup.Open(box);

View File

@@ -60,14 +60,14 @@ namespace Robust.Client.UserInterface.Controls
_label = new Label
{
StyleClasses = { StyleClassOptionButton },
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
};
hBox.AddChild(_label);
_triangle = new TextureRect
{
StyleClasses = { StyleClassOptionTriangle },
SizeFlagsVertical = SizeFlags.ShrinkCenter,
VerticalAlignment = VAlignment.Center,
Visible = !HideTriangle
};
hBox.AddChild(_triangle);
@@ -118,7 +118,8 @@ namespace Robust.Client.UserInterface.Controls
if (show)
{
var globalPos = GlobalPosition;
var (minX, minY) = _popupVBox.CombinedMinimumSize;
_popupVBox.Measure(Vector2.Infinity);
var (minX, minY) = _popupVBox.DesiredSize;
var box = UIBox2.FromDimensions(globalPos, (Math.Max(minX, Width), minY));
UserInterfaceManager.ModalRoot.AddChild(_popup);
_popup.Open(box);

View File

@@ -31,8 +31,7 @@ namespace Robust.Client.UserInterface.Controls
_scrollBar = new VScrollBar
{
Name = "_v_scroll",
SizeFlagsVertical = SizeFlags.Fill,
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
HorizontalAlignment = HAlignment.Right
};
AddChild(_scrollBar);
_scrollBar.OnValueChanged += _ => _isAtBottom = _scrollBar.IsAtEnd;
@@ -44,7 +43,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_styleBoxOverride = value;
MinimumSizeChanged();
InvalidateMeasure();
_invalidateEntries();
}
}
@@ -168,7 +167,7 @@ namespace Robust.Client.UserInterface.Controls
_invalidateEntries();
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
return _getStyleBox()?.MinimumSize ?? Vector2.Zero;
}

View File

@@ -17,26 +17,32 @@ namespace Robust.Client.UserInterface.Controls
style?.Draw(handle, PixelSizeBox);
}
protected override void LayoutUpdateOverride()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var contentBox = _getStyleBox()?.GetContentBox(PixelSizeBox) ?? PixelSizeBox;
foreach (var child in Children)
{
FitChildInPixelBox(child, (UIBox2i) contentBox);
}
}
protected override Vector2 CalculateMinimumSize()
{
var styleSize = _getStyleBox()?.MinimumSize ?? Vector2.Zero;
var styleSize = (_getStyleBox()?.MinimumSize ?? Vector2.Zero) / UIScale;
var measureSize = Vector2.ComponentMax(availableSize - styleSize, Vector2.Zero);
var childSize = Vector2.Zero;
foreach (var child in Children)
{
childSize = Vector2.ComponentMax(childSize, child.CombinedMinimumSize);
child.Measure(measureSize);
childSize = Vector2.ComponentMax(childSize, child.DesiredSize);
}
return styleSize / UIScale + childSize;
return styleSize + childSize;
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var pixelSize = finalSize * UIScale;
var ourSize = UIBox2.FromDimensions(Vector2.Zero, pixelSize);
var contentBox = _getStyleBox()?.GetContentBox(ourSize) ?? ourSize;
foreach (var child in Children)
{
child.ArrangePixel((UIBox2i) contentBox);
}
return finalSize;
}
[System.Diagnostics.Contracts.Pure]

View File

@@ -30,7 +30,7 @@ namespace Robust.Client.UserInterface.Controls
PopupContainer.SetAltOrigin(this, altPos);
_desiredSize = box.Value.Size;
MinimumSizeChanged();
InvalidateMeasure();
}
Visible = true;
@@ -52,9 +52,11 @@ namespace Robust.Client.UserInterface.Controls
OnPopupHide?.Invoke();
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
return Vector2.ComponentMax(_desiredSize, base.CalculateMinimumSize());
return Vector2.ComponentMax(
_desiredSize,
base.MeasureOverride(Vector2.ComponentMax(availableSize, _desiredSize)));
}
}
}

View File

@@ -54,15 +54,15 @@ namespace Robust.Client.UserInterface.Controls
{
if (owner.Parent is PopupContainer container)
{
container.UpdateLayout();
container.InvalidateArrange();
}
}
protected override void LayoutUpdateOverride()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
foreach (var child in Children)
{
var size = child.CombinedMinimumSize;
var size = child.DesiredSize;
var offset = child.GetValue<Vector2>(PopupOriginProperty);
var altPos = child.GetValue<Vector2?>(AltOriginProperty);
@@ -105,22 +105,25 @@ namespace Robust.Client.UserInterface.Controls
offset -= (0, offset.Y);
}
FitChildInBox(child, UIBox2.FromDimensions(offset, size));
child.Arrange(UIBox2.FromDimensions(offset, size));
}
return finalSize;
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
// Do NOT inherit minimum size from contents!
// Just clip 'em.
return (0, 0);
// Measure to availableSize so that child controls never get too large to fit the whole screen.
base.MeasureOverride(availableSize);
return availableSize;
}
protected override void Resized()
{
base.Resized();
UpdateLayout();
InvalidateArrange();
}
}
}

View File

@@ -18,7 +18,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_backgroundStyleBoxOverride = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -28,7 +28,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_foregroundStyleBoxOverride = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -76,7 +76,7 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var bgSize = _getBackground()?.MinimumSize ?? Vector2.Zero;
var fgSize = _getForeground()?.MinimumSize ?? Vector2.Zero;

View File

@@ -11,13 +11,11 @@ namespace Robust.Client.UserInterface.Controls
private FormattedMessage? _message;
private RichTextEntry _entry;
public float? MaxWidth { get; set; }
public void SetMessage(FormattedMessage message)
{
_message = message;
_entry = new RichTextEntry(_message);
_updateEntry();
InvalidateMeasure();
}
public void SetMessage(string message)
@@ -27,42 +25,17 @@ namespace Robust.Client.UserInterface.Controls
SetMessage(msg);
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
if (_message == null)
{
return Vector2.Zero;
}
var width = 0f;
if (MaxWidth.HasValue)
{
width = _entry.Width / UIScale;
}
return (width, _entry.Height / UIScale);
}
private void _updateEntry()
{
var font = _getFont();
_entry.Update(font, availableSize.X * UIScale, UIScale);
if (_message != null)
{
var oldHeight = _entry.Height;
var oldWidth = _entry.Width;
_entry.Update(font, (MaxWidth ?? Width) * UIScale, UIScale);
if (oldHeight != _entry.Height || MaxWidth != null && _entry.Width != oldWidth)
{
MinimumSizeChanged();
}
}
}
protected override void StylePropertiesChanged()
{
base.StylePropertiesChanged();
_updateEntry();
return (_entry.Width / UIScale, _entry.Height / UIScale);
}
protected internal override void Draw(DrawingHandleScreen handle)
@@ -77,13 +50,6 @@ namespace Robust.Client.UserInterface.Controls
_entry.Draw(handle, _getFont(), SizeBox, 0, new Stack<FormattedMessage.Tag>(), UIScale);
}
protected override void Resized()
{
base.Resized();
_updateEntry();
}
[Pure]
private Font _getFont()
{

View File

@@ -129,13 +129,13 @@ namespace Robust.Client.UserInterface.Controls
if (_grabData == null)
{
var box = _getGrabberBox();
_isHovered = box.Contains(args.RelativePosition);
_isHovered = box.Contains(args.RelativePixelPosition);
_updatePseudoClass();
return;
}
var (grabPos, grabValue) = _grabData.Value;
var (grabRelX, grabRelY) = args.RelativePosition - grabPos;
var (grabRelX, grabRelY) = args.RelativePixelPosition - grabPos;
float moved;
if (_orientation == OrientationMode.Horizontal)
@@ -219,7 +219,7 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
return _getGrabberStyleBox()?.MinimumSize ?? Vector2.Zero;
}

View File

@@ -26,14 +26,14 @@ namespace Robust.Client.UserInterface.Controls
_hScrollBar = new HScrollBar
{
Visible = false,
SizeFlagsVertical = SizeFlags.ShrinkEnd,
SizeFlagsHorizontal = SizeFlags.Fill
VerticalAlignment = VAlignment.Bottom,
HorizontalAlignment = HAlignment.Stretch
};
_vScrollBar = new VScrollBar
{
Visible = false,
SizeFlagsVertical = SizeFlags.Fill,
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
VerticalAlignment = VAlignment.Stretch,
HorizontalAlignment = HAlignment.Right
};
AddChild(_hScrollBar);
AddChild(_vScrollBar);
@@ -47,7 +47,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_vScrollEnabled = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -57,17 +57,50 @@ namespace Robust.Client.UserInterface.Controls
set
{
_hScrollEnabled = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
protected override void LayoutUpdateOverride()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
if (_vScrollEnabled)
{
_vScrollBar.Measure(availableSize);
availableSize.X -= _vScrollBar.DesiredSize.X;
}
if (_hScrollEnabled)
{
_hScrollBar.Measure(availableSize);
availableSize.Y -= _hScrollBar.DesiredSize.Y;
}
var constraint = new Vector2(
_hScrollEnabled ? float.PositiveInfinity : availableSize.X,
_vScrollEnabled ? float.PositiveInfinity : availableSize.Y);
var size = Vector2.Zero;
foreach (var child in Children)
{
child.Measure(constraint);
size = Vector2.ComponentMax(size, child.DesiredSize);
}
// Unlike WPF/Avalonia we report ZERO here instead of available size.
// This is to fix a bunch of jank with e.g. BoxContainer.
// Tbh this might be a mistake.
// DockPanel when.
return Vector2.Zero;
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
if (_vScrollBar?.Parent == null || _hScrollBar?.Parent == null)
{
// Just don't run this before we're properly initialized.
return;
return Vector2.Zero;
}
var maxChildMinSize = Vector2.Zero;
foreach (var child in Children)
@@ -77,31 +110,31 @@ namespace Robust.Client.UserInterface.Controls
continue;
}
maxChildMinSize = Vector2.ComponentMax(child.CombinedMinimumSize, maxChildMinSize);
maxChildMinSize = Vector2.ComponentMax(child.DesiredSize, maxChildMinSize);
}
var (cWidth, cHeight) = maxChildMinSize;
var hBarSize = _hScrollBar.CombinedMinimumSize.Y;
var vBarSize = _vScrollBar.CombinedMinimumSize.X;
var hBarSize = _hScrollBar.DesiredSize.Y;
var vBarSize = _vScrollBar.DesiredSize.X;
var (sWidth, sHeight) = Size;
var (sWidth, sHeight) = finalSize;
try
{
// Suppress events to avoid weird recursion.
_suppressScrollValueChanged = true;
if (Width < cWidth)
if (sWidth < cWidth && _hScrollEnabled)
{
sHeight -= hBarSize;
}
if (Height < cHeight)
if (sHeight < cHeight && _vScrollEnabled)
{
sWidth -= vBarSize;
}
if (sWidth < cWidth)
if (sWidth < cWidth && _hScrollEnabled)
{
_hScrollBar.Visible = _hScrollVisible = true;
_hScrollBar.Page = sWidth;
@@ -112,7 +145,7 @@ namespace Robust.Client.UserInterface.Controls
_hScrollBar.Visible = _hScrollVisible = false;
}
if (sHeight < cHeight)
if (sHeight < cHeight && _vScrollEnabled)
{
_vScrollBar.Visible = _vScrollVisible = true;
_vScrollBar.Page = sHeight;
@@ -129,10 +162,19 @@ namespace Robust.Client.UserInterface.Controls
_suppressScrollValueChanged = false;
}
var sSize = (sWidth, sHeight);
if (_vScrollVisible)
{
_vScrollBar.Arrange(UIBox2.FromDimensions(Vector2.Zero, finalSize));
}
FitChildInPixelBox(_vScrollBar, PixelSizeBox);
FitChildInPixelBox(_hScrollBar, PixelSizeBox);
if (_hScrollVisible)
{
_hScrollBar.Arrange(UIBox2.FromDimensions(Vector2.Zero, finalSize));
}
var realFinalSize = (
_hScrollEnabled ? Math.Max(cWidth, sWidth) : sWidth,
_vScrollEnabled ? Math.Max(cHeight, sHeight) : sHeight);
foreach (var child in Children)
{
@@ -142,47 +184,11 @@ namespace Robust.Client.UserInterface.Controls
}
var position = -_getScrollValue();
var rect = UIBox2.FromDimensions(position, Vector2.ComponentMax(child.CombinedMinimumSize, sSize));
FitChildInBox(child, rect);
}
}
protected override Vector2 CalculateMinimumSize()
{
var totalX = 0f;
var totalY = 0f;
foreach (var child in Children)
{
if (child == _hScrollBar || child == _vScrollBar)
{
continue;
}
if (!_vScrollEnabled)
{
totalY = Math.Max(totalY, child.CombinedMinimumSize.Y);
}
if (!_hScrollEnabled)
{
totalX = Math.Max(totalX, child.CombinedMinimumSize.X);
}
var rect = UIBox2.FromDimensions(position, realFinalSize);
child.Arrange(rect);
}
if (_vScrollEnabled)
{
totalX += _vScrollBar.CombinedMinimumSize.X;
totalY = Math.Max(_vScrollBar.CombinedMinimumSize.Y, totalY);
}
if (_hScrollEnabled)
{
totalY += _hScrollBar.CombinedMinimumSize.Y;
totalX = Math.Max(_vScrollBar.CombinedMinimumSize.X, totalX);
}
return new Vector2(totalX, totalY);
return finalSize;
}
protected internal override void MouseWheel(GUIMouseWheelEventArgs args)
@@ -223,10 +229,12 @@ namespace Robust.Client.UserInterface.Controls
{
h = 0;
}
if (!_vScrollVisible)
{
v = 0;
}
return new Vector2(h, v);
}
@@ -237,7 +245,7 @@ namespace Robust.Client.UserInterface.Controls
return;
}
UpdateLayout();
InvalidateArrange();
}
}
}

View File

@@ -109,7 +109,7 @@ namespace Robust.Client.UserInterface.Controls
{
var ratio = GetAsRatio();
var margin = (Width - _grabber.CombinedMinimumSize.X) * ratio + _grabber.CombinedMinimumSize.X / 2;
var margin = (Width - _grabber.DesiredSize.X) * ratio + _grabber.DesiredSize.X / 2;
SetMarginRight(_fillPanel, margin);
SetMarginLeft(_grabber, margin);
SetMarginRight(_grabber, margin);
@@ -156,7 +156,7 @@ namespace Robust.Client.UserInterface.Controls
private void HandlePositionChange(Vector2 position)
{
var grabberWidth = _grabber.CombinedMinimumSize.X;
var grabberWidth = _grabber.DesiredSize.X;
var ratio = (position.X - grabberWidth / 2) / (Width - grabberWidth);
SetAsRatio(ratio);
}

View File

@@ -58,8 +58,8 @@ namespace Robust.Client.UserInterface.Controls
_lineEdit = new LineEdit
{
CustomMinimumSize = new Vector2(40, 0),
SizeFlagsHorizontal = SizeFlags.FillExpand
MinSize = new Vector2(40, 0),
HorizontalExpand = true
};
AddChild(_lineEdit);

View File

@@ -31,8 +31,9 @@ namespace Robust.Client.UserInterface.Controls
// min / max x and y extents in relative virtual pixels of where the split can go regardless
// of anything else.
private float SplitMin => SplitWidth + SplitEdgeSeparation;
private float SplitMax => Vertical ? Height - (SplitWidth + SplitEdgeSeparation) :
Width - (SplitWidth + SplitEdgeSeparation);
private float SplitMax =>
Vertical ? Height - (SplitWidth + SplitEdgeSeparation) : Width - (SplitWidth + SplitEdgeSeparation);
public SplitContainer()
{
@@ -56,11 +57,10 @@ namespace Robust.Client.UserInterface.Controls
_splitCenter = ClampSplitCenter(newOffset);
DefaultCursorShape = Vertical ? CursorShape.VResize : CursorShape.HResize;
ForceRunLayoutUpdate();
InvalidateArrange();
}
else
{
// on mouseover, check if they are over the split and change the cursor accordingly
var cursor = CursorShape.Arrow;
if (CanDragAt(args.RelativePosition))
@@ -124,37 +124,32 @@ namespace Robust.Client.UserInterface.Controls
var first = GetChild(0);
var second = GetChild(1);
firstMinSize ??= (Vertical ? first.CombinedMinimumSize.Y : first.CombinedMinimumSize.X);
secondMinSize ??= (Vertical ? second.CombinedMinimumSize.Y : second.CombinedMinimumSize.X);
firstMinSize ??= (Vertical ? first.DesiredSize.Y : first.DesiredSize.X);
secondMinSize ??= (Vertical ? second.DesiredSize.Y : second.DesiredSize.X);
var size = Vertical ? Height : Width;
splitCenter = MathHelper.Clamp(splitCenter, firstMinSize.Value, size - (secondMinSize.Value + SplitWidth));
splitCenter = MathHelper.Clamp(splitCenter, firstMinSize.Value,
size - (secondMinSize.Value + SplitWidth));
}
return splitCenter;
}
protected override void LayoutUpdateOverride()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
base.LayoutUpdateOverride();
if (ChildCount != 2)
{
return;
return finalSize;
}
var first = GetChild(0);
var second = GetChild(1);
var firstExpand = Vertical
? (first.SizeFlagsVertical & SizeFlags.Expand) != 0
: (first.SizeFlagsHorizontal & SizeFlags.Expand) != 0;
var secondExpand = Vertical
? (second.SizeFlagsVertical & SizeFlags.Expand) != 0
: (second.SizeFlagsHorizontal & SizeFlags.Expand) != 0;
var firstExpand = Vertical ? first.VerticalExpand : first.HorizontalExpand;
var secondExpand = Vertical ? second.VerticalExpand : second.HorizontalExpand;
var firstMinSize = Vertical ? first.CombinedMinimumSize.Y : first.CombinedMinimumSize.X;
var secondMinSize = Vertical ? second.CombinedMinimumSize.Y : second.CombinedMinimumSize.X;
var firstMinSize = Vertical ? first.DesiredSize.Y : first.DesiredSize.X;
var secondMinSize = Vertical ? second.DesiredSize.Y : second.DesiredSize.X;
var size = Vertical ? Height : Width;
@@ -181,24 +176,27 @@ namespace Robust.Client.UserInterface.Controls
_splitCenter = firstMinSize;
}
_splitCenter += MathHelper.Clamp(0f, firstMinSize - _splitCenter, size - secondMinSize - SplitWidth - _splitCenter);
_splitCenter += MathHelper.Clamp(0f, firstMinSize - _splitCenter,
size - secondMinSize - SplitWidth - _splitCenter);
break;
}
}
if (Vertical)
{
FitChildInBox(first, new UIBox2(0, 0, Width, _splitCenter));
FitChildInBox(second, new UIBox2(0, _splitCenter + SplitWidth, Width, Height));
first.Arrange(new UIBox2(0, 0, Width, _splitCenter));
second.Arrange(new UIBox2(0, _splitCenter + SplitWidth, Width, Height));
}
else
{
FitChildInBox(first, new UIBox2(0, 0, _splitCenter, Height));
FitChildInBox(second, new UIBox2(_splitCenter + SplitWidth, 0, Width, Height));
first.Arrange(new UIBox2(0, 0, _splitCenter, Height));
second.Arrange(new UIBox2(_splitCenter + SplitWidth, 0, Width, Height));
}
return finalSize;
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
if (ChildCount != 2)
{
@@ -208,8 +206,12 @@ namespace Robust.Client.UserInterface.Controls
var first = GetChild(0);
var second = GetChild(1);
var (firstSizeX, firstSizeY) = first.CombinedMinimumSize;
var (secondSizeX, secondSizeY) = second.CombinedMinimumSize;
// TODO: Probably bad implementation with the new WPF layout.
first.Measure(availableSize);
second.Measure(availableSize);
var (firstSizeX, firstSizeY) = first.DesiredSize;
var (secondSizeX, secondSizeY) = second.DesiredSize;
if (Vertical)
{
@@ -236,6 +238,7 @@ namespace Robust.Client.UserInterface.Controls
/// Don't allow user to move the split.
/// </summary>
NotResizable = -1,
/// <summary>
/// User can resize the split but can't shrink either child
/// beyond its minimum size.
@@ -255,6 +258,7 @@ namespace Robust.Client.UserInterface.Controls
/// Automatically adjust the split based on the width of the children
/// </summary>
Auto = 0,
/// <summary>
/// Manually adjust the split by dragging it
/// </summary>

View File

@@ -14,7 +14,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_scale = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -34,7 +34,7 @@ namespace Robust.Client.UserInterface.Controls
RectClipContent = true;
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
// TODO: make this not hardcoded.
// It'll break on larger things.

View File

@@ -47,7 +47,7 @@ namespace Robust.Client.UserInterface.Controls
GetChild(old).Visible = false;
var newSelected = GetChild(value);
newSelected.Visible = true;
_fixChildMargins(newSelected);
InvalidateMeasure();
OnTabChanged?.Invoke(value);
}
@@ -59,7 +59,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_tabsVisible = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -124,7 +124,6 @@ namespace Robust.Client.UserInterface.Controls
{
// This is our first child so it must always be visible.
newChild.Visible = true;
_fixChildMargins(newChild);
}
else
{
@@ -212,44 +211,52 @@ namespace Robust.Client.UserInterface.Controls
}
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var total = Vector2i.Zero;
var headerSize = Vector2.Zero;
if (TabsVisible)
{
headerSize = (0, _getHeaderSize() / UIScale);
}
var panel = _getPanel();
var panelSize = (panel?.MinimumSize ?? Vector2.Zero) / UIScale;
var contentsSize = availableSize - headerSize - panelSize;
var total = Vector2.Zero;
foreach (var child in Children)
{
if (child.Visible)
{
total = Vector2i.ComponentMax(child.CombinedPixelMinimumSize, total);
child.Measure(contentsSize);
total = Vector2.ComponentMax(child.DesiredSize, total);
}
}
if (TabsVisible)
{
total += (0, _getHeaderSize());
}
var panel = _getPanel();
total += (Vector2i)(panel?.MinimumSize ?? Vector2.Zero);
return total / UIScale;
return total + headerSize + panelSize;
}
private void _fixChildMargins(Control child)
{
FitChildInPixelBox(child, _getContentBox());
}
protected override void LayoutUpdateOverride()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
if (ChildCount == 0 || _currentTab >= ChildCount)
{
return;
return finalSize;
}
var headerSize = _getHeaderSize();
var panel = _getPanel();
var contentBox = new UIBox2i(0, headerSize, (int) (finalSize.X * UIScale), (int) (finalSize.Y * UIScale));
if (panel != null)
{
contentBox = (UIBox2i) panel.GetContentBox(contentBox);
}
var control = GetChild(_currentTab);
control.Visible = true;
_fixChildMargins(control);
control.ArrangePixel(contentBox);
return finalSize;
}
protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
@@ -313,19 +320,6 @@ namespace Robust.Client.UserInterface.Controls
}
}
[System.Diagnostics.Contracts.Pure]
private UIBox2i _getContentBox()
{
var headerSize = _getHeaderSize();
var panel = _getPanel();
var panelBox = new UIBox2i(0, headerSize, PixelWidth, PixelHeight);
if (panel != null)
{
return (UIBox2i) panel.GetContentBox(panelBox);
}
return panelBox;
}
[System.Diagnostics.Contracts.Pure]
private int _getHeaderSize()
{

View File

@@ -27,7 +27,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_textureNormal = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -37,7 +37,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_scale = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -78,7 +78,7 @@ namespace Robust.Client.UserInterface.Controls
handle.DrawTextureRectRegion(texture, PixelSizeBox);
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var texture = TextureNormal;

View File

@@ -32,7 +32,7 @@ namespace Robust.Client.UserInterface.Controls
if (value?.Size != oldSize)
{
MinimumSizeChanged();
InvalidateMeasure();
}
}
}
@@ -49,7 +49,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_textureScale = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -66,7 +66,7 @@ namespace Robust.Client.UserInterface.Controls
set
{
_canShrink = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -223,7 +223,7 @@ namespace Robust.Client.UserInterface.Controls
KeepAspectCovered = 8
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var texture = _texture;

View File

@@ -34,8 +34,8 @@ namespace Robust.Client.UserInterface.Controls
_scrollBar = new VScrollBar
{
Name = "_v_scroll",
SizeFlagsVertical = SizeFlags.Fill,
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
VerticalAlignment = VAlignment.Stretch,
HorizontalAlignment = HAlignment.Right
};
AddChild(_scrollBar);
}

View File

@@ -1,8 +1,10 @@
using System;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
namespace Robust.Client.UserInterface.CustomControls
{
@@ -125,34 +127,39 @@ namespace Robust.Client.UserInterface.CustomControls
}
else
{
var top = Rect.Top;
var bottom = Rect.Bottom;
var left = Rect.Left;
var right = Rect.Right;
var (minSizeX, minSizeY) = CombinedMinimumSize;
var (left, top) = Position;
var (right, bottom) = Position + SetSize;
if ((CurrentDrag & DragMode.Top) == DragMode.Top)
{
var maxY = bottom - minSizeY;
top = Math.Min(args.GlobalPosition.Y - DragOffsetTopLeft.Y, maxY);
top = Math.Min(args.GlobalPosition.Y - DragOffsetTopLeft.Y, bottom);
}
else if ((CurrentDrag & DragMode.Bottom) == DragMode.Bottom)
{
bottom = Math.Max(args.GlobalPosition.Y + DragOffsetBottomRight.Y, top + minSizeY);
bottom = Math.Max(args.GlobalPosition.Y + DragOffsetBottomRight.Y, top);
}
if ((CurrentDrag & DragMode.Left) == DragMode.Left)
{
var maxX = right - minSizeX;
left = Math.Min(args.GlobalPosition.X - DragOffsetTopLeft.X, maxX);
left = Math.Min(args.GlobalPosition.X - DragOffsetTopLeft.X, right);
}
else if ((CurrentDrag & DragMode.Right) == DragMode.Right)
{
right = Math.Max(args.GlobalPosition.X + DragOffsetBottomRight.X, left + minSizeX);
right = Math.Max(args.GlobalPosition.X + DragOffsetBottomRight.X, left);
}
var rect = new UIBox2(left, top, right, bottom);
LayoutContainer.SetPosition(this, rect.TopLeft);
LayoutContainer.SetSize(this, rect.Size);
SetSize = rect.Size;
/*
var timing = IoCManager.Resolve<IGameTiming>();
var l = GetValue<float>(LayoutContainer.MarginLeftProperty);
var t = GetValue<float>(LayoutContainer.MarginTopProperty);
Logger.Debug($"{timing.CurFrame}: {rect.TopLeft}/({l}, {t}), {rect.Size}/{SetSize}");
*/
}
}
@@ -215,7 +222,8 @@ namespace Robust.Client.UserInterface.CustomControls
{
if (_firstTimeOpened)
{
LayoutContainer.SetSize(this, CombinedMinimumSize);
Measure(Vector2.Infinity);
SetSize = DesiredSize;
Open();
// An explaination: The BadOpenGLVersionWindow was showing up off the top-left corner of the screen.
// Basically, if OpenCentered happens super-early, RootControl doesn't get time to layout children.
@@ -233,7 +241,8 @@ namespace Robust.Client.UserInterface.CustomControls
{
if (_firstTimeOpened)
{
LayoutContainer.SetSize(this, CombinedMinimumSize);
Measure(Vector2.Infinity);
SetSize = DesiredSize;
Open();
LayoutContainer.SetPosition(this, (0, (Parent!.Size.Y - Size.Y) / 2));
_firstTimeOpened = false;

View File

@@ -77,7 +77,7 @@ namespace Robust.Client.UserInterface.CustomControls
{
(Output = new OutputPanel
{
SizeFlagsVertical = SizeFlags.FillExpand,
VerticalExpand = true,
StyleBoxOverride = styleBox
}),
(CommandBar = new HistoryLineEdit {PlaceHolder = "Command Here"})

View File

@@ -27,11 +27,11 @@ namespace Robust.Client.UserInterface.CustomControls
{
IoCManager.InjectDependencies(this);
SizeFlagsHorizontal = SizeFlags.None;
HorizontalAlignment = HAlignment.Left;
_contents = new Label
{
FontColorShadowOverride = Color.Black,
FontColorShadowOverride = Color.Black
};
AddChild(_contents);
@@ -43,6 +43,7 @@ namespace Robust.Client.UserInterface.CustomControls
};
MouseFilter = _contents.MouseFilter = MouseFilterMode.Ignore;
MinWidth = 175;
}
protected override void FrameUpdate(FrameEventArgs args)
@@ -70,8 +71,10 @@ namespace Robust.Client.UserInterface.CustomControls
}
else
{
mouseGridPos = new EntityCoordinates(_mapManager.GetMapEntityId(mouseWorldMap.MapId), mouseWorldMap.Position);
tile = new TileRef(mouseWorldMap.MapId, GridId.Invalid, mouseGridPos.ToVector2i(_entityManager, _mapManager), Tile.Empty);
mouseGridPos = new EntityCoordinates(_mapManager.GetMapEntityId(mouseWorldMap.MapId),
mouseWorldMap.Position);
tile = new TileRef(mouseWorldMap.MapId, GridId.Invalid,
mouseGridPos.ToVector2i(_entityManager, _mapManager), Tile.Empty);
}
var controlHovered = UserInterfaceManager.CurrentlyHovered;
@@ -103,7 +106,8 @@ Mouse Pos:
{1}
{2}
EntId: {3}
GridID: {4}", playerScreen, playerWorldOffset, playerCoordinates, entityTransform.Owner.Uid, entityTransform.GridID);
GridID: {4}", playerScreen, playerWorldOffset, playerCoordinates, entityTransform.Owner.Uid,
entityTransform.GridID);
}
if (controlHovered != null)
@@ -112,7 +116,7 @@ Mouse Pos:
}
_contents.Text = stringBuilder.ToString();
MinimumSizeChanged();
// MinimumSizeChanged();
}
protected internal override void Draw(DrawingHandleScreen handle)
@@ -133,10 +137,5 @@ Mouse Pos:
handle.DrawRect(renderBox, Color.Red, false);
}
protected override Vector2 CalculateMinimumSize()
{
return new(175, _contents.CombinedMinimumSize.Y + 10);
}
}
}

View File

@@ -17,7 +17,7 @@ namespace Robust.Client.UserInterface.CustomControls
public DebugMemoryPanel()
{
SizeFlagsHorizontal = SizeFlags.None;
HorizontalAlignment = HAlignment.Left;
AddChild(_label = new Label());

View File

@@ -69,12 +69,12 @@ namespace Robust.Client.UserInterface.CustomControls
AddChild(_debugClydePanel = new DebugClydePanel
{
SizeFlagsHorizontal = SizeFlags.None
HorizontalAlignment = HAlignment.Left
});
AddChild(_debugInputPanel = new DebugInputPanel
{
SizeFlagsHorizontal = SizeFlags.None
HorizontalAlignment = HAlignment.Left
});
}
}

View File

@@ -26,7 +26,7 @@ namespace Robust.Client.UserInterface.CustomControls
_contents = new Label();
SizeFlagsHorizontal = SizeFlags.None;
HorizontalAlignment = HAlignment.Left;
_contents = new Label
{
@@ -62,12 +62,7 @@ namespace Robust.Client.UserInterface.CustomControls
_contents.Text = string.Join('\n', bandwidth);
MinimumSizeChanged();
}
protected override Vector2 CalculateMinimumSize()
{
return new(_contents.CombinedMinimumSize.X + 10, _contents.CombinedMinimumSize.Y + 10);
// MinimumSizeChanged();
}
}
}

View File

@@ -33,7 +33,7 @@ namespace Robust.Client.UserInterface.CustomControls
contents = new Label();
SizeFlagsHorizontal = SizeFlags.None;
HorizontalAlignment = HAlignment.Left;
contents = new Label
{
@@ -68,7 +68,6 @@ namespace Robust.Client.UserInterface.CustomControls
if (!NetManager.IsConnected)
{
contents.Text = "Not connected to server.";
MinimumSizeChanged();
return;
}
@@ -89,12 +88,7 @@ namespace Robust.Client.UserInterface.CustomControls
DOWN: {receivedBytes / ONE_KIBIBYTE:N} KiB/s, {receivedPackets} pckt/s, {LastReceivedBytes / ONE_KIBIBYTE:N} KiB, {LastReceivedPackets} pckt
PING: {NetManager.ServerChannel?.Ping ?? -1} ms";
MinimumSizeChanged();
}
protected override Vector2 CalculateMinimumSize()
{
return new(contents.CombinedMinimumSize.X + 10, contents.CombinedMinimumSize.Y + 10);
// MinimumSizeChanged();
}
}
}

View File

@@ -33,7 +33,7 @@ namespace Robust.Client.UserInterface.CustomControls
MouseFilter = _contents.MouseFilter = MouseFilterMode.Ignore;
SizeFlagsHorizontal = SizeFlags.None;
HorizontalAlignment = HAlignment.Left;
}
protected override void Update(FrameEventArgs args)
@@ -52,13 +52,6 @@ namespace Robust.Client.UserInterface.CustomControls
_contents.Text = $@"Paused: {_gameTiming.Paused}, CurTick: {_gameTiming.CurTick}/{_gameTiming.CurTick-1}, CurServerTick: {_gameState.CurServerTick}, Pred: {_gameTiming.CurTick.Value - _gameState.CurServerTick.Value-1}
CurTime: {_gameTiming.CurTime:hh\:mm\:ss\.ff}, RealTime: {_gameTiming.RealTime:hh\:mm\:ss\.ff}, CurFrame: {_gameTiming.CurFrame}
ServerTime: {_gameTiming.ServerTime}, TickTimingAdjustment: {_gameTiming.TickTimingAdjustment}";
MinimumSizeChanged();
}
protected override Vector2 CalculateMinimumSize()
{
return new(_contents.CombinedMinimumSize.X + 10, _contents.CombinedMinimumSize.Y + 10);
}
}
}

View File

@@ -27,11 +27,13 @@ namespace Robust.Client.UserInterface.CustomControls
private OptionButton OverrideMenu;
private Button ClearButton;
private Button EraseButton;
private EntitySpawnButton MeasureButton;
protected override Vector2 ContentsMinimumSize => MainVBox?.CombinedMinimumSize ?? Vector2.Zero;
//protected override Vector2 ContentsMinimumSize => MainVBox?.CombinedMinimumSize ?? Vector2.Zero;
// List of prototypes that are visible based on current filter criteria.
private readonly List<EntityPrototype> _filteredPrototypes = new();
// The indices of the visible prototypes last time UpdateVisiblePrototypes was ran.
// This is inclusive, so end is the index of the last prototype, not right after it.
private (int start, int end) _lastPrototypeIndices;
@@ -55,8 +57,6 @@ namespace Robust.Client.UserInterface.CustomControls
private EntitySpawnButton? SelectedButton;
private EntityPrototype? SelectedPrototype;
protected override Vector2? CustomSize => (250, 300);
public EntitySpawnWindow(IPlacementManager placementManager,
IPrototypeManager prototypeManager,
IResourceCache resourceCache)
@@ -67,8 +67,12 @@ namespace Robust.Client.UserInterface.CustomControls
Title = Loc.GetString("Entity Spawn Panel");
SetSize = (250, 300);
MinSize = (250, 200);
Contents.AddChild(MainVBox = new VBoxContainer
{
Name = "AAAAAA",
Children =
{
new HBoxContainer
@@ -77,7 +81,7 @@ namespace Robust.Client.UserInterface.CustomControls
{
(SearchBar = new LineEdit
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = Loc.GetString("Search")
}),
@@ -90,8 +94,8 @@ namespace Robust.Client.UserInterface.CustomControls
},
new ScrollContainer
{
CustomMinimumSize = new Vector2(200.0f, 0.0f),
SizeFlagsVertical = SizeFlags.FillExpand,
MinSize = new Vector2(200.0f, 0.0f),
VerticalExpand = true,
Children =
{
(PrototypeList = new PrototypeListContainer())
@@ -109,15 +113,24 @@ namespace Robust.Client.UserInterface.CustomControls
(OverrideMenu = new OptionButton
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
ToolTip = Loc.GetString("Override placement")
})
}
},
(MeasureButton = new EntitySpawnButton {Visible = false})
new DoNotMeasure
{
Visible = false,
Children =
{
(MeasureButton = new EntitySpawnButton())
}
}
}
});
MeasureButton.Measure(Vector2.Infinity);
for (var i = 0; i < initOpts.Length; i++)
{
OverrideMenu.AddItem(initOpts[i], i);
@@ -225,7 +238,7 @@ namespace Robust.Client.UserInterface.CustomControls
// Update visible buttons in the prototype list.
// Calculate index of first prototype to render based on current scroll.
var height = MeasureButton.CombinedMinimumSize.Y + PrototypeListContainer.Separation;
var height = MeasureButton.DesiredSize.Y + PrototypeListContainer.Separation;
var offset = -PrototypeList.Position.Y;
var startIndex = (int) Math.Floor(offset / height);
PrototypeList.ItemOffset = startIndex;
@@ -394,7 +407,7 @@ namespace Robust.Client.UserInterface.CustomControls
set
{
_totalItemCount = value;
MinimumSizeChanged();
InvalidateMeasure();
}
}
@@ -404,13 +417,13 @@ namespace Robust.Client.UserInterface.CustomControls
set
{
_itemOffset = value;
UpdateLayout();
InvalidateMeasure();
}
}
public const float Separation = 2;
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
if (ChildCount == 0)
{
@@ -419,28 +432,31 @@ namespace Robust.Client.UserInterface.CustomControls
var first = GetChild(0);
var (minX, minY) = first.CombinedMinimumSize;
first.Measure(availableSize);
var (minX, minY) = first.DesiredSize;
return (minX, minY * TotalItemCount + (TotalItemCount - 1) * Separation);
}
protected override void LayoutUpdateOverride()
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
if (ChildCount == 0)
{
return;
return Vector2.Zero;
}
var first = GetChild(0);
var height = first.CombinedMinimumSize.Y;
var height = first.DesiredSize.Y;
var offset = ItemOffset * height + (ItemOffset - 1) * Separation;
foreach (var child in Children)
{
FitChildInBox(child, UIBox2.FromDimensions(0, offset, Width, height));
child.Arrange(UIBox2.FromDimensions(0, offset, Width, height));
offset += Separation + height;
}
return finalSize;
}
}
@@ -458,8 +474,6 @@ namespace Robust.Client.UserInterface.CustomControls
{
AddChild(ActualButton = new Button
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsVertical = SizeFlags.FillExpand,
ToggleMode = true,
});
@@ -469,16 +483,16 @@ namespace Robust.Client.UserInterface.CustomControls
{
(EntityTextureRects = new LayeredTextureRect
{
CustomMinimumSize = (32, 32),
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
SizeFlagsVertical = SizeFlags.ShrinkCenter,
MinSize = (32, 32),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
Stretch = TextureRect.StretchMode.KeepAspectCentered,
CanShrink = true
}),
(EntityLabel = new Label
{
SizeFlagsVertical = SizeFlags.ShrinkCenter,
SizeFlagsHorizontal = SizeFlags.FillExpand,
VerticalAlignment = VAlignment.Center,
HorizontalExpand = true,
Text = "Backpack",
ClipText = true
})
@@ -497,5 +511,13 @@ namespace Robust.Client.UserInterface.CustomControls
EraseButton.Pressed = false;
}
private class DoNotMeasure : Control
{
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
return Vector2.Zero;
}
}
}
}

View File

@@ -39,10 +39,10 @@ namespace Robust.Client.UserInterface.CustomControls
{
_gameTiming = gameTiming;
SizeFlagsHorizontal = SizeFlags.None;
HorizontalAlignment = HAlignment.Left;
}
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
return (TrackedFrames * FrameWidth, FrameHeight * 2);
}

View File

@@ -1,17 +1,13 @@
<SS14Window xmlns="https://spacestation14.io">
<SS14Window xmlns="https://spacestation14.io" MinWidth="100" MinHeight="50">
<PanelContainer StyleClasses="windowPanel" />
<VBoxContainer SeparationOverride="0">
<PanelContainer Name="WindowHeader" StyleClasses="windowHeader">
<HBoxContainer>
<MarginContainer MarginLeftOverride="5" SizeFlagsHorizontal="FillExpand">
<Label Name="TitleLabel" StyleIdentifier="foo" ClipText="True"
Text="{Loc Exemplary Window Title Here}" VAlign="Center" StyleClasses="windowTitle" />
</MarginContainer>
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton" SizeFlagsVertical="ShrinkCenter" />
<Label Margin="5 0 0 0" HorizontalExpand="true" Name="TitleLabel" StyleIdentifier="foo" ClipText="True"
Text="{Loc Exemplary Window Title Here}" VAlign="Center" StyleClasses="windowTitle" />
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton" VerticalAlignment="Center" />
</HBoxContainer>
</PanelContainer>
<MarginContainer Name="ContentsContainer" MarginBottomOverride="10" MarginLeftOverride="10"
MarginRightOverride="10" MarginTopOverride="10" RectClipContent="True"
SizeFlagsVertical="FillExpand" />
<Control Name="ContentsContainer" Margin="10" RectClipContent="True" VerticalExpand="true" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Robust.Client.AutoGenerated;
@@ -18,6 +19,7 @@ namespace Robust.Client.UserInterface.CustomControls
public const string StyleClassWindowHeader = "windowHeader";
public const string StyleClassWindowCloseButton = "windowCloseButton";
[Obsolete("Set SetSize instead.")]
protected virtual Vector2? CustomSize => null;
public SS14Window()
@@ -25,7 +27,7 @@ namespace Robust.Client.UserInterface.CustomControls
RobustXamlLoader.Load(this);
MouseFilter = MouseFilterMode.Stop;
WindowHeader.CustomMinimumSize = (0, HEADER_SIZE_Y);
WindowHeader.MinSize = (0, HEADER_SIZE_Y);
Contents = ContentsContainer;
@@ -33,7 +35,7 @@ namespace Robust.Client.UserInterface.CustomControls
XamlChildren = new SS14ContentCollection(this);
}
public MarginContainer Contents { get; private set; }
public Control Contents { get; private set; }
//private TextureButton CloseButton;
private const int DRAG_MARGIN_SIZE = 7;
@@ -42,19 +44,24 @@ namespace Robust.Client.UserInterface.CustomControls
private const float HEADER_SIZE_Y = 25;
protected virtual Vector2 ContentsMinimumSize => (50, 50);
protected override Vector2 CalculateMinimumSize()
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
return Vector2.ComponentMax(ContentsMinimumSize, base.CalculateMinimumSize());
return Vector2.ComponentMax(
ContentsMinimumSize,
base.MeasureOverride(Vector2.ComponentMax(availableSize, ContentsMinimumSize)));
}
protected override void Opened()
{
base.Opened();
#pragma warning disable 618
if (_firstTimeOpened && CustomSize != null)
{
LayoutContainer.SetSize(this, CustomSize.Value);
SetSize = CustomSize.Value;
}
#pragma warning restore 618
}
//private Label TitleLabel;

View File

@@ -26,12 +26,9 @@ namespace Robust.Client.UserInterface.CustomControls
},
Children =
{
(OutputPanel = new OutputPanel
{
SizeFlagsVertical = SizeFlags.FillExpand,
})
(OutputPanel = new OutputPanel())
},
SizeFlagsVertical = SizeFlags.FillExpand
VerticalExpand = true,
},
new HBoxContainer
{
@@ -39,7 +36,7 @@ namespace Robust.Client.UserInterface.CustomControls
{
(InputBar = new HistoryLineEdit
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = Loc.GetString("Your C# code here.")
}),
(RunButton = new Button {Text = Loc.GetString("Run")})
@@ -50,7 +47,7 @@ namespace Robust.Client.UserInterface.CustomControls
InputBar.OnTextEntered += _ => Run();
RunButton.OnPressed += _ => Run();
CustomMinimumSize = (550, 300);
MinSize = (550, 300);
}
protected abstract void Run();

View File

@@ -25,8 +25,6 @@ namespace Robust.Client.UserInterface.CustomControls
private bool _clearingSelections;
protected override Vector2? CustomSize => (300, 300);
public TileSpawnWindow(ITileDefinitionManager tileDefinitionManager, IPlacementManager placementManager,
IResourceCache resourceCache)
{
@@ -38,7 +36,7 @@ namespace Robust.Client.UserInterface.CustomControls
Contents.AddChild(vBox);
var hBox = new HBoxContainer();
vBox.AddChild(hBox);
SearchBar = new LineEdit {PlaceHolder = "Search", SizeFlagsHorizontal = SizeFlags.FillExpand};
SearchBar = new LineEdit {PlaceHolder = "Search", HorizontalExpand = true};
SearchBar.OnTextChanged += OnSearchBarTextChanged;
hBox.AddChild(SearchBar);
@@ -46,7 +44,7 @@ namespace Robust.Client.UserInterface.CustomControls
ClearButton.OnPressed += OnClearButtonPressed;
hBox.AddChild(ClearButton);
TileList = new ItemList {SizeFlagsVertical = SizeFlags.FillExpand};
TileList = new ItemList {VerticalExpand = true};
TileList.OnItemSelected += TileListOnOnItemSelected;
TileList.OnItemDeselected += TileListOnOnItemDeselected;
vBox.AddChild(TileList);
@@ -57,6 +55,8 @@ namespace Robust.Client.UserInterface.CustomControls
Title = "Place Tiles";
SearchBar.GrabKeyboardFocus();
SetSize = (300, 300);
}
protected override void Dispose(bool disposing)

View File

@@ -45,7 +45,8 @@ namespace Robust.Client.UserInterface
void Render(IRenderHandle renderHandle);
void QueueStyleUpdate(Control control);
void QueueLayoutUpdate(Control control);
void QueueMeasureUpdate(Control control);
void QueueArrangeUpdate(Control control);
void CursorChanged(Control control);
/// <summary>
/// Hides the tooltip for the indicated control, if tooltip for that control is currently showing.

View File

@@ -39,7 +39,8 @@ namespace Robust.Client.UserInterface
{
LayoutContainer.SetPosition(tooltip, screenPosition);
var combinedMinSize = tooltip.CombinedMinimumSize;
tooltip.Measure(Vector2.Infinity);
var combinedMinSize = tooltip.DesiredSize;
var (right, bottom) = tooltip.Position + combinedMinSize;
if (right > screenBounds.X)

View File

@@ -17,6 +17,7 @@ using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
namespace Robust.Client.UserInterface
{
@@ -34,9 +35,9 @@ namespace Robust.Client.UserInterface
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
public UITheme ThemeDefaults { get; private set; } = default!;
[ViewVariables] public UITheme ThemeDefaults { get; private set; } = default!;
public Stylesheet? Stylesheet
[ViewVariables] public Stylesheet? Stylesheet
{
get => _stylesheet;
set
@@ -50,26 +51,28 @@ namespace Robust.Client.UserInterface
}
}
public Control? KeyboardFocused { get; private set; }
[ViewVariables] public Control? KeyboardFocused { get; private set; }
public Control? ControlFocused { get; private set; }
[ViewVariables] public Control? ControlFocused { get; private set; }
public LayoutContainer StateRoot { get; private set; } = default!;
public PopupContainer ModalRoot { get; private set; } = default!;
public Control? CurrentlyHovered { get; private set; } = default!;
public float UIScale { get; private set; } = 1;
public float DefaultUIScale => _displayManager.DefaultWindowScale.X;
public Control RootControl { get; private set; } = default!;
public LayoutContainer WindowRoot { get; private set; } = default!;
public LayoutContainer PopupRoot { get; private set; } = default!;
public DebugConsole DebugConsole { get; private set; } = default!;
public IDebugMonitors DebugMonitors => _debugMonitors;
[ViewVariables] public LayoutContainer StateRoot { get; private set; } = default!;
[ViewVariables] public PopupContainer ModalRoot { get; private set; } = default!;
[ViewVariables] public Control? CurrentlyHovered { get; private set; } = default!;
[ViewVariables] public float UIScale { get; private set; } = 1;
[ViewVariables] public float DefaultUIScale => _displayManager.DefaultWindowScale.X;
[ViewVariables] public Control RootControl { get; private set; } = default!;
[ViewVariables] public LayoutContainer WindowRoot { get; private set; } = default!;
[ViewVariables] public LayoutContainer PopupRoot { get; private set; } = default!;
[ViewVariables] public DebugConsole DebugConsole { get; private set; } = default!;
[ViewVariables] public IDebugMonitors DebugMonitors => _debugMonitors;
private DebugMonitors _debugMonitors = default!;
private readonly List<Control> _modalStack = new();
private bool _rendering = true;
private float _tooltipTimer;
// set to null when not counting down
private float? _tooltipDelay;
private Tooltip _tooltip = default!;
@@ -78,7 +81,8 @@ namespace Robust.Client.UserInterface
private const float TooltipDelay = 1;
private readonly Queue<Control> _styleUpdateQueue = new();
private readonly Queue<Control> _layoutUpdateQueue = new();
private readonly Queue<Control> _measureUpdateQueue = new();
private readonly Queue<Control> _arrangeUpdateQueue = new();
private Stylesheet? _stylesheet;
private ICursor? _worldCursor;
private bool _needUpdateActiveCursor;
@@ -120,9 +124,14 @@ namespace Robust.Client.UserInterface
{
Name = "UIRoot",
MouseFilter = Control.MouseFilterMode.Ignore,
HorizontalAlignment = Control.HAlignment.Stretch,
VerticalAlignment = Control.VAlignment.Stretch,
IsInsideTree = true
};
RootControl.Size = _displayManager.ScreenSize / UIScale;
RootControl.InvalidateMeasure();
QueueMeasureUpdate(RootControl);
_displayManager.OnWindowResized += args => _updateRootSize();
StateRoot = new LayoutContainer
@@ -192,16 +201,28 @@ namespace Robust.Client.UserInterface
control.DoStyleUpdate();
}
while (_layoutUpdateQueue.Count != 0)
while (_measureUpdateQueue.Count != 0)
{
var control = _layoutUpdateQueue.Dequeue();
var control = _measureUpdateQueue.Dequeue();
if (control.Disposed)
{
continue;
}
control.DoLayoutUpdate();
RunMeasure(control);
}
while (_arrangeUpdateQueue.Count != 0)
{
var control = _arrangeUpdateQueue.Dequeue();
if (control.Disposed)
{
continue;
}
RunArrange(control);
}
// count down tooltip delay if we're not showing one yet and
@@ -222,6 +243,46 @@ namespace Robust.Client.UserInterface
}
}
private void RunMeasure(Control control)
{
if (control.IsMeasureValid || !control.IsInsideTree)
return;
if (control.Parent != null)
{
RunMeasure(control.Parent);
}
if (control == RootControl)
{
control.Measure(_displayManager.ScreenSize / 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 == RootControl)
{
control.Arrange(UIBox2.FromDimensions(Vector2.Zero, _displayManager.ScreenSize / UIScale));
}
else if (control.PreviousArrange.HasValue)
{
control.Arrange(control.PreviousArrange.Value);
}
}
public bool HandleCanFocusDown(Vector2 pointerPosition)
{
var control = MouseGetControl(pointerPosition);
@@ -254,6 +315,7 @@ namespace Robust.Client.UserInterface
{
return false;
}
ControlFocused?.ControlFocusExited();
ControlFocused = control;
@@ -441,6 +503,7 @@ namespace Robust.Client.UserInterface
}
public Vector2 MousePositionScaled => ScreenToUIPosition(_inputManager.MouseScreenPosition);
public Vector2 ScreenToUIPosition(Vector2 position)
{
return position / UIScale;
@@ -556,9 +619,15 @@ namespace Robust.Client.UserInterface
_styleUpdateQueue.Enqueue(control);
}
public void QueueLayoutUpdate(Control control)
public void QueueMeasureUpdate(Control control)
{
_layoutUpdateQueue.Enqueue(control);
_measureUpdateQueue.Enqueue(control);
_arrangeUpdateQueue.Enqueue(control);
}
public void QueueArrangeUpdate(Control control)
{
_arrangeUpdateQueue.Enqueue(control);
}
public void CursorChanged(Control control)
@@ -711,6 +780,7 @@ namespace Robust.Client.UserInterface
PopupRoot.RemoveChild(_suppliedTooltip);
_suppliedTooltip = null;
}
CurrentlyHovered?.PerformHideTooltip();
_resetTooltipTimer();
showingTooltip = false;
@@ -760,7 +830,7 @@ namespace Robust.Client.UserInterface
// show simple tooltip if there is one
_tooltip.Visible = true;
_tooltip.Text = hovered.ToolTip;
Tooltips.PositionTooltip(_tooltip);
Tooltips.PositionTooltip(_tooltip);
}
hovered.PerformShowTooltip();
@@ -791,7 +861,7 @@ namespace Robust.Client.UserInterface
private void _updateRootSize()
{
RootControl.Size = _displayManager.ScreenSize / UIScale;
RootControl.InvalidateMeasure();
}
/// <summary>
@@ -813,6 +883,7 @@ namespace Robust.Client.UserInterface
{
return true;
}
return false;
}
}

View File

@@ -11,14 +11,14 @@ namespace Robust.Client.ViewVariables.Editors
{
var hBox = new HBoxContainer
{
CustomMinimumSize = new Vector2(200, 0)
MinSize = new Vector2(200, 0)
};
var angle = (Angle) value!;
var lineEdit = new LineEdit
{
Text = angle.Degrees.ToString(CultureInfo.InvariantCulture),
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand
HorizontalExpand = true
};
if (!ReadOnly)
{

View File

@@ -13,7 +13,7 @@ namespace Robust.Client.ViewVariables.Editors
Pressed = (bool)value!,
Disabled = ReadOnly,
Text = value!.ToString()!,
CustomMinimumSize = new Vector2(70, 0)
MinSize = new Vector2(70, 0)
};
if (!ReadOnly)
{

View File

@@ -12,7 +12,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = ((Color)value!).ToHex(),
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
ToolTip = "Hex color here",
PlaceHolder = "Hex color here"
};

View File

@@ -20,7 +20,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = value == null ? "null" : value.ToString() ?? "<null ToString()>",
Align = Label.AlignMode.Right,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true
};
}
}

View File

@@ -15,17 +15,17 @@ namespace Robust.Client.ViewVariables.Editors
var coords = (EntityCoordinates) value!;
var hBoxContainer = new HBoxContainer
{
CustomMinimumSize = new Vector2(240, 0),
MinSize = new Vector2(240, 0),
};
hBoxContainer.AddChild(new Label {Text = "grid: "});
var entityManager = IoCManager.Resolve<IEntityManager>();
var gridId = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "Grid ID",
ToolTip = "Grid ID",
Text = coords.GetGridId(entityManager).ToString()
@@ -38,7 +38,7 @@ namespace Robust.Client.ViewVariables.Editors
var x = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "X",
ToolTip = "X",
Text = coords.X.ToString(CultureInfo.InvariantCulture)
@@ -49,7 +49,7 @@ namespace Robust.Client.ViewVariables.Editors
var y = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "Y",
ToolTip = "Y",
Text = coords.Y.ToString(CultureInfo.InvariantCulture)
@@ -63,7 +63,7 @@ namespace Robust.Client.ViewVariables.Editors
var mapManager = IoCManager.Resolve<IMapManager>();
var xVal = float.Parse(x.Text, CultureInfo.InvariantCulture);
var yVal = float.Parse(y.Text, CultureInfo.InvariantCulture);
if (!mapManager.TryGetGrid(new GridId(gridVal), out var grid))
{
ValueChanged(new EntityCoordinates(EntityUid.Invalid, (xVal, yVal)));

View File

@@ -11,7 +11,7 @@ namespace Robust.Client.ViewVariables.Editors
{
var hBox = new HBoxContainer
{
CustomMinimumSize = new Vector2(200, 0)
MinSize = new Vector2(200, 0)
};
var uid = (EntityUid)value!;
@@ -19,7 +19,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = uid.ToString(),
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand
HorizontalExpand = true,
};
if (!ReadOnly)
{

View File

@@ -13,7 +13,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = ((ISelfSerialize)value!).Serialize(),
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
};
if (!ReadOnly)

View File

@@ -22,7 +22,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = NumberToText(value!),
Editable = !ReadOnly,
CustomMinimumSize = new Vector2(240, 0)
MinSize = new Vector2(240, 0)
};
lineEdit.OnTextEntered += e =>
{

View File

@@ -28,7 +28,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = $"Ref: {toString}",
ClipText = true,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand
HorizontalExpand = true,
};
button.OnPressed += ButtonOnOnPressed;
return button;

View File

@@ -11,7 +11,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = (string) value!,
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
};
if (!ReadOnly)

View File

@@ -13,7 +13,7 @@ namespace Robust.Client.ViewVariables.Editors
{
Text = ts.ToString(),
Editable = !ReadOnly,
CustomMinimumSize = (240, 0)
MinSize = (240, 0)
};
lineEdit.OnTextEntered += e =>

View File

@@ -19,13 +19,13 @@ namespace Robust.Client.ViewVariables.Editors
{
var hBoxContainer = new HBoxContainer
{
CustomMinimumSize = new Vector2(200, 0),
MinSize = new Vector2(200, 0),
};
var left = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "Left",
ToolTip = "Left"
};
@@ -33,7 +33,7 @@ namespace Robust.Client.ViewVariables.Editors
var top = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "Top",
ToolTip = "Top"
};
@@ -41,7 +41,7 @@ namespace Robust.Client.ViewVariables.Editors
var right = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "Right",
ToolTip = "Right"
};
@@ -49,7 +49,7 @@ namespace Robust.Client.ViewVariables.Editors
var bottom = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "Bottom",
ToolTip = "Bottom"
};

View File

@@ -18,13 +18,13 @@ namespace Robust.Client.ViewVariables.Editors
{
var hBoxContainer = new HBoxContainer
{
CustomMinimumSize = new Vector2(240, 0),
MinSize = new Vector2(240, 0),
};
var x = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "X",
ToolTip = "X"
};
@@ -34,7 +34,7 @@ namespace Robust.Client.ViewVariables.Editors
var y = new LineEdit
{
Editable = !ReadOnly,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
HorizontalExpand = true,
PlaceHolder = "Y",
ToolTip = "Y"
};

View File

@@ -73,11 +73,7 @@ namespace Robust.Client.ViewVariables.Instances
var scrollContainer = new ScrollContainer();
//scrollContainer.SetAnchorPreset(Control.LayoutPreset.Wide, true);
window.Contents.AddChild(scrollContainer);
var vBoxContainer = new VBoxContainer
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsVertical = SizeFlags.FillExpand,
};
var vBoxContainer = new VBoxContainer();
scrollContainer.AddChild(vBoxContainer);
// Handle top bar displaying type and ToString().
@@ -107,7 +103,7 @@ namespace Robust.Client.ViewVariables.Instances
if (_entity.TryGetComponent(out ISpriteComponent? sprite))
{
var hBox = new HBoxContainer();
top.SizeFlagsHorizontal = SizeFlags.FillExpand;
top.HorizontalExpand = true;
hBox.AddChild(top);
hBox.AddChild(new SpriteView {Sprite = sprite});
vBoxContainer.AddChild(hBox);
@@ -167,13 +163,13 @@ namespace Robust.Client.ViewVariables.Instances
_clientComponents.AddChild(_clientComponentsSearchBar = new LineEdit
{
PlaceHolder = Loc.GetString("Search"),
SizeFlagsHorizontal = SizeFlags.FillExpand
HorizontalExpand = true,
});
_clientComponents.AddChild(_clientComponentsAddButton = new Button()
{
Text = Loc.GetString("Add Component"),
SizeFlagsHorizontal = SizeFlags.FillExpand
HorizontalExpand = true,
});
_clientComponentsAddButton.OnPressed += OnClientComponentsAddButtonPressed;
@@ -187,7 +183,7 @@ namespace Robust.Client.ViewVariables.Instances
var removeButton = new TextureButton()
{
StyleClasses = { SS14Window.StyleClassWindowCloseButton },
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
HorizontalAlignment = HAlignment.Right
};
button.OnPressed += _ => ViewVariablesManager.OpenVV(component);
removeButton.OnPressed += _ => RemoveClientComponent(component);
@@ -203,13 +199,13 @@ namespace Robust.Client.ViewVariables.Instances
_serverComponents.AddChild(_serverComponentsSearchBar = new LineEdit
{
PlaceHolder = Loc.GetString("Search"),
SizeFlagsHorizontal = SizeFlags.FillExpand
HorizontalExpand = true,
});
_serverComponents.AddChild(_serverComponentsAddButton = new Button()
{
Text = Loc.GetString("Add Component"),
SizeFlagsHorizontal = SizeFlags.FillExpand
HorizontalExpand = true,
});
_serverComponentsSearchBar.OnTextChanged += OnServerComponentsSearchBarChanged;
@@ -238,7 +234,7 @@ namespace Robust.Client.ViewVariables.Instances
var removeButton = new TextureButton()
{
StyleClasses = { SS14Window.StyleClassWindowCloseButton },
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
HorizontalAlignment = HAlignment.Right
};
button.OnPressed += _ =>
{

Some files were not shown because too many files have changed in this diff Show More