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