using Content.Shared.Administration;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.UserInterface.Controls;
// mfw they ported input() from BYOND
///
/// Client-side dialog with multiple prompts.
/// Used by admin tools quick dialog system among other things.
///
[GenerateTypedNameReferences]
public sealed partial class DialogWindow : FancyWindow
{
///
/// Action for when the ok button is pressed or the last field has enter pressed.
/// Results maps prompt FieldIds to the LineEdit's text contents.
///
public Action>? OnConfirmed;
///
/// Action for when the cancel button is pressed or the window is closed.
///
public Action? OnCancelled;
///
/// Used to ensure that only one output action is invoked.
/// E.g. Pressing cancel will invoke then close the window, but OnClose will not invoke.
///
private bool _finished;
private List<(string, LineEdit)> _promptLines;
///
/// Create and open a new dialog with some prompts.
///
/// String to use for the window title.
/// Quick dialog entries to create prompts with.
/// Whether to have an Ok button.
/// Whether to have a Cancel button. Closing the window will still cancel it.
///
/// Won't do anything on its own, you need to handle or network with and .
///
public DialogWindow(string title, List entries, bool ok = true, bool cancel = true)
{
RobustXamlLoader.Load(this);
Title = title;
OkButton.Visible = ok;
CancelButton.Visible = cancel;
_promptLines = new(entries.Count);
for (int i = 0; i < entries.Count; i++)
{
var entry = entries[i];
var box = new BoxContainer();
box.AddChild(new Label() { Text = entry.Prompt, HorizontalExpand = true, SizeFlagsStretchRatio = 0.5f });
var edit = new LineEdit() { HorizontalExpand = true };
(Func, string) pair = entry.Type switch
{
QuickDialogEntryType.Integer => (VerifyInt, "integer"),
QuickDialogEntryType.Float => (VerifyFloat, "float"),
QuickDialogEntryType.ShortText => (VerifyShortText, "short-text"),
QuickDialogEntryType.LongText => (VerifyLongText, "long-text"),
_ => throw new ArgumentOutOfRangeException()
};
var (valid, name) = pair;
edit.IsValid += valid;
// try use placeholder from the caller, fall back to the generic one for whatever type is being validated.
edit.PlaceHolder = entry.Placeholder ?? Loc.GetString($"quick-dialog-ui-{name}");
// Last text box gets enter confirmation.
// Only the last so you don't accidentally confirm early.
if (i == entries.Count - 1)
edit.OnTextEntered += _ => Confirm();
_promptLines.Add((entry.FieldId, edit));
box.AddChild(edit);
Prompts.AddChild(box);
}
// Grab keyboard focus for the first dialog entry
_promptLines[0].Item2.GrabKeyboardFocus();
OkButton.OnPressed += _ => Confirm();
CancelButton.OnPressed += _ =>
{
_finished = true;
OnCancelled?.Invoke();
Close();
};
OnClose += () =>
{
if (!_finished)
OnCancelled?.Invoke();
};
MinWidth *= 2; // Just double it.
OpenCentered();
}
private void Confirm()
{
var results = new Dictionary();
foreach (var (field, edit) in _promptLines)
{
results[field] = edit.Text;
}
_finished = true;
OnConfirmed?.Invoke(results);
Close();
}
#region Input validation
private bool VerifyInt(string input)
{
return int.TryParse(input, out var _);
}
private bool VerifyFloat(string input)
{
return float.TryParse(input, out var _);
}
private bool VerifyShortText(string input)
{
return input.Length <= 100;
}
private bool VerifyLongText(string input)
{
return input.Length <= 2000;
}
#endregion
}