diff --git a/Content.Client/Access/UI/AccessLevelControl.xaml b/Content.Client/Access/UI/AccessLevelControl.xaml
new file mode 100644
index 00000000000..56968d89839
--- /dev/null
+++ b/Content.Client/Access/UI/AccessLevelControl.xaml
@@ -0,0 +1,4 @@
+
+
diff --git a/Content.Client/Access/UI/AccessLevelControl.xaml.cs b/Content.Client/Access/UI/AccessLevelControl.xaml.cs
new file mode 100644
index 00000000000..34db80b7af9
--- /dev/null
+++ b/Content.Client/Access/UI/AccessLevelControl.xaml.cs
@@ -0,0 +1,52 @@
+using System.Linq;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+using Content.Shared.Access;
+using Content.Shared.Access.Systems;
+
+namespace Content.Client.Access.UI;
+
+[GenerateTypedNameReferences]
+public sealed partial class AccessLevelControl : GridContainer
+{
+ public readonly Dictionary, Button> ButtonsList = new();
+
+ public AccessLevelControl()
+ {
+ RobustXamlLoader.Load(this);
+ }
+
+ public void Populate(List> accessLevels, IPrototypeManager prototypeManager)
+ {
+ foreach (var access in accessLevels)
+ {
+ if (!prototypeManager.TryIndex(access, out var accessLevel))
+ {
+ Logger.Error($"Unable to find accesslevel for {access}");
+ continue;
+ }
+
+ var newButton = new Button
+ {
+ Text = accessLevel.GetAccessLevelName(),
+ ToggleMode = true,
+ };
+ AddChild(newButton);
+ ButtonsList.Add(accessLevel.ID, newButton);
+ }
+ }
+
+ public void UpdateState(
+ List> pressedList,
+ List>? enabledList = null)
+ {
+ foreach (var (accessName, button) in ButtonsList)
+ {
+ button.Pressed = pressedList.Contains(accessName);
+ button.Disabled = !(enabledList?.Contains(accessName) ?? true);
+ }
+ }
+}
diff --git a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs
index 0c23542f798..c1b63dc4d05 100644
--- a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs
+++ b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs
@@ -64,7 +64,7 @@ protected override void UpdateState(BoundUserInterfaceState state)
_window?.UpdateState(castState);
}
- public void SubmitData(List newAccessList)
+ public void SubmitData(List> newAccessList)
{
SendMessage(new WriteToTargetAccessReaderIdMessage(newAccessList));
}
diff --git a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs
index 2fd00571215..6025c3b551f 100644
--- a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs
+++ b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs
@@ -16,7 +16,6 @@ public sealed partial class AccessOverriderWindow : DefaultWindow
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- private readonly ISawmill _logMill = default!;
private readonly AccessOverriderBoundUserInterface _owner;
private readonly Dictionary _accessButtons = new();
@@ -25,7 +24,7 @@ public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototype
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
- _logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill);
+ var logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill);
_owner = owner;
@@ -33,13 +32,13 @@ public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototype
{
if (!prototypeManager.TryIndex(access, out var accessLevel))
{
- _logMill.Error($"Unable to find accesslevel for {access}");
+ logMill.Error($"Unable to find accesslevel for {access}");
continue;
}
var newButton = new Button
{
- Text = GetAccessLevelName(accessLevel),
+ Text = accessLevel.GetAccessLevelName(),
ToggleMode = true,
};
@@ -49,14 +48,6 @@ public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototype
}
}
- private static string GetAccessLevelName(AccessLevelPrototype prototype)
- {
- if (prototype.Name is { } name)
- return Loc.GetString(name);
-
- return prototype.ID;
- }
-
public void UpdateState(AccessOverriderBoundUserInterfaceState state)
{
PrivilegedIdLabel.Text = state.PrivilegedIdName;
@@ -105,7 +96,7 @@ private void SubmitData()
_owner.SubmitData(
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
- _accessButtons.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
+ _accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId(x.Key)).ToList());
}
}
}
diff --git a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs
index 898792aa030..5b7011c195a 100644
--- a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs
+++ b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs
@@ -1,5 +1,6 @@
using Content.Shared.Access;
using Content.Shared.Access.Components;
+using Content.Shared.Access;
using Content.Shared.Access.Systems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.CrewManifest;
@@ -28,7 +29,6 @@ protected override void Open()
if (EntMan.TryGetComponent(Owner, out var idCard))
{
accessLevels = idCard.AccessLevels;
- accessLevels.Sort();
}
else
{
@@ -65,7 +65,7 @@ protected override void UpdateState(BoundUserInterfaceState state)
_window?.UpdateState(castState);
}
- public void SubmitData(string newFullName, string newJobTitle, List newAccessList, string newJobPrototype)
+ public void SubmitData(string newFullName, string newJobTitle, List> newAccessList, string newJobPrototype)
{
if (newFullName.Length > MaxFullNameLength)
newFullName = newFullName[..MaxFullNameLength];
diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml b/Content.Client/Access/UI/IdCardConsoleWindow.xaml
index c29adc8ebd3..a2f5f3382bb 100644
--- a/Content.Client/Access/UI/IdCardConsoleWindow.xaml
+++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml
@@ -30,10 +30,6 @@
-
-
-
-
-
+
diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
index bf5984e8096..298912e7d53 100644
--- a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
+++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
@@ -20,7 +20,7 @@ public sealed partial class IdCardConsoleWindow : DefaultWindow
private readonly IdCardConsoleBoundUserInterface _owner;
- private readonly Dictionary _accessButtons = new();
+ private AccessLevelControl _accessButtons = new();
private readonly List _jobPrototypeIds = new();
private string? _lastFullName;
@@ -66,36 +66,18 @@ public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, IPrototypeMana
JobPresetOptionButton.OnItemSelected += SelectJobPreset;
- foreach (var access in accessLevels)
- {
- if (!prototypeManager.TryIndex(access, out var accessLevel))
- {
- _logMill.Error($"Unable to find accesslevel for {access}");
- continue;
- }
+ _accessButtons.Populate(accessLevels, prototypeManager);
+ AccessLevelControlContainer.AddChild(_accessButtons);
- var newButton = new Button
- {
- Text = GetAccessLevelName(accessLevel),
- ToggleMode = true,
- };
- AccessLevelGrid.AddChild(newButton);
- _accessButtons.Add(accessLevel.ID, newButton);
- newButton.OnPressed += _ => SubmitData();
+ foreach (var (id, button) in _accessButtons.ButtonsList)
+ {
+ button.OnPressed += _ => SubmitData();
}
}
- private static string GetAccessLevelName(AccessLevelPrototype prototype)
- {
- if (prototype.Name is { } name)
- return Loc.GetString(name);
-
- return prototype.ID;
- }
-
private void ClearAllAccess()
{
- foreach (var button in _accessButtons.Values)
+ foreach (var button in _accessButtons.ButtonsList.Values)
{
if (button.Pressed)
{
@@ -119,7 +101,7 @@ private void SelectJobPreset(OptionButton.ItemSelectedEventArgs args)
// this is a sussy way to do this
foreach (var access in job.Access)
{
- if (_accessButtons.TryGetValue(access, out var button) && !button.Disabled)
+ if (_accessButtons.ButtonsList.TryGetValue(access, out var button) && !button.Disabled)
{
button.Pressed = true;
}
@@ -134,7 +116,7 @@ private void SelectJobPreset(OptionButton.ItemSelectedEventArgs args)
foreach (var access in groupPrototype.Tags)
{
- if (_accessButtons.TryGetValue(access, out var button) && !button.Disabled)
+ if (_accessButtons.ButtonsList.TryGetValue(access, out var button) && !button.Disabled)
{
button.Pressed = true;
}
@@ -184,15 +166,10 @@ public void UpdateState(IdCardConsoleBoundUserInterfaceState state)
JobPresetOptionButton.Disabled = !interfaceEnabled;
- foreach (var (accessName, button) in _accessButtons)
- {
- button.Disabled = !interfaceEnabled;
- if (interfaceEnabled)
- {
- button.Pressed = state.TargetIdAccessList?.Contains(accessName) ?? false;
- button.Disabled = (!state.AllowedModifyAccessList?.Contains(accessName)) ?? true;
- }
- }
+ _accessButtons.UpdateState(state.TargetIdAccessList?.ToList() ??
+ new List>(),
+ state.AllowedModifyAccessList?.ToList() ??
+ new List>());
var jobIndex = _jobPrototypeIds.IndexOf(state.TargetIdJobPrototype);
if (jobIndex >= 0)
@@ -215,7 +192,7 @@ private void SubmitData()
FullNameLineEdit.Text,
JobTitleLineEdit.Text,
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
- _accessButtons.Where(x => x.Value.Pressed).Select(x => x.Key).ToList(),
+ _accessButtons.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList(),
jobProtoDirty ? _jobPrototypeIds[JobPresetOptionButton.SelectedId] : string.Empty);
}
}
diff --git a/Content.Client/Anomaly/Ui/AnomalyScannerMenu.xaml b/Content.Client/Anomaly/Ui/AnomalyScannerMenu.xaml
index ac4adf7e0e4..36a750d0098 100644
--- a/Content.Client/Anomaly/Ui/AnomalyScannerMenu.xaml
+++ b/Content.Client/Anomaly/Ui/AnomalyScannerMenu.xaml
@@ -1,9 +1,9 @@
-
+ MinSize="350 400"
+ SetSize="350 400">
diff --git a/Content.Client/Chemistry/Components/HyposprayComponent.cs b/Content.Client/Chemistry/Components/HyposprayComponent.cs
deleted file mode 100644
index 705b79ad84c..00000000000
--- a/Content.Client/Chemistry/Components/HyposprayComponent.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Content.Shared.Chemistry.Components;
-using Content.Shared.FixedPoint;
-
-namespace Content.Client.Chemistry.Components
-{
- [RegisterComponent]
- public sealed partial class HyposprayComponent : SharedHyposprayComponent
- {
- [ViewVariables]
- public FixedPoint2 CurrentVolume;
- [ViewVariables]
- public FixedPoint2 TotalVolume;
- [ViewVariables(VVAccess.ReadWrite)]
- public bool UiUpdateNeeded;
- }
-}
diff --git a/Content.Client/Chemistry/EntitySystems/HypospraySystem.cs b/Content.Client/Chemistry/EntitySystems/HypospraySystem.cs
new file mode 100644
index 00000000000..ee7aa3aafe3
--- /dev/null
+++ b/Content.Client/Chemistry/EntitySystems/HypospraySystem.cs
@@ -0,0 +1,15 @@
+using Content.Client.Chemistry.UI;
+using Content.Client.Items;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+
+namespace Content.Client.Chemistry.EntitySystems;
+
+public sealed class HypospraySystem : SharedHypospraySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+ Subs.ItemStatus(ent => new HyposprayStatusControl(ent, _solutionContainers));
+ }
+}
diff --git a/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs
index 12eb7f3d14d..0131a283c8c 100644
--- a/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs
+++ b/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs
@@ -1,4 +1,3 @@
-using Content.Client.Chemistry.Components;
using Content.Client.Chemistry.UI;
using Content.Client.Items;
using Content.Shared.Chemistry.Components;
@@ -13,17 +12,5 @@ public override void Initialize()
{
base.Initialize();
Subs.ItemStatus(ent => new InjectorStatusControl(ent, SolutionContainers));
- SubscribeLocalEvent(OnHandleHyposprayState);
- Subs.ItemStatus(ent => new HyposprayStatusControl(ent));
- }
-
- private void OnHandleHyposprayState(EntityUid uid, HyposprayComponent component, ref ComponentHandleState args)
- {
- if (args.Current is not HyposprayComponentState cState)
- return;
-
- component.CurrentVolume = cState.CurVolume;
- component.TotalVolume = cState.MaxVolume;
- component.UiUpdateNeeded = true;
}
}
diff --git a/Content.Client/Chemistry/UI/HyposprayStatusControl.cs b/Content.Client/Chemistry/UI/HyposprayStatusControl.cs
index bd85cd546cc..4a4d90dc4d5 100644
--- a/Content.Client/Chemistry/UI/HyposprayStatusControl.cs
+++ b/Content.Client/Chemistry/UI/HyposprayStatusControl.cs
@@ -1,6 +1,8 @@
-using Content.Client.Chemistry.Components;
using Content.Client.Message;
using Content.Client.Stylesheets;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.FixedPoint;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
@@ -9,34 +11,48 @@ namespace Content.Client.Chemistry.UI;
public sealed class HyposprayStatusControl : Control
{
- private readonly HyposprayComponent _parent;
+ private readonly Entity _parent;
private readonly RichTextLabel _label;
+ private readonly SharedSolutionContainerSystem _solutionContainers;
- public HyposprayStatusControl(HyposprayComponent parent)
+ private FixedPoint2 PrevVolume;
+ private FixedPoint2 PrevMaxVolume;
+ private bool PrevOnlyAffectsMobs;
+
+ public HyposprayStatusControl(Entity parent, SharedSolutionContainerSystem solutionContainers)
{
_parent = parent;
- _label = new RichTextLabel {StyleClasses = {StyleNano.StyleClassItemStatus}};
+ _solutionContainers = solutionContainers;
+ _label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
AddChild(_label);
-
- Update();
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
- if (!_parent.UiUpdateNeeded)
+
+ if (!_solutionContainers.TryGetSolution(_parent.Owner, _parent.Comp.SolutionName, out _, out var solution))
return;
- Update();
- }
- public void Update()
- {
+ // only updates the UI if any of the details are different than they previously were
+ if (PrevVolume == solution.Volume
+ && PrevMaxVolume == solution.MaxVolume
+ && PrevOnlyAffectsMobs == _parent.Comp.OnlyAffectsMobs)
+ return;
+
+ PrevVolume = solution.Volume;
+ PrevMaxVolume = solution.MaxVolume;
+ PrevOnlyAffectsMobs = _parent.Comp.OnlyAffectsMobs;
- _parent.UiUpdateNeeded = false;
+ var modeStringLocalized = Loc.GetString(_parent.Comp.OnlyAffectsMobs switch
+ {
+ false => "hypospray-all-mode-text",
+ true => "hypospray-mobs-only-mode-text",
+ });
- _label.SetMarkup(Loc.GetString(
- "hypospray-volume-text",
- ("currentVolume", _parent.CurrentVolume),
- ("totalVolume", _parent.TotalVolume)));
+ _label.SetMarkup(Loc.GetString("hypospray-volume-label",
+ ("currentVolume", solution.Volume),
+ ("totalVolume", solution.MaxVolume),
+ ("modeString", modeStringLocalized)));
}
}
diff --git a/Content.Client/Chemistry/UI/InjectorStatusControl.cs b/Content.Client/Chemistry/UI/InjectorStatusControl.cs
index 9cb699330c2..ba1f97cd1e4 100644
--- a/Content.Client/Chemistry/UI/InjectorStatusControl.cs
+++ b/Content.Client/Chemistry/UI/InjectorStatusControl.cs
@@ -17,6 +17,7 @@ public sealed class InjectorStatusControl : Control
private FixedPoint2 PrevVolume;
private FixedPoint2 PrevMaxVolume;
+ private FixedPoint2 PrevTransferAmount;
private InjectorToggleMode PrevToggleState;
public InjectorStatusControl(Entity parent, SharedSolutionContainerSystem solutionContainers)
@@ -37,11 +38,13 @@ protected override void FrameUpdate(FrameEventArgs args)
// only updates the UI if any of the details are different than they previously were
if (PrevVolume == solution.Volume
&& PrevMaxVolume == solution.MaxVolume
+ && PrevTransferAmount == _parent.Comp.TransferAmount
&& PrevToggleState == _parent.Comp.ToggleState)
return;
PrevVolume = solution.Volume;
PrevMaxVolume = solution.MaxVolume;
+ PrevTransferAmount = _parent.Comp.TransferAmount;
PrevToggleState = _parent.Comp.ToggleState;
// Update current volume and injector state
diff --git a/Content.Client/Disposal/Systems/DisposalUnitSystem.cs b/Content.Client/Disposal/Systems/DisposalUnitSystem.cs
index 8c40c784219..b9e4a386604 100644
--- a/Content.Client/Disposal/Systems/DisposalUnitSystem.cs
+++ b/Content.Client/Disposal/Systems/DisposalUnitSystem.cs
@@ -96,24 +96,22 @@ private void OnAppearanceChange(EntityUid uid, SharedDisposalUnitComponent unit,
private void UpdateState(EntityUid uid, SharedDisposalUnitComponent unit, SpriteComponent sprite, AppearanceComponent appearance)
{
if (!_appearanceSystem.TryGetData(uid, Visuals.VisualState, out var state, appearance))
- {
return;
- }
sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == VisualState.UnAnchored);
sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == VisualState.Anchored);
- sprite.LayerSetVisible(DisposalUnitVisualLayers.BaseFlush, state is VisualState.Flushing or VisualState.Charging);
+ sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFlush, state is VisualState.OverlayFlushing or VisualState.OverlayCharging);
var chargingState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseCharging, out var chargingLayer)
? sprite.LayerGetState(chargingLayer)
: new RSI.StateId(DefaultChargeState);
// This is a transient state so not too worried about replaying in range.
- if (state == VisualState.Flushing)
+ if (state == VisualState.OverlayFlushing)
{
if (!_animationSystem.HasRunningAnimation(uid, AnimationKey))
{
- var flushState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseFlush, out var flushLayer)
+ var flushState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.OverlayFlush, out var flushLayer)
? sprite.LayerGetState(flushLayer)
: new RSI.StateId(DefaultFlushState);
@@ -125,7 +123,7 @@ private void UpdateState(EntityUid uid, SharedDisposalUnitComponent unit, Sprite
{
new AnimationTrackSpriteFlick
{
- LayerKey = DisposalUnitVisualLayers.BaseFlush,
+ LayerKey = DisposalUnitVisualLayers.OverlayFlush,
KeyFrames =
{
// Play the flush animation
@@ -154,26 +152,18 @@ private void UpdateState(EntityUid uid, SharedDisposalUnitComponent unit, Sprite
_animationSystem.Play(uid, anim, AnimationKey);
}
}
- else if (state == VisualState.Charging)
- {
- sprite.LayerSetState(DisposalUnitVisualLayers.BaseFlush, chargingState);
- }
+ else if (state == VisualState.OverlayCharging)
+ sprite.LayerSetState(DisposalUnitVisualLayers.OverlayFlush, new RSI.StateId("disposal-charging"));
else
- {
_animationSystem.Stop(uid, AnimationKey);
- }
if (!_appearanceSystem.TryGetData(uid, Visuals.Handle, out var handleState, appearance))
- {
handleState = HandleState.Normal;
- }
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayEngaged, handleState != HandleState.Normal);
if (!_appearanceSystem.TryGetData(uid, Visuals.Light, out var lightState, appearance))
- {
lightState = LightStates.Off;
- }
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayCharging,
(lightState & LightStates.Charging) != 0);
@@ -189,7 +179,7 @@ public enum DisposalUnitVisualLayers : byte
Unanchored,
Base,
BaseCharging,
- BaseFlush,
+ OverlayFlush,
OverlayCharging,
OverlayReady,
OverlayFull,
diff --git a/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs
new file mode 100644
index 00000000000..cd7ea717ce3
--- /dev/null
+++ b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs
@@ -0,0 +1,59 @@
+using Content.Shared.Access;
+using Content.Shared.Doors.Electronics;
+using Robust.Client.GameObjects;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Doors.Electronics;
+
+public sealed class DoorElectronicsBoundUserInterface : BoundUserInterface
+{
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+
+ private DoorElectronicsConfigurationMenu? _window;
+
+ public DoorElectronicsBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+ List> accessLevels = new();
+
+ foreach (var accessLevel in _prototypeManager.EnumeratePrototypes())
+ {
+ if (accessLevel.Name != null)
+ {
+ accessLevels.Add(accessLevel.ID);
+ }
+ }
+
+ accessLevels.Sort();
+
+ _window = new DoorElectronicsConfigurationMenu(this, accessLevels, _prototypeManager);
+ _window.OnClose += Close;
+ _window.OpenCentered();
+ }
+
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+
+ var castState = (DoorElectronicsConfigurationState) state;
+
+ _window?.UpdateState(castState);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing) return;
+
+ _window?.Dispose();
+ }
+
+ public void UpdateConfiguration(List> newAccessList)
+ {
+ SendMessage(new DoorElectronicsUpdateConfigurationMessage(newAccessList));
+ }
+}
diff --git a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml
new file mode 100644
index 00000000000..4cd59f38b23
--- /dev/null
+++ b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs
new file mode 100644
index 00000000000..c01f13a462e
--- /dev/null
+++ b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs
@@ -0,0 +1,41 @@
+using System.Linq;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+using Content.Client.Access.UI;
+using Content.Client.Doors.Electronics;
+using Content.Shared.Access;
+using Content.Shared.Doors.Electronics;
+using FancyWindow = Content.Client.UserInterface.Controls.FancyWindow;
+
+namespace Content.Client.Doors.Electronics;
+
+[GenerateTypedNameReferences]
+public sealed partial class DoorElectronicsConfigurationMenu : FancyWindow
+{
+ private readonly DoorElectronicsBoundUserInterface _owner;
+ private AccessLevelControl _buttonsList = new();
+
+ public DoorElectronicsConfigurationMenu(DoorElectronicsBoundUserInterface ui, List> accessLevels, IPrototypeManager prototypeManager)
+ {
+ RobustXamlLoader.Load(this);
+
+ _owner = ui;
+
+ _buttonsList.Populate(accessLevels, prototypeManager);
+ AccessLevelControlContainer.AddChild(_buttonsList);
+
+ foreach (var (id, button) in _buttonsList.ButtonsList)
+ {
+ button.OnPressed += _ => _owner.UpdateConfiguration(
+ _buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
+ }
+ }
+
+ public void UpdateState(DoorElectronicsConfigurationState state)
+ {
+ _buttonsList.UpdateState(state.AccessList);
+ }
+}
diff --git a/Content.Client/Examine/ExamineSystem.cs b/Content.Client/Examine/ExamineSystem.cs
index 1be472b06d6..45db4efa53c 100644
--- a/Content.Client/Examine/ExamineSystem.cs
+++ b/Content.Client/Examine/ExamineSystem.cs
@@ -212,14 +212,16 @@ public void OpenTooltip(EntityUid player, EntityUid target, bool centeredOnCurso
var vBox = new BoxContainer
{
Name = "ExaminePopupVbox",
- Orientation = LayoutOrientation.Vertical
+ Orientation = LayoutOrientation.Vertical,
+ MaxWidth = _examineTooltipOpen.MaxWidth
};
panel.AddChild(vBox);
var hBox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
- SeparationOverride = 5
+ SeparationOverride = 5,
+ Margin = new Thickness(6, 0, 6, 0)
};
vBox.AddChild(hBox);
@@ -229,8 +231,7 @@ public void OpenTooltip(EntityUid player, EntityUid target, bool centeredOnCurso
var spriteView = new SpriteView
{
OverrideDirection = Direction.South,
- SetSize = new Vector2(32, 32),
- Margin = new Thickness(2, 0, 2, 0),
+ SetSize = new Vector2(32, 32)
};
spriteView.SetEntity(target);
hBox.AddChild(spriteView);
@@ -238,19 +239,17 @@ public void OpenTooltip(EntityUid player, EntityUid target, bool centeredOnCurso
if (knowTarget)
{
- hBox.AddChild(new Label
- {
- Text = Identity.Name(target, EntityManager, player),
- HorizontalExpand = true,
- });
+ var itemName = FormattedMessage.RemoveMarkup(Identity.Name(target, EntityManager, player));
+ var labelMessage = FormattedMessage.FromMarkup($"[bold]{itemName}[/bold]");
+ var label = new RichTextLabel();
+ label.SetMessage(labelMessage);
+ hBox.AddChild(label);
}
else
{
- hBox.AddChild(new Label
- {
- Text = "???",
- HorizontalExpand = true,
- });
+ var label = new RichTextLabel();
+ label.SetMessage(FormattedMessage.FromMarkup("[bold]???[/bold]"));
+ hBox.AddChild(label);
}
panel.Measure(Vector2Helpers.Infinity);
diff --git a/Content.Client/Fluids/PuddleSystem.cs b/Content.Client/Fluids/PuddleSystem.cs
index 54b1d5b86b9..5dbffe0fd2f 100644
--- a/Content.Client/Fluids/PuddleSystem.cs
+++ b/Content.Client/Fluids/PuddleSystem.cs
@@ -1,7 +1,9 @@
using Content.Client.IconSmoothing;
+using Content.Shared.Chemistry.Components;
using Content.Shared.Fluids;
using Content.Shared.Fluids.Components;
using Robust.Client.GameObjects;
+using Robust.Shared.Map;
namespace Content.Client.Fluids;
@@ -21,7 +23,7 @@ private void OnPuddleAppearance(EntityUid uid, PuddleComponent component, ref Ap
if (args.Sprite == null)
return;
- float volume = 1f;
+ var volume = 1f;
if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
{
@@ -64,4 +66,38 @@ private void OnPuddleAppearance(EntityUid uid, PuddleComponent component, ref Ap
args.Sprite.Color *= baseColor;
}
}
+
+ #region Spill
+
+ // Maybe someday we'll have clientside prediction for entity spawning, but not today.
+ // Until then, these methods do nothing on the client.
+ ///
+ public override bool TrySplashSpillAt(EntityUid uid, EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true, EntityUid? user = null)
+ {
+ puddleUid = EntityUid.Invalid;
+ return false;
+ }
+
+ ///
+ public override bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true)
+ {
+ puddleUid = EntityUid.Invalid;
+ return false;
+ }
+
+ ///
+ public override bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true, TransformComponent? transformComponent = null)
+ {
+ puddleUid = EntityUid.Invalid;
+ return false;
+ }
+
+ ///
+ public override bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true, bool tileReact = true)
+ {
+ puddleUid = EntityUid.Invalid;
+ return false;
+ }
+
+ #endregion Spill
}
diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs
index 589de6d6a78..2e888b3df98 100644
--- a/Content.Client/Input/ContentContexts.cs
+++ b/Content.Client/Input/ContentContexts.cs
@@ -45,6 +45,9 @@ public static void SetupContexts(IInputContextContainer contexts)
// Not in engine because the engine doesn't understand what a flipped object is
common.AddFunction(ContentKeyFunctions.EditorFlipObject);
+ // Not in engine so that the RCD can rotate objects
+ common.AddFunction(EngineKeyFunctions.EditorRotateObject);
+
var human = contexts.GetContext("human");
human.AddFunction(EngineKeyFunctions.MoveUp);
human.AddFunction(EngineKeyFunctions.MoveDown);
diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml b/Content.Client/Lathe/UI/LatheMenu.xaml
index 2b97166f05a..6f484d8c7be 100644
--- a/Content.Client/Lathe/UI/LatheMenu.xaml
+++ b/Content.Client/Lathe/UI/LatheMenu.xaml
@@ -124,9 +124,7 @@
+ Orientation="Vertical">
-
-
+
+
+
+
diff --git a/Content.Client/Materials/UI/MaterialStorageControl.xaml.cs b/Content.Client/Materials/UI/MaterialStorageControl.xaml.cs
index 3ef247d5297..31d99624a8a 100644
--- a/Content.Client/Materials/UI/MaterialStorageControl.xaml.cs
+++ b/Content.Client/Materials/UI/MaterialStorageControl.xaml.cs
@@ -11,7 +11,7 @@ namespace Content.Client.Materials.UI;
/// This widget is one row in the lathe eject menu.
///
[GenerateTypedNameReferences]
-public sealed partial class MaterialStorageControl : BoxContainer
+public sealed partial class MaterialStorageControl : ScrollContainer
{
[Dependency] private readonly IEntityManager _entityManager = default!;
@@ -63,7 +63,7 @@ protected override void FrameUpdate(FrameEventArgs args)
}
var children = new List();
- children.AddRange(Children.OfType());
+ children.AddRange(MaterialList.Children.OfType());
foreach (var display in children)
{
@@ -71,7 +71,7 @@ protected override void FrameUpdate(FrameEventArgs args)
if (extra.Contains(mat))
{
- RemoveChild(display);
+ MaterialList.RemoveChild(display);
continue;
}
@@ -83,7 +83,7 @@ protected override void FrameUpdate(FrameEventArgs args)
foreach (var mat in missing)
{
var volume = mats[mat];
- AddChild(new MaterialDisplay(_owner.Value, mat, volume, canEject));
+ MaterialList.AddChild(new MaterialDisplay(_owner.Value, mat, volume, canEject));
}
_currentMaterials = mats;
diff --git a/Content.Client/Nutrition/EntitySystems/OpenableSystem.cs b/Content.Client/Nutrition/EntitySystems/OpenableSystem.cs
deleted file mode 100644
index f8c3f7c447f..00000000000
--- a/Content.Client/Nutrition/EntitySystems/OpenableSystem.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using Content.Shared.Nutrition.EntitySystems;
-
-namespace Content.Client.Nutrition.EntitySystems;
-
-public sealed class OpenableSystem : SharedOpenableSystem
-{
-}
diff --git a/Content.Client/Options/UI/Tabs/MiscTab.xaml b/Content.Client/Options/UI/Tabs/MiscTab.xaml
index 2ee59910f70..5564d7b2263 100644
--- a/Content.Client/Options/UI/Tabs/MiscTab.xaml
+++ b/Content.Client/Options/UI/Tabs/MiscTab.xaml
@@ -25,6 +25,14 @@
+
+
+
+
+
-
-
-
diff --git a/Content.Client/Options/UI/Tabs/MiscTab.xaml.cs b/Content.Client/Options/UI/Tabs/MiscTab.xaml.cs
index 3b9c41efdfb..476e7289ea9 100644
--- a/Content.Client/Options/UI/Tabs/MiscTab.xaml.cs
+++ b/Content.Client/Options/UI/Tabs/MiscTab.xaml.cs
@@ -66,6 +66,7 @@ public MiscTab()
EnableColorNameCheckBox.OnToggled += OnCheckBoxToggled;
ColorblindFriendlyCheckBox.OnToggled += OnCheckBoxToggled;
ReducedMotionCheckBox.OnToggled += OnCheckBoxToggled;
+ ChatWindowOpacitySlider.OnValueChanged += OnChatWindowOpacitySliderChanged;
ScreenShakeIntensitySlider.OnValueChanged += OnScreenShakeIntensitySliderChanged;
// ToggleWalk.OnToggled += OnCheckBoxToggled;
StaticStorageUI.OnToggled += OnCheckBoxToggled;
@@ -81,6 +82,7 @@ public MiscTab()
EnableColorNameCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableColorName);
ColorblindFriendlyCheckBox.Pressed = _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
ReducedMotionCheckBox.Pressed = _cfg.GetCVar(CCVars.ReducedMotion);
+ ChatWindowOpacitySlider.Value = _cfg.GetCVar(CCVars.ChatWindowOpacity);
ScreenShakeIntensitySlider.Value = _cfg.GetCVar(CCVars.ScreenShakeIntensity) * 100f;
// ToggleWalk.Pressed = _cfg.GetCVar(CCVars.ToggleWalk);
StaticStorageUI.Pressed = _cfg.GetCVar(CCVars.StaticStorageUI);
@@ -101,6 +103,13 @@ private void OnHudThemeChanged(OptionButton.ItemSelectedEventArgs args)
UpdateApplyButton();
}
+ private void OnChatWindowOpacitySliderChanged(Range range)
+ {
+ ChatWindowOpacityLabel.Text = Loc.GetString("ui-options-chat-window-opacity-percent",
+ ("opacity", range.Value));
+ UpdateApplyButton();
+ }
+
private void OnScreenShakeIntensitySliderChanged(Range obj)
{
ScreenShakeIntensityLabel.Text = Loc.GetString("ui-options-screen-shake-percent", ("intensity", ScreenShakeIntensitySlider.Value / 100f));
@@ -127,6 +136,7 @@ private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
_cfg.SetCVar(CCVars.ChatEnableColorName, EnableColorNameCheckBox.Pressed);
_cfg.SetCVar(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox.Pressed);
_cfg.SetCVar(CCVars.ReducedMotion, ReducedMotionCheckBox.Pressed);
+ _cfg.SetCVar(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider.Value);
_cfg.SetCVar(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider.Value / 100f);
// _cfg.SetCVar(CCVars.ToggleWalk, ToggleWalk.Pressed);
_cfg.SetCVar(CCVars.StaticStorageUI, StaticStorageUI.Pressed);
@@ -154,6 +164,7 @@ private void UpdateApplyButton()
var isEnableColorNameSame = EnableColorNameCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableColorName);
var isColorblindFriendly = ColorblindFriendlyCheckBox.Pressed == _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
var isReducedMotionSame = ReducedMotionCheckBox.Pressed == _cfg.GetCVar(CCVars.ReducedMotion);
+ var isChatWindowOpacitySame = Math.Abs(ChatWindowOpacitySlider.Value - _cfg.GetCVar(CCVars.ChatWindowOpacity)) < 0.01f;
var isScreenShakeIntensitySame = Math.Abs(ScreenShakeIntensitySlider.Value / 100f - _cfg.GetCVar(CCVars.ScreenShakeIntensity)) < 0.01f;
// var isToggleWalkSame = ToggleWalk.Pressed == _cfg.GetCVar(CCVars.ToggleWalk);
var isStaticStorageUISame = StaticStorageUI.Pressed == _cfg.GetCVar(CCVars.StaticStorageUI);
@@ -170,6 +181,7 @@ private void UpdateApplyButton()
isEnableColorNameSame &&
isColorblindFriendly &&
isReducedMotionSame &&
+ isChatWindowOpacitySame &&
isScreenShakeIntensitySame &&
// isToggleWalkSame &&
isStaticStorageUISame;
diff --git a/Content.Client/Paint/PaintVisualizerSystem.cs b/Content.Client/Paint/PaintVisualizerSystem.cs
deleted file mode 100644
index 8d037811fab..00000000000
--- a/Content.Client/Paint/PaintVisualizerSystem.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-using System.Linq;
-using Robust.Client.GameObjects;
-using static Robust.Client.GameObjects.SpriteComponent;
-using Content.Shared.Clothing;
-using Content.Shared.Hands;
-using Content.Shared.Paint;
-using Robust.Client.Graphics;
-using Robust.Shared.Prototypes;
-
-namespace Content.Client.Paint;
-
-public sealed class PaintedVisualizerSystem : VisualizerSystem
-{
- ///
- /// Visualizer for Paint which applies a shader and colors the entity.
- ///
-
- [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
- [Dependency] private readonly IPrototypeManager _protoMan = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent(OnHeldVisualsUpdated);
- SubscribeLocalEvent(OnShutdown);
- SubscribeLocalEvent(OnEquipmentVisualsUpdated);
- }
-
- protected override void OnAppearanceChange(EntityUid uid, PaintedComponent component, ref AppearanceChangeEvent args)
- {
- var shader = _protoMan.Index(component.ShaderName).Instance();
-
- if (args.Sprite == null)
- return;
-
- // What is this even doing? It's not even checking what the value is.
- if (!_appearance.TryGetData(uid, PaintVisuals.Painted, out bool isPainted))
- return;
-
- var sprite = args.Sprite;
-
- foreach (var spriteLayer in sprite.AllLayers)
- {
- if (spriteLayer is not Layer layer)
- continue;
-
- if (layer.Shader == null) // If shader isn't null we dont want to replace the original shader.
- {
- layer.Shader = shader;
- layer.Color = component.Color;
- }
- }
- }
-
- private void OnHeldVisualsUpdated(EntityUid uid, PaintedComponent component, HeldVisualsUpdatedEvent args)
- {
- if (args.RevealedLayers.Count == 0)
- return;
-
- if (!TryComp(args.User, out SpriteComponent? sprite))
- return;
-
- foreach (var revealed in args.RevealedLayers)
- {
- if (!sprite.LayerMapTryGet(revealed, out var layer))
- continue;
-
- sprite.LayerSetShader(layer, component.ShaderName);
- sprite.LayerSetColor(layer, component.Color);
- }
- }
-
- private void OnEquipmentVisualsUpdated(EntityUid uid, PaintedComponent component, EquipmentVisualsUpdatedEvent args)
- {
- if (args.RevealedLayers.Count == 0)
- return;
-
- if (!TryComp(args.Equipee, out SpriteComponent? sprite))
- return;
-
- foreach (var revealed in args.RevealedLayers)
- {
- if (!sprite.LayerMapTryGet(revealed, out var layer))
- continue;
-
- sprite.LayerSetShader(layer, component.ShaderName);
- sprite.LayerSetColor(layer, component.Color);
- }
- }
-
- private void OnShutdown(EntityUid uid, PaintedComponent component, ref ComponentShutdown args)
- {
- if (!TryComp(uid, out SpriteComponent? sprite))
- return;
-
- component.BeforeColor = sprite.Color;
- var shader = _protoMan.Index(component.ShaderName).Instance();
-
- if (!Terminating(uid))
- {
- foreach (var spriteLayer in sprite.AllLayers)
- {
- if (spriteLayer is not Layer layer)
- continue;
-
- if (layer.Shader == shader) // If shader isn't same as one in component we need to ignore it.
- {
- layer.Shader = null;
- if (layer.Color == component.Color) // If color isn't the same as one in component we don't want to change it.
- layer.Color = component.BeforeColor;
- }
- }
- }
- }
-}
diff --git a/Content.Client/Pinpointer/UI/NavMapControl.cs b/Content.Client/Pinpointer/UI/NavMapControl.cs
index a8ec7b37a0b..677092e1918 100644
--- a/Content.Client/Pinpointer/UI/NavMapControl.cs
+++ b/Content.Client/Pinpointer/UI/NavMapControl.cs
@@ -114,9 +114,16 @@ public NavMapControl() : base(MinDisplayedRange, MaxDisplayedRange, DefaultDispl
VerticalExpand = false,
Children =
{
- _zoom,
- _beacons,
- _recenter,
+ new BoxContainer()
+ {
+ Orientation = BoxContainer.LayoutOrientation.Horizontal,
+ Children =
+ {
+ _zoom,
+ _beacons,
+ _recenter
+ }
+ }
}
};
diff --git a/Content.Client/Popups/PopupSystem.cs b/Content.Client/Popups/PopupSystem.cs
index 479fb02906c..fcc8bfc420a 100644
--- a/Content.Client/Popups/PopupSystem.cs
+++ b/Content.Client/Popups/PopupSystem.cs
@@ -163,10 +163,13 @@ public override void PopupEntity(string? message, EntityUid uid, Filter filter,
PopupEntity(message, uid, type);
}
- public override void PopupClient(string? message, EntityUid uid, EntityUid recipient, PopupType type = PopupType.Small)
+ public override void PopupClient(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
{
+ if (recipient == null)
+ return;
+
if (_timing.IsFirstTimePredicted)
- PopupEntity(message, uid, recipient, type);
+ PopupEntity(message, uid, recipient.Value, type);
}
public override void PopupEntity(string? message, EntityUid uid, PopupType type = PopupType.Small)
diff --git a/Content.Client/RCD/AlignRCDConstruction.cs b/Content.Client/RCD/AlignRCDConstruction.cs
new file mode 100644
index 00000000000..da7b22c91a8
--- /dev/null
+++ b/Content.Client/RCD/AlignRCDConstruction.cs
@@ -0,0 +1,122 @@
+using System.Numerics;
+using Content.Client.Gameplay;
+using Content.Shared.Hands.Components;
+using Content.Shared.Interaction;
+using Content.Shared.RCD.Components;
+using Content.Shared.RCD.Systems;
+using Robust.Client.Placement;
+using Robust.Client.Player;
+using Robust.Client.State;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+
+namespace Content.Client.RCD;
+
+public sealed class AlignRCDConstruction : PlacementMode
+{
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly SharedMapSystem _mapSystem = default!;
+ [Dependency] private readonly RCDSystem _rcdSystem = default!;
+ [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IStateManager _stateManager = default!;
+
+ private const float SearchBoxSize = 2f;
+ private const float PlaceColorBaseAlpha = 0.5f;
+
+ private EntityCoordinates _unalignedMouseCoords = default;
+
+ ///
+ /// This placement mode is not on the engine because it is content specific (i.e., for the RCD)
+ ///
+ public AlignRCDConstruction(PlacementManager pMan) : base(pMan)
+ {
+ var dependencies = IoCManager.Instance!;
+ _entityManager = dependencies.Resolve();
+ _mapManager = dependencies.Resolve();
+ _playerManager = dependencies.Resolve();
+ _stateManager = dependencies.Resolve();
+
+ _mapSystem = _entityManager.System();
+ _rcdSystem = _entityManager.System();
+ _transformSystem = _entityManager.System();
+
+ ValidPlaceColor = ValidPlaceColor.WithAlpha(PlaceColorBaseAlpha);
+ }
+
+ public override void AlignPlacementMode(ScreenCoordinates mouseScreen)
+ {
+ _unalignedMouseCoords = ScreenToCursorGrid(mouseScreen);
+ MouseCoords = _unalignedMouseCoords.AlignWithClosestGridTile(SearchBoxSize, _entityManager, _mapManager);
+
+ var gridId = MouseCoords.GetGridUid(_entityManager);
+
+ if (!_entityManager.TryGetComponent(gridId, out var mapGrid))
+ return;
+
+ CurrentTile = _mapSystem.GetTileRef(gridId.Value, mapGrid, MouseCoords);
+
+ float tileSize = mapGrid.TileSize;
+ GridDistancing = tileSize;
+
+ if (pManager.CurrentPermission!.IsTile)
+ {
+ MouseCoords = new EntityCoordinates(MouseCoords.EntityId, new Vector2(CurrentTile.X + tileSize / 2,
+ CurrentTile.Y + tileSize / 2));
+ }
+ else
+ {
+ MouseCoords = new EntityCoordinates(MouseCoords.EntityId, new Vector2(CurrentTile.X + tileSize / 2 + pManager.PlacementOffset.X,
+ CurrentTile.Y + tileSize / 2 + pManager.PlacementOffset.Y));
+ }
+ }
+
+ public override bool IsValidPosition(EntityCoordinates position)
+ {
+ var player = _playerManager.LocalSession?.AttachedEntity;
+
+ // If the destination is out of interaction range, set the placer alpha to zero
+ if (!_entityManager.TryGetComponent(player, out var xform))
+ return false;
+
+ if (!xform.Coordinates.InRange(_entityManager, _transformSystem, position, SharedInteractionSystem.InteractionRange))
+ {
+ InvalidPlaceColor = InvalidPlaceColor.WithAlpha(0);
+ return false;
+ }
+
+ // Otherwise restore the alpha value
+ else
+ {
+ InvalidPlaceColor = InvalidPlaceColor.WithAlpha(PlaceColorBaseAlpha);
+ }
+
+ // Determine if player is carrying an RCD in their active hand
+ if (!_entityManager.TryGetComponent(player, out var hands))
+ return false;
+
+ var heldEntity = hands.ActiveHand?.HeldEntity;
+
+ if (!_entityManager.TryGetComponent(heldEntity, out var rcd))
+ return false;
+
+ // Retrieve the map grid data for the position
+ if (!_rcdSystem.TryGetMapGridData(position, out var mapGridData))
+ return false;
+
+ // Determine if the user is hovering over a target
+ var currentState = _stateManager.CurrentState;
+
+ if (currentState is not GameplayStateBase screen)
+ return false;
+
+ var target = screen.GetClickedEntity(_unalignedMouseCoords.ToMap(_entityManager, _transformSystem));
+
+ // Determine if the RCD operation is valid or not
+ if (!_rcdSystem.IsRCDOperationStillValid(heldEntity.Value, rcd, mapGridData.Value, target, player.Value, false))
+ return false;
+
+ return true;
+ }
+}
diff --git a/Content.Client/RCD/RCDConstructionGhostSystem.cs b/Content.Client/RCD/RCDConstructionGhostSystem.cs
new file mode 100644
index 00000000000..792916b8922
--- /dev/null
+++ b/Content.Client/RCD/RCDConstructionGhostSystem.cs
@@ -0,0 +1,78 @@
+using Content.Shared.Hands.Components;
+using Content.Shared.Interaction;
+using Content.Shared.RCD;
+using Content.Shared.RCD.Components;
+using Content.Shared.RCD.Systems;
+using Robust.Client.Placement;
+using Robust.Client.Player;
+using Robust.Shared.Enums;
+
+namespace Content.Client.RCD;
+
+public sealed class RCDConstructionGhostSystem : EntitySystem
+{
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly RCDSystem _rcdSystem = default!;
+ [Dependency] private readonly IPlacementManager _placementManager = default!;
+
+ private string _placementMode = typeof(AlignRCDConstruction).Name;
+ private Direction _placementDirection = default;
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ // Get current placer data
+ var placerEntity = _placementManager.CurrentPermission?.MobUid;
+ var placerProto = _placementManager.CurrentPermission?.EntityType;
+ var placerIsRCD = HasComp(placerEntity);
+
+ // Exit if erasing or the current placer is not an RCD (build mode is active)
+ if (_placementManager.Eraser || (placerEntity != null && !placerIsRCD))
+ return;
+
+ // Determine if player is carrying an RCD in their active hand
+ var player = _playerManager.LocalSession?.AttachedEntity;
+
+ if (!TryComp(player, out var hands))
+ return;
+
+ var heldEntity = hands.ActiveHand?.HeldEntity;
+
+ if (!TryComp(heldEntity, out var rcd))
+ {
+ // If the player was holding an RCD, but is no longer, cancel placement
+ if (placerIsRCD)
+ _placementManager.Clear();
+
+ return;
+ }
+
+ // Update the direction the RCD prototype based on the placer direction
+ if (_placementDirection != _placementManager.Direction)
+ {
+ _placementDirection = _placementManager.Direction;
+ RaiseNetworkEvent(new RCDConstructionGhostRotationEvent(GetNetEntity(heldEntity.Value), _placementDirection));
+ }
+
+ // If the placer has not changed, exit
+ _rcdSystem.UpdateCachedPrototype(heldEntity.Value, rcd);
+
+ if (heldEntity == placerEntity && rcd.CachedPrototype.Prototype == placerProto)
+ return;
+
+ // Create a new placer
+ var newObjInfo = new PlacementInformation
+ {
+ MobUid = heldEntity.Value,
+ PlacementOption = _placementMode,
+ EntityType = rcd.CachedPrototype.Prototype,
+ Range = (int) Math.Ceiling(SharedInteractionSystem.InteractionRange),
+ IsTile = (rcd.CachedPrototype.Mode == RcdMode.ConstructTile),
+ UseEditorContext = false,
+ };
+
+ _placementManager.Clear();
+ _placementManager.BeginPlacing(newObjInfo);
+ }
+}
diff --git a/Content.Client/RCD/RCDMenu.xaml b/Content.Client/RCD/RCDMenu.xaml
new file mode 100644
index 00000000000..b3d5367a5fd
--- /dev/null
+++ b/Content.Client/RCD/RCDMenu.xaml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/RCD/RCDMenu.xaml.cs b/Content.Client/RCD/RCDMenu.xaml.cs
new file mode 100644
index 00000000000..8679e789dc7
--- /dev/null
+++ b/Content.Client/RCD/RCDMenu.xaml.cs
@@ -0,0 +1,137 @@
+using Content.Client.UserInterface.Controls;
+using Content.Shared.RCD;
+using Content.Shared.RCD.Components;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+using System.Numerics;
+
+namespace Content.Client.RCD;
+
+[GenerateTypedNameReferences]
+public sealed partial class RCDMenu : RadialMenu
+{
+ [Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly IPrototypeManager _protoManager = default!;
+
+ private readonly SpriteSystem _spriteSystem;
+
+ public event Action>? SendRCDSystemMessageAction;
+
+ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui)
+ {
+ IoCManager.InjectDependencies(this);
+ RobustXamlLoader.Load(this);
+
+ _spriteSystem = _entManager.System();
+
+ // Find the main radial container
+ var main = FindControl("Main");
+
+ if (main == null)
+ return;
+
+ // Populate secondary radial containers
+ if (!_entManager.TryGetComponent(owner, out var rcd))
+ return;
+
+ foreach (var protoId in rcd.AvailablePrototypes)
+ {
+ if (!_protoManager.TryIndex(protoId, out var proto))
+ continue;
+
+ if (proto.Mode == RcdMode.Invalid)
+ continue;
+
+ var parent = FindControl(proto.Category);
+
+ if (parent == null)
+ continue;
+
+ var name = Loc.GetString(proto.SetName);
+ name = char.ToUpper(name[0]) + name.Remove(0, 1);
+
+ var button = new RCDMenuButton()
+ {
+ StyleClasses = { "RadialMenuButton" },
+ SetSize = new Vector2(64f, 64f),
+ ToolTip = name,
+ ProtoId = protoId,
+ };
+
+ if (proto.Sprite != null)
+ {
+ var tex = new TextureRect()
+ {
+ VerticalAlignment = VAlignment.Center,
+ HorizontalAlignment = HAlignment.Center,
+ Texture = _spriteSystem.Frame0(proto.Sprite),
+ TextureScale = new Vector2(2f, 2f),
+ };
+
+ button.AddChild(tex);
+ }
+
+ parent.AddChild(button);
+
+ // Ensure that the button that transitions the menu to the associated category layer
+ // is visible in the main radial container (as these all start with Visible = false)
+ foreach (var child in main.Children)
+ {
+ var castChild = child as RadialMenuTextureButton;
+
+ if (castChild is not RadialMenuTextureButton)
+ continue;
+
+ if (castChild.TargetLayer == proto.Category)
+ {
+ castChild.Visible = true;
+ break;
+ }
+ }
+ }
+
+ // Set up menu actions
+ foreach (var child in Children)
+ AddRCDMenuButtonOnClickActions(child);
+
+ OnChildAdded += AddRCDMenuButtonOnClickActions;
+
+ SendRCDSystemMessageAction += bui.SendRCDSystemMessage;
+ }
+
+ private void AddRCDMenuButtonOnClickActions(Control control)
+ {
+ var radialContainer = control as RadialContainer;
+
+ if (radialContainer == null)
+ return;
+
+ foreach (var child in radialContainer.Children)
+ {
+ var castChild = child as RCDMenuButton;
+
+ if (castChild == null)
+ continue;
+
+ castChild.OnButtonUp += _ =>
+ {
+ SendRCDSystemMessageAction?.Invoke(castChild.ProtoId);
+ Close();
+ };
+ }
+ }
+}
+
+public sealed class RCDMenuButton : RadialMenuTextureButton
+{
+ public ProtoId ProtoId { get; set; }
+
+ public RCDMenuButton()
+ {
+
+ }
+}
diff --git a/Content.Client/RCD/RCDMenuBoundUserInterface.cs b/Content.Client/RCD/RCDMenuBoundUserInterface.cs
new file mode 100644
index 00000000000..a37dbcecf8c
--- /dev/null
+++ b/Content.Client/RCD/RCDMenuBoundUserInterface.cs
@@ -0,0 +1,49 @@
+using Content.Shared.RCD;
+using Content.Shared.RCD.Components;
+using JetBrains.Annotations;
+using Robust.Client.Graphics;
+using Robust.Client.Input;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.RCD;
+
+[UsedImplicitly]
+public sealed class RCDMenuBoundUserInterface : BoundUserInterface
+{
+ [Dependency] private readonly IClyde _displayManager = default!;
+ [Dependency] private readonly IInputManager _inputManager = default!;
+
+ private RCDMenu? _menu;
+
+ public RCDMenuBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ IoCManager.InjectDependencies(this);
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _menu = new(Owner, this);
+ _menu.OnClose += Close;
+
+ // Open the menu, centered on the mouse
+ var vpSize = _displayManager.ScreenSize;
+ _menu.OpenCenteredAt(_inputManager.MouseScreenPosition.Position / vpSize);
+ }
+
+ public void SendRCDSystemMessage(ProtoId protoId)
+ {
+ // A predicted message cannot be used here as the RCD UI is closed immediately
+ // after this message is sent, which will stop the server from receiving it
+ SendMessage(new RCDSystemMessage(protoId));
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing) return;
+
+ _menu?.Dispose();
+ }
+}
diff --git a/Content.Client/Shuttles/UI/MapScreen.xaml.cs b/Content.Client/Shuttles/UI/MapScreen.xaml.cs
index 8430699bae1..10800b8c5f7 100644
--- a/Content.Client/Shuttles/UI/MapScreen.xaml.cs
+++ b/Content.Client/Shuttles/UI/MapScreen.xaml.cs
@@ -5,6 +5,7 @@
using Content.Shared.Shuttles.Components;
using Content.Shared.Shuttles.Systems;
using Content.Shared.Shuttles.UI.MapObjects;
+using Content.Shared.Timing;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
@@ -38,16 +39,11 @@ public sealed partial class MapScreen : BoxContainer
private EntityUid? _shuttleEntity;
private FTLState _state;
- private float _ftlDuration;
+ private StartEndTime _ftlTime;
private List _beacons = new();
private List _exclusions = new();
- ///
- /// When the next FTL state change happens.
- ///
- private TimeSpan _nextFtlTime;
-
private TimeSpan _nextPing;
private TimeSpan _pingCooldown = TimeSpan.FromSeconds(3);
private TimeSpan _nextMapDequeue;
@@ -114,8 +110,7 @@ public void UpdateState(ShuttleMapInterfaceState state)
_beacons = state.Destinations;
_exclusions = state.Exclusions;
_state = state.FTLState;
- _ftlDuration = state.FTLDuration;
- _nextFtlTime = _timing.CurTime + TimeSpan.FromSeconds(_ftlDuration);
+ _ftlTime = state.FTLTime;
MapRadar.InFtl = true;
MapFTLState.Text = Loc.GetString($"shuttle-console-ftl-state-{_state.ToString()}");
@@ -268,9 +263,10 @@ private void RebuildMapObjects()
while (mapComps.MoveNext(out var mapComp, out var mapXform, out var mapMetadata))
{
- if (!_shuttles.CanFTLTo(_shuttleEntity.Value, mapComp.MapId))
- continue;
-
+ if (_console != null && !_shuttles.CanFTLTo(_shuttleEntity.Value, mapComp.MapId, _console.Value))
+ {
+ continue;
+ }
var mapName = mapMetadata.EntityName;
if (string.IsNullOrEmpty(mapName))
@@ -315,7 +311,6 @@ private void RebuildMapObjects()
};
_mapHeadings.Add(mapComp.MapId, gridContents);
-
foreach (var grid in _mapManager.GetAllMapGrids(mapComp.MapId))
{
_entManager.TryGetComponent(grid.Owner, out IFFComponent? iffComp);
@@ -332,8 +327,8 @@ private void RebuildMapObjects()
{
AddMapObject(mapComp.MapId, gridObj);
}
- else if (iffComp == null ||
- (iffComp.Flags & IFFFlags.Hide) == 0x0)
+ else if (!_shuttles.IsBeaconMap(_mapManager.GetMapEntityId(mapComp.MapId)) && (iffComp == null ||
+ (iffComp.Flags & IFFFlags.Hide) == 0x0))
{
_pendingMapObjects.Add((mapComp.MapId, gridObj));
}
@@ -511,20 +506,8 @@ protected override void FrameUpdate(FrameEventArgs args)
MapRebuildButton.Disabled = false;
}
- var ftlDiff = (float) (_nextFtlTime - _timing.CurTime).TotalSeconds;
-
- float ftlRatio;
-
- if (_ftlDuration.Equals(0f))
- {
- ftlRatio = 1f;
- }
- else
- {
- ftlRatio = Math.Clamp(1f - (ftlDiff / _ftlDuration), 0f, 1f);
- }
-
- FTLBar.Value = ftlRatio;
+ var progress = _ftlTime.ProgressAt(curTime);
+ FTLBar.Value = float.IsFinite(progress) ? progress : 1;
}
protected override void Draw(DrawingHandleScreen handle)
diff --git a/Content.Client/Store/Ui/StoreBoundUserInterface.cs b/Content.Client/Store/Ui/StoreBoundUserInterface.cs
index b549918d7c4..f87b92bc615 100644
--- a/Content.Client/Store/Ui/StoreBoundUserInterface.cs
+++ b/Content.Client/Store/Ui/StoreBoundUserInterface.cs
@@ -1,22 +1,27 @@
using Content.Shared.Store;
using JetBrains.Annotations;
-using Robust.Client.GameObjects;
using System.Linq;
-using System.Threading;
-using Serilog;
-using Timer = Robust.Shared.Timing.Timer;
+using Robust.Shared.Prototypes;
namespace Content.Client.Store.Ui;
[UsedImplicitly]
public sealed class StoreBoundUserInterface : BoundUserInterface
{
+ private IPrototypeManager _prototypeManager = default!;
+
[ViewVariables]
private StoreMenu? _menu;
[ViewVariables]
private string _windowName = Loc.GetString("store-ui-default-title");
+ [ViewVariables]
+ private string _search = "";
+
+ [ViewVariables]
+ private HashSet _listings = new();
+
public StoreBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
@@ -49,6 +54,12 @@ protected override void Open()
SendMessage(new StoreRequestUpdateInterfaceMessage());
};
+ _menu.SearchTextUpdated += (_, search) =>
+ {
+ _search = search.Trim().ToLowerInvariant();
+ UpdateListingsWithSearchFilter();
+ };
+
_menu.OnRefundAttempt += (_) =>
{
SendMessage(new StoreRequestRefundMessage());
@@ -64,10 +75,10 @@ protected override void UpdateState(BoundUserInterfaceState state)
switch (state)
{
case StoreUpdateState msg:
- _menu.UpdateBalance(msg.Balance);
- _menu.PopulateStoreCategoryButtons(msg.Listings);
+ _listings = msg.Listings;
- _menu.UpdateListing(msg.Listings.ToList());
+ _menu.UpdateBalance(msg.Balance);
+ UpdateListingsWithSearchFilter();
_menu.SetFooterVisibility(msg.ShowFooter);
_menu.UpdateRefund(msg.AllowRefund);
break;
@@ -89,4 +100,19 @@ protected override void Dispose(bool disposing)
_menu?.Close();
_menu?.Dispose();
}
+
+ private void UpdateListingsWithSearchFilter()
+ {
+ if (_menu == null)
+ return;
+
+ var filteredListings = new HashSet(_listings);
+ if (!string.IsNullOrEmpty(_search))
+ {
+ filteredListings.RemoveWhere(listingData => !ListingLocalisationHelpers.GetLocalisedNameOrEntityName(listingData, _prototypeManager).Trim().ToLowerInvariant().Contains(_search) &&
+ !ListingLocalisationHelpers.GetLocalisedDescriptionOrEntityDescription(listingData, _prototypeManager).Trim().ToLowerInvariant().Contains(_search));
+ }
+ _menu.PopulateStoreCategoryButtons(filteredListings);
+ _menu.UpdateListing(filteredListings.ToList());
+ }
}
diff --git a/Content.Client/Store/Ui/StoreMenu.xaml b/Content.Client/Store/Ui/StoreMenu.xaml
index 4b38352a44a..fc4cbe444fc 100644
--- a/Content.Client/Store/Ui/StoreMenu.xaml
+++ b/Content.Client/Store/Ui/StoreMenu.xaml
@@ -28,7 +28,8 @@
HorizontalAlignment="Right"
Text="Refund" />
-
+
+
diff --git a/Content.Client/Store/Ui/StoreMenu.xaml.cs b/Content.Client/Store/Ui/StoreMenu.xaml.cs
index 5dc1ab246bd..67e5d360a3a 100644
--- a/Content.Client/Store/Ui/StoreMenu.xaml.cs
+++ b/Content.Client/Store/Ui/StoreMenu.xaml.cs
@@ -1,5 +1,4 @@
using System.Linq;
-using System.Threading;
using Content.Client.Actions;
using Content.Client.GameTicking.Managers;
using Content.Client.Message;
@@ -27,6 +26,7 @@ public sealed partial class StoreMenu : DefaultWindow
private StoreWithdrawWindow? _withdrawWindow;
+ public event EventHandler? SearchTextUpdated;
public event Action? OnListingButtonPressed;
public event Action? OnCategoryButtonPressed;
public event Action? OnWithdrawAttempt;
@@ -46,6 +46,7 @@ public StoreMenu(string name)
WithdrawButton.OnButtonDown += OnWithdrawButtonDown;
RefreshButton.OnButtonDown += OnRefreshButtonDown;
RefundButton.OnButtonDown += OnRefundButtonDown;
+ SearchBar.OnTextChanged += _ => SearchTextUpdated?.Invoke(this, SearchBar.Text);
if (Window != null)
Window.Title = name;
@@ -59,7 +60,7 @@ public void UpdateBalance(Dictionary balance)
(type.Key, type.Value), type => _prototypeManager.Index(type.Key));
var balanceStr = string.Empty;
- foreach (var ((type, amount),proto) in currency)
+ foreach (var ((_, amount), proto) in currency)
{
balanceStr += Loc.GetString("store-ui-balance-display", ("amount", amount),
("currency", Loc.GetString(proto.DisplayName, ("amount", 1))));
@@ -81,7 +82,6 @@ public void UpdateListing(List listings)
{
var sorted = listings.OrderBy(l => l.Priority).ThenBy(l => l.Cost.Values.Sum());
-
// should probably chunk these out instead. to-do if this clogs the internet tubes.
// maybe read clients prototypes instead?
ClearListings();
@@ -129,8 +129,8 @@ private void AddListingGui(ListingData listing)
if (!listing.Categories.Contains(CurrentCategory))
return;
- var listingName = Loc.GetString(listing.Name);
- var listingDesc = Loc.GetString(listing.Description);
+ var listingName = ListingLocalisationHelpers.GetLocalisedNameOrEntityName(listing, _prototypeManager);
+ var listingDesc = ListingLocalisationHelpers.GetLocalisedDescriptionOrEntityDescription(listing, _prototypeManager);
var listingPrice = listing.Cost;
var canBuy = CanBuyListing(Balance, listingPrice);
@@ -144,12 +144,6 @@ private void AddListingGui(ListingData listing)
{
if (texture == null)
texture = spriteSys.GetPrototypeIcon(listing.ProductEntity).Default;
-
- var proto = _prototypeManager.Index(listing.ProductEntity);
- if (listingName == string.Empty)
- listingName = proto.Name;
- if (listingDesc == string.Empty)
- listingDesc = proto.Description;
}
else if (listing.ProductAction != null)
{
@@ -243,13 +237,16 @@ public void PopulateStoreCategoryButtons(HashSet listings)
allCategories = allCategories.OrderBy(c => c.Priority).ToList();
+ // This will reset the Current Category selection if nothing matches the search.
+ if (allCategories.All(category => category.ID != CurrentCategory))
+ CurrentCategory = string.Empty;
+
if (CurrentCategory == string.Empty && allCategories.Count > 0)
CurrentCategory = allCategories.First().ID;
- if (allCategories.Count <= 1)
- return;
-
CategoryListContainer.Children.Clear();
+ if (allCategories.Count < 1)
+ return;
foreach (var proto in allCategories)
{
diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs
index 426af1616ec..a589abb83aa 100644
--- a/Content.Client/Stylesheets/StyleNano.cs
+++ b/Content.Client/Stylesheets/StyleNano.cs
@@ -45,6 +45,7 @@ public sealed class StyleNano : StyleBase
public const string StyleClassBorderedWindowPanel = "BorderedWindowPanel";
public const string StyleClassInventorySlotBackground = "InventorySlotBackground";
public const string StyleClassHandSlotHighlight = "HandSlotHighlight";
+ public const string StyleClassChatPanel = "ChatPanel";
public const string StyleClassChatSubPanel = "ChatSubPanel";
public const string StyleClassTransparentBorderedWindowPanel = "TransparentBorderedWindowPanel";
public const string StyleClassHotbarPanel = "HotbarPanel";
@@ -144,6 +145,8 @@ public sealed class StyleNano : StyleBase
public const string StyleClassButtonColorRed = "ButtonColorRed";
public const string StyleClassButtonColorGreen = "ButtonColorGreen";
+ public static readonly Color ChatBackgroundColor = Color.FromHex("#25252ADD");
+
public override Stylesheet Stylesheet { get; }
public StyleNano(IResourceCache resCache) : base(resCache)
@@ -290,7 +293,7 @@ public StyleNano(IResourceCache resCache) : base(resCache)
var buttonTex = resCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
var topButtonBase = new StyleBoxTexture
{
- Texture = buttonTex,
+ Texture = buttonTex,
};
topButtonBase.SetPatchMargin(StyleBox.Margin.All, 10);
topButtonBase.SetPadding(StyleBox.Margin.All, 0);
@@ -298,19 +301,19 @@ public StyleNano(IResourceCache resCache) : base(resCache)
var topButtonOpenRight = new StyleBoxTexture(topButtonBase)
{
- Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(0, 0), new Vector2(14, 24))),
+ Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(0, 0), new Vector2(14, 24))),
};
topButtonOpenRight.SetPatchMargin(StyleBox.Margin.Right, 0);
var topButtonOpenLeft = new StyleBoxTexture(topButtonBase)
{
- Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(14, 24))),
+ Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(14, 24))),
};
topButtonOpenLeft.SetPatchMargin(StyleBox.Margin.Left, 0);
var topButtonSquare = new StyleBoxTexture(topButtonBase)
{
- Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(3, 24))),
+ Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(3, 24))),
};
topButtonSquare.SetPatchMargin(StyleBox.Margin.Horizontal, 0);
@@ -346,12 +349,16 @@ public StyleNano(IResourceCache resCache) : base(resCache)
lineEdit.SetPatchMargin(StyleBox.Margin.All, 3);
lineEdit.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
- var chatSubBGTex = resCache.GetTexture("/Textures/Interface/Nano/chat_sub_background.png");
- var chatSubBG = new StyleBoxTexture
+ var chatBg = new StyleBoxFlat
+ {
+ BackgroundColor = ChatBackgroundColor
+ };
+
+ var chatSubBg = new StyleBoxFlat
{
- Texture = chatSubBGTex,
+ BackgroundColor = ChatBackgroundColor,
};
- chatSubBG.SetPatchMargin(StyleBox.Margin.All, 2);
+ chatSubBg.SetContentMarginOverride(StyleBox.Margin.All, 2);
var actionSearchBoxTex = resCache.GetTexture("/Textures/Interface/Nano/black_panel_dark_thin_border.png");
var actionSearchBox = new StyleBoxTexture
@@ -368,9 +375,9 @@ public StyleNano(IResourceCache resCache) : base(resCache)
};
tabContainerPanel.SetPatchMargin(StyleBox.Margin.All, 2);
- var tabContainerBoxActive = new StyleBoxFlat {BackgroundColor = new Color(64, 64, 64)};
+ var tabContainerBoxActive = new StyleBoxFlat { BackgroundColor = new Color(64, 64, 64) };
tabContainerBoxActive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
- var tabContainerBoxInactive = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 32)};
+ var tabContainerBoxInactive = new StyleBoxFlat { BackgroundColor = new Color(32, 32, 32) };
tabContainerBoxInactive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
var progressBarBackground = new StyleBoxFlat
@@ -409,21 +416,21 @@ public StyleNano(IResourceCache resCache) : base(resCache)
// Placeholder
var placeholderTexture = resCache.GetTexture("/Textures/Interface/Nano/placeholder.png");
- var placeholder = new StyleBoxTexture {Texture = placeholderTexture};
+ var placeholder = new StyleBoxTexture { Texture = placeholderTexture };
placeholder.SetPatchMargin(StyleBox.Margin.All, 19);
placeholder.SetExpandMargin(StyleBox.Margin.All, -5);
placeholder.Mode = StyleBoxTexture.StretchMode.Tile;
- var itemListBackgroundSelected = new StyleBoxFlat {BackgroundColor = new Color(75, 75, 86)};
+ var itemListBackgroundSelected = new StyleBoxFlat { BackgroundColor = new Color(75, 75, 86) };
itemListBackgroundSelected.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListBackgroundSelected.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
- var itemListItemBackgroundDisabled = new StyleBoxFlat {BackgroundColor = new Color(10, 10, 12)};
+ var itemListItemBackgroundDisabled = new StyleBoxFlat { BackgroundColor = new Color(10, 10, 12) };
itemListItemBackgroundDisabled.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackgroundDisabled.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
- var itemListItemBackground = new StyleBoxFlat {BackgroundColor = new Color(55, 55, 68)};
+ var itemListItemBackground = new StyleBoxFlat { BackgroundColor = new Color(55, 55, 68) };
itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
- var itemListItemBackgroundTransparent = new StyleBoxFlat {BackgroundColor = Color.Transparent};
+ var itemListItemBackgroundTransparent = new StyleBoxFlat { BackgroundColor = Color.Transparent };
itemListItemBackgroundTransparent.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackgroundTransparent.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
@@ -489,9 +496,9 @@ public StyleNano(IResourceCache resCache) : base(resCache)
sliderForeBox.SetPatchMargin(StyleBox.Margin.All, 12);
sliderGrabBox.SetPatchMargin(StyleBox.Margin.All, 12);
- var sliderFillGreen = new StyleBoxTexture(sliderFillBox) {Modulate = Color.LimeGreen};
- var sliderFillRed = new StyleBoxTexture(sliderFillBox) {Modulate = Color.Red};
- var sliderFillBlue = new StyleBoxTexture(sliderFillBox) {Modulate = Color.Blue};
+ var sliderFillGreen = new StyleBoxTexture(sliderFillBox) { Modulate = Color.LimeGreen };
+ var sliderFillRed = new StyleBoxTexture(sliderFillBox) { Modulate = Color.Red };
+ var sliderFillBlue = new StyleBoxTexture(sliderFillBox) { Modulate = Color.Blue };
var sliderFillWhite = new StyleBoxTexture(sliderFillBox) { Modulate = Color.White };
var boxFont13 = resCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13);
@@ -850,19 +857,19 @@ public StyleNano(IResourceCache resCache) : base(resCache)
Element().Pseudo(TextEdit.StylePseudoClassPlaceholder)
.Prop("font-color", Color.Gray),
- // Chat lineedit - we don't actually draw a stylebox around the lineedit itself, we put it around the
- // input + other buttons, so we must clear the default stylebox
- new StyleRule(new SelectorElement(typeof(LineEdit), new[] {StyleClassChatLineEdit}, null, null),
+ // chat subpanels (chat lineedit backing, popup backings)
+ new StyleRule(new SelectorElement(typeof(PanelContainer), new[] {StyleClassChatPanel}, null, null),
new[]
{
- new StyleProperty(LineEdit.StylePropertyStyleBox, new StyleBoxEmpty()),
+ new StyleProperty(PanelContainer.StylePropertyPanel, chatBg),
}),
- // chat subpanels (chat lineedit backing, popup backings)
- new StyleRule(new SelectorElement(typeof(PanelContainer), new[] {StyleClassChatSubPanel}, null, null),
+ // Chat lineedit - we don't actually draw a stylebox around the lineedit itself, we put it around the
+ // input + other buttons, so we must clear the default stylebox
+ new StyleRule(new SelectorElement(typeof(LineEdit), new[] {StyleClassChatLineEdit}, null, null),
new[]
{
- new StyleProperty(PanelContainer.StylePropertyPanel, chatSubBG),
+ new StyleProperty(LineEdit.StylePropertyStyleBox, new StyleBoxEmpty()),
}),
// Action searchbox lineedit
@@ -1468,6 +1475,25 @@ public StyleNano(IResourceCache resCache) : base(resCache)
Element