diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs
index 0c40f67c5..8de8708b3 100644
--- a/Terminal.Gui/Core/View.cs
+++ b/Terminal.Gui/Core/View.cs
@@ -2399,7 +2399,7 @@ namespace Terminal.Gui {
}
}
- bool oldEnabled;
+ bool oldEnabled = true;
///
public override bool Enabled {
diff --git a/Terminal.Gui/Windows/Wizard.cs b/Terminal.Gui/Windows/Wizard.cs
index ea762233c..abb9de422 100644
--- a/Terminal.Gui/Windows/Wizard.cs
+++ b/Terminal.Gui/Windows/Wizard.cs
@@ -22,6 +22,11 @@ namespace Terminal.Gui {
///
/// If s are added, do not set to true as this will conflict
/// with the Next button of the Wizard.
+ ///
+ /// Subscribe to the event to be notified when the step is active; see also: .
+ ///
+ /// To enable or disable a step from being shown to the user, set .
+ ///
///
public class WizardStep : View {
///
@@ -94,6 +99,7 @@ namespace Terminal.Gui {
helpTextView.ReadOnly = true;
helpTextView.WordWrap = true;
this.Add (helpTextView);
+
ShowHide ();
var scrollBar = new ScrollBarView (helpTextView, true);
@@ -143,6 +149,13 @@ namespace Terminal.Gui {
this.Add (scrollBar);
}
+ //public override void OnEnabledChanged()
+ //{
+ // if (Enabled) { }
+ // base.OnEnabledChanged ();
+ //}
+
+
///
/// 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.
@@ -281,24 +294,102 @@ namespace Terminal.Gui {
var args = new WizardButtonEventArgs ();
MovingNext?.Invoke (args);
if (!args.Cancel) {
- var current = steps.Find (CurrentStep);
- if (current != null && current.Next != null) {
- GotoStep (current.Next.Value);
- }
+ GoNext ();
}
}
}
+ ///
+ /// Causes the wizad to move to the next enabled step (or last step if is not set).
+ /// If there is no previous step, does nothing.
+ ///
+ public void GoNext ()
+ {
+ var nextStep = GetNextStep ();
+ if (nextStep != null) {
+ GoToStep (nextStep);
+ }
+ }
+
+ ///
+ /// Returns the next enabled after the current step. Takes into account steps which
+ /// are disabled. If is `null` returns the first enabled step.
+ ///
+ /// The next step after the current step, if there is one; otherwise returns `null`, which
+ /// indicates either there are no enabled steps or the current step is the last enabled step.
+ public WizardStep GetNextStep ()
+ {
+ LinkedListNode step = null;
+ if (CurrentStep == null) {
+ // Get last step, assume it is next
+ step = steps.First;
+ } else {
+ // Get the step after current
+ step = steps.Find (CurrentStep);
+ if (step != null) {
+ step = step.Next;
+ }
+ }
+
+ // step now points to the potential next step
+ while (step != null) {
+ if (step.Value.Enabled) {
+ return step.Value;
+ }
+ step = step.Next;
+ }
+ return null;
+ }
+
private void BackBtn_Clicked ()
{
var args = new WizardButtonEventArgs ();
MovingBack?.Invoke (args);
if (!args.Cancel) {
- var current = steps.Find (CurrentStep);
- if (current != null && current.Previous != null) {
- GotoStep (current.Previous.Value);
+ GoBack ();
+ }
+ }
+
+ ///
+ /// Causes the wizad to move to the previous enabled step (or first step if is not set).
+ /// If there is no previous step, does nothing.
+ ///
+ public void GoBack ()
+ {
+ var previous = GetPreviousStep ();
+ if (previous != null) {
+ GoToStep (previous);
+ }
+ }
+
+ ///
+ /// Returns the first enabled before the current step. Takes into account steps which
+ /// are disabled. If is `null` returns the last enabled step.
+ ///
+ /// The first step ahead of the current step, if there is one; otherwise returns `null`, which
+ /// indicates either there are no enabled steps or the current step is the first enabled step.
+ public WizardStep GetPreviousStep ()
+ {
+ LinkedListNode step = null;
+ if (CurrentStep == null) {
+ // Get last step, assume it is previous
+ step = steps.Last;
+ } else {
+ // Get the step before current
+ step = steps.Find (CurrentStep);
+ if (step != null) {
+ step = step.Previous;
}
}
+
+ // step now points to the potential previous step
+ while (step != null) {
+ if (step.Value.Enabled) {
+ return step.Value;
+ }
+ step = step.Previous;
+ }
+ return null;
}
private LinkedList steps = new LinkedList ();
@@ -449,7 +540,7 @@ namespace Terminal.Gui {
public WizardStep CurrentStep {
get => currentStep;
set {
- GotoStep (value);
+ GoToStep (value);
}
}
@@ -484,9 +575,9 @@ namespace Terminal.Gui {
///
/// The step to go to.
/// True if the transition to the step succeeded. False if the step was not found or the operation was cancelled.
- public bool GotoStep (WizardStep newStep)
+ public bool GoToStep (WizardStep newStep)
{
- if (OnStepChanging (currentStep, newStep)) {
+ if (OnStepChanging (currentStep, newStep) || (newStep != null && !newStep.Enabled)) {
return false;
}
@@ -495,17 +586,20 @@ namespace Terminal.Gui {
step.Visible = (step == newStep);
}
- base.Title = $"{wizardTitle}{(steps.Count > 0 ? " - " + newStep.Title : string.Empty)}";
+ if (newStep != null) {
- // Configure the Back button
- backBtn.Text = newStep.BackButtonText != ustring.Empty ? newStep.BackButtonText : Strings.wzBack; // "_Back";
- backBtn.Visible = (newStep != steps.First.Value);
+ base.Title = $"{wizardTitle}{(steps.Count > 0 ? " - " + newStep.Title : string.Empty)}";
- // Configure the Next/Finished button
- if (newStep == steps.Last.Value) {
- nextfinishBtn.Text = newStep.NextButtonText != ustring.Empty ? newStep.NextButtonText : Strings.wzFinish; // "Fi_nish";
- } else {
- nextfinishBtn.Text = newStep.NextButtonText != ustring.Empty ? newStep.NextButtonText : Strings.wzNext; // "_Next...";
+ // Configure the Back button
+ backBtn.Text = newStep.BackButtonText != ustring.Empty ? newStep.BackButtonText : Strings.wzBack; // "_Back";
+ backBtn.Visible = (newStep != steps.First.Value);
+
+ // Configure the Next/Finished button
+ if (newStep == steps.Last.Value) {
+ nextfinishBtn.Text = newStep.NextButtonText != ustring.Empty ? newStep.NextButtonText : Strings.wzFinish; // "Fi_nish";
+ } else {
+ nextfinishBtn.Text = newStep.NextButtonText != ustring.Empty ? newStep.NextButtonText : Strings.wzNext; // "_Next...";
+ }
}
// Set focus to the nav buttons
@@ -515,7 +609,7 @@ namespace Terminal.Gui {
nextfinishBtn.SetFocus ();
}
- var oldStep = currentStep;
+ var oldStep = currentStep;
currentStep = newStep;
LayoutSubviews ();
diff --git a/UICatalog/Scenarios/Wizards.cs b/UICatalog/Scenarios/Wizards.cs
index 80a178f78..c6f7e5c9b 100644
--- a/UICatalog/Scenarios/Wizards.cs
+++ b/UICatalog/Scenarios/Wizards.cs
@@ -176,15 +176,15 @@ namespace UICatalog.Scenarios {
lbl = new Label () { Text = "Last Name: ", AutoSize = true, X = 1, Y = Pos.Bottom (lbl) };
var lastNameField = new TextField () { Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
viewForControls.Add (lbl, lastNameField);
- var checkBox = new CheckBox () { Text = "Un-check me!", Checked = true, X = Pos.Left (lastNameField), Y = Pos.Bottom (lastNameField) };
- viewForControls.Add (checkBox);
+ var thirdStepEnabledCeckBox = new CheckBox () { Text = "Enable Step _3", Checked = false, X = Pos.Left (lastNameField), Y = Pos.Bottom (lastNameField) };
+ viewForControls.Add (thirdStepEnabledCeckBox);
// Add a frame to demonstrate difference between adding controls to
// WizardStep.Controls vs. WizardStep directly. This is here to demonstrate why
// adding to .Controls is preferred.
var frame = new FrameView ($"A Broken Frame - {frameMsg}") {
X = 0,
- Y = Pos.Bottom (checkBox) + 2,
+ Y = Pos.Bottom (thirdStepEnabledCeckBox) + 2,
Width = Dim.Fill (),
Height = 4,
//ColorScheme = Colors.Error,
@@ -192,10 +192,23 @@ namespace UICatalog.Scenarios {
frame.Add (new TextField ("This is a TextField inside of the frame."));
viewForControls.Add (frame);
- // Add 3rd step
- var thirdStep = new Wizard.WizardStep ("Third Step");
+ // Add 3rd (optional) step
+ var thirdStep = new Wizard.WizardStep ("Third Step (Optional)");
+
+ thirdStep.Enabled = thirdStepEnabledCeckBox.Checked;
+ thirdStepEnabledCeckBox.Toggled += (args) => {
+ thirdStep.Enabled = thirdStepEnabledCeckBox.Checked;
+ };
+
wizard.AddStep (thirdStep);
- thirdStep.HelpText = "This is the help text for the Third Step.";
+ thirdStep.HelpText = "This is step is optional (WizardStep.Enabled = false). Enable it with the checkbox in Step 2.";
+ var step3Label = new Label () {
+ Text = "This step is optional.",
+ X = 0,
+ Y = 0,
+ AutoSize = true
+ };
+ thirdStep.Controls.Add (step3Label);
var progLbl = new Label () { Text = "Third Step ProgressBar: ", AutoSize = true, X = 1, Y = 10 };
var progressBar = new ProgressBar () {
X = Pos.Right (progLbl),
@@ -222,18 +235,18 @@ namespace UICatalog.Scenarios {
//fourthStep.NextButtonText = "4";
var scrollBar = new ScrollBarView (someText, true);
- wizard.StepChanging += (args) => {
- if (args.NewStep == fourthStep) {
- var btn = MessageBox.ErrorQuery ("Wizards", "Move to Step Four?", "Yes", "No");
- args.Cancel = btn == 1;
- }
- };
+ //wizard.StepChanging += (args) => {
+ // if (args.NewStep == fourthStep) {
+ // var btn = MessageBox.ErrorQuery ("Wizards", "Move to Step Four?", "Yes", "No");
+ // args.Cancel = btn == 1;
+ // }
+ //};
- wizard.StepChanged += (args) => {
- if (args.NewStep == fourthStep) {
- var btn = MessageBox.ErrorQuery ("Wizards", "Yay. Moved to Step Four", "Ok");
- }
- };
+ //wizard.StepChanged += (args) => {
+ // if (args.NewStep == fourthStep) {
+ // var btn = MessageBox.ErrorQuery ("Wizards", "Yay. Moved to Step Four", "Ok");
+ // }
+ //};
scrollBar.ChangedPosition += () => {
someText.TopRow = scrollBar.Position;
diff --git a/UnitTests/WizardTests.cs b/UnitTests/WizardTests.cs
index b76eeb9a0..15d80a960 100644
--- a/UnitTests/WizardTests.cs
+++ b/UnitTests/WizardTests.cs
@@ -191,5 +191,220 @@ namespace Terminal.Gui.Views {
Application.End (Application.Begin (wizard));
GraphViewTests.AssertDriverContentsWithFrameAre ($"{topRow}\n{separatorRow}\n{buttonRow}\n{bottomRow}", output);
}
+
+ [Fact, AutoInitShutdown]
+ public void Navigate_GetPreviousStep_Correct ()
+ {
+ var wizard = new Wizard ();
+
+ // If no steps should be null
+ Assert.Null (wizard.GetPreviousStep ());
+
+ var step1 = new Wizard.WizardStep ("step1");
+ wizard.AddStep (step1);
+
+ // If no current step, should be last step
+ Assert.Equal (step1.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ wizard.CurrentStep = step1;
+ // If there is 1 step it's current step should be null
+ Assert.Null (wizard.GetPreviousStep ());
+
+ // If one disabled step should be null
+ step1.Enabled = false;
+ Assert.Null (wizard.GetPreviousStep ());
+
+ // If two steps and at 2 and step 1 is `Enabled = true`should be step1
+ var step2 = new Wizard.WizardStep ("step2");
+ wizard.AddStep (step2);
+ wizard.CurrentStep = step2;
+ step1.Enabled = true;
+ Assert.Equal (step1.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ // If two steps and at 2 and step 1 is `Enabled = false` should be null
+ step1.Enabled = false;
+ Assert.Null (wizard.GetPreviousStep ());
+
+ // If three steps with Step2.Enabled = true
+ // At step 1 should be null
+ // At step 2 should be step 1
+ // At step 3 should be step 2
+ var step3 = new Wizard.WizardStep ("step3");
+ wizard.AddStep (step3);
+ step1.Enabled = true;
+ wizard.CurrentStep = step1;
+ step2.Enabled = true;
+ step3.Enabled = true;
+ Assert.Null (wizard.GetPreviousStep ());
+ wizard.CurrentStep = step2;
+ Assert.Equal (step1.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+ wizard.CurrentStep = step3;
+ Assert.Equal (step2.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ // If three steps with Step2.Enabled = false
+ // At step 1 should be null
+ // At step 3 should be step1
+ step1.Enabled = true;
+ step2.Enabled = false;
+ step3.Enabled = true;
+ wizard.CurrentStep = step1;
+ Assert.Null (wizard.GetPreviousStep ());
+ wizard.CurrentStep = step3;
+ Assert.Equal (step1.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ // If three steps with Step1.Enabled = false & Step2.Enabled = false
+ // At step 3 should be null
+
+ // If no current step, GetPreviousStep provides equivalent to GetLastStep
+ wizard.CurrentStep = null;
+ step1.Enabled = true;
+ step2.Enabled = true;
+ step3.Enabled = true;
+ Assert.Equal (step3.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ step1.Enabled = false;
+ step2.Enabled = true;
+ step3.Enabled = true;
+ Assert.Equal (step3.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ step1.Enabled = false;
+ step2.Enabled = false;
+ step3.Enabled = true;
+ Assert.Equal (step3.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ step1.Enabled = false;
+ step2.Enabled = true;
+ step3.Enabled = false;
+ Assert.Equal (step2.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+
+ step1.Enabled = true;
+ step2.Enabled = false;
+ step3.Enabled = false;
+ Assert.Equal (step1.Title.ToString(), wizard.GetPreviousStep ().Title.ToString());
+ }
+
+ [Fact, AutoInitShutdown]
+ public void Navigate_GetNextStep_Correct ()
+ {
+ var wizard = new Wizard ();
+
+ // If no steps should be null
+ Assert.Null (wizard.GetNextStep ());
+
+ var step1 = new Wizard.WizardStep ("step1");
+ wizard.AddStep (step1);
+
+ // If no current step, should be first step
+ Assert.Equal (step1.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+
+ wizard.CurrentStep = step1;
+ // If there is 1 step it's current step should be null
+ Assert.Null (wizard.GetNextStep ());
+
+ // If one disabled step should be null
+ step1.Enabled = false;
+ Assert.Null (wizard.GetNextStep ());
+
+ // If two steps and at 1 and step 2 is `Enabled = true`should be step 2
+ var step2 = new Wizard.WizardStep ("step2");
+ wizard.AddStep (step2);
+ Assert.Equal (step2.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+
+ // If two steps and at 1 and step 2 is `Enabled = false` should be null
+ step1.Enabled = true;
+ wizard.CurrentStep = step1;
+ step2.Enabled = false;
+ Assert.Null (wizard.GetNextStep ());
+
+ // If three steps with Step2.Enabled = true
+ // At step 1 should be step 2
+ // At step 2 should be step 3
+ // At step 3 should be null
+ var step3 = new Wizard.WizardStep ("step3");
+ wizard.AddStep (step3);
+ step1.Enabled = true;
+ wizard.CurrentStep = step1;
+ step2.Enabled = true;
+ step3.Enabled = true;
+ Assert.Equal (step2.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+ wizard.CurrentStep = step2;
+ Assert.Equal (step3.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+ wizard.CurrentStep = step3;
+ Assert.Null (wizard.GetNextStep ());
+
+ // If three steps with Step2.Enabled = false
+ // At step 1 should be step 3
+ // At step 3 should be null
+ step1.Enabled = true;
+ wizard.CurrentStep = step1;
+ step2.Enabled = false;
+ step3.Enabled = true;
+ Assert.Equal (step3.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+ wizard.CurrentStep = step3;
+ Assert.Null (wizard.GetNextStep ());
+
+ // If three steps with Step2.Enabled = false & Step3.Enabled = false
+ // At step 1 should be null
+ step1.Enabled = true;
+ wizard.CurrentStep = step1;
+ step2.Enabled = false;
+ step3.Enabled = false;
+ Assert.Null (wizard.GetNextStep ());
+
+ // If no current step, GetNextStep provides equivalent to GetFirstStep
+ wizard.CurrentStep = null;
+ step1.Enabled = true;
+ step2.Enabled = true;
+ step3.Enabled = true;
+ Assert.Equal (step1.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+
+ step1.Enabled = false;
+ step2.Enabled = true;
+ step3.Enabled = true;
+ Assert.Equal (step2.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+
+ step1.Enabled = false;
+ step2.Enabled = false;
+ step3.Enabled = true;
+ Assert.Equal (step3.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+
+ step1.Enabled = false;
+ step2.Enabled = true;
+ step3.Enabled = false;
+ Assert.Equal (step2.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+
+ step1.Enabled = true;
+ step2.Enabled = false;
+ step3.Enabled = false;
+ Assert.Equal (step1.Title.ToString(), wizard.GetNextStep ().Title.ToString());
+ }
+
+ [Fact, AutoInitShutdown]
+ public void Navigate_GoNext_Works ()
+ {
+ // If zero steps do nothing
+
+ // If one step do nothing (enabled or disabled)
+
+ // If two steps
+ // If current is 1
+ // If 2 is enabled 2 becomes current
+ // If 2 is disabled 1 stays current
+ // If current is 2 does nothing
+ }
+
+ [Fact, AutoInitShutdown]
+ public void Navigate_GoBack_Works ()
+ {
+ // If zero steps do nothing
+
+ // If one step do nothing (enabled or disabled)
+
+ // If two steps
+ // If current is 1 does nothing
+ // If current is 2 does nothing
+ // If 1 is enabled 2 becomes current
+ // If 1 is disabled 1 stays current
+ }
}
}
\ No newline at end of file