GasAnalyzerWindow.xaml.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. using System.Numerics;
  2. using Content.Client.UserInterface.Controls;
  3. using Content.Shared.Atmos;
  4. using Content.Shared.Temperature;
  5. using Robust.Client.Graphics;
  6. using Robust.Client.UserInterface;
  7. using Robust.Client.UserInterface.Controls;
  8. using Robust.Client.UserInterface.CustomControls;
  9. using Robust.Client.AutoGenerated;
  10. using Robust.Client.UserInterface.XAML;
  11. using static Content.Shared.Atmos.Components.GasAnalyzerComponent;
  12. using Direction = Robust.Shared.Maths.Direction;
  13. namespace Content.Client.Atmos.UI
  14. {
  15. [GenerateTypedNameReferences]
  16. public sealed partial class GasAnalyzerWindow : DefaultWindow
  17. {
  18. private NetEntity _currentEntity = NetEntity.Invalid;
  19. public GasAnalyzerWindow()
  20. {
  21. RobustXamlLoader.Load(this);
  22. }
  23. public void Populate(GasAnalyzerUserMessage msg)
  24. {
  25. if (msg.Error != null)
  26. {
  27. CTopBox.AddChild(new Label
  28. {
  29. Text = Loc.GetString("gas-analyzer-window-error-text", ("errorText", msg.Error)),
  30. FontColorOverride = Color.Red
  31. });
  32. return;
  33. }
  34. if (msg.NodeGasMixes.Length == 0)
  35. {
  36. CTopBox.AddChild(new Label
  37. {
  38. Text = Loc.GetString("gas-analyzer-window-no-data")
  39. });
  40. MinSize = new Vector2(CTopBox.DesiredSize.X + 40, MinSize.Y);
  41. return;
  42. }
  43. Vector2 minSize;
  44. // Environment Tab
  45. var envMix = msg.NodeGasMixes[0];
  46. CTabContainer.SetTabTitle(1, envMix.Name);
  47. CEnvironmentMix.RemoveAllChildren();
  48. GenerateGasDisplay(envMix, CEnvironmentMix);
  49. // Device Tab
  50. if (msg.NodeGasMixes.Length > 1)
  51. {
  52. if (_currentEntity != msg.DeviceUid)
  53. {
  54. // when we get new device data switch to the device tab
  55. CTabContainer.CurrentTab = 0;
  56. _currentEntity = msg.DeviceUid;
  57. }
  58. CTabContainer.SetTabVisible(0, true);
  59. CTabContainer.SetTabTitle(0, Loc.GetString("gas-analyzer-window-tab-title-capitalized", ("title", msg.DeviceName)));
  60. // Set up Grid
  61. GridIcon.OverrideDirection = msg.NodeGasMixes.Length switch
  62. {
  63. // Unary layout
  64. 2 => Direction.South,
  65. // Binary layout
  66. 3 => Direction.East,
  67. // Trinary layout
  68. 4 => Direction.East,
  69. _ => GridIcon.OverrideDirection
  70. };
  71. GridIcon.SetEntity(IoCManager.Resolve<IEntityManager>().GetEntity(msg.DeviceUid));
  72. LeftPanel.RemoveAllChildren();
  73. MiddlePanel.RemoveAllChildren();
  74. RightPanel.RemoveAllChildren();
  75. if (msg.NodeGasMixes.Length == 2)
  76. {
  77. // Unary, use middle
  78. LeftPanelLabel.Text = string.Empty;
  79. MiddlePanelLabel.Text = Loc.GetString("gas-analyzer-window-tab-title-capitalized", ("title", msg.NodeGasMixes[1].Name));
  80. RightPanelLabel.Text = string.Empty;
  81. LeftPanel.Visible = false;
  82. MiddlePanel.Visible = true;
  83. RightPanel.Visible = false;
  84. GenerateGasDisplay(msg.NodeGasMixes[1], MiddlePanel);
  85. minSize = new Vector2(CDeviceGrid.DesiredSize.X + 40, MinSize.Y);
  86. }
  87. else if (msg.NodeGasMixes.Length == 3)
  88. {
  89. // Binary, use left and right
  90. LeftPanelLabel.Text = Loc.GetString("gas-analyzer-window-tab-title-capitalized", ("title", msg.NodeGasMixes[1].Name));
  91. MiddlePanelLabel.Text = string.Empty;
  92. RightPanelLabel.Text = Loc.GetString("gas-analyzer-window-tab-title-capitalized", ("title", msg.NodeGasMixes[2].Name));
  93. LeftPanel.Visible = true;
  94. MiddlePanel.Visible = false;
  95. RightPanel.Visible = true;
  96. GenerateGasDisplay(msg.NodeGasMixes[1], LeftPanel);
  97. GenerateGasDisplay(msg.NodeGasMixes[2], RightPanel);
  98. minSize = new Vector2(CDeviceGrid.DesiredSize.X + 40, MinSize.Y);
  99. }
  100. else if (msg.NodeGasMixes.Length == 4)
  101. {
  102. // Trinary, use all three
  103. // Trinary can be flippable, which complicates how to display things currently
  104. LeftPanelLabel.Text = Loc.GetString("gas-analyzer-window-tab-title-capitalized",
  105. ("title", msg.DeviceFlipped ? msg.NodeGasMixes[1].Name : msg.NodeGasMixes[3].Name));
  106. MiddlePanelLabel.Text = Loc.GetString("gas-analyzer-window-tab-title-capitalized", ("title", msg.NodeGasMixes[2].Name));
  107. RightPanelLabel.Text = Loc.GetString("gas-analyzer-window-tab-title-capitalized",
  108. ("title", msg.DeviceFlipped ? msg.NodeGasMixes[3].Name : msg.NodeGasMixes[1].Name));
  109. LeftPanel.Visible = true;
  110. MiddlePanel.Visible = true;
  111. RightPanel.Visible = true;
  112. GenerateGasDisplay(msg.DeviceFlipped ? msg.NodeGasMixes[1] : msg.NodeGasMixes[3], LeftPanel);
  113. GenerateGasDisplay(msg.NodeGasMixes[2], MiddlePanel);
  114. GenerateGasDisplay(msg.DeviceFlipped ? msg.NodeGasMixes[3] : msg.NodeGasMixes[1], RightPanel);
  115. minSize = new Vector2(CDeviceGrid.DesiredSize.X + 40, MinSize.Y);
  116. }
  117. else
  118. {
  119. // oh shit of fuck its more than 4 this ui isn't gonna look pretty anymore
  120. for (var i = 1; i < msg.NodeGasMixes.Length; i++)
  121. {
  122. GenerateGasDisplay(msg.NodeGasMixes[i], CDeviceMixes);
  123. }
  124. LeftPanel.Visible = false;
  125. MiddlePanel.Visible = false;
  126. RightPanel.Visible = false;
  127. minSize = new Vector2(CDeviceMixes.DesiredSize.X + 40, MinSize.Y);
  128. }
  129. }
  130. else
  131. {
  132. // Hide device tab, no device selected
  133. CTabContainer.SetTabVisible(0, false);
  134. CTabContainer.CurrentTab = 1;
  135. minSize = new Vector2(CEnvironmentMix.DesiredSize.X + 40, MinSize.Y);
  136. _currentEntity = NetEntity.Invalid;
  137. }
  138. MinSize = minSize;
  139. }
  140. private void GenerateGasDisplay(GasMixEntry gasMix, Control parent)
  141. {
  142. var panel = new PanelContainer
  143. {
  144. VerticalExpand = true,
  145. HorizontalExpand = true,
  146. Margin = new Thickness(4),
  147. PanelOverride = new StyleBoxFlat{BorderColor = Color.FromHex("#4f4f4f"), BorderThickness = new Thickness(1)}
  148. };
  149. var dataContainer = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Vertical, VerticalExpand = true, Margin = new Thickness(4)};
  150. parent.AddChild(panel);
  151. panel.AddChild(dataContainer);
  152. // Volume label
  153. var volBox = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Horizontal };
  154. volBox.AddChild(new Label
  155. {
  156. Text = Loc.GetString("gas-analyzer-window-volume-text")
  157. });
  158. volBox.AddChild(new Control
  159. {
  160. MinSize = new Vector2(10, 0),
  161. HorizontalExpand = true
  162. });
  163. volBox.AddChild(new Label
  164. {
  165. Text = Loc.GetString("gas-analyzer-window-volume-val-text", ("volume", $"{gasMix.Volume:0.##}")),
  166. Align = Label.AlignMode.Right,
  167. HorizontalExpand = true
  168. });
  169. dataContainer.AddChild(volBox);
  170. // Pressure label
  171. var presBox = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Horizontal };
  172. presBox.AddChild(new Label
  173. {
  174. Text = Loc.GetString("gas-analyzer-window-pressure-text")
  175. });
  176. presBox.AddChild(new Control
  177. {
  178. MinSize = new Vector2(10, 0),
  179. HorizontalExpand = true
  180. });
  181. presBox.AddChild(new Label
  182. {
  183. Text = Loc.GetString("gas-analyzer-window-pressure-val-text", ("pressure", $"{gasMix.Pressure:0.##}")),
  184. Align = Label.AlignMode.Right,
  185. HorizontalExpand = true
  186. });
  187. dataContainer.AddChild(presBox);
  188. // If there is no gas, it doesn't really have a temperature, so skip displaying it
  189. if (gasMix.Pressure > Atmospherics.GasMinMoles)
  190. {
  191. // Temperature label
  192. var tempBox = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Horizontal };
  193. tempBox.AddChild(new Label
  194. {
  195. Text = Loc.GetString("gas-analyzer-window-temperature-text")
  196. });
  197. tempBox.AddChild(new Control
  198. {
  199. MinSize = new Vector2(10, 0),
  200. HorizontalExpand = true
  201. });
  202. tempBox.AddChild(new Label
  203. {
  204. Text = Loc.GetString("gas-analyzer-window-temperature-val-text",
  205. ("tempK", $"{gasMix.Temperature:0.#}"),
  206. ("tempC", $"{TemperatureHelpers.KelvinToCelsius(gasMix.Temperature):0.#}")),
  207. Align = Label.AlignMode.Right,
  208. HorizontalExpand = true
  209. });
  210. dataContainer.AddChild(tempBox);
  211. }
  212. if (gasMix.Gases == null || gasMix.Gases?.Length == 0)
  213. {
  214. // Separator
  215. dataContainer.AddChild(new Control
  216. {
  217. MinSize = new Vector2(0, 10)
  218. });
  219. // Add a label that there are no gases so it's less confusing
  220. dataContainer.AddChild(new Label
  221. {
  222. Text = Loc.GetString("gas-analyzer-window-no-gas-text"),
  223. FontColorOverride = Color.Gray
  224. });
  225. // return, everything below is for the fancy gas display stuff
  226. return;
  227. }
  228. // Separator
  229. dataContainer.AddChild(new Control
  230. {
  231. MinSize = new Vector2(0, 10)
  232. });
  233. // Add a table with all the gases
  234. var tableKey = new BoxContainer
  235. {
  236. Orientation = BoxContainer.LayoutOrientation.Vertical
  237. };
  238. var tableVal = new BoxContainer
  239. {
  240. Orientation = BoxContainer.LayoutOrientation.Vertical
  241. };
  242. var tablePercent = new BoxContainer
  243. {
  244. Orientation = BoxContainer.LayoutOrientation.Vertical
  245. };
  246. dataContainer.AddChild(new BoxContainer
  247. {
  248. Orientation = BoxContainer.LayoutOrientation.Horizontal,
  249. Children =
  250. {
  251. tableKey,
  252. new Control
  253. {
  254. MinSize = new Vector2(10, 0),
  255. HorizontalExpand = true
  256. },
  257. tableVal,
  258. new Control
  259. {
  260. MinSize = new Vector2(10, 0),
  261. HorizontalExpand = true
  262. },
  263. tablePercent
  264. }
  265. });
  266. // This is the gas bar thingy
  267. var height = 30;
  268. var gasBar = new SplitBar
  269. {
  270. MinHeight = height,
  271. MinBarSize = new Vector2(12, 0)
  272. };
  273. // Separator
  274. dataContainer.AddChild(new Control
  275. {
  276. MinSize = new Vector2(0, 10),
  277. VerticalExpand = true
  278. });
  279. var totalGasAmount = 0f;
  280. foreach (var gas in gasMix.Gases!)
  281. {
  282. totalGasAmount += gas.Amount;
  283. }
  284. tableKey.AddChild(new Label
  285. { Text = Loc.GetString("gas-analyzer-window-gas-column-name"), Align = Label.AlignMode.Center });
  286. tableVal.AddChild(new Label
  287. { Text = Loc.GetString("gas-analyzer-window-molarity-column-name"), Align = Label.AlignMode.Center });
  288. tablePercent.AddChild(new Label
  289. { Text = Loc.GetString("gas-analyzer-window-percentage-column-name"), Align = Label.AlignMode.Center });
  290. tableKey.AddChild(new StripeBack());
  291. tableVal.AddChild(new StripeBack());
  292. tablePercent.AddChild(new StripeBack());
  293. for (var j = 0; j < gasMix.Gases.Length; j++)
  294. {
  295. var gas = gasMix.Gases[j];
  296. var color = Color.FromHex($"#{gas.Color}", Color.White);
  297. // Add to the table
  298. tableKey.AddChild(new Label
  299. {
  300. Text = Loc.GetString(gas.Name)
  301. });
  302. tableVal.AddChild(new Label
  303. {
  304. Text = Loc.GetString("gas-analyzer-window-molarity-text",
  305. ("mol", $"{gas.Amount:0.00}")),
  306. Align = Label.AlignMode.Right,
  307. });
  308. tablePercent.AddChild(new Label
  309. {
  310. Text = Loc.GetString("gas-analyzer-window-percentage-text",
  311. ("percentage", $"{(gas.Amount / totalGasAmount * 100):0.0}")),
  312. Align = Label.AlignMode.Right
  313. });
  314. // Add to the gas bar //TODO: highlight the currently hover one
  315. gasBar.AddEntry(gas.Amount, color, tooltip: Loc.GetString("gas-analyzer-window-molarity-percentage-text",
  316. ("gasName", gas.Name),
  317. ("amount", $"{gas.Amount:0.##}"),
  318. ("percentage", $"{(gas.Amount / totalGasAmount * 100):0.#}")));
  319. }
  320. dataContainer.AddChild(gasBar);
  321. }
  322. }
  323. }