Merge pull request #10721 from vulppine/air-alarm-fixup
Air sensors & air alarm fixup
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class AtmosAlarmableVisualsComponent : Component
|
||||
{
|
||||
[DataField("layerMap")]
|
||||
public string LayerMap { get; } = string.Empty;
|
||||
|
||||
[DataField("alarmStates")]
|
||||
public readonly Dictionary<AtmosAlarmType, string> AlarmStates = new();
|
||||
|
||||
[DataField("hideOnDepowered")]
|
||||
public readonly List<string>? HideOnDepowered;
|
||||
|
||||
// eh...
|
||||
[DataField("setOnDepowered")]
|
||||
public readonly Dictionary<string, string>? SetOnDepowered;
|
||||
}
|
||||
52
Content.Client/Atmos/Monitor/AtmosAlarmableVisualsSystem.cs
Normal file
52
Content.Client/Atmos/Monitor/AtmosAlarmableVisualsSystem.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Power;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor;
|
||||
|
||||
public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmableVisualsComponent>
|
||||
{
|
||||
protected override void OnAppearanceChange(EntityUid uid, AtmosAlarmableVisualsComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite == null || !args.Sprite.LayerMapTryGet(component.LayerMap, out var layer))
|
||||
return;
|
||||
|
||||
if (!args.AppearanceData.TryGetValue(PowerDeviceVisuals.Powered, out var poweredObject) ||
|
||||
poweredObject is not bool powered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.HideOnDepowered != null)
|
||||
{
|
||||
foreach (var visLayer in component.HideOnDepowered)
|
||||
{
|
||||
if (args.Sprite.LayerMapTryGet(visLayer, out int powerVisibilityLayer))
|
||||
args.Sprite.LayerSetVisible(powerVisibilityLayer, powered);
|
||||
}
|
||||
}
|
||||
|
||||
if (component.SetOnDepowered != null && !powered)
|
||||
{
|
||||
foreach (var (setLayer, powerState) in component.SetOnDepowered)
|
||||
{
|
||||
if (args.Sprite.LayerMapTryGet(setLayer, out int setStateLayer))
|
||||
args.Sprite.LayerSetState(setStateLayer, new RSI.StateId(powerState));
|
||||
}
|
||||
}
|
||||
|
||||
if (args.AppearanceData.TryGetValue(AtmosMonitorVisuals.AlarmType, out var alarmTypeObject)
|
||||
&& alarmTypeObject is AtmosAlarmType alarmType
|
||||
&& powered
|
||||
&& component.AlarmStates.TryGetValue(alarmType, out var state))
|
||||
{
|
||||
args.Sprite.LayerSetState(layer, new RSI.StateId(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Power;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor
|
||||
{
|
||||
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)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
[Obsolete("Subscribe to AppearanceChangeEvent instead.")]
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,82 +6,78 @@ 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, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
private AirAlarmWindow? _window;
|
||||
}
|
||||
|
||||
public AirAlarmBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
|
||||
{}
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
protected override void Open()
|
||||
_window = new AirAlarmWindow();
|
||||
|
||||
if (State != 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;
|
||||
UpdateState(State);
|
||||
}
|
||||
|
||||
private void ResyncAllDevices()
|
||||
_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)
|
||||
{
|
||||
SendMessage(new AirAlarmResyncAllDevicesMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
private void OnDeviceDataChanged(string address, IAtmosDeviceData data)
|
||||
{
|
||||
SendMessage(new AirAlarmUpdateDeviceDataMessage(address, data));
|
||||
}
|
||||
_window.UpdateState(cast);
|
||||
}
|
||||
|
||||
private void OnAirAlarmModeChanged(AirAlarmMode mode)
|
||||
{
|
||||
SendMessage(new AirAlarmUpdateAlarmModeMessage(mode));
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
private void OnThresholdChanged(AtmosMonitorThresholdType type, AtmosAlarmThreshold threshold, Gas? gas = null)
|
||||
{
|
||||
SendMessage(new AirAlarmUpdateAlarmThresholdMessage(type, threshold, gas));
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case AirAlarmSetAddressMessage addrMsg:
|
||||
_window.SetAddress(addrMsg.Address);
|
||||
break;
|
||||
case AirAlarmUpdateDeviceDataMessage deviceMsg:
|
||||
_window.UpdateDeviceData(deviceMsg.Address, deviceMsg.Data);
|
||||
break;
|
||||
case AirAlarmUpdateAlarmModeMessage alarmMsg:
|
||||
_window.UpdateModeSelector(alarmMsg.Mode);
|
||||
break;
|
||||
case AirAlarmUpdateAlarmThresholdMessage thresholdMsg:
|
||||
_window.UpdateThreshold(ref thresholdMsg);
|
||||
break;
|
||||
case AirAlarmUpdateAirDataMessage airDataMsg:
|
||||
_window.UpdateGasData(ref airDataMsg.AirData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing) _window?.Dispose();
|
||||
}
|
||||
if (disposing) _window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,22 @@
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<!-- Right column (address, device total) -->
|
||||
<BoxContainer Orientation="Horizontal" Margin="0 0 2 0" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal" Margin="0 0 2 0" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||
<Label Text="{Loc 'air-alarm-ui-window-address-label'}" />
|
||||
<Label Text="{Loc 'air-alarm-ui-window-device-count-label'}" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||
<Label Name="CDeviceAddress" HorizontalAlignment="Right" />
|
||||
<Label Name="CDeviceTotal" HorizontalAlignment="Right" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<Button Name="CResyncButton" Text="{Loc 'air-alarm-ui-window-resync-devices-label'}" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
|
||||
</BoxContainer>
|
||||
<!-- Gas/Device Data -->
|
||||
<TabContainer Name="CTabContainer" VerticalExpand="True" Margin="0 0 0 2">
|
||||
<!-- Gas readout -->
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Name="CGasContainer" Orientation="Vertical" VerticalExpand="True" Margin="2 2 2 2" />
|
||||
</ScrollContainer>
|
||||
<!-- Vent devices -->
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Name="CVentContainer" Orientation="Vertical"/>
|
||||
@@ -40,32 +42,11 @@
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Name="CScrubberContainer" Orientation="Vertical"/>
|
||||
</ScrollContainer>
|
||||
<!-- Alarm thresholds -->
|
||||
<!-- Sensors -->
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
<BoxContainer Name="CPressureThreshold" Orientation="Vertical" Margin="2 0 2 0" />
|
||||
<BoxContainer Name="CTemperatureThreshold" Orientation="Vertical" Margin="2 0 2 0" />
|
||||
<Collapsible Orientation="Vertical">
|
||||
<CollapsibleHeading Title="Gases" />
|
||||
<CollapsibleBody Margin="4 2 4 2">
|
||||
<BoxContainer Name="CGasThresholdContainer" Orientation="Vertical" Margin="2 0 2 0" />
|
||||
</CollapsibleBody>
|
||||
</Collapsible>
|
||||
</BoxContainer>
|
||||
<BoxContainer Name="CSensorContainer" Orientation="Vertical"/>
|
||||
</ScrollContainer>
|
||||
</TabContainer>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 0 0 2">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Label Text="{Loc 'air-alarm-ui-window-address-label'}" HorizontalExpand="True"/>
|
||||
<Label Name="CDeviceAddress" HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 4 0" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Label Text="{Loc 'air-alarm-ui-window-device-count-label'}" HorizontalExpand="True"/>
|
||||
<Label Name="CDeviceTotal" HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 4 0" />
|
||||
</BoxContainer>
|
||||
<Button Name="CResyncButton" Text="{Loc 'air-alarm-ui-window-resync-devices-label'}" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<!-- Mode buttons -->
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'air-alarm-ui-window-mode-label'}" Margin="0 0 2 0" />
|
||||
|
||||
@@ -13,180 +13,141 @@ 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<AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? AtmosAlarmThresholdChanged;
|
||||
public event Action<AirAlarmMode>? AirAlarmModeChanged;
|
||||
public event Action<string>? ResyncDeviceRequested;
|
||||
public event Action? ResyncAllRequested;
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
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 _gasReadout => CGasContainer;
|
||||
private BoxContainer _ventDevices => CVentContainer;
|
||||
private BoxContainer _scrubberDevices => CScrubberContainer;
|
||||
private BoxContainer _pressureThreshold => CPressureThreshold;
|
||||
private BoxContainer _temperatureThreshold => CTemperatureThreshold;
|
||||
private BoxContainer _gasThreshold => CGasThresholdContainer;
|
||||
|
||||
private Dictionary<string, PumpControl> _pumps = new();
|
||||
private Dictionary<string, ScrubberControl> _scrubbers = new();
|
||||
private Button _resyncDevices => CResyncButton;
|
||||
|
||||
private ThresholdControl? _pressureThresholdControl;
|
||||
private ThresholdControl? _temperatureThresholdControl;
|
||||
private Dictionary<Gas, ThresholdControl> _gasThresholdControls = new();
|
||||
|
||||
private Dictionary<Gas, Label> _gasLabels = new();
|
||||
|
||||
private OptionButton _modes => CModeButton;
|
||||
|
||||
public AirAlarmWindow()
|
||||
foreach (var mode in Enum.GetValues<AirAlarmMode>())
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
foreach (var mode in Enum.GetValues<AirAlarmMode>())
|
||||
_modes.AddItem($"{mode}", (int) mode);
|
||||
|
||||
_modes.OnItemSelected += args =>
|
||||
{
|
||||
_modes.SelectId(args.Id);
|
||||
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
|
||||
};
|
||||
|
||||
foreach (var gas in Enum.GetValues<Gas>())
|
||||
{
|
||||
var gasLabel = new Label();
|
||||
_gasReadout.AddChild(gasLabel);
|
||||
_gasLabels.Add(gas, gasLabel);
|
||||
}
|
||||
|
||||
_tabContainer.SetTabTitle(0, Loc.GetString("air-alarm-ui-window-tab-gas"));
|
||||
_tabContainer.SetTabTitle(1, Loc.GetString("air-alarm-ui-window-tab-vents"));
|
||||
_tabContainer.SetTabTitle(2, Loc.GetString("air-alarm-ui-window-tab-scrubbers"));
|
||||
_tabContainer.SetTabTitle(3, Loc.GetString("air-alarm-ui-window-tab-thresholds"));
|
||||
|
||||
_resyncDevices.OnPressed += _ =>
|
||||
{
|
||||
_ventDevices.RemoveAllChildren();
|
||||
_pumps.Clear();
|
||||
_scrubberDevices.RemoveAllChildren();
|
||||
_scrubbers.Clear();
|
||||
ResyncAllRequested!.Invoke();
|
||||
};
|
||||
_modes.AddItem($"{mode}", (int) mode);
|
||||
}
|
||||
|
||||
public void SetAddress(string address)
|
||||
_modes.OnItemSelected += args =>
|
||||
{
|
||||
_address.Text = address;
|
||||
_modes.SelectId(args.Id);
|
||||
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
|
||||
};
|
||||
|
||||
_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"));
|
||||
|
||||
_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 UpdateGasData(ref AirAlarmAirData state)
|
||||
_tabContainer.CurrentTab = (int) state.Tab;
|
||||
}
|
||||
|
||||
public void UpdateModeSelector(AirAlarmMode mode)
|
||||
{
|
||||
_modes.SelectId((int) mode);
|
||||
}
|
||||
|
||||
public void UpdateDeviceData(string addr, IAtmosDeviceData device)
|
||||
{
|
||||
switch (device)
|
||||
{
|
||||
_pressure.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure", ("pressure", $"{state.Pressure:0.##}")));
|
||||
_temperature.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature", ("tempC", $"{TemperatureHelpers.KelvinToCelsius(state.Temperature ?? 0):0.#}"), ("temperature", $"{state.Temperature:0.##}")));
|
||||
_alarmState.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state", ("state", $"{state.AlarmState}")));
|
||||
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);
|
||||
}
|
||||
|
||||
if (state.Gases != null)
|
||||
foreach (var (gas, amount) in state.Gases)
|
||||
_gasLabels[gas].Text = Loc.GetString("air-alarm-ui-gases", ("gas", $"{gas}"), ("amount", $"{amount:0.####}"), ("percentage", $"{(amount / state.TotalMoles):0.##}"));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
_deviceTotal.Text = $"{_pumps.Count + _scrubbers.Count}";
|
||||
}
|
||||
|
||||
public void UpdateThreshold(ref AirAlarmUpdateAlarmThresholdMessage message)
|
||||
{
|
||||
switch (message.Type)
|
||||
{
|
||||
case AtmosMonitorThresholdType.Pressure:
|
||||
if (_pressureThresholdControl == null)
|
||||
{
|
||||
_pressureThresholdControl = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-pressure-title"), message.Threshold, message.Type);
|
||||
_pressureThresholdControl.ThresholdDataChanged += AtmosAlarmThresholdChanged!.Invoke;
|
||||
_pressureThreshold.AddChild(_pressureThresholdControl);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pressureThresholdControl.UpdateThresholdData(message.Threshold);
|
||||
}
|
||||
|
||||
break;
|
||||
case AtmosMonitorThresholdType.Temperature:
|
||||
if (_temperatureThresholdControl == null)
|
||||
{
|
||||
_temperatureThresholdControl = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"), message.Threshold, message.Type);
|
||||
_temperatureThresholdControl.ThresholdDataChanged += AtmosAlarmThresholdChanged!.Invoke;
|
||||
_temperatureThreshold.AddChild(_temperatureThresholdControl);
|
||||
}
|
||||
else
|
||||
{
|
||||
_temperatureThresholdControl.UpdateThresholdData(message.Threshold);
|
||||
}
|
||||
|
||||
break;
|
||||
case AtmosMonitorThresholdType.Gas:
|
||||
if (_gasThresholdControls.TryGetValue((Gas) message.Gas!, out var control))
|
||||
{
|
||||
control.UpdateThresholdData(message.Threshold);
|
||||
break;
|
||||
}
|
||||
|
||||
var gasThreshold = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title", ("gas", $"{(Gas) message.Gas!}")), message.Threshold, AtmosMonitorThresholdType.Gas, (Gas) message.Gas!, 100);
|
||||
gasThreshold.ThresholdDataChanged += AtmosAlarmThresholdChanged!.Invoke;
|
||||
_gasThresholdControls.Add((Gas) message.Gas!, gasThreshold);
|
||||
_gasThreshold.AddChild(gasThreshold);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,96 +8,99 @@ 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;
|
||||
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;
|
||||
_internalBound.Value = (float) _data.InternalPressureBound;
|
||||
_internalBound.OnValueChanged += _ =>
|
||||
{
|
||||
_data.InternalPressureBound = _internalBound.Value;
|
||||
PumpDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
_internalBound.IsValid += value => value >= 0;
|
||||
|
||||
_data = data;
|
||||
_address = address;
|
||||
_externalBound.Value = (float) _data.ExternalPressureBound;
|
||||
_externalBound.OnValueChanged += _ =>
|
||||
{
|
||||
_data.ExternalPressureBound = _externalBound.Value;
|
||||
PumpDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
_externalBound.IsValid += value => value >= 0;
|
||||
|
||||
_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);
|
||||
};
|
||||
foreach (var value in Enum.GetValues<VentPumpDirection>())
|
||||
{
|
||||
_pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
|
||||
}
|
||||
|
||||
public void ChangeData(GasVentPumpData data)
|
||||
_pumpDirection.SelectId((int) _data.PumpDirection);
|
||||
_pumpDirection.OnItemSelected += args =>
|
||||
{
|
||||
_data.Enabled = data.Enabled;
|
||||
_enabled.Pressed = _data.Enabled;
|
||||
_pumpDirection.SelectId(args.Id);
|
||||
_data.PumpDirection = (VentPumpDirection) args.Id;
|
||||
PumpDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
|
||||
_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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,113 +11,116 @@ 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;
|
||||
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;
|
||||
|
||||
_addressLabel.Title = Loc.GetString("air-alarm-ui-atmos-net-device-label", ("address", $"{address}"));
|
||||
|
||||
_enabled.Pressed = data.Enabled;
|
||||
_enabled.OnToggled += _ =>
|
||||
{
|
||||
_data.Enabled = _enabled.Pressed;
|
||||
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);
|
||||
}
|
||||
_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);
|
||||
}
|
||||
|
||||
public void ChangeData(GasVentScrubberData data)
|
||||
_pumpDirection.SelectId((int) _data.PumpDirection);
|
||||
_pumpDirection.OnItemSelected += args =>
|
||||
{
|
||||
_data.Enabled = data.Enabled;
|
||||
_enabled.Pressed = _data.Enabled;
|
||||
_pumpDirection.SelectId(args.Id);
|
||||
_data.PumpDirection = (ScrubberPumpDirection) args.Id;
|
||||
ScrubberDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
|
||||
_data.PumpDirection = data.PumpDirection;
|
||||
_pumpDirection.Select((int) _data.PumpDirection);
|
||||
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);
|
||||
|
||||
_data.VolumeRate = data.VolumeRate;
|
||||
_volumeRate.Value = _data.VolumeRate;
|
||||
ScrubberDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
_gasControls.Add(value, gasButton);
|
||||
_gases.AddChild(gasButton);
|
||||
}
|
||||
|
||||
_data.WideNet = data.WideNet;
|
||||
_wideNet.Pressed = _data.WideNet;
|
||||
}
|
||||
|
||||
var intersect = _data.FilterGases.Intersect(data.FilterGases);
|
||||
public void ChangeData(GasVentScrubberData data)
|
||||
{
|
||||
_data.Enabled = data.Enabled;
|
||||
_enabled.Pressed = _data.Enabled;
|
||||
|
||||
foreach (var value in Enum.GetValues<Gas>())
|
||||
if (!intersect.Contains(value))
|
||||
_gasControls[value].Pressed = false;
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml
Normal file
42
Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml
Normal file
@@ -0,0 +1,42 @@
|
||||
<BoxContainer xmlns="https://spacestation14.io" HorizontalExpand="True">
|
||||
<Collapsible Orientation="Vertical">
|
||||
<CollapsibleHeading Name="SensorAddress" />
|
||||
<CollapsibleBody Margin="2">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" Margin="0 0 2 0" HorizontalExpand="True">
|
||||
<Label Text="{Loc 'air-alarm-ui-window-pressure-label'}" />
|
||||
<Label Text="{Loc 'air-alarm-ui-window-temperature-label'}" />
|
||||
<Label Text="{Loc 'air-alarm-ui-window-alarm-state-label'}" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||
<RichTextLabel Name="PressureLabel" />
|
||||
<RichTextLabel Name="TemperatureLabel" />
|
||||
<RichTextLabel Name="AlarmStateLabel" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<Collapsible Orientation="Vertical" Margin="2">
|
||||
<CollapsibleHeading Title="{Loc 'air-alarm-ui-sensor-gases'}" />
|
||||
<CollapsibleBody>
|
||||
<BoxContainer Name="GasContainer" Orientation="Vertical" Margin="2" />
|
||||
</CollapsibleBody>
|
||||
</Collapsible>
|
||||
<Collapsible Orientation="Vertical" Margin="2">
|
||||
<CollapsibleHeading Title="{Loc 'air-alarm-ui-sensor-thresholds'}" />
|
||||
<CollapsibleBody>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Control Name="PressureThresholdContainer" Margin="2 0 2 0" />
|
||||
<Control Name="TemperatureThresholdContainer" Margin="2 0 2 0" />
|
||||
<Collapsible Orientation="Vertical" Margin="2 0 2 0">
|
||||
<CollapsibleHeading Title="{Loc 'air-alarm-ui-sensor-gases'}" />
|
||||
<CollapsibleBody Margin="4 2 4 2">
|
||||
<BoxContainer Name="GasThresholds" Orientation="Vertical" Margin="2 0 2 0" />
|
||||
</CollapsibleBody>
|
||||
</Collapsible>
|
||||
</BoxContainer>
|
||||
</CollapsibleBody>
|
||||
</Collapsible>
|
||||
</BoxContainer>
|
||||
</CollapsibleBody>
|
||||
</Collapsible>
|
||||
</BoxContainer>
|
||||
105
Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs
Normal file
105
Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using Content.Client.Message;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Temperature;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SensorInfo : BoxContainer
|
||||
{
|
||||
public Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? OnThresholdUpdate;
|
||||
private string _address;
|
||||
|
||||
private ThresholdControl _pressureThreshold;
|
||||
private ThresholdControl _temperatureThreshold;
|
||||
private Dictionary<Gas, ThresholdControl> _gasThresholds = new();
|
||||
private Dictionary<Gas, Label> _gasLabels = new();
|
||||
|
||||
public SensorInfo(AtmosSensorData data, string address)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
_address = address;
|
||||
|
||||
SensorAddress.Title = $"{address} : {data.AlarmState}";
|
||||
|
||||
PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure", ("pressure", $"{data.Pressure:0.##}")));
|
||||
TemperatureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature", ("tempC", $"{TemperatureHelpers.KelvinToCelsius(data.Temperature):0.#}"), ("temperature", $"{data.Temperature:0.##}")));
|
||||
AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state", ("state", $"{data.AlarmState}")));
|
||||
|
||||
foreach (var (gas, amount) in data.Gases)
|
||||
{
|
||||
var label = new Label();
|
||||
label.Text = Loc.GetString("air-alarm-ui-gases", ("gas", $"{gas}"),
|
||||
("amount", $"{amount:0.####}"),
|
||||
("percentage", $"{(amount / data.TotalMoles):0.##}"));
|
||||
GasContainer.AddChild(label);
|
||||
_gasLabels.Add(gas, label);
|
||||
}
|
||||
|
||||
_pressureThreshold =
|
||||
new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-pressure-title"), data.PressureThreshold, AtmosMonitorThresholdType.Pressure);
|
||||
PressureThresholdContainer.AddChild(_pressureThreshold);
|
||||
_temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"), data.TemperatureThreshold,
|
||||
AtmosMonitorThresholdType.Temperature);
|
||||
TemperatureThresholdContainer.AddChild(_temperatureThreshold);
|
||||
|
||||
_pressureThreshold.ThresholdDataChanged += (type, threshold, arg3) =>
|
||||
{
|
||||
OnThresholdUpdate!(_address, type, threshold, arg3);
|
||||
};
|
||||
|
||||
_temperatureThreshold.ThresholdDataChanged += (type, threshold, arg3) =>
|
||||
{
|
||||
OnThresholdUpdate!(_address, type, threshold, arg3);
|
||||
};
|
||||
|
||||
foreach (var (gas, threshold) in data.GasThresholds)
|
||||
{
|
||||
var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title", ("gas", $"{gas}")), threshold, AtmosMonitorThresholdType.Gas, gas, 100);
|
||||
gasThresholdControl.ThresholdDataChanged += (type, threshold, arg3) =>
|
||||
{
|
||||
OnThresholdUpdate!(_address, type, threshold, arg3);
|
||||
};
|
||||
|
||||
_gasThresholds.Add(gas, gasThresholdControl);
|
||||
GasThresholds.AddChild(gasThresholdControl);
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeData(AtmosSensorData data)
|
||||
{
|
||||
SensorAddress.Title = $"{_address} : {data.AlarmState}";
|
||||
PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure", ("pressure", $"{data.Pressure:0.##}")));
|
||||
TemperatureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature", ("tempC", $"{TemperatureHelpers.KelvinToCelsius(data.Temperature):0.#}"), ("temperature", $"{data.Temperature:0.##}")));
|
||||
AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state", ("state", $"{data.AlarmState}")));
|
||||
|
||||
foreach (var (gas, amount) in data.Gases)
|
||||
{
|
||||
if (!_gasLabels.TryGetValue(gas, out var label))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
label.Text = Loc.GetString("air-alarm-ui-gases", ("gas", $"{gas}"),
|
||||
("amount", $"{amount:0.####}"),
|
||||
("percentage", $"{(amount / data.TotalMoles):0.##}"));
|
||||
}
|
||||
|
||||
_pressureThreshold.UpdateThresholdData(data.PressureThreshold);
|
||||
_temperatureThreshold.UpdateThresholdData(data.TemperatureThreshold);
|
||||
foreach (var (gas, control) in _gasThresholds)
|
||||
{
|
||||
if (!data.GasThresholds.TryGetValue(gas, out var threshold))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
control.UpdateThresholdData(threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,287 +8,290 @@ using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
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;
|
||||
HorizontalExpand = true;
|
||||
Orientation = LayoutOrientation.Vertical;
|
||||
|
||||
public event Action? OnValidBoundChanged;
|
||||
public Func<float?, float?>? OnBoundChanged;
|
||||
public Func<float>? OnBoundEnabled;
|
||||
AddChild(new Label { Text = Loc.GetString($"air-alarm-ui-thresholds-{name}") });
|
||||
_bound = new FloatSpinBox(.01f, 2);
|
||||
AddChild(_bound);
|
||||
|
||||
public void SetValue(float? value)
|
||||
_boundEnabled = new CheckBox
|
||||
{
|
||||
Text = Loc.GetString("Enabled")
|
||||
};
|
||||
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();
|
||||
}
|
||||
// otherwise, just set it to the last known value
|
||||
else
|
||||
{
|
||||
_value = _lastValue;
|
||||
_bound.Value = ModifiedLastValue;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateThreshold(float value) => (_value != null) && (value >= 0);
|
||||
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)
|
||||
{
|
||||
return _value != null && value >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user