More user friendly crew monitor UI (#17328)

This commit is contained in:
Ahion
2023-06-15 05:29:52 +02:00
committed by GitHub
parent 4837ae03bd
commit de63c5230b
7 changed files with 75 additions and 44 deletions

View File

@@ -1,4 +1,4 @@
<controls:FancyWindow xmlns="https://spacestation14.io" <controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.Pinpointer.UI" xmlns:ui="clr-namespace:Content.Client.Pinpointer.UI"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls" xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'crew-monitoring-user-interface-title'}" Title="{Loc 'crew-monitoring-user-interface-title'}"
@@ -7,7 +7,7 @@
<BoxContainer Orientation="Horizontal"> <BoxContainer Orientation="Horizontal">
<ScrollContainer HorizontalExpand="True" <ScrollContainer HorizontalExpand="True"
VerticalExpand="True" VerticalExpand="True"
Margin="0, 0, 8, 0"> Margin="8, 8, 8, 8">
<GridContainer Name="SensorsTable" <GridContainer Name="SensorsTable"
HorizontalExpand="True" HorizontalExpand="True"
VerticalExpand="True" VerticalExpand="True"
@@ -26,6 +26,12 @@
<!-- Table rows are filled by code --> <!-- Table rows are filled by code -->
</GridContainer> </GridContainer>
<Label Name="NoServerLabel"
Text="{Loc 'crew-monitoring-user-interface-no-server'}"
StyleClasses="LabelHeading"
FontColorOverride="Red"
HorizontalAlignment="Center"
Visible="false"/>
</ScrollContainer> </ScrollContainer>
<ui:NavMapControl Name="NavMap" <ui:NavMapControl Name="NavMap"
Margin="5 5"/> Margin="5 5"/>

View File

