using Content.Client.UserInterface.Controls; using Content.Shared.Medical.SuitSensor; using Robust.Client.AutoGenerated; using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Map; using Robust.Shared.Timing; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Medical.CrewMonitoring { [GenerateTypedNameReferences] public sealed partial class CrewMonitoringWindow : DefaultWindow { private List _rowsContent = new(); private List<(DirectionIcon Icon, Vector2 Position)> _directionIcons = new(); private readonly IEyeManager _eye; public static int IconSize = 16; // XAML has a `VSeparationOverride` of 20 for each row. public CrewMonitoringWindow() { RobustXamlLoader.Load(this); _eye = IoCManager.Resolve(); } public void ShowSensors(List stSensors, Vector2 worldPosition, bool snap, float precision) { ClearAllSensors(); // TODO scroll container // TODO filter by name & occupation // TODO make each row a xaml-control. Get rid of some of this c# control creation. // add a row for each sensor foreach (var sensor in stSensors) { // add users name and job // format: UserName (Job) var nameLabel = new Label() { Text = $"{sensor.Name} ({sensor.Job})" }; nameLabel.HorizontalExpand = true; SensorsTable.AddChild(nameLabel); _rowsContent.Add(nameLabel); // add users status and damage // format: IsAlive (TotalDamage) var statusText = Loc.GetString(sensor.IsAlive ? "crew-monitoring-user-interface-alive" : "crew-monitoring-user-interface-dead"); if (sensor.TotalDamage != null) { statusText += $" ({sensor.TotalDamage})"; } var statusLabel = new Label() { Text = statusText }; SensorsTable.AddChild(statusLabel); _rowsContent.Add(statusLabel); // add users positions // format: (x, y) var box = GetPositionBox(sensor.Coordinates, worldPosition, snap, precision); SensorsTable.AddChild(box); _rowsContent.Add(box); } } private BoxContainer GetPositionBox(MapCoordinates? coordinates, Vector2 sensorPosition, bool snap, float precision) { var box = new BoxContainer() { Orientation = LayoutOrientation.Horizontal }; if (coordinates == null) { var dirIcon = new DirectionIcon() { SetSize = (IconSize, IconSize), Margin = new(0, 0, 4, 0) }; box.AddChild(dirIcon); box.AddChild(new Label() { Text = Loc.GetString("crew-monitoring-user-interface-no-info") }); } else { // todo: add locations names (kitchen, bridge, etc) var pos = (Vector2i) coordinates.Value.Position; var dirIcon = new DirectionIcon(snap, precision) { SetSize = (IconSize, IconSize), Margin = new(0, 0, 4, 0) }; box.AddChild(dirIcon); box.AddChild(new Label() { Text = pos.ToString() }); _directionIcons.Add((dirIcon, coordinates.Value.Position - sensorPosition)); } return box; } protected override void FrameUpdate(FrameEventArgs args) { // the window is separate from any specific viewport, so there is no real way to get an eye-rotation without // using IEyeManager. Eventually this will have to be reworked for a station AI with multi-viewports. foreach (var (icon, pos) in _directionIcons) { icon.UpdateDirection(pos, -_eye.CurrentEye.Rotation); } } private void ClearAllSensors() { foreach (var child in _rowsContent) { SensorsTable.RemoveChild(child); } _rowsContent.Clear(); } } }