using Content.Client.Administration.Managers; using Content.Client.Station; using Content.Client.UserInterface.Controls; using Robust.Client.AutoGenerated; using Robust.Client.Console; using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.XAML; using Robust.Shared.Map.Components; namespace Content.Client.Administration.UI.Tabs.ObjectsTab; [GenerateTypedNameReferences] public sealed partial class ObjectsTab : Control { [Dependency] private readonly IClientAdminManager _admin = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IClientConsoleHost _console = default!; private readonly Color _altColor = Color.FromHex("#292B38"); private readonly Color _defaultColor = Color.FromHex("#2F2F3B"); private bool _ascending; private ObjectsTabHeader.Header _headerClicked = ObjectsTabHeader.Header.ObjectName; private readonly List _selections = []; public event Action? OnEntryKeyBindDown; public ObjectsTab() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); ObjectTypeOptions.OnItemSelected += ev => { ObjectTypeOptions.SelectId(ev.Id); RefreshObjectList(_selections[ev.Id]); }; foreach (var type in Enum.GetValues()) { _selections.Add(type); ObjectTypeOptions.AddItem(GetLocalizedEnumValue(type)); } ListHeader.OnHeaderClicked += HeaderClicked; SearchList.SearchBar = SearchLineEdit; SearchList.GenerateItem += GenerateButton; SearchList.DataFilterCondition += DataFilterCondition; SearchList.ItemKeyBindDown += (args, data) => OnEntryKeyBindDown?.Invoke(args, data); RefreshListButton.OnPressed += _ => RefreshObjectList(); var defaultSelection = ObjectsTabSelection.Grids; ObjectTypeOptions.SelectId((int)defaultSelection); RefreshObjectList(defaultSelection); } private void TeleportTo(NetEntity nent) { _console.ExecuteCommand($"tpto {nent}"); } private void Delete(NetEntity nent) { _console.ExecuteCommand($"delete {nent}"); } public void RefreshObjectList() { RefreshObjectList(_selections[ObjectTypeOptions.SelectedId]); } private void RefreshObjectList(ObjectsTabSelection selection) { var entities = new List<(string Name, NetEntity Entity)>(); switch (selection) { case ObjectsTabSelection.Stations: entities.AddRange(_entityManager.EntitySysManager.GetEntitySystem().GetStationNames()); break; case ObjectsTabSelection.Grids: { var query = _entityManager.AllEntityQueryEnumerator(); while (query.MoveNext(out var uid, out _, out var metadata)) { entities.Add((metadata.EntityName, _entityManager.GetNetEntity(uid))); } break; } case ObjectsTabSelection.Maps: { var query = _entityManager.AllEntityQueryEnumerator(); while (query.MoveNext(out var uid, out _, out var metadata)) { entities.Add((metadata.EntityName, _entityManager.GetNetEntity(uid))); } break; } default: throw new ArgumentOutOfRangeException(nameof(selection), selection, null); } entities.Sort((a, b) => { var valueA = GetComparableValue(a, _headerClicked); var valueB = GetComparableValue(b, _headerClicked); return _ascending ? Comparer.Default.Compare(valueA, valueB) : Comparer.Default.Compare(valueB, valueA); }); var listData = new List(); for (var index = 0; index < entities.Count; index++) { var info = entities[index]; listData.Add(new ObjectsListData(info, $"{info.Name} {info.Entity}", index % 2 == 0 ? _altColor : _defaultColor)); } SearchList.PopulateList(listData); } private void GenerateButton(ListData data, ListContainerButton button) { if (data is not ObjectsListData { Info: var info, BackgroundColor: var backgroundColor }) return; var entry = new ObjectsTabEntry(_admin, info.Name, info.Entity, new StyleBoxFlat { BackgroundColor = backgroundColor }); entry.OnTeleport += TeleportTo; entry.OnDelete += Delete; button.ToolTip = $"{info.Name}, {info.Entity}"; button.AddChild(entry); button.StyleClasses.Clear(); } private bool DataFilterCondition(string filter, ListData listData) { if (listData is not ObjectsListData { FilteringString: var filteringString }) return false; // If the filter is empty, do not filter out any entries if (string.IsNullOrEmpty(filter)) return true; return filteringString.Contains(filter, StringComparison.CurrentCultureIgnoreCase); } private object GetComparableValue((string Name, NetEntity Entity) entity, ObjectsTabHeader.Header header) { return header switch { ObjectsTabHeader.Header.ObjectName => entity.Name, ObjectsTabHeader.Header.EntityID => entity.Entity.ToString(), _ => entity.Name, }; } private void HeaderClicked(ObjectsTabHeader.Header header) { if (_headerClicked == header) { _ascending = !_ascending; } else { _headerClicked = header; _ascending = true; } ListHeader.UpdateHeaderSymbols(_headerClicked, _ascending); RefreshObjectList(); } private string GetLocalizedEnumValue(ObjectsTabSelection selection) { return selection switch { ObjectsTabSelection.Grids => Loc.GetString("object-tab-object-type-grids"), ObjectsTabSelection.Maps => Loc.GetString("object-tab-object-type-maps"), ObjectsTabSelection.Stations => Loc.GetString("object-tab-object-type-stations"), _ => throw new ArgumentOutOfRangeException(nameof(selection), selection, null), }; } private enum ObjectsTabSelection { Grids, Maps, Stations, } } public record ObjectsListData((string Name, NetEntity Entity) Info, string FilteringString, Color BackgroundColor) : ListData;