diff --git a/Examples/FluentExample/FluentExample.csproj b/Examples/FluentExample/FluentExample.csproj index 2086af6edb..a95c7a0253 100644 --- a/Examples/FluentExample/FluentExample.csproj +++ b/Examples/FluentExample/FluentExample.csproj @@ -4,6 +4,7 @@ net8.0 preview enable + $(DefineConstants);POST_4148 diff --git a/Terminal.Gui/Views/Dialog.cs b/Terminal.Gui/Views/Dialog.cs index 03797368dc..81dd7ac140 100644 --- a/Terminal.Gui/Views/Dialog.cs +++ b/Terminal.Gui/Views/Dialog.cs @@ -6,13 +6,21 @@ namespace Terminal.Gui.Views; /// scheme. /// /// -/// To run the modally, create the , and pass it to -/// . This will execute the dialog until -/// it terminates via the (`Esc` by default), -/// or when one of the views or buttons added to the dialog calls -/// . +/// +/// To run the modally, create the , and pass it to +/// . This will execute the dialog until +/// it terminates via the (`Esc` by default), +/// or when one of the views or buttons added to the dialog calls +/// . +/// +/// +/// Phase 2: now implements with +/// int? as the result type, returning the index of the clicked button. The +/// property replaces the need for manual result tracking. A result of indicates +/// the dialog was canceled (ESC pressed, window closed without clicking a button). +/// /// -public class Dialog : Window +public class Dialog : Window, IRunnable { private static LineStyle _defaultBorderStyle = LineStyle.Heavy; // Resources/config.json overrides private static Alignment _defaultButtonAlignment = Alignment.End; // Resources/config.json overrides @@ -91,7 +99,13 @@ public Button [] Buttons } /// Gets a value indicating whether the was canceled. - /// The default value is . + /// + /// The default value is . + /// + /// Deprecated: Use instead. This property is maintained for backward + /// compatibility. A indicates the dialog was canceled. + /// + /// public bool Canceled { get { return _canceled; } @@ -107,6 +121,21 @@ public bool Canceled } } + /// + /// Gets or sets the result data extracted when the dialog was accepted, or if not accepted. + /// + /// + /// + /// Returns the zero-based index of the button that was clicked, or if the + /// dialog was canceled (ESC pressed, window closed without clicking a button). + /// + /// + /// This property is automatically set in when the dialog is + /// closing. The result is extracted by finding which button has focus when the dialog stops. + /// + /// + public int? Result { get; set; } + /// /// Defines the default border styling for . Can be configured via /// . @@ -198,4 +227,67 @@ protected override bool OnGettingAttributeForRole (in VisualRole role, ref Attri return false; } + + #region IRunnable Implementation + + /// + /// Called when the dialog is about to stop running. Extracts the button result before the dialog is removed + /// from the runnable stack. + /// + /// The current value of IsRunning. + /// The new value of IsRunning (true = starting, false = stopping). + /// to cancel; to proceed. + /// + /// 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. + /// + 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 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 } diff --git a/Terminal.Gui/Views/MessageBox.cs b/Terminal.Gui/Views/MessageBox.cs index e9e874285e..a80d0cca11 100644 --- a/Terminal.Gui/Views/MessageBox.cs +++ b/Terminal.Gui/Views/MessageBox.cs @@ -106,8 +106,14 @@ public static int DefaultMinimumHeight /// The index of the selected button, or if the user pressed . /// /// - /// This global variable is useful for web-based consoles without a SynchronizationContext or TaskScheduler. - /// Warning: Not thread-safe. + /// + /// Warning: This is a global variable and should be used with caution. It is not thread safe. + /// + /// + /// Deprecated: This property is maintained for backward compatibility. The MessageBox methods + /// now return the button index directly, and provides a cleaner, + /// non-global alternative for custom dialog implementations. + /// /// public static int? Clicked { get; private set; } @@ -573,7 +579,6 @@ params string [] buttons // Create button array for Dialog var count = 0; List