Files
Terminal.Gui/Examples/UICatalog/Scenarios/Dialogs.cs
Tig fd3ac9c95e Improve Dialog/MessageBox sizing and design-time support
Refactor Dialog and MessageBox sizing logic to use the greater of percentage-based minimums or required subview size, ensuring dialogs are never too small for their content. Lower default minimum sizes for both Dialog and MessageBox.

Implement IDesignable for Dialog, providing design-time sample content and buttons. Dialog appearance now switches styles based on modal/design mode.

Refactor Dialogs demo for clarity, error handling, and modern C# usage. Update View content size calculations to include all subviews (including padding) for more accurate layout.

General code modernization: use C# 9/10 features, improve readability, and maintainability.
2025-12-23 11:18:57 -07:00

346 lines
10 KiB
C#

#nullable enable
namespace UICatalog.Scenarios;
[ScenarioMetadata ("Dialogs", "Demonstrates how to the Dialog class")]
[ScenarioCategory ("Dialogs")]
public class Dialogs : Scenario
{
private const int CODE_POINT = '你'; // We know this is a wide char
public override void Main ()
{
Application.Init ();
using IApplication app = Application.Instance;
using Window mainWindow = new ();
mainWindow.Title = GetQuitKeyAndName ();
FrameView frame = new ()
{
TabStop = TabBehavior.TabStop, // FrameView normally sets to TabGroup
X = Pos.Center (),
Y = 1,
Width = Dim.Percent (75),
Height = Dim.Auto (DimAutoStyle.Content),
Title = "Dialog Options"
};
Label numButtonsLabel = new ()
{
X = 0,
TextAlignment = Alignment.End,
Text = "_Number of Buttons:"
};
Label label = new ()
{
X = 0,
Y = 0,
Width = Dim.Width (numButtonsLabel),
Height = 1,
TextAlignment = Alignment.End,
Text = "_Width:"
};
frame.Add (label);
TextField widthEdit = new ()
{
X = Pos.Right (numButtonsLabel) + 1,
Y = Pos.Top (label),
Width = 5,
Height = 1,
Text = "0"
};
frame.Add (widthEdit);
label = new ()
{
X = 0,
Y = Pos.Bottom (label),
Width = Dim.Width (numButtonsLabel),
Height = 1,
TextAlignment = Alignment.End,
Text = "_Height:"
};
frame.Add (label);
TextField heightEdit = new ()
{
X = Pos.Right (numButtonsLabel) + 1,
Y = Pos.Top (label),
Width = 5,
Height = 1,
Text = "0"
};
frame.Add (heightEdit);
frame.Add (
new Label
{
X = Pos.Right (widthEdit) + 2,
Y = Pos.Top (widthEdit),
Text = $"If width is 0, the dimension will be greater than {Dialog.DefaultMinimumWidth}%."
}
);
frame.Add (
new Label
{
X = Pos.Right (heightEdit) + 2,
Y = Pos.Top (heightEdit),
Text = $"If height is 0, the dimension will be greater {Dialog.DefaultMinimumHeight}%."
}
);
label = new ()
{
X = 0,
Y = Pos.Bottom (label),
Width = Dim.Width (numButtonsLabel),
Height = 1,
TextAlignment = Alignment.End,
Text = "_Title:"
};
frame.Add (label);
TextField titleEdit = new ()
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Width = Dim.Fill (),
Height = 1,
Text = "Title"
};
frame.Add (titleEdit);
numButtonsLabel.Y = Pos.Bottom (label);
frame.Add (numButtonsLabel);
TextField numButtonsEdit = new ()
{
X = Pos.Right (numButtonsLabel) + 1,
Y = Pos.Top (numButtonsLabel),
Width = 5,
Height = 1,
Text = "3"
};
frame.Add (numButtonsEdit);
CheckBox glyphsNotWords = new ()
{
X = Pos.Right (numButtonsLabel) + 1,
Y = Pos.Bottom (numButtonsLabel),
TextAlignment = Alignment.End,
Text = $"_Add {char.ConvertFromUtf32 (CODE_POINT)} to button text to stress wide char support",
CheckedState = CheckState.UnChecked
};
frame.Add (glyphsNotWords);
label = new ()
{
X = 0,
Y = Pos.Bottom (glyphsNotWords),
Width = Dim.Width (numButtonsLabel),
Height = 1,
TextAlignment = Alignment.End,
Text = "Button A_lignment:"
};
frame.Add (label);
OptionSelector<Alignment> alignmentOptionSelector = new ()
{
X = Pos.Right (label) + 1,
Y = Pos.Top (label),
Title = "Ali_gn",
AssignHotKeys = true
};
frame.Add (alignmentOptionSelector);
alignmentOptionSelector.Value = Dialog.DefaultButtonAlignment;
frame.ValidatePosDim = true;
mainWindow.Add (frame);
label = new ()
{
X = Pos.Center (), Y = Pos.Bottom (frame) + 4, TextAlignment = Alignment.End, Text = "Button Pressed:"
};
mainWindow.Add (label);
Label buttonPressedLabel = new ()
{
X = Pos.Center (), Y = Pos.Bottom (frame) + 5, SchemeName = "Error", Text = " "
};
Button showDialogButton = new ()
{
X = Pos.Center (), Y = Pos.Bottom (frame) + 2, IsDefault = true, Text = "_Show Dialog"
};
mainWindow.Accepting += (s, e) =>
{
Dialog? dlg = CreateDemoDialog (
widthEdit,
heightEdit,
titleEdit,
numButtonsEdit,
glyphsNotWords,
alignmentOptionSelector,
buttonPressedLabel
);
if (dlg is null)
{
MessageBox.ErrorQuery ((s as View)!.App!, "Error", "Could not create Dialog. Invalid options.", "_Ok");
}
else
{
app.Run (dlg);
dlg.Dispose ();
}
e.Handled = true;
};
mainWindow.Add (showDialogButton, buttonPressedLabel);
app.Run (mainWindow);
}
private static Dialog? CreateDemoDialog (
TextField widthEdit,
TextField heightEdit,
TextField titleEdit,
TextField numButtonsEdit,
CheckBox glyphsNotWords,
OptionSelector alignmentGroup,
Label buttonPressedLabel
)
{
if (!int.TryParse (widthEdit.Text, out int width)
|| !int.TryParse (heightEdit.Text, out int height)
|| !int.TryParse (numButtonsEdit.Text, out int numButtons))
{
return null;
}
// Add the buttons that go on the bottom of the dialog
List<Button> dlgButtons = [];
int clicked = -1;
for (var i = 0; i < numButtons; i++)
{
int buttonId = i;
Button button;
if (glyphsNotWords.CheckedState == CheckState.Checked)
{
buttonId = i;
button = new ()
{
Text = "_" + NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
};
}
else
{
button = new () { Text = "_" + NumberToWords.Convert (buttonId) };
}
button.Accepting += (s, e) =>
{
clicked = buttonId;
e.Handled = true;
(s as View)!.App?.RequestStop ();
};
dlgButtons.Add (button);
}
// This tests dynamically adding buttons; ensuring the dialog resizes if needed and
// the buttons are laid out correctly
Dialog dialog = new ()
{
Title = titleEdit.Text,
Text = "Dialog Text - Test",
ButtonAlignment = (Alignment)Enum.Parse (typeof (Alignment), alignmentGroup.Labels! [alignmentGroup.Value!.Value] [0..]),
Buttons = dlgButtons.ToArray ()
};
if (width != 0)
{
dialog.Width = width;
}
if (height != 0)
{
dialog.Height = height;
}
dialog.IsRunningChanged += (_, e) =>
{
if (!e.Value)
{
buttonPressedLabel.Text = $"{clicked}";
}
};
return dialog;
}
public override List<Key> GetDemoKeyStrokes ()
{
List<Key> keys =
[
Key.D6,
Key.D5,
Key.Tab,
Key.D2,
Key.D0,
Key.Enter
];
for (int i = 0; i < 5; i++)
{
keys.Add (Key.A);
}
keys.Add (Key.Enter);
keys.Add (Key.S.WithAlt);
keys.Add (Key.Enter);
for (int i = 0; i < 5; i++)
{
keys.Add (Key.A);
}
keys.Add (Key.Enter);
keys.Add (Key.E.WithAlt);
keys.Add (Key.Enter);
for (int i = 0; i < 5; i++)
{
keys.Add (Key.A);
}
keys.Add (Key.Enter);
keys.Add (Key.C.WithAlt);
keys.Add (Key.Enter);
for (int i = 0; i < 5; i++)
{
keys.Add (Key.A);
}
keys.Add (Key.Enter);
keys.Add (Key.F.WithAlt);
keys.Add (Key.Enter);
for (int i = 0; i < 5; i++)
{
keys.Add (Key.A);
}
keys.Add (Key.Enter);
return keys;
}
}