namespace Terminal.Gui.Views;
///
/// Displays a modal message box with a title, message, and buttons. Returns the index of the selected button,
/// or if the user cancels with .
///
///
///
/// MessageBox provides static methods for displaying modal dialogs with customizable buttons and messages.
/// All methods return where the value is the 0-based index of the button pressed,
/// or if the user pressed (typically Esc).
///
///
/// uses the default Dialog color scheme.
/// uses the Error color scheme.
///
///
/// Important: All MessageBox methods require an instance to be passed.
/// This enables proper modal dialog management and respects the application's lifecycle. Pass your
/// application instance (from ) or use the legacy
/// if using the static Application pattern.
///
///
/// Example using instance-based pattern:
///
/// IApplication app = Application.Create();
/// app.Init();
///
/// int? result = MessageBox.Query(app, "Quit Demo", "Are you sure you want to quit?", "Yes", "No");
/// if (result == 0) // User clicked "Yes"
/// app.RequestStop();
/// else if (result == null) // User pressed Esc
/// // Handle cancellation
///
/// app.Shutdown();
///
///
///
/// Example using legacy static pattern:
///
/// Application.Init();
///
/// int? result = MessageBox.Query(ApplicationImpl.Instance, "Quit Demo", "Are you sure?", "Yes", "No");
/// if (result == 0) // User clicked "Yes"
/// Application.RequestStop();
///
/// Application.Shutdown();
///
///
///
/// The property provides a global variable alternative for web-based consoles
/// without SynchronizationContext. However, using the return value is preferred as it's more thread-safe
/// and follows modern async patterns.
///
///
public static class MessageBox
{
private static LineStyle _defaultBorderStyle = LineStyle.Heavy; // Resources/config.json overrides
private static Alignment _defaultButtonAlignment = Alignment.Center; // Resources/config.json overrides
private static int _defaultMinimumWidth = 0; // Resources/config.json overrides
private static int _defaultMinimumHeight = 0; // Resources/config.json overrides
///
/// Defines the default border styling for . Can be configured via
/// .
///
[ConfigurationProperty (Scope = typeof (ThemeScope))]
public static LineStyle DefaultBorderStyle
{
get => _defaultBorderStyle;
set => _defaultBorderStyle = value;
}
/// The default for .
/// This property can be set in a Theme.
[ConfigurationProperty (Scope = typeof (ThemeScope))]
public static Alignment DefaultButtonAlignment
{
get => _defaultButtonAlignment;
set => _defaultButtonAlignment = value;
}
///
/// Defines the default minimum MessageBox width, as a percentage of the screen width. Can be configured via
/// .
///
[ConfigurationProperty (Scope = typeof (ThemeScope))]
public static int DefaultMinimumWidth
{
get => _defaultMinimumWidth;
set => _defaultMinimumWidth = value;
}
///
/// Defines the default minimum Dialog height, as a percentage of the screen width. Can be configured via
/// .
///
[ConfigurationProperty (Scope = typeof (ThemeScope))]
public static int DefaultMinimumHeight
{
get => _defaultMinimumHeight;
set => _defaultMinimumHeight = value;
}
///
/// The index of the selected button, or if the user pressed .
///
///
/// This global variable is useful for web-based consoles without a SynchronizationContext or TaskScheduler.
/// Warning: Not thread-safe.
///
public static int? Clicked { get; private set; }
///
/// Displays an error with fixed dimensions.
///
/// The application instance. If , uses .
/// Width for the MessageBox.
/// Height for the MessageBox.
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// Consider using which automatically sizes the
/// MessageBox.
///
public static int? ErrorQuery (
IApplication? app,
int width,
int height,
string title,
string message,
params string [] buttons
)
{
return QueryFull (
app,
true,
width,
height,
title,
message,
0,
true,
buttons);
}
///
/// Displays an auto-sized error .
///
/// The application instance. If , uses .
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// The MessageBox is centered and auto-sized based on title, message, and buttons.
///
public static int? ErrorQuery (IApplication? app, string title, string message, params string [] buttons)
{
return QueryFull (
app,
true,
0,
0,
title,
message,
0,
true,
buttons);
}
///
/// Displays an error with fixed dimensions and a default button.
///
/// The application instance. If , uses .
/// Width for the MessageBox.
/// Height for the MessageBox.
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Index of the default button (0-based).
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// Consider using which automatically sizes the
/// MessageBox.
///
public static int? ErrorQuery (
IApplication? app,
int width,
int height,
string title,
string message,
int defaultButton = 0,
params string [] buttons
)
{
return QueryFull (
app,
true,
width,
height,
title,
message,
defaultButton,
true,
buttons);
}
///
/// Displays an auto-sized error with a default button.
///
/// The application instance. If , uses .
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Index of the default button (0-based).
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// The MessageBox is centered and auto-sized based on title, message, and buttons.
///
public static int? ErrorQuery (IApplication? app, string title, string message, int defaultButton = 0, params string [] buttons)
{
return QueryFull (
app,
true,
0,
0,
title,
message,
defaultButton,
true,
buttons);
}
///
/// Displays an error with fixed dimensions, a default button, and word-wrap control.
///
/// The application instance. If , uses .
/// Width for the MessageBox.
/// Height for the MessageBox.
/// Title for the MessageBox.
/// Message to display. May contain multiple lines.
/// Index of the default button (0-based).
///
/// If , word-wraps the message; otherwise displays as-is with multi-line
/// support.
///
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// Consider using which automatically
/// sizes the MessageBox.
///
public static int? ErrorQuery (
IApplication? app,
int width,
int height,
string title,
string message,
int defaultButton = 0,
bool wrapMessage = true,
params string [] buttons
)
{
return QueryFull (
app,
true,
width,
height,
title,
message,
defaultButton,
wrapMessage,
buttons);
}
///
/// Displays an auto-sized error with a default button and word-wrap control.
///
/// The application instance. If , uses .
/// Title for the MessageBox.
/// Message to display. May contain multiple lines.
/// Index of the default button (0-based).
///
/// If , word-wraps the message; otherwise displays as-is with multi-line
/// support.
///
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// The MessageBox is centered and auto-sized based on title, message, and buttons.
///
public static int? ErrorQuery (
IApplication? app,
string title,
string message,
int defaultButton = 0,
bool wrapMessage = true,
params string [] buttons
)
{
return QueryFull (
app,
true,
0,
0,
title,
message,
defaultButton,
wrapMessage,
buttons);
}
///
/// Displays a with fixed dimensions.
///
/// The application instance. If , uses .
/// Width for the MessageBox.
/// Height for the MessageBox.
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// Consider using which automatically sizes the
/// MessageBox.
///
public static int? Query (IApplication? app, int width, int height, string title, string message, params string [] buttons)
{
return QueryFull (
app,
false,
width,
height,
title,
message,
0,
true,
buttons);
}
///
/// Displays an auto-sized .
///
/// The application instance. If , uses .
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// The MessageBox is centered and auto-sized based on title, message, and buttons.
///
public static int? Query (IApplication? app, string title, string message, params string [] buttons)
{
return QueryFull (
app,
false,
0,
0,
title,
message,
0,
true,
buttons);
}
///
/// Displays a with fixed dimensions and a default button.
///
/// The application instance. If , uses .
/// Width for the MessageBox.
/// Height for the MessageBox.
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Index of the default button (0-based).
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// Consider using which automatically sizes the
/// MessageBox.
///
public static int? Query (
IApplication? app,
int width,
int height,
string title,
string message,
int defaultButton = 0,
params string [] buttons
)
{
return QueryFull (
app,
false,
width,
height,
title,
message,
defaultButton,
true,
buttons);
}
///
/// Displays an auto-sized with a default button.
///
/// The application instance. If , uses .
/// Title for the MessageBox.
/// Message to display. May contain multiple lines and will be word-wrapped.
/// Index of the default button (0-based).
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// The MessageBox is centered and auto-sized based on title, message, and buttons.
///
public static int? Query (IApplication? app, string title, string message, int defaultButton = 0, params string [] buttons)
{
return QueryFull (
app,
false,
0,
0,
title,
message,
defaultButton,
true,
buttons);
}
///
/// Displays a with fixed dimensions, a default button, and word-wrap control.
///
/// The application instance. If , uses .
/// Width for the MessageBox.
/// Height for the MessageBox.
/// Title for the MessageBox.
/// Message to display. May contain multiple lines.
/// Index of the default button (0-based).
///
/// If , word-wraps the message; otherwise displays as-is with multi-line
/// support.
///
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// Consider using which automatically sizes
/// the MessageBox.
///
public static int? Query (
IApplication? app,
int width,
int height,
string title,
string message,
int defaultButton = 0,
bool wrapMessage = true,
params string [] buttons
)
{
return QueryFull (
app,
false,
width,
height,
title,
message,
defaultButton,
wrapMessage,
buttons);
}
///
/// Displays an auto-sized with a default button and word-wrap control.
///
/// The application instance. If , uses .
/// Title for the MessageBox.
/// Message to display. May contain multiple lines.
/// Index of the default button (0-based).
///
/// If , word-wraps the message; otherwise displays as-is with multi-line
/// support.
///
/// Array of button labels.
///
/// The index of the selected button, or if the user pressed
/// .
///
/// Thrown if is .
///
/// The MessageBox is centered and auto-sized based on title, message, and buttons.
///
public static int? Query (
IApplication? app,
string title,
string message,
int defaultButton = 0,
bool wrapMessage = true,
params string [] buttons
)
{
return QueryFull (
app,
false,
0,
0,
title,
message,
defaultButton,
wrapMessage,
buttons);
}
private static int? QueryFull (
IApplication? app,
bool useErrorColors,
int width,
int height,
string title,
string message,
int defaultButton = 0,
bool wrapMessage = true,
params string [] buttons
)
{
ArgumentNullException.ThrowIfNull (app);
// Create button array for Dialog
var count = 0;
List