file-scoped namespaces

This commit is contained in:
vulppine
2022-08-23 10:55:46 -07:00
parent df25715ed3
commit b3a4ef9997
20 changed files with 2503 additions and 2525 deletions

View File

@@ -8,63 +8,62 @@ using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Client.Atmos.Monitor
namespace Content.Client.Atmos.Monitor;
public sealed class AtmosMonitorVisualizer : AppearanceVisualizer
{
public sealed class AtmosMonitorVisualizer : AppearanceVisualizer
[Dependency] IEntityManager _entityManager = default!;
[DataField("layerMap")]
private string _layerMap { get; } = string.Empty;
[DataField("alarmStates")]
private readonly Dictionary<AtmosMonitorAlarmType, string> _alarmStates = new();
[DataField("hideOnDepowered")]
private readonly List<string>? _hideOnDepowered;
// eh...
[DataField("setOnDepowered")]
private readonly Dictionary<string, string>? _setOnDepowered;
[Obsolete("Subscribe to your component being initialised instead.")]
public override void InitializeEntity(EntityUid entity)
{
[Dependency] IEntityManager _entityManager = default!;
[DataField("layerMap")]
private string _layerMap { get; } = string.Empty;
base.InitializeEntity(entity);
[DataField("alarmStates")]
private readonly Dictionary<AtmosMonitorAlarmType, string> _alarmStates = new();
IoCManager.InjectDependencies(this);
}
[DataField("hideOnDepowered")]
private readonly List<string>? _hideOnDepowered;
[Obsolete("Subscribe to AppearanceChangeEvent instead.")]
public override void OnChangeData(AppearanceComponent component)
{
if (!_entityManager.TryGetComponent<SpriteComponent>(component.Owner, out var sprite))
return;
// eh...
[DataField("setOnDepowered")]
private readonly Dictionary<string, string>? _setOnDepowered;
if (!sprite.LayerMapTryGet(_layerMap, out int layer))
return;
[Obsolete("Subscribe to your component being initialised instead.")]
public override void InitializeEntity(EntityUid entity)
if (component.TryGetData<bool>(PowerDeviceVisuals.Powered, out var powered))
{
base.InitializeEntity(entity);
if (_hideOnDepowered != null)
foreach (var visLayer in _hideOnDepowered)
if (sprite.LayerMapTryGet(visLayer, out int powerVisibilityLayer))
sprite.LayerSetVisible(powerVisibilityLayer, powered);
IoCManager.InjectDependencies(this);
if (_setOnDepowered != null && !powered)
foreach (var (setLayer, state) in _setOnDepowered)
if (sprite.LayerMapTryGet(setLayer, out int setStateLayer))
sprite.LayerSetState(setStateLayer, new RSI.StateId(state));
}
[Obsolete("Subscribe to AppearanceChangeEvent instead.")]
public override void OnChangeData(AppearanceComponent component)
if (component.TryGetData<Vector2>(AtmosMonitorVisuals.Offset, out Vector2 offset))
{
if (!_entityManager.TryGetComponent<SpriteComponent>(component.Owner, out var sprite))
return;
if (!sprite.LayerMapTryGet(_layerMap, out int layer))
return;
if (component.TryGetData<bool>(PowerDeviceVisuals.Powered, out var powered))
{
if (_hideOnDepowered != null)
foreach (var visLayer in _hideOnDepowered)
if (sprite.LayerMapTryGet(visLayer, out int powerVisibilityLayer))
sprite.LayerSetVisible(powerVisibilityLayer, powered);
if (_setOnDepowered != null && !powered)
foreach (var (setLayer, state) in _setOnDepowered)
if (sprite.LayerMapTryGet(setLayer, out int setStateLayer))
sprite.LayerSetState(setStateLayer, new RSI.StateId(state));
}
if (component.TryGetData<Vector2>(AtmosMonitorVisuals.Offset, out Vector2 offset))
{
sprite.Offset = offset;
}
if (component.TryGetData<AtmosMonitorAlarmType>(AtmosMonitorVisuals.AlarmType, out var alarmType)
&& powered)
if (_alarmStates.TryGetValue(alarmType, out var state))
sprite.LayerSetState(layer, new RSI.StateId(state));
sprite.Offset = offset;
}
if (component.TryGetData<AtmosMonitorAlarmType>(AtmosMonitorVisuals.AlarmType, out var alarmType)
&& powered)
if (_alarmStates.TryGetValue(alarmType, out var state))
sprite.LayerSetState(layer, new RSI.StateId(state));
}
}

View File

