mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Implement step 2: Update Dialog to implement IRunnable<int?>
- Changed Dialog to implement IRunnable<int?> interface - Added Result property that returns the index of the clicked button or null if canceled - Implemented OnIsRunningChanging to extract button result before dialog closes - Maintained backward compatibility with legacy Canceled property - Dialog can still inherit from Window (as per new requirement) Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
@@ -7,13 +7,21 @@ namespace Terminal.Gui.Views;
|
||||
/// scheme.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To run the <see cref="Dialog"/> modally, create the <see cref="Dialog"/>, and pass it to
|
||||
/// <see cref="IApplication.Run(Toplevel, Func{Exception, bool})"/>. This will execute the dialog until
|
||||
/// it terminates via the <see cref="Application.QuitKey"/> (`Esc` by default),
|
||||
/// or when one of the views or buttons added to the dialog calls
|
||||
/// <see cref="Application.RequestStop"/>.
|
||||
/// <para>
|
||||
/// To run the <see cref="Dialog"/> modally, create the <see cref="Dialog"/>, and pass it to
|
||||
/// <see cref="IApplication.Run(Toplevel, Func{Exception, bool})"/>. This will execute the dialog until
|
||||
/// it terminates via the <see cref="Application.QuitKey"/> (`Esc` by default),
|
||||
/// or when one of the views or buttons added to the dialog calls
|
||||
/// <see cref="Application.RequestStop"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>Phase 2:</b> <see cref="Dialog"/> now implements <see cref="IRunnable{TResult}"/> with
|
||||
/// <c>int?</c> as the result type, returning the index of the clicked button. The <see cref="Result"/>
|
||||
/// property replaces the need for manual result tracking. A result of <see langword="null"/> indicates
|
||||
/// the dialog was canceled (ESC pressed, window closed without clicking a button).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Dialog : Window
|
||||
public class Dialog : Window, IRunnable<int?>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Dialog"/> class with no <see cref="Button"/>s.
|
||||
@@ -85,7 +93,13 @@ public class Dialog : Window
|
||||
}
|
||||
|
||||
/// <summary>Gets a value indicating whether the <see cref="Dialog"/> was canceled.</summary>
|
||||
/// <remarks>The default value is <see langword="true"/>.</remarks>
|
||||
/// <remarks>
|
||||
/// <para>The default value is <see langword="true"/>.</para>
|
||||
/// <para>
|
||||
/// <b>Deprecated:</b> Use <see cref="Result"/> instead. This property is maintained for backward
|
||||
/// compatibility. A <see langword="null"/> <see cref="Result"/> indicates the dialog was canceled.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool Canceled
|
||||
{
|
||||
get { return _canceled; }
|
||||
@@ -101,6 +115,21 @@ public class Dialog : Window
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the result data extracted when the dialog was accepted, or <see langword="null"/> if not accepted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Returns the zero-based index of the button that was clicked, or <see langword="null"/> if the
|
||||
/// dialog was canceled (ESC pressed, window closed without clicking a button).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This property is automatically set in <see cref="OnIsRunningChanging"/> when the dialog is
|
||||
/// closing. The result is extracted by finding which button has focus when the dialog stops.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public int? Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines the default border styling for <see cref="Dialog"/>. Can be configured via
|
||||
/// <see cref="ConfigurationManager"/>.
|
||||
@@ -168,4 +197,67 @@ public class Dialog : Window
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region IRunnable<int> Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Called when the dialog is about to stop running. Extracts the button result before the dialog is removed
|
||||
/// from the runnable stack.
|
||||
/// </summary>
|
||||
/// <param name="oldIsRunning">The current value of IsRunning.</param>
|
||||
/// <param name="newIsRunning">The new value of IsRunning (true = starting, false = stopping).</param>
|
||||
/// <returns><see langword="true"/> to cancel; <see langword="false"/> to proceed.</returns>
|
||||
/// <remarks>
|
||||
/// This method is called by the IRunnable infrastructure when the dialog is stopping. It extracts
|
||||
/// which button was clicked (if any) before views are disposed.
|
||||
/// </remarks>
|
||||
protected virtual bool OnIsRunningChanging (bool oldIsRunning, bool newIsRunning)
|
||||
{
|
||||
if (!newIsRunning && oldIsRunning) // Stopping
|
||||
{
|
||||
// Extract result BEFORE disposal - find which button has focus or was last clicked
|
||||
Result = null; // Default: canceled (null = no button clicked)
|
||||
|
||||
for (var i = 0; i < _buttons.Count; i++)
|
||||
{
|
||||
if (_buttons [i].HasFocus)
|
||||
{
|
||||
Result = i;
|
||||
_canceled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no button has focus, check if any button was the last focused view
|
||||
if (Result is null && MostFocused is Button btn && _buttons.Contains (btn))
|
||||
{
|
||||
Result = _buttons.IndexOf (btn);
|
||||
_canceled = false;
|
||||
}
|
||||
|
||||
// Update legacy Canceled property for backward compatibility
|
||||
if (Result is null)
|
||||
{
|
||||
_canceled = true;
|
||||
}
|
||||
}
|
||||
else if (newIsRunning) // Starting
|
||||
{
|
||||
// Clear result when starting
|
||||
Result = null;
|
||||
_canceled = true; // Default to canceled until a button is clicked
|
||||
}
|
||||
|
||||
// Call base implementation (Toplevel.IRunnable.RaiseIsRunningChanging)
|
||||
return ((IRunnable)this).RaiseIsRunningChanging (oldIsRunning, newIsRunning);
|
||||
}
|
||||
|
||||
// Explicitly implement IRunnable<int> to override the behavior from Toplevel's IRunnable
|
||||
bool IRunnable.RaiseIsRunningChanging (bool oldIsRunning, bool newIsRunning)
|
||||
{
|
||||
// Call our virtual method so subclasses can override
|
||||
return OnIsRunningChanging (oldIsRunning, newIsRunning);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user