@@ -21,6 +21,7 @@ namespace Content.Client.Medical.CrewMonitoring
private readonly IEntityManager _entManager; private readonly IEntityManager _entManager;
private readonly IEyeManager _eye; private readonly IEyeManager _eye;
private EntityUid? _stationUid; private EntityUid? _stationUid;
private CrewMonitoringButton? _trackedButton;
public static int IconSize = 16; // XAML has a `VSeparationOverride` of 20 for each row. public static int IconSize = 16; // XAML has a `VSeparationOverride` of 20 for each row.
@@ -52,27 +53,28 @@ namespace Content.Client.Medical.CrewMonitoring
// TODO scroll container // TODO scroll container
// TODO filter by name & occupation // TODO filter by name & occupation
// TODO make each row a xaml-control. Get rid of some of this c# control creation. // TODO make each row a xaml-control. Get rid of some of this c# control creation.
if (stSensors.Count == 0)
{
NoServerLabel.Visible = true;
return;
}
NoServerLabel.Visible = false;
// add a row for each sensor // add a row for each sensor
foreach (var sensor in stSensors.OrderBy(a => a.Name)) foreach (var sensor in stSensors.OrderBy(a => a.Name))
{ {
// add users name // add button with username
// format: UserName var nameButton = new CrewMonitoringButton()
var nameLabel = new PanelContainer()
{
PanelOverride = new StyleBoxFlat()
{
BackgroundColor = StyleNano.ButtonColorDisabled,
},
Children =
{
new Label()
{ {
SuitSensorUid = sensor.SuitSensorUid,
Coordinates = sensor.Coordinates,
Text = sensor.Name, Text = sensor.Name,
Margin = new Thickness(5f, 5f), Margin = new Thickness(5f, 5f),
}
}
}; };
if (sensor.SuitSensorUid == _trackedButton?.SuitSensorUid)
nameButton.AddStyleClass(StyleNano.StyleClassButtonColorGreen);
SensorsTable.AddChild(nameButton);
_rowsContent.Add(nameButton);
// add users job // add users job
// format: JobName // format: JobName
@@ -81,9 +83,6 @@ namespace Content.Client.Medical.CrewMonitoring
Text = sensor.Job, Text = sensor.Job,
HorizontalExpand = true HorizontalExpand = true
}; };
SensorsTable.AddChild(nameLabel);
_rowsContent.Add(nameLabel);
SensorsTable.AddChild(jobLabel); SensorsTable.AddChild(jobLabel);
_rowsContent.Add(jobLabel); _rowsContent.Add(jobLabel);
@@ -112,33 +111,32 @@ namespace Content.Client.Medical.CrewMonitoring
if (sensor.Coordinates != null && NavMap.Visible) if (sensor.Coordinates != null && NavMap.Visible)
{ {
NavMap.TrackedCoordinates.TryAdd(sensor.Coordinates.Value, (true, Color.FromHex("#B02E26"))); NavMap.TrackedCoordinates.TryAdd(sensor.Coordinates.Value,
nameLabel.MouseFilter = MouseFilterMode.Stop; (true, sensor.SuitSensorUid == _trackedButton?.SuitSensorUid ? StyleNano.PointGreen : StyleNano.PointRed));
// Hide all others upon mouseover. nameButton.OnButtonUp += args =>
nameLabel.OnMouseEntered += args =>
{ {
foreach (var (coord, value) in NavMap.TrackedCoordinates) if (_trackedButton != null && _trackedButton?.Coordinates != null)
{ //Make previous point red
if (coord == sensor.Coordinates) NavMap.TrackedCoordinates[_trackedButton.Coordinates.Value] = (true, StyleNano.PointRed);
continue;
NavMap.TrackedCoordinates[coord] = (false, value.Color); NavMap.TrackedCoordinates[sensor.Coordinates.Value] = (true, StyleNano.PointGreen);
} NavMap.CenterToCoordinates(sensor.Coordinates.Value);
};
nameButton.AddStyleClass(StyleNano.StyleClassButtonColorGreen);
nameLabel.OnMouseExited += args => if (_trackedButton != null)
{ { //Make previous button default
foreach (var (coord, value) in NavMap.TrackedCoordinates) var previosButton = SensorsTable.GetChild(_trackedButton.IndexInTable);
{ previosButton.RemoveStyleClass(StyleNano.StyleClassButtonColorGreen);
NavMap.TrackedCoordinates[coord] = (true, value.Color);
} }
_trackedButton = nameButton;
_trackedButton.IndexInTable = nameButton.GetPositionInParent();
}; };
} }
} }
// For debugging. // Show monitor point
//if (monitorCoords != null) if (monitorCoords != null)
// NavMap.TrackedCoordinates.Add(monitorCoords.Value, (true, Color.FromHex("#FF00FF"))); NavMap.TrackedCoordinates.Add(monitorCoords.Value, (true, StyleNano.PointMagenta));
} }
private BoxContainer GetPositionBox(EntityCoordinates? coordinates, Vector2 monitorCoordsInStationSpace, bool snap, float precision) private BoxContainer GetPositionBox(EntityCoordinates? coordinates, Vector2 monitorCoordsInStationSpace, bool snap, float precision)
@@ -203,10 +201,16 @@ namespace Content.Client.Medical.CrewMonitoring
{ {
SensorsTable.RemoveChild(child); SensorsTable.RemoveChild(child);
} }
_rowsContent.Clear(); _rowsContent.Clear();
_directionIcons.Clear(); _directionIcons.Clear();
NavMap.TrackedCoordinates.Clear(); NavMap.TrackedCoordinates.Clear();
} }
} }
public sealed class CrewMonitoringButton : Button
{
public int IndexInTable;
public EntityUid? SuitSensorUid;
public EntityCoordinates? Coordinates;
}
} }

View File