@@ -6,75 +6,74 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
namespace Content.Client.Atmos.Monitor.UI
namespace Content.Client.Atmos.Monitor.UI;
public sealed class AirAlarmBoundUserInterface : BoundUserInterface
{
public sealed class AirAlarmBoundUserInterface : BoundUserInterface
private AirAlarmWindow? _window;
public AirAlarmBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{}
protected override void Open()
{
private AirAlarmWindow? _window;
base.Open();
public AirAlarmBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{}
_window = new AirAlarmWindow();
protected override void Open()
if (State != null) UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window.AtmosDeviceDataChanged += OnDeviceDataChanged;
_window.AtmosAlarmThresholdChanged += OnThresholdChanged;
_window.AirAlarmModeChanged += OnAirAlarmModeChanged;
_window.ResyncAllRequested += ResyncAllDevices;
_window.AirAlarmTabChange += OnTabChanged;
}
private void ResyncAllDevices()
{
SendMessage(new AirAlarmResyncAllDevicesMessage());
}
private void OnDeviceDataChanged(string address, IAtmosDeviceData data)
{
SendMessage(new AirAlarmUpdateDeviceDataMessage(address, data));
}
private void OnAirAlarmModeChanged(AirAlarmMode mode)
{
SendMessage(new AirAlarmUpdateAlarmModeMessage(mode));
}
private void OnThresholdChanged(string address, AtmosMonitorThresholdType type, AtmosAlarmThreshold threshold, Gas? gas = null)
{
SendMessage(new AirAlarmUpdateAlarmThresholdMessage(address, type, threshold, gas));
}
private void OnTabChanged(AirAlarmTab tab)
{
SendMessage(new AirAlarmTabSetMessage(tab));
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not AirAlarmUIState cast || _window == null)
{
base.Open();
_window = new AirAlarmWindow();
if (State != null) UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window.AtmosDeviceDataChanged += OnDeviceDataChanged;
_window.AtmosAlarmThresholdChanged += OnThresholdChanged;
_window.AirAlarmModeChanged += OnAirAlarmModeChanged;
_window.ResyncAllRequested += ResyncAllDevices;
_window.AirAlarmTabChange += OnTabChanged;
return;
}
private void ResyncAllDevices()
{
SendMessage(new AirAlarmResyncAllDevicesMessage());
}
_window.UpdateState(cast);
}
private void OnDeviceDataChanged(string address, IAtmosDeviceData data)
{
SendMessage(new AirAlarmUpdateDeviceDataMessage(address, data));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
private void OnAirAlarmModeChanged(AirAlarmMode mode)
{
SendMessage(new AirAlarmUpdateAlarmModeMessage(mode));
}
private void OnThresholdChanged(string address, AtmosMonitorThresholdType type, AtmosAlarmThreshold threshold, Gas? gas = null)
{
SendMessage(new AirAlarmUpdateAlarmThresholdMessage(address, type, threshold, gas));
}
private void OnTabChanged(AirAlarmTab tab)
{
SendMessage(new AirAlarmTabSetMessage(tab));
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not AirAlarmUIState cast || _window == null)
{
return;
}
_window.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing) _window?.Dispose();
}
if (disposing) _window?.Dispose();
}
}

View File

