using System.Diagnostics.CodeAnalysis; using Sandbox; using Sandbox.Game.Gui; using Sandbox.Game.Localization; using Sandbox.Graphics.GUI; using VRage; using VRage.Game; using VRage.Utils; using VRageMath; using Color = VRageMath.Color; namespace PluginLoader.GUI; [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public abstract class TableDialogBase : MyGuiScreenDebugBase { protected readonly string Caption; protected readonly string DefaultKey; protected readonly Dictionary NamesByKey = new(); protected MyGuiControlButton CancelButton; protected int ColumnCount; protected MyGuiControlButton DeleteButton; protected MyGuiControlButton LoadButton; protected MyGuiControlButton RenameButton; protected MyGuiControlTable Table; protected TableDialogBase( string caption, string defaultKey = null) : base(new(0.5f, 0.5f), new Vector2(1f, 0.8f), MyGuiConstants.SCREEN_BACKGROUND_COLOR * MySandboxGame.Config.UIBkOpacity, true) { Caption = caption; DefaultKey = defaultKey; // ReSharper disable once VirtualMemberCallInConstructor RecreateControls(true); CanBeHidden = true; CanHideOthers = true; CloseButtonEnabled = true; m_onEnterCallback = LoadAndClose; } protected abstract string ItemName { get; } protected abstract string[] ColumnHeaders { get; } protected abstract float[] ColumnWidths { get; } protected abstract object[] ExampleValues { get; } private Vector2 DialogSize => m_size ?? Vector2.One; private string SelectedKey => Table.SelectedRow?.UserData as string; public override string GetFriendlyName() { return "ListDialog"; } protected virtual string NormalizeName(string name) { return name.Trim(); } protected virtual int CompareNames(string a, string b) { return string.Compare(a, b, StringComparison.CurrentCultureIgnoreCase); } protected abstract IEnumerable IterItemKeys(); protected abstract ItemView GetItemView(string key); protected abstract void OnLoad(string key); protected abstract void OnRenamed(string key, string name); protected abstract void OnDelete(string key); public override void RecreateControls(bool constructor) { base.RecreateControls(constructor); AddCaption(Caption, Color.White.ToVector4(), new Vector2(0.0f, 0.003f)); CreateTable(); CreateButtons(); } private void CreateTable() { var columnHeaders = ColumnHeaders; var columnWidths = ColumnWidths; if (columnHeaders == null || columnWidths == null) return; ColumnCount = columnHeaders.Length; Table = new() { Position = new(0.001f, -0.5f * DialogSize.Y + 0.1f), Size = new(0.85f * DialogSize.X, DialogSize.Y - 0.25f), OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP, ColumnsCount = ColumnCount, VisibleRowsCount = 15 }; Table.SetCustomColumnWidths(columnWidths); var exampleValues = ExampleValues; for (var colIdx = 0; colIdx < ColumnCount; colIdx++) { Table.SetColumnName(colIdx, new(columnHeaders[colIdx])); switch (exampleValues[colIdx]) { case int _: Table.SetColumnComparison(colIdx, CellIntComparison); break; default: Table.SetColumnComparison(colIdx, CellTextComparison); break; } } AddItems(); Table.SortByColumn(0); Table.ItemDoubleClicked += OnItemDoubleClicked; Controls.Add(Table); } private int CellTextComparison(MyGuiControlTable.Cell x, MyGuiControlTable.Cell y) { var a = NormalizeName(x.Text.ToString()); var b = NormalizeName(y.Text.ToString()); return CompareNames(a, b); } private int CellIntComparison(MyGuiControlTable.Cell x, MyGuiControlTable.Cell y) { return (x.UserData as int? ?? 0) - (y.UserData as int? ?? 0); } private void CreateButtons() { LoadButton = new( visualStyle: MyGuiControlButtonStyleEnum.Default, originAlign: MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, text: new("Load"), onButtonClick: OnLoadButtonClick); RenameButton = new( visualStyle: MyGuiControlButtonStyleEnum.Small, originAlign: MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, text: new("Rename"), onButtonClick: OnRenameButtonClick); DeleteButton = new( visualStyle: MyGuiControlButtonStyleEnum.Small, originAlign: MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, text: new("Delete"), onButtonClick: OnDeleteButtonClick); CancelButton = new( visualStyle: MyGuiControlButtonStyleEnum.Default, originAlign: MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, text: MyTexts.Get(MyCommonTexts.Cancel), onButtonClick: OnCancelButtonClick); var xs = 0.85f * DialogSize.X; var y = 0.5f * (DialogSize.Y - 0.15f); LoadButton.Position = new(-0.39f * xs, y); RenameButton.Position = new(-0.08f * xs, y); DeleteButton.Position = new(0.08f * xs, y); CancelButton.Position = new(0.39f * xs, y); LoadButton.SetToolTip($"Loads the selected {ItemName}"); RenameButton.SetToolTip($"Renames the selected {ItemName}"); DeleteButton.SetToolTip($"Deletes the selected {ItemName}"); CancelButton.SetToolTip(MyTexts.GetString(MySpaceTexts.ToolTipOptionsSpace_Cancel)); Controls.Add(LoadButton); Controls.Add(RenameButton); Controls.Add(DeleteButton); Controls.Add(CancelButton); } private void AddItems() { NamesByKey.Clear(); foreach (var key in IterItemKeys()) AddRow(key); if (TryFindRow(DefaultKey, out var rowIdx)) Table.SelectedRowIndex = rowIdx; } private void AddRow(string key) { var view = GetItemView(key); if (view == null) return; var row = new MyGuiControlTable.Row(key); for (var i = 0; i < ColumnCount; i++) row.AddCell(new(view.Labels[i], view.Values[i])); Table.Add(row); NamesByKey[key] = view.Labels[0]; } private void OnItemDoubleClicked(MyGuiControlTable table, MyGuiControlTable.EventArgs args) { LoadAndClose(); } private void OnLoadButtonClick(MyGuiControlButton _) { LoadAndClose(); } private void LoadAndClose() { if (string.IsNullOrEmpty(SelectedKey)) return; OnLoad(SelectedKey); CloseScreen(); } private void OnCancelButtonClick(MyGuiControlButton _) { CloseScreen(); } private void OnRenameButtonClick(MyGuiControlButton _) { if (string.IsNullOrEmpty(SelectedKey)) return; if (!NamesByKey.TryGetValue(SelectedKey, out var oldName)) return; MyGuiSandbox.AddScreen(new NameDialog(newName => OnNewNameSpecified(SelectedKey, newName), $"Rename saved {ItemName}", oldName)); } private void OnNewNameSpecified(string key, string newName) { newName = NormalizeName(newName); if (!TryFindRow(key, out var rowIdx)) return; OnRenamed(key, newName); var view = GetItemView(key); NamesByKey[key] = view.Labels[0]; var row = Table.GetRow(rowIdx); for (var colIdx = 0; colIdx < ColumnCount; colIdx++) { var cell = row.GetCell(colIdx); var sb = cell.Text; sb.Clear(); sb.Append(view.Labels[colIdx]); } Table.Sort(); } private void OnDeleteButtonClick(MyGuiControlButton _) { var key = SelectedKey; if (string.IsNullOrEmpty(key)) return; var name = NamesByKey.GetValueOrDefault(key) ?? "?"; MyGuiSandbox.AddScreen( MyGuiSandbox.CreateMessageBox(buttonType: MyMessageBoxButtonsType.YES_NO, messageText: new( $"Are you sure to delete this saved {ItemName}?\r\n\r\n{name}"), messageCaption: new("Confirmation"), callback: result => OnDeleteForSure(result, key))); } private void OnDeleteForSure(MyGuiScreenMessageBox.ResultEnum result, string key) { if (result != MyGuiScreenMessageBox.ResultEnum.YES) return; NamesByKey.Remove(key); if (TryFindRow(key, out var rowIdx)) Table.Remove(Table.GetRow(rowIdx)); OnDelete(key); } private bool TryFindRow(string key, out int index) { if (key == null) { index = -1; return false; } var count = Table.RowsCount; for (index = 0; index < count; index++) if (Table.GetRow(index).UserData as string == key) return true; index = -1; return false; } }