@@ -95,6 +95,15 @@ public sealed class NavMapControl : MapGridControl
}; };
} }
public void CenterToCoordinates(EntityCoordinates coordinates)
{
if (_entManager.TryGetComponent<PhysicsComponent>(MapUid, out var physics))
{
_offset = new Vector2(coordinates.X, coordinates.Y) - physics.LocalCenter;
}
_recenter.Disabled = false;
}
protected override void KeyBindDown(GUIBoundKeyEventArgs args) protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{ {
base.KeyBindDown(args); base.KeyBindDown(args);

View File

@@ -104,6 +104,11 @@ namespace Content.Client.Stylesheets
public static readonly Color ButtonColorGoodDefault = Color.FromHex("#3E6C45"); public static readonly Color ButtonColorGoodDefault = Color.FromHex("#3E6C45");
public static readonly Color ButtonColorGoodHovered = Color.FromHex("#31843E"); public static readonly Color ButtonColorGoodHovered = Color.FromHex("#31843E");
//NavMap
public static readonly Color PointRed = Color.FromHex("#B02E26");
public static readonly Color PointGreen = Color.FromHex("#38b026");
public static readonly Color PointMagenta = Color.FromHex("#FF00FF");
// Context menu button colors // Context menu button colors
public static readonly Color ButtonColorContext = Color.FromHex("#1119"); public static readonly Color ButtonColorContext = Color.FromHex("#1119");
public static readonly Color ButtonColorContextHover = Color.DarkSlateGray; public static readonly Color ButtonColorContextHover = Color.DarkSlateGray;

View File

@@ -321,7 +321,7 @@ namespace Content.Server.Medical.SuitSensors
totalDamage = damageable.TotalDamage.Int(); totalDamage = damageable.TotalDamage.Int();
// finally, form suit sensor status // finally, form suit sensor status
var status = new SuitSensorStatus(userName, userJob); var status = new SuitSensorStatus(uid, userName, userJob);
switch (sensor.Mode) switch (sensor.Mode)
{ {
case SuitSensorMode.SensorBinary: case SuitSensorMode.SensorBinary:
@@ -371,6 +371,7 @@ namespace Content.Server.Medical.SuitSensors
[SuitSensorConstants.NET_NAME] = status.Name, [SuitSensorConstants.NET_NAME] = status.Name,
[SuitSensorConstants.NET_JOB] = status.Job, [SuitSensorConstants.NET_JOB] = status.Job,
[SuitSensorConstants.NET_IS_ALIVE] = status.IsAlive, [SuitSensorConstants.NET_IS_ALIVE] = status.IsAlive,
[SuitSensorConstants.NET_SUIT_SENSOR_UID] = status.SuitSensorUid,
}; };
if (status.TotalDamage != null) if (status.TotalDamage != null)
@@ -397,12 +398,13 @@ namespace Content.Server.Medical.SuitSensors
if (!payload.TryGetValue(SuitSensorConstants.NET_NAME, out string? name)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_NAME, out string? name)) return null;
if (!payload.TryGetValue(SuitSensorConstants.NET_JOB, out string? job)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_JOB, out string? job)) return null;
if (!payload.TryGetValue(SuitSensorConstants.NET_IS_ALIVE, out bool? isAlive)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_IS_ALIVE, out bool? isAlive)) return null;
if (!payload.TryGetValue(SuitSensorConstants.NET_SUIT_SENSOR_UID, out EntityUid suitSensorUid)) return null;
// try get total damage and cords (optionals) // try get total damage and cords (optionals)
payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE, out int? totalDamage); payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE, out int? totalDamage);
payload.TryGetValue(SuitSensorConstants.NET_COORDINATES, out EntityCoordinates? cords); payload.TryGetValue(SuitSensorConstants.NET_COORDINATES, out EntityCoordinates? cords);
var status = new SuitSensorStatus(name, job) var status = new SuitSensorStatus(suitSensorUid, name, job)
{ {
IsAlive = isAlive.Value, IsAlive = isAlive.Value,
TotalDamage = totalDamage, TotalDamage = totalDamage,

View File

@@ -1,4 +1,4 @@
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Medical.SuitSensor namespace Content.Shared.Medical.SuitSensor
@@ -6,13 +6,15 @@ namespace Content.Shared.Medical.SuitSensor
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed class SuitSensorStatus public sealed class SuitSensorStatus
{ {
public SuitSensorStatus(string name, string job) public SuitSensorStatus(EntityUid suitSensorUid, string name, string job)
{ {
SuitSensorUid = suitSensorUid;
Name = name; Name = name;
Job = job; Job = job;
} }
public TimeSpan Timestamp; public TimeSpan Timestamp;
public EntityUid SuitSensorUid;
public string Name; public string Name;
public string Job; public string Job;
public bool IsAlive; public bool IsAlive;
@@ -51,6 +53,7 @@ namespace Content.Shared.Medical.SuitSensor
public const string NET_IS_ALIVE = "alive"; public const string NET_IS_ALIVE = "alive";
public const string NET_TOTAL_DAMAGE = "vitals"; public const string NET_TOTAL_DAMAGE = "vitals";
public const string NET_COORDINATES = "coords"; public const string NET_COORDINATES = "coords";
public const string NET_SUIT_SENSOR_UID = "uid";
///Used by the CrewMonitoringServerSystem to send the status of all connected suit sensors to each crew monitor ///Used by the CrewMonitoringServerSystem to send the status of all connected suit sensors to each crew monitor
public const string NET_STATUS_COLLECTION = "suit-status-collection"; public const string NET_STATUS_COLLECTION = "suit-status-collection";

View File

@@ -10,3 +10,5 @@ crew-monitoring-user-interface-location = Location
crew-monitoring-user-interface-alive = Alive crew-monitoring-user-interface-alive = Alive
crew-monitoring-user-interface-dead = Dead crew-monitoring-user-interface-dead = Dead
crew-monitoring-user-interface-no-info = N/A crew-monitoring-user-interface-no-info = N/A
crew-monitoring-user-interface-no-server = Server not found