@@ -13,140 +13,139 @@ using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;
namespace Content.Client.Atmos.Monitor.UI
namespace Content.Client.Atmos.Monitor.UI;
[GenerateTypedNameReferences]
public sealed partial class AirAlarmWindow : DefaultWindow
{
[GenerateTypedNameReferences]
public sealed partial class AirAlarmWindow : DefaultWindow
public event Action<string, IAtmosDeviceData>? AtmosDeviceDataChanged;
public event Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? AtmosAlarmThresholdChanged;
public event Action<AirAlarmMode>? AirAlarmModeChanged;
public event Action<string>? ResyncDeviceRequested;
public event Action? ResyncAllRequested;
public event Action<AirAlarmTab>? AirAlarmTabChange;
private Label _address => CDeviceAddress;
private Label _deviceTotal => CDeviceTotal;
private RichTextLabel _pressure => CPressureLabel;
private RichTextLabel _temperature => CTemperatureLabel;
private RichTextLabel _alarmState => CStatusLabel;
private TabContainer _tabContainer => CTabContainer;
private BoxContainer _ventDevices => CVentContainer;
private BoxContainer _scrubberDevices => CScrubberContainer;
private Dictionary<string, PumpControl> _pumps = new();
private Dictionary<string, ScrubberControl> _scrubbers = new();
private Dictionary<string, SensorInfo> _sensors = new();
private Button _resyncDevices => CResyncButton;
private Dictionary<Gas, Label> _gasLabels = new();
private OptionButton _modes => CModeButton;
public AirAlarmWindow()
{
public event Action<string, IAtmosDeviceData>? AtmosDeviceDataChanged;
public event Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? AtmosAlarmThresholdChanged;
public event Action<AirAlarmMode>? AirAlarmModeChanged;
public event Action<string>? ResyncDeviceRequested;
public event Action? ResyncAllRequested;
public event Action<AirAlarmTab>? AirAlarmTabChange;
RobustXamlLoader.Load(this);
private Label _address => CDeviceAddress;
private Label _deviceTotal => CDeviceTotal;
private RichTextLabel _pressure => CPressureLabel;
private RichTextLabel _temperature => CTemperatureLabel;
private RichTextLabel _alarmState => CStatusLabel;
foreach (var mode in Enum.GetValues<AirAlarmMode>())
_modes.AddItem($"{mode}", (int) mode);
private TabContainer _tabContainer => CTabContainer;
private BoxContainer _ventDevices => CVentContainer;
private BoxContainer _scrubberDevices => CScrubberContainer;
private Dictionary<string, PumpControl> _pumps = new();
private Dictionary<string, ScrubberControl> _scrubbers = new();
private Dictionary<string, SensorInfo> _sensors = new();
private Button _resyncDevices => CResyncButton;
private Dictionary<Gas, Label> _gasLabels = new();
private OptionButton _modes => CModeButton;
public AirAlarmWindow()
_modes.OnItemSelected += args =>
{
RobustXamlLoader.Load(this);
_modes.SelectId(args.Id);
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
};
foreach (var mode in Enum.GetValues<AirAlarmMode>())
_modes.AddItem($"{mode}", (int) mode);
_tabContainer.SetTabTitle(0, Loc.GetString("air-alarm-ui-window-tab-vents"));
_tabContainer.SetTabTitle(1, Loc.GetString("air-alarm-ui-window-tab-scrubbers"));
_tabContainer.SetTabTitle(2, Loc.GetString("air-alarm-ui-window-tab-sensors"));
_modes.OnItemSelected += args =>
{
_modes.SelectId(args.Id);
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
};
_tabContainer.OnTabChanged += idx =>
{
AirAlarmTabChange!((AirAlarmTab) idx);
};
_tabContainer.SetTabTitle(0, Loc.GetString("air-alarm-ui-window-tab-vents"));
_tabContainer.SetTabTitle(1, Loc.GetString("air-alarm-ui-window-tab-scrubbers"));
_tabContainer.SetTabTitle(2, Loc.GetString("air-alarm-ui-window-tab-sensors"));
_resyncDevices.OnPressed += _ =>
{
_ventDevices.RemoveAllChildren();
_pumps.Clear();
_scrubberDevices.RemoveAllChildren();
_scrubbers.Clear();
CSensorContainer.RemoveAllChildren();
_sensors.Clear();
ResyncAllRequested!.Invoke();
};
}
_tabContainer.OnTabChanged += idx =>
{
AirAlarmTabChange!((AirAlarmTab) idx);
};
_resyncDevices.OnPressed += _ =>
{
_ventDevices.RemoveAllChildren();
_pumps.Clear();
_scrubberDevices.RemoveAllChildren();
_scrubbers.Clear();
CSensorContainer.RemoveAllChildren();
_sensors.Clear();
ResyncAllRequested!.Invoke();
};
public void UpdateState(AirAlarmUIState state)
{
_address.Text = state.Address;
_deviceTotal.Text = $"{state.DeviceCount}";
_pressure.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure", ("pressure", $"{state.PressureAverage:0.##}")));
_temperature.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature", ("tempC", $"{TemperatureHelpers.KelvinToCelsius(state.TemperatureAverage):0.#}"), ("temperature", $"{state.TemperatureAverage:0.##}")));
_alarmState.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state", ("state", $"{state.AlarmType}")));
UpdateModeSelector(state.Mode);
foreach (var (addr, dev) in state.DeviceData)
{
UpdateDeviceData(addr, dev);
}
public void UpdateState(AirAlarmUIState state)
_tabContainer.CurrentTab = (int) state.Tab;
}
public void UpdateModeSelector(AirAlarmMode mode)
{
_modes.SelectId((int) mode);
}
public void UpdateDeviceData(string addr, IAtmosDeviceData device)
{
switch (device)
{
_address.Text = state.Address;
_deviceTotal.Text = $"{state.DeviceCount}";
_pressure.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure", ("pressure", $"{state.PressureAverage:0.##}")));
_temperature.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature", ("tempC", $"{TemperatureHelpers.KelvinToCelsius(state.TemperatureAverage):0.#}"), ("temperature", $"{state.TemperatureAverage:0.##}")));
_alarmState.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state", ("state", $"{state.AlarmType}")));
UpdateModeSelector(state.Mode);
foreach (var (addr, dev) in state.DeviceData)
{
UpdateDeviceData(addr, dev);
}
case GasVentPumpData pump:
if (!_pumps.TryGetValue(addr, out var pumpControl))
{
var control= new PumpControl(pump, addr);
control.PumpDataChanged += AtmosDeviceDataChanged!.Invoke;
_pumps.Add(addr, control);
CVentContainer.AddChild(control);
}
else
{
pumpControl.ChangeData(pump);
}
_tabContainer.CurrentTab = (int) state.Tab;
}
break;
case GasVentScrubberData scrubber:
if (!_scrubbers.TryGetValue(addr, out var scrubberControl))
{
var control = new ScrubberControl(scrubber, addr);
control.ScrubberDataChanged += AtmosDeviceDataChanged!.Invoke;
_scrubbers.Add(addr, control);
CScrubberContainer.AddChild(control);
}
else
{
scrubberControl.ChangeData(scrubber);
}
public void UpdateModeSelector(AirAlarmMode mode)
{
_modes.SelectId((int) mode);
}
break;
case AtmosSensorData sensor:
if (!_sensors.TryGetValue(addr, out var sensorControl))
{
var control = new SensorInfo(sensor, addr);
control.OnThresholdUpdate += AtmosAlarmThresholdChanged;
_sensors.Add(addr, control);
CSensorContainer.AddChild(control);
}
else
{
sensorControl.ChangeData(sensor);
}
public void UpdateDeviceData(string addr, IAtmosDeviceData device)
{
switch (device)
{
case GasVentPumpData pump:
if (!_pumps.TryGetValue(addr, out var pumpControl))
{
var control= new PumpControl(pump, addr);
control.PumpDataChanged += AtmosDeviceDataChanged!.Invoke;
_pumps.Add(addr, control);
CVentContainer.AddChild(control);
}
else
{
pumpControl.ChangeData(pump);
}
break;
case GasVentScrubberData scrubber:
if (!_scrubbers.TryGetValue(addr, out var scrubberControl))
{
var control = new ScrubberControl(scrubber, addr);
control.ScrubberDataChanged += AtmosDeviceDataChanged!.Invoke;
_scrubbers.Add(addr, control);
CScrubberContainer.AddChild(control);
}
else
{
scrubberControl.ChangeData(scrubber);
}
break;
case AtmosSensorData sensor:
if (!_sensors.TryGetValue(addr, out var sensorControl))
{
var control = new SensorInfo(sensor, addr);
control.OnThresholdUpdate += AtmosAlarmThresholdChanged;
_sensors.Add(addr, control);
CSensorContainer.AddChild(control);
}
else
{
sensorControl.ChangeData(sensor);
}
break;
}
break;
}
}
}

View File

@@ -8,96 +8,95 @@ using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;
namespace Content.Client.Atmos.Monitor.UI.Widgets
namespace Content.Client.Atmos.Monitor.UI.Widgets;
[GenerateTypedNameReferences]
public sealed partial class PumpControl : BoxContainer
{
[GenerateTypedNameReferences]
public sealed partial class PumpControl : BoxContainer
private GasVentPumpData _data;
private string _address;
public event Action<string, IAtmosDeviceData>? PumpDataChanged;
private CheckBox _enabled => CEnableDevice;
private CollapsibleHeading _addressLabel => CAddress;
private OptionButton _pumpDirection => CPumpDirection;
private OptionButton _pressureCheck => CPressureCheck;
private FloatSpinBox _externalBound => CExternalBound;
private FloatSpinBox _internalBound => CInternalBound;
public PumpControl(GasVentPumpData data, string address)
{
private GasVentPumpData _data;
private string _address;
RobustXamlLoader.Load(this);
public event Action<string, IAtmosDeviceData>? PumpDataChanged;
this.Name = address;
private CheckBox _enabled => CEnableDevice;
private CollapsibleHeading _addressLabel => CAddress;
private OptionButton _pumpDirection => CPumpDirection;
private OptionButton _pressureCheck => CPressureCheck;
private FloatSpinBox _externalBound => CExternalBound;
private FloatSpinBox _internalBound => CInternalBound;
_data = data;
_address = address;
public PumpControl(GasVentPumpData data, string address)
_addressLabel.Title = Loc.GetString("air-alarm-ui-atmos-net-device-label", ("address", $"{address}"));
_enabled.Pressed = data.Enabled;
_enabled.OnToggled += _ =>
{
RobustXamlLoader.Load(this);
_data.Enabled = _enabled.Pressed;
PumpDataChanged?.Invoke(_address, _data);
};
this.Name = address;
_data = data;
_address = address;
_addressLabel.Title = Loc.GetString("air-alarm-ui-atmos-net-device-label", ("address", $"{address}"));
_enabled.Pressed = data.Enabled;
_enabled.OnToggled += _ =>
{
_data.Enabled = _enabled.Pressed;
PumpDataChanged?.Invoke(_address, _data);
};
_internalBound.Value = (float) _data.InternalPressureBound;
_internalBound.OnValueChanged += _ =>
{
_data.InternalPressureBound = _internalBound.Value;
PumpDataChanged?.Invoke(_address, _data);
};
_internalBound.IsValid += value => value >= 0;
_externalBound.Value = (float) _data.ExternalPressureBound;
_externalBound.OnValueChanged += _ =>
{
_data.ExternalPressureBound = _externalBound.Value;
PumpDataChanged?.Invoke(_address, _data);
};
_externalBound.IsValid += value => value >= 0;
foreach (var value in Enum.GetValues<VentPumpDirection>())
_pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
_pumpDirection.SelectId((int) _data.PumpDirection);
_pumpDirection.OnItemSelected += args =>
{
_pumpDirection.SelectId(args.Id);
_data.PumpDirection = (VentPumpDirection) args.Id;
PumpDataChanged?.Invoke(_address, _data);
};
foreach (var value in Enum.GetValues<VentPressureBound>())
_pressureCheck.AddItem(Loc.GetString($"{value}"), (int) value);
_pressureCheck.SelectId((int) _data.PressureChecks);
_pressureCheck.OnItemSelected += args =>
{
_pressureCheck.SelectId(args.Id);
_data.PressureChecks = (VentPressureBound) args.Id;
PumpDataChanged?.Invoke(_address, _data);
};
}
public void ChangeData(GasVentPumpData data)
_internalBound.Value = (float) _data.InternalPressureBound;
_internalBound.OnValueChanged += _ =>
{
_data.Enabled = data.Enabled;
_enabled.Pressed = _data.Enabled;
_data.InternalPressureBound = _internalBound.Value;
PumpDataChanged?.Invoke(_address, _data);
};
_internalBound.IsValid += value => value >= 0;
_data.PumpDirection = data.PumpDirection;
_pumpDirection.SelectId((int) _data.PumpDirection);
_externalBound.Value = (float) _data.ExternalPressureBound;
_externalBound.OnValueChanged += _ =>
{
_data.ExternalPressureBound = _externalBound.Value;
PumpDataChanged?.Invoke(_address, _data);
};
_externalBound.IsValid += value => value >= 0;
_data.PressureChecks = data.PressureChecks;
_pressureCheck.SelectId((int) _data.PressureChecks);
foreach (var value in Enum.GetValues<VentPumpDirection>())
_pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
_data.ExternalPressureBound = data.ExternalPressureBound;
_externalBound.Value = _data.ExternalPressureBound;
_pumpDirection.SelectId((int) _data.PumpDirection);
_pumpDirection.OnItemSelected += args =>
{
_pumpDirection.SelectId(args.Id);
_data.PumpDirection = (VentPumpDirection) args.Id;
PumpDataChanged?.Invoke(_address, _data);
};
_data.InternalPressureBound = data.InternalPressureBound;
_internalBound.Value = _data.InternalPressureBound;
}
foreach (var value in Enum.GetValues<VentPressureBound>())
_pressureCheck.AddItem(Loc.GetString($"{value}"), (int) value);
_pressureCheck.SelectId((int) _data.PressureChecks);
_pressureCheck.OnItemSelected += args =>
{
_pressureCheck.SelectId(args.Id);
_data.PressureChecks = (VentPressureBound) args.Id;
PumpDataChanged?.Invoke(_address, _data);
};
}
public void ChangeData(GasVentPumpData data)
{
_data.Enabled = data.Enabled;
_enabled.Pressed = _data.Enabled;
_data.PumpDirection = data.PumpDirection;
_pumpDirection.SelectId((int) _data.PumpDirection);
_data.PressureChecks = data.PressureChecks;
_pressureCheck.SelectId((int) _data.PressureChecks);
_data.ExternalPressureBound = data.ExternalPressureBound;
_externalBound.Value = _data.ExternalPressureBound;
_data.InternalPressureBound = data.InternalPressureBound;
_internalBound.Value = _data.InternalPressureBound;
}
}

View File

@@ -11,113 +11,112 @@ using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;
namespace Content.Client.Atmos.Monitor.UI.Widgets
namespace Content.Client.Atmos.Monitor.UI.Widgets;
[GenerateTypedNameReferences]
public sealed partial class ScrubberControl : BoxContainer
{
[GenerateTypedNameReferences]
public sealed partial class ScrubberControl : BoxContainer
private GasVentScrubberData _data;
private string _address;
public event Action<string, IAtmosDeviceData>? ScrubberDataChanged;
private CheckBox _enabled => CEnableDevice;
private CollapsibleHeading _addressLabel => CAddress;
private OptionButton _pumpDirection => CPumpDirection;
private FloatSpinBox _volumeRate => CVolumeRate;
private CheckBox _wideNet => CWideNet;
private GridContainer _gases => CGasContainer;
private Dictionary<Gas, Button> _gasControls = new();
public ScrubberControl(GasVentScrubberData data, string address)
{
private GasVentScrubberData _data;
private string _address;
RobustXamlLoader.Load(this);
public event Action<string, IAtmosDeviceData>? ScrubberDataChanged;
this.Name = address;
private CheckBox _enabled => CEnableDevice;
private CollapsibleHeading _addressLabel => CAddress;
private OptionButton _pumpDirection => CPumpDirection;
private FloatSpinBox _volumeRate => CVolumeRate;
private CheckBox _wideNet => CWideNet;
_data = data;
_address = address;
private GridContainer _gases => CGasContainer;
private Dictionary<Gas, Button> _gasControls = new();
_addressLabel.Title = Loc.GetString("air-alarm-ui-atmos-net-device-label", ("address", $"{address}"));
public ScrubberControl(GasVentScrubberData data, string address)
_enabled.Pressed = data.Enabled;
_enabled.OnToggled += _ =>
{
RobustXamlLoader.Load(this);
_data.Enabled = _enabled.Pressed;
ScrubberDataChanged?.Invoke(_address, _data);
};
this.Name = address;
_wideNet.Pressed = data.WideNet;
_wideNet.OnToggled += _ =>
{
_data.WideNet = _wideNet.Pressed;
ScrubberDataChanged?.Invoke(_address, _data);
};
_data = data;
_address = address;
_volumeRate.Value = _data.VolumeRate;
_volumeRate.OnValueChanged += _ =>
{
_data.VolumeRate = _volumeRate.Value;
ScrubberDataChanged?.Invoke(_address, _data);
};
_volumeRate.IsValid += value => value >= 0;
_addressLabel.Title = Loc.GetString("air-alarm-ui-atmos-net-device-label", ("address", $"{address}"));
foreach (var value in Enum.GetValues<ScrubberPumpDirection>())
_pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
_enabled.Pressed = data.Enabled;
_enabled.OnToggled += _ =>
_pumpDirection.SelectId((int) _data.PumpDirection);
_pumpDirection.OnItemSelected += args =>
{
_pumpDirection.SelectId(args.Id);
_data.PumpDirection = (ScrubberPumpDirection) args.Id;
ScrubberDataChanged?.Invoke(_address, _data);
};
foreach (var value in Enum.GetValues<Gas>())
{
var gasButton = new Button
{
_data.Enabled = _enabled.Pressed;
Name = value.ToString(),
Text = Loc.GetString($"{value}"),
ToggleMode = true,
HorizontalExpand = true,
Pressed = _data.FilterGases.Contains(value)
};
gasButton.OnToggled += args =>
{
if (args.Pressed)
_data.FilterGases.Add(value);
else
_data.FilterGases.Remove(value);
ScrubberDataChanged?.Invoke(_address, _data);
};
_wideNet.Pressed = data.WideNet;
_wideNet.OnToggled += _ =>
{
_data.WideNet = _wideNet.Pressed;
ScrubberDataChanged?.Invoke(_address, _data);
};
_volumeRate.Value = _data.VolumeRate;
_volumeRate.OnValueChanged += _ =>
{
_data.VolumeRate = _volumeRate.Value;
ScrubberDataChanged?.Invoke(_address, _data);
};
_volumeRate.IsValid += value => value >= 0;
foreach (var value in Enum.GetValues<ScrubberPumpDirection>())
_pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
_pumpDirection.SelectId((int) _data.PumpDirection);
_pumpDirection.OnItemSelected += args =>
{
_pumpDirection.SelectId(args.Id);
_data.PumpDirection = (ScrubberPumpDirection) args.Id;
ScrubberDataChanged?.Invoke(_address, _data);
};
foreach (var value in Enum.GetValues<Gas>())
{
var gasButton = new Button
{
Name = value.ToString(),
Text = Loc.GetString($"{value}"),
ToggleMode = true,
HorizontalExpand = true,
Pressed = _data.FilterGases.Contains(value)
};
gasButton.OnToggled += args =>
{
if (args.Pressed)
_data.FilterGases.Add(value);
else
_data.FilterGases.Remove(value);
ScrubberDataChanged?.Invoke(_address, _data);
};
_gasControls.Add(value, gasButton);
_gases.AddChild(gasButton);
}
_gasControls.Add(value, gasButton);
_gases.AddChild(gasButton);
}
public void ChangeData(GasVentScrubberData data)
{
_data.Enabled = data.Enabled;
_enabled.Pressed = _data.Enabled;
_data.PumpDirection = data.PumpDirection;
_pumpDirection.Select((int) _data.PumpDirection);
_data.VolumeRate = data.VolumeRate;
_volumeRate.Value = _data.VolumeRate;
_data.WideNet = data.WideNet;
_wideNet.Pressed = _data.WideNet;
var intersect = _data.FilterGases.Intersect(data.FilterGases);
foreach (var value in Enum.GetValues<Gas>())
if (!intersect.Contains(value))
_gasControls[value].Pressed = false;
}
}
}
public void ChangeData(GasVentScrubberData data)
{
_data.Enabled = data.Enabled;
_enabled.Pressed = _data.Enabled;
_data.PumpDirection = data.PumpDirection;
_pumpDirection.Select((int) _data.PumpDirection);
_data.VolumeRate = data.VolumeRate;
_volumeRate.Value = _data.VolumeRate;
_data.WideNet = data.WideNet;
_wideNet.Pressed = _data.WideNet;
var intersect = _data.FilterGases.Intersect(data.FilterGases);
foreach (var value in Enum.GetValues<Gas>())
if (!intersect.Contains(value))
_gasControls[value].Pressed = false;
}
}

View File

@@ -11,286 +11,285 @@ using Robust.Shared.Localization;
// holy FUCK
// this technically works because some of this you can *not* do in XAML but holy FUCK
namespace Content.Client.Atmos.Monitor.UI.Widgets
namespace Content.Client.Atmos.Monitor.UI.Widgets;
[GenerateTypedNameReferences]
public sealed partial class ThresholdControl : BoxContainer
{
[GenerateTypedNameReferences]
public sealed partial class ThresholdControl : BoxContainer
private AtmosAlarmThreshold _threshold;
private AtmosMonitorThresholdType _type;
private Gas? _gas;
public event Action<AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? ThresholdDataChanged;
private CollapsibleHeading _name => CName;
private CheckBox _ignore => CIgnore;
private BoxContainer _dangerBounds => CDangerBounds;
private BoxContainer _warningBounds => CWarningBounds;
private ThresholdBoundControl _upperBoundControl;
private ThresholdBoundControl _lowerBoundControl;
private ThresholdBoundControl _upperWarningBoundControl;
private ThresholdBoundControl _lowerWarningBoundControl;
// i have played myself by making threshold values nullable to
// indicate validity/disabled status, with several layers of side effect
// dependent on the other three values when you change one :HECK:
public ThresholdControl(string name, AtmosAlarmThreshold threshold, AtmosMonitorThresholdType type, Gas? gas = null, float modifier = 1)
{
private AtmosAlarmThreshold _threshold;
private AtmosMonitorThresholdType _type;
private Gas? _gas;
RobustXamlLoader.Load(this);
public event Action<AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? ThresholdDataChanged;
_threshold = threshold;
_type = type;
_gas = gas;
private CollapsibleHeading _name => CName;
private CheckBox _ignore => CIgnore;
private BoxContainer _dangerBounds => CDangerBounds;
private BoxContainer _warningBounds => CWarningBounds;
private ThresholdBoundControl _upperBoundControl;
private ThresholdBoundControl _lowerBoundControl;
private ThresholdBoundControl _upperWarningBoundControl;
private ThresholdBoundControl _lowerWarningBoundControl;
_name.Title = name;
// i have played myself by making threshold values nullable to
// indicate validity/disabled status, with several layers of side effect
// dependent on the other three values when you change one :HECK:
public ThresholdControl(string name, AtmosAlarmThreshold threshold, AtmosMonitorThresholdType type, Gas? gas = null, float modifier = 1)
// i miss rust macros
_upperBoundControl = new ThresholdBoundControl("upper-bound", _threshold.UpperBound, modifier);
_upperBoundControl.OnBoundChanged += value =>
{
RobustXamlLoader.Load(this);
// a lot of threshold logic is baked into the properties,
// so setting this just returns if a change occurred or not
_threshold.TrySetPrimaryBound(AtmosMonitorThresholdBound.Upper, value);
return _threshold.UpperBound;
};
_upperBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
_threshold = threshold;
_type = type;
_gas = gas;
if (_threshold.LowerWarningBound != null)
value = (float) _threshold.LowerWarningBound + 0.1f;
else if (_threshold.LowerBound != null)
value = (float) _threshold.LowerBound + 0.1f;
_name.Title = name;
return value;
};
_upperBoundControl.OnValidBoundChanged += () =>
{
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
};
_dangerBounds.AddChild(_upperBoundControl);
// i miss rust macros
_lowerBoundControl = new ThresholdBoundControl("lower-bound", _threshold.LowerBound, modifier);
_lowerBoundControl.OnBoundChanged += value =>
{
_threshold.TrySetPrimaryBound(AtmosMonitorThresholdBound.Lower, value);
return _threshold.LowerBound;
};
_lowerBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
_upperBoundControl = new ThresholdBoundControl("upper-bound", _threshold.UpperBound, modifier);
_upperBoundControl.OnBoundChanged += value =>
{
// a lot of threshold logic is baked into the properties,
// so setting this just returns if a change occurred or not
_threshold.TrySetPrimaryBound(AtmosMonitorThresholdBound.Upper, value);
return _threshold.UpperBound;
};
_upperBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
if (_threshold.UpperWarningBound != null)
value = (float) _threshold.UpperWarningBound - 0.1f;
else if (_threshold.UpperBound != null)
value = (float) _threshold.UpperBound - 0.1f;
if (_threshold.LowerWarningBound != null)
value = (float) _threshold.LowerWarningBound + 0.1f;
else if (_threshold.LowerBound != null)
value = (float) _threshold.LowerBound + 0.1f;
return value;
};
_lowerBoundControl.OnValidBoundChanged += () =>
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
_dangerBounds.AddChild(_lowerBoundControl);
return value;
};
_upperBoundControl.OnValidBoundChanged += () =>
{
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
};
_dangerBounds.AddChild(_upperBoundControl);
_upperWarningBoundControl = new ThresholdBoundControl("upper-warning-bound", _threshold.UpperWarningBound, modifier);
_upperWarningBoundControl.OnBoundChanged += value =>
{
_threshold.TrySetWarningBound(AtmosMonitorThresholdBound.Upper, value);
return _threshold.UpperWarningBound;
};
_upperWarningBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
_lowerBoundControl = new ThresholdBoundControl("lower-bound", _threshold.LowerBound, modifier);
_lowerBoundControl.OnBoundChanged += value =>
{
_threshold.TrySetPrimaryBound(AtmosMonitorThresholdBound.Lower, value);
return _threshold.LowerBound;
};
_lowerBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
if (_threshold.LowerWarningBound != null)
value = (float) _threshold.LowerWarningBound + 0.1f;
else if (_threshold.LowerBound != null)
value = (float) _threshold.LowerBound + 0.1f;
if (_threshold.UpperWarningBound != null)
value = (float) _threshold.UpperWarningBound - 0.1f;
else if (_threshold.UpperBound != null)
value = (float) _threshold.UpperBound - 0.1f;
return value;
};
_upperWarningBoundControl.OnValidBoundChanged += () =>
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
_warningBounds.AddChild(_upperWarningBoundControl);
return value;
};
_lowerBoundControl.OnValidBoundChanged += () =>
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
_dangerBounds.AddChild(_lowerBoundControl);
_lowerWarningBoundControl = new ThresholdBoundControl("lower-warning-bound", _threshold.LowerWarningBound, modifier);
_lowerWarningBoundControl.OnBoundChanged += value =>
{
_threshold.TrySetWarningBound(AtmosMonitorThresholdBound.Lower, value);
return _threshold.LowerWarningBound;
};
_lowerWarningBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
_upperWarningBoundControl = new ThresholdBoundControl("upper-warning-bound", _threshold.UpperWarningBound, modifier);
_upperWarningBoundControl.OnBoundChanged += value =>
{
_threshold.TrySetWarningBound(AtmosMonitorThresholdBound.Upper, value);
return _threshold.UpperWarningBound;
};
_upperWarningBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
if (_threshold.UpperWarningBound != null)
value = (float) _threshold.UpperWarningBound - 0.1f;
else if (_threshold.UpperBound != null)
value = (float) _threshold.UpperBound - 0.1f;
if (_threshold.LowerWarningBound != null)
value = (float) _threshold.LowerWarningBound + 0.1f;
else if (_threshold.LowerBound != null)
value = (float) _threshold.LowerBound + 0.1f;
return value;
};
_lowerWarningBoundControl.OnValidBoundChanged += () =>
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
return value;
};
_upperWarningBoundControl.OnValidBoundChanged += () =>
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
_warningBounds.AddChild(_upperWarningBoundControl);
_warningBounds.AddChild(_lowerWarningBoundControl);
_lowerWarningBoundControl = new ThresholdBoundControl("lower-warning-bound", _threshold.LowerWarningBound, modifier);
_lowerWarningBoundControl.OnBoundChanged += value =>
{
_threshold.TrySetWarningBound(AtmosMonitorThresholdBound.Lower, value);
return _threshold.LowerWarningBound;
};
_lowerWarningBoundControl.OnBoundEnabled += () =>
{
var value = 0f;
_ignore.OnToggled += args =>
{
_threshold.Ignore = args.Pressed;
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
};
_ignore.Pressed = _threshold.Ignore;
}
if (_threshold.UpperWarningBound != null)
value = (float) _threshold.UpperWarningBound - 0.1f;
else if (_threshold.UpperBound != null)
value = (float) _threshold.UpperBound - 0.1f;
public void UpdateThresholdData(AtmosAlarmThreshold threshold)
{
_upperBoundControl.SetValue(threshold.UpperBound);
_lowerBoundControl.SetValue(threshold.LowerBound);
_upperWarningBoundControl.SetValue(threshold.UpperWarningBound);
_lowerWarningBoundControl.SetValue(threshold.LowerWarningBound);
_ignore.Pressed = threshold.Ignore;
}
return value;
};
_lowerWarningBoundControl.OnValidBoundChanged += () =>
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
_warningBounds.AddChild(_lowerWarningBoundControl);
private sealed class ThresholdBoundControl : BoxContainer
{
// raw values to use in thresholds, prefer these
// over directly setting Modified(Value/LastValue)
// when working with the FloatSpinBox
private float? _value;
private float _lastValue;
_ignore.OnToggled += args =>
{
_threshold.Ignore = args.Pressed;
ThresholdDataChanged!.Invoke(_type, _threshold, _gas);
};
_ignore.Pressed = _threshold.Ignore;
// convenience thing for getting multiplied values
// and also setting value to a usable value
private float? ModifiedValue
{
get => _value * _modifier;
set => _value = value / _modifier;
}
public void UpdateThresholdData(AtmosAlarmThreshold threshold)
private float ModifiedLastValue
{
_upperBoundControl.SetValue(threshold.UpperBound);
_lowerBoundControl.SetValue(threshold.LowerBound);
_upperWarningBoundControl.SetValue(threshold.UpperWarningBound);
_lowerWarningBoundControl.SetValue(threshold.LowerWarningBound);
_ignore.Pressed = threshold.Ignore;
get => _lastValue * _modifier;
set => _lastValue = value / _modifier;
}
private float _modifier;
private sealed class ThresholdBoundControl : BoxContainer
private FloatSpinBox _bound;
private CheckBox _boundEnabled;
public event Action? OnValidBoundChanged;
public Func<float?, float?>? OnBoundChanged;
public Func<float>? OnBoundEnabled;
public void SetValue(float? value)
{
// raw values to use in thresholds, prefer these
// over directly setting Modified(Value/LastValue)
// when working with the FloatSpinBox
private float? _value;
private float _lastValue;
_value = value;
// convenience thing for getting multiplied values
// and also setting value to a usable value
private float? ModifiedValue
if (_value == null)
{
get => _value * _modifier;
set => _value = value / _modifier;
_boundEnabled.Pressed = false;
_bound.Value = 0;
}
private float ModifiedLastValue
else
{
get => _lastValue * _modifier;
set => _lastValue = value / _modifier;
_boundEnabled.Pressed = true;
_bound.Value = (float) ModifiedValue!;
}
}
private float _modifier;
// Modifier indicates what factor the value should be multiplied by.
// Mostly useful to convert tiny decimals to human-readable 'percentages'
// (yes it's still a float, but floatspinbox unfucks that)
public ThresholdBoundControl(string name, float? value, float modifier = 1)
{
_modifier = modifier > 0 ? modifier : 1;
_value = value;
private FloatSpinBox _bound;
private CheckBox _boundEnabled;
this.HorizontalExpand = true;
this.Orientation = LayoutOrientation.Vertical;
public event Action? OnValidBoundChanged;
public Func<float?, float?>? OnBoundChanged;
public Func<float>? OnBoundEnabled;
this.AddChild(new Label { Text = Loc.GetString($"air-alarm-ui-thresholds-{name}") });
_bound = new FloatSpinBox(.01f, 2);
this.AddChild(_bound);
public void SetValue(float? value)
_boundEnabled = new CheckBox
{
Text = Loc.GetString("Enabled")
};
this.AddChild(_boundEnabled);
_bound.Value = ModifiedValue ?? 0;
_lastValue = _value ?? 0;
_boundEnabled.Pressed = _value != null;
_bound.OnValueChanged += ChangeValue;
_bound.IsValid += ValidateThreshold;
_boundEnabled.OnToggled += ToggleBound;
}
private void ChangeValue(FloatSpinBox.FloatSpinBoxEventArgs args)
{
// ensure that the value in the spinbox is transformed
ModifiedValue = args.Value;
// set the value in the scope above
var value = OnBoundChanged!(_value);
// is the value not null, or has it changed?
if (value != null || value != _lastValue)
{
_value = value;
if (_value == null)
{
_boundEnabled.Pressed = false;
_bound.Value = 0;
}
else
{
_boundEnabled.Pressed = true;
_bound.Value = (float) ModifiedValue!;
}
}
// Modifier indicates what factor the value should be multiplied by.
// Mostly useful to convert tiny decimals to human-readable 'percentages'
// (yes it's still a float, but floatspinbox unfucks that)
public ThresholdBoundControl(string name, float? value, float modifier = 1)
{
_modifier = modifier > 0 ? modifier : 1;
_value = value;
this.HorizontalExpand = true;
this.Orientation = LayoutOrientation.Vertical;
this.AddChild(new Label { Text = Loc.GetString($"air-alarm-ui-thresholds-{name}") });
_bound = new FloatSpinBox(.01f, 2);
this.AddChild(_bound);
_boundEnabled = new CheckBox
{
Text = Loc.GetString("Enabled")
};
this.AddChild(_boundEnabled);
_bound.Value = ModifiedValue ?? 0;
_lastValue = _value ?? 0;
_boundEnabled.Pressed = _value != null;
_bound.OnValueChanged += ChangeValue;
_bound.IsValid += ValidateThreshold;
_boundEnabled.OnToggled += ToggleBound;
}
private void ChangeValue(FloatSpinBox.FloatSpinBoxEventArgs args)
{
// ensure that the value in the spinbox is transformed
ModifiedValue = args.Value;
// set the value in the scope above
var value = OnBoundChanged!(_value);
// is the value not null, or has it changed?
if (value != null || value != _lastValue)
{
_value = value;
_lastValue = (float) value!;
OnValidBoundChanged!.Invoke();
}
// otherwise, just set it to the last known value
else
{
_value = _lastValue;
_bound.Value = ModifiedLastValue;
}
}
private void ToggleBound(BaseButton.ButtonToggledEventArgs args)
{
if (args.Pressed)
{
var value = OnBoundChanged!(_lastValue);
if (value != _lastValue)
{
value = OnBoundChanged!(OnBoundEnabled!());
if (value == null || value < 0)
{
// TODO: Improve UX here, this is ass
// basically this implies that the bound
// you currently have is too aggressive
// for the other set of values, so a
// default value (which is +/-0.1) can't
// be used
_boundEnabled.Pressed = false;
return;
}
}
_value = value;
_bound.Value = (float) ModifiedValue!;
_lastValue = (float) _value;
}
else
{
_value = null;
_bound.Value = 0f;
OnBoundChanged!(_value);
}
_lastValue = (float) value!;
OnValidBoundChanged!.Invoke();
}
private bool ValidateThreshold(float value) => (_value != null) && (value >= 0);
// otherwise, just set it to the last known value
else
{
_value = _lastValue;
_bound.Value = ModifiedLastValue;
}
}
private void ToggleBound(BaseButton.ButtonToggledEventArgs args)
{
if (args.Pressed)
{
var value = OnBoundChanged!(_lastValue);
if (value != _lastValue)
{
value = OnBoundChanged!(OnBoundEnabled!());
if (value == null || value < 0)
{
// TODO: Improve UX here, this is ass
// basically this implies that the bound
// you currently have is too aggressive
// for the other set of values, so a
// default value (which is +/-0.1) can't
// be used
_boundEnabled.Pressed = false;
return;
}
}
_value = value;
_bound.Value = (float) ModifiedValue!;
_lastValue = (float) _value;
}
else
{
_value = null;
_bound.Value = 0f;
OnBoundChanged!(_value);
}
OnValidBoundChanged!.Invoke();
}
private bool ValidateThreshold(float value) => (_value != null) && (value >= 0);
}
}