Progress on refactoring nav

This commit is contained in:
Charlie Kindel
2022-06-15 12:18:40 -07:00
committed by Tig Kindel
parent 76542360ad
commit 1bc2c79938
4 changed files with 360 additions and 38 deletions

View File

@@ -2399,7 +2399,7 @@ namespace Terminal.Gui {
}
}
bool oldEnabled;
bool oldEnabled = true;
/// <inheritdoc/>
public override bool Enabled {

View File

@@ -22,6 +22,11 @@ namespace Terminal.Gui {
/// <remarks>
/// If <see cref="Button"/>s are added, do not set <see cref="Button.IsDefault"/> to true as this will conflict
/// with the Next button of the Wizard.
///
/// Subscribe to the <see cref="View.VisibleChanged"/> event to be notified when the step is active; see also: <see cref="Wizard.StepChanged"/>.
///
/// To enable or disable a step from being shown to the user, set <see cref="View.Enabled"/>.
///
/// </remarks>
public class WizardStep : View {
/// <summary>
@@ -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 ();
//}
/// <summary>
/// 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 ();
}
}
}
/// <summary>
/// Causes the wizad to move to the next enabled step (or last step if <see cref="CurrentStep"/> is not set).
/// If there is no previous step, does nothing.
/// </summary>
public void GoNext ()
{
var nextStep = GetNextStep ();
if (nextStep != null) {
GoToStep (nextStep);
}
}
/// <summary>
/// Returns the next enabled <see cref="WizardStep"/> after the current step. Takes into account steps which
/// are disabled. If <see cref="CurrentStep"/> is `null` returns the first enabled step.
/// </summary>
/// <returns>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.</returns>
public WizardStep GetNextStep ()
{
LinkedListNode<WizardStep> 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 ();
}
}
/// <summary>
/// Causes the wizad to move to the previous enabled step (or first step if <see cref="CurrentStep"/> is not set).
/// If there is no previous step, does nothing.
/// </summary>
public void GoBack ()
{
var previous = GetPreviousStep ();
if (previous != null) {
GoToStep (previous);
}
}
/// <summary>
/// Returns the first enabled <see cref="WizardStep"/> before the current step. Takes into account steps which
/// are disabled. If <see cref="CurrentStep"/> is `null` returns the last enabled step.
/// </summary>
/// <returns>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.</returns>
public WizardStep GetPreviousStep ()
{
LinkedListNode<WizardStep> 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<WizardStep> steps = new LinkedList<WizardStep> ();
@@ -449,7 +540,7 @@ namespace Terminal.Gui {
public WizardStep CurrentStep {
get => currentStep;
set {
GotoStep (value);
GoToStep (value);
}
}
@@ -484,9 +575,9 @@ namespace Terminal.Gui {
/// </summary>
/// <param name="newStep">The step to go to.</param>
/// <returns>True if the transition to the step succeeded. False if the step was not found or the operation was cancelled.</returns>
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 ();

View File

@@ -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;

View File

@@ -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
}
}
}