| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- using System.Numerics;
- using Content.Client.UserInterface.Controls;
- using Content.Shared.DeviceLinking;
- using Content.Shared.DeviceNetwork;
- using Robust.Client.AutoGenerated;
- using Robust.Client.Graphics;
- using Robust.Client.UserInterface;
- using Robust.Client.UserInterface.Controls;
- using Robust.Client.UserInterface.XAML;
- using Robust.Shared.Prototypes;
- namespace Content.Client.NetworkConfigurator;
- [GenerateTypedNameReferences]
- public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
- {
- private const string PanelBgColor = "#202023";
- private readonly LinksRender _links;
- private readonly List<SourcePortPrototype> _sources = new();
- private readonly List<SinkPortPrototype> _sinks = new();
- private (ButtonPosition position, string id, int index)? _selectedButton;
- private List<(string left, string right)>? _defaults;
- public event Action? OnClearLinks;
- public event Action<string, string>? OnToggleLink;
- public event Action<List<(string left, string right)>>? OnLinkDefaults;
- public NetworkConfiguratorLinkMenu()
- {
- RobustXamlLoader.Load(this);
- var footerStyleBox = new StyleBoxFlat()
- {
- BorderThickness = new Thickness(0, 2, 0, 0),
- BorderColor = Color.FromHex("#5A5A5A")
- };
- FooterPanel.PanelOverride = footerStyleBox;
- MainPanel.PanelOverride = new StyleBoxFlat(Color.FromHex(PanelBgColor));
- ButtonClear.AddStyleClass("ButtonColorRed");
- ButtonLinkDefault.Disabled = true;
- _links = new LinksRender(ButtonContainerLeft, ButtonContainerRight);
- _links.VerticalExpand = true;
- MiddleContainer.AddChild(_links);
- ButtonOk.OnPressed += _ => Close();
- ButtonLinkDefault.OnPressed += _ => LinkDefaults();
- ButtonClear.OnPressed += _ => OnClearLinks?.Invoke();
- }
- public void UpdateState(DeviceLinkUserInterfaceState linkState)
- {
- ButtonContainerLeft.RemoveAllChildren();
- ButtonContainerRight.RemoveAllChildren();
- _sources.Clear();
- _sources.AddRange(linkState.Sources);
- _links.SourceButtons.Clear();
- var i = 0;
- foreach (var source in _sources)
- {
- var button = CreateButton(ButtonPosition.Left, source.Name, source.Description, source.ID, i);
- ButtonContainerLeft.AddChild(button);
- _links.SourceButtons.Add(source.ID, button);
- i++;
- }
- _sinks.Clear();
- _sinks.AddRange(linkState.Sinks);
- _links.SinkButtons.Clear();
- i = 0;
- foreach (var sink in _sinks)
- {
- var button = CreateButton(ButtonPosition.Right, sink.Name, sink.Description, sink.ID, i);
- ButtonContainerRight.AddChild(button);
- _links.SinkButtons.Add(sink.ID, button);
- i++;
- }
- _links.Links.Clear();
- _links.Links.AddRange(linkState.Links);
- _defaults = linkState.Defaults;
- ButtonLinkDefault.Disabled = _defaults == default;
- FromAddressLabel.Text = linkState.SourceAddress;
- ToAddressLabel.Text = linkState.SinkAddress;
- }
- private void LinkDefaults()
- {
- if (_defaults == default)
- return;
- OnLinkDefaults?.Invoke(_defaults);
- }
- private Button CreateButton(ButtonPosition position, string name, string description, string id, int index)
- {
- var button = new Button();
- button.AddStyleClass("OpenBoth");
- button.Text = Loc.GetString(name);
- button.ToolTip = Loc.GetString(description);
- button.ToggleMode = true;
- button.OnPressed += args => OnButtonPressed(args, position, id, index);
- return button;
- }
- private void OnButtonPressed(BaseButton.ButtonEventArgs args, ButtonPosition position, string id, int index)
- {
- var key = (position, id, index);
- if (_selectedButton == key)
- {
- args.Button.Pressed = false;
- _selectedButton = null;
- return;
- }
- if (!_selectedButton.HasValue)
- {
- args.Button.Pressed = true;
- _selectedButton = key;
- return;
- }
- if (_selectedButton.Value.position == position)
- {
- args.Button.Pressed = false;
- return;
- }
- var left = _selectedButton.Value.position == ButtonPosition.Left ? _selectedButton.Value.id : id;
- var right = _selectedButton.Value.position == ButtonPosition.Left ? id : _selectedButton.Value.id;
- OnToggleLink?.Invoke(left, right);
- args.Button.Pressed = false;
- var container = _selectedButton.Value.position == ButtonPosition.Left ? ButtonContainerLeft : ButtonContainerRight;
- if (container.GetChild(_selectedButton.Value.index) is Button button)
- button.Pressed = false;
- _selectedButton = null;
- }
- private enum ButtonPosition
- {
- Left,
- Right
- }
- /// <summary>
- /// Draws lines between linked ports using bezier curve calculated with polynomial coefficients
- /// See: https://youtu.be/jvPPXbo87ds?t=351
- /// </summary>
- private sealed class LinksRender : Control
- {
- public readonly List<(ProtoId<SourcePortPrototype>, ProtoId<SinkPortPrototype>)> Links = new();
- public readonly Dictionary<string, Button> SourceButtons = new();
- public readonly Dictionary<string, Button> SinkButtons = new();
- private readonly BoxContainer _leftButtonContainer;
- private readonly BoxContainer _rightButtonContainer;
- public LinksRender(BoxContainer leftButtonContainer, BoxContainer rightButtonContainer)
- {
- _leftButtonContainer = leftButtonContainer;
- _rightButtonContainer = rightButtonContainer;
- }
- protected override void Draw(DrawingHandleScreen handle)
- {
- foreach (var (left, right) in Links)
- {
- if (!SourceButtons.TryGetValue(left, out var leftChild) || !SinkButtons.TryGetValue(right, out var rightChild))
- continue;
- var leftOffset = _leftButtonContainer.PixelPosition.Y;
- var rightOffset = _rightButtonContainer.PixelPosition.Y;
- var y1 = leftChild.PixelPosition.Y + leftChild.PixelHeight / 2 + leftOffset;
- var y2 = rightChild.PixelPosition.Y + rightChild.PixelHeight / 2 + rightOffset;
- if (left == right)
- {
- handle.DrawLine(new Vector2(0, y1), new Vector2(PixelWidth, y2), Color.Cyan);
- continue;
- }
- var controls = new List<Vector2>
- {
- new(0, y1),
- new(30, y1),
- new(PixelWidth - 30, y2),
- new(PixelWidth, y2),
- };
- //Calculate coefficients
- var c0 = controls[0];
- var c1 = controls[0] * -3 + controls[1] * 3;
- var c2 = controls[0] * 3 + controls[1] * -6 + controls[2] * 3;
- var c3 = controls[0] * -1 + controls[1] * 3 + controls[2] * -3 + controls[3];
- var points = new List<Vector2>();
- //Calculate points using coefficients
- for (float t = 0; t <= 1; t += 0.0001f)
- {
- var point = c0 + c1 * t + c2 * (t * t) + c3 * (t * t * t);
- points.Add(point);
- }
- handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, points.ToArray(), Color.Cyan);
- }
- }
- }
- }
|