diff --git a/Terminal.Gui/Windows/Wizard.cs b/Terminal.Gui/Windows/Wizard.cs index d3c4b38b1..578bd1434 100644 --- a/Terminal.Gui/Windows/Wizard.cs +++ b/Terminal.Gui/Windows/Wizard.cs @@ -6,16 +6,21 @@ namespace Terminal.Gui { /// /// Provides a step-based "wizard" UI. The Wizard supports multiple steps. Each step () can host /// arbitrary s, much like a . Each step also has a pane for help text. Along the - /// bottom of the Wizard view are buttons enabling the user to navigate through the Wizard. + /// bottom of the Wizard view are customizable buttons enabling the user to navigate forward and backward through the Wizard. /// /// /// public class Wizard : Dialog { /// - /// One step for the Wizard. + /// One step for the Wizard. The view hosts two sub-views: 1) add s to , + /// 2) use to set the contents of the that shows on the + /// right side. Use and to + /// control wether the control or help pane are shown. /// /// + /// If s are added, do not set to true as this will conflict + /// with the Next button of the Wizard. /// public class WizardStep : View { @@ -25,26 +30,36 @@ namespace Terminal.Gui { public ustring Title; private View controlPane = new FrameView (); + /// - /// THe pane that holds the controls for the . + /// THe pane that holds the controls for the . Use `Add(View`) to add + /// controls. Note that the Controls view is sized to take 70% of the Wizard's width and the + /// takes the other 30%. This can be adjusted by setting `Width` from `Dim.Percent(70)` to + /// another value. If is set to `false` the control pane will fill the entire + /// Wizard. /// public View Controls { get => controlPane; } private TextView helpTextView = new TextView (); + /// - /// The pane that displays help or the . + /// Sets or gets help text for the .If is set to + /// `false` the control pane will fill the entire wizard. /// + /// The help text is displayed using a read-only . public ustring HelpText { get => helpTextView.Text; set => helpTextView.Text = value; } private ustring backButtonText = ustring.Empty; - private ustring nextButtonText = ustring.Empty; - /// - /// Sets or gets the text for the back button. + /// Sets or gets the text for the back button. The back button will only be visible on + /// steps after the first step. /// /// The default text is "Back" public ustring BackButtonText { get => backButtonText; set => backButtonText = value; } + + private ustring nextButtonText = ustring.Empty; + /// /// Sets or gets the text for the next/finish button. /// @@ -74,7 +89,6 @@ namespace Terminal.Gui { this.Add (Controls); helpTextView.ColorScheme = Colors.Menu; - //helpTextView.Border.Padding = new Thickness (0, 0, 0, 0); helpTextView.Y = 0; helpTextView.ReadOnly = true; helpTextView.WordWrap = true; @@ -110,16 +124,11 @@ namespace Terminal.Gui { scrollBar.Refresh (); }; this.Add (scrollBar); - - //separator = new LineView (Graphs.Orientation.Vertical); - //separator.X = Pos.Right (ControlPane); - //separator.Height = Dim.Fill (); - //this.Add (separator); } private bool showHelp = true; /// - /// If true (the default) the help pane will be visible. If false, the help pane will not be shown and the control pane will + /// If true (the default) the help will be visible. If false, the help will not be shown and the control pane will /// fill the wizard step. /// public bool ShowHelp { @@ -132,7 +141,7 @@ namespace Terminal.Gui { private bool showControls = true; /// - /// If true (the default) the help pane will be visible. If false, the help pane will not be shown and the control pane will + /// If true (the default) the View will be visible. If false, the controls will not be shown and the help will /// fill the wizard step. /// public bool ShowControls { @@ -142,6 +151,7 @@ namespace Terminal.Gui { ShowHide (); } } + private void ShowHide () { Controls.Height = Dim.Fill (1); @@ -197,8 +207,8 @@ namespace Terminal.Gui { /// Initializes a new instance of the class using positioning. /// /// - /// The Wizard will be vertically and horizontally centered in the container and the size will be 85% of the container. - /// After initialization use X, Y, Width, and Height to override this with a location or size. + /// The Wizard will be vertically and horizontally centered in the container. + /// After initialization use X, Y, Width, and Height change size and position. /// public Wizard () : this (ustring.Empty) { @@ -209,17 +219,16 @@ namespace Terminal.Gui { /// /// Title for the Wizard. /// - /// The Wizard will be vertically and horizontally centered in the container and the size will be 85% of the container. - /// After initialization use X, Y, Width, and Height to override this with a location or size. + /// The Wizard will be vertically and horizontally centered in the container. + /// After initialization use X, Y, Width, and Height change size and position. /// public Wizard (ustring title) { ButtonAlignment = ButtonAlignments.Justify; + this.Border.BorderStyle = BorderStyle.Double; - //this.ColorScheme = Colors.TopLevel; - - // Store the passed in title - this.title = title; + // Store the passed in title in Dialog's Title + base.Title = title; // Add a horiz separator var separator = new LineView (Graphs.Orientation.Horizontal) { @@ -276,9 +285,11 @@ namespace Terminal.Gui { private int currentStep = 0; /// - /// Adds a step to the wizard. + /// Adds a step to the wizard. The Next and Back buttons navigate through the added steps in the + /// order they were added. /// /// + /// The "Next..." button of the last step added will read "Finish" (unless changed from default). public void AddStep (WizardStep newStep) { steps.Add (newStep); @@ -303,7 +314,7 @@ namespace Terminal.Gui { /// public new ustring Title { get { - return title; + return base.Title; } set { title = value; diff --git a/UICatalog/Scenarios/Wizards.cs b/UICatalog/Scenarios/Wizards.cs index e29a535b7..8ed9c1cc1 100644 --- a/UICatalog/Scenarios/Wizards.cs +++ b/UICatalog/Scenarios/Wizards.cs @@ -29,7 +29,7 @@ namespace UICatalog.Scenarios { TextAlignment = Terminal.Gui.TextAlignment.Right, }; frame.Add (label); - var widthEdit = new TextField ("0") { + var widthEdit = new TextField ("80") { X = Pos.Right (label) + 1, Y = Pos.Top (label), Width = 5, @@ -45,7 +45,7 @@ namespace UICatalog.Scenarios { TextAlignment = Terminal.Gui.TextAlignment.Right, }; frame.Add (label); - var heightEdit = new TextField ("0") { + var heightEdit = new TextField ("20") { X = Pos.Right (label) + 1, Y = Pos.Top (label), Width = 5, @@ -53,15 +53,6 @@ namespace UICatalog.Scenarios { }; frame.Add (heightEdit); - frame.Add (new Label ("If height & width are both 0,") { - X = Pos.Right (widthEdit) + 2, - Y = Pos.Top (widthEdit), - }); - frame.Add (new Label ("the Wizard will size to 80% of container.") { - X = Pos.Right (heightEdit) + 2, - Y = Pos.Top (heightEdit), - }); - label = new Label ("Title:") { X = 0, Y = Pos.Bottom (label), @@ -109,8 +100,12 @@ namespace UICatalog.Scenarios { int width = int.Parse (widthEdit.Text.ToString ()); int height = int.Parse (heightEdit.Text.ToString ()); - var wizard = new Wizard (); - wizard.Title = titleEdit.Text; + var wizard = new Wizard () { + Title = titleEdit.Text, + Width = width, + Height = height + }; + wizard.MovingBack += (args) => { //args.Cancel = true; actionLabel.Text = "Moving Back"; @@ -131,7 +126,7 @@ namespace UICatalog.Scenarios { wizard.AddStep (firstStep); firstStep.ShowControls = false; firstStep.NextButtonText = "Accept"; - firstStep.HelpText = "This is the End User License Agreement.\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\n\n\n\n\n\n\nTHe end of the EULA."; + firstStep.HelpText = "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA."; // Add 2nd step var secondStep = new Wizard.WizardStep ("Second Step"); diff --git a/UnitTests/WizardTests.cs b/UnitTests/WizardTests.cs new file mode 100644 index 000000000..03d79e0cb --- /dev/null +++ b/UnitTests/WizardTests.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using Terminal.Gui; +using Xunit; +using System.Globalization; +using Xunit.Abstractions; +using NStack; + +namespace Terminal.Gui.Views { + + public class WizardTests { + readonly ITestOutputHelper output; + + public WizardTests (ITestOutputHelper output) + { + this.output = output; + } + + private void RunButtonTestWizard (string title, int width, int height) + { + var wizard = new Wizard (title) { Width = width, Height = height }; + Application.End (Application.Begin (wizard)); + } + + [Fact] + [AutoInitShutdown] + public void ZeroStepWizard_Shows () + { + var d = ((FakeDriver)Application.Driver); + + var title = "1234"; + + int width = 30; + int height = 6; + d.SetBufferSize (width, height); + + var btnBackText = "Back"; + var btnBack = $"{d.LeftBracket} {btnBackText} {d.RightBracket}"; + var btnNextText = "Next..."; + var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}"; + + var topRow = $"┌ {title} {new String (d.HDLine.ToString () [0], width - title.Length - 4)}┐"; + var row2 = $"{d.VDLine}{new String (' ', width - 2)}{d.VDLine}"; + var row3 = row2; + var separatorRow = $"{d.VDLine}{new String (d.HDLine.ToString () [0], width - 2)}{d.VDLine}"; + var buttonRow = $"{d.VDLine}{btnBack}{new String (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDLine}"; + var bottomRow = $"└{new String (d.HDLine.ToString () [0], width - 2)}┘"; + + var wizard = new Wizard (title) { Width = width, Height = height }; + Application.End (Application.Begin (wizard)); + GraphViewTests.AssertDriverContentsWithFrameAre ($"{topRow}\n{row2}\n{row3}\n{separatorRow}\n{buttonRow}\n{bottomRow}", output); + } + + [Fact] + [AutoInitShutdown] + // this test is needed because Wizard overrides Dialog's title behavior ("Title - StepTitle") + public void Setting_Title_Works () + { + var d = ((FakeDriver)Application.Driver); + + var title = "1234"; + var stepTitle = " - ABCD"; + + int width = 30; + int height = 4; + d.SetBufferSize (width, height); + + var btnBackText = "Back"; + var btnBack = $"{d.LeftBracket} {btnBackText} {d.RightBracket}"; + var btnNextText = "Finish"; + var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}"; + + var topRow = $"{d.ULDCorner} {title}{stepTitle} {new String (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDCorner}"; + var separatorRow = $"{d.VDLine}{new String (d.HLine.ToString () [0], width - 2)}{d.VDLine}"; + var buttonRow = $"{d.VDLine}{new String (' ', width - btnNext.Length - 2)}{btnNext}{d.VDLine}"; + var bottomRow = $"{d.LLDCorner}{new String (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}"; + + var wizard = new Wizard (title) { Width = width, Height = height }; + wizard.AddStep (new Wizard.WizardStep ("ABCD")); + + Application.End (Application.Begin (wizard)); + GraphViewTests.AssertDriverContentsWithFrameAre ($"{topRow}\n{separatorRow}\n{buttonRow}\n{bottomRow}", output); + } + } +} \ No newline at end of file