浏览代码

Fixes #3209 - Formalize Cancellable Work Pattern and add helpers (#4092)

Tig 3 月之前
父节点
当前提交
764a804ddd
共有 100 个文件被更改,包括 1585 次插入1002 次删除
  1. 4 2
      .editorconfig
  2. 4 30
      CONTRIBUTING.md
  3. 2 2
      Examples/UICatalog/Resources/config.json
  4. 2 2
      Examples/UICatalog/Scenario.cs
  5. 2 2
      Examples/UICatalog/Scenarios/Adornments.cs
  6. 2 2
      Examples/UICatalog/Scenarios/Arrangement.cs
  7. 8 8
      Examples/UICatalog/Scenarios/Bars.cs
  8. 1 0
      Examples/UICatalog/Scenarios/Buttons.cs
  9. 3 3
      Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs
  10. 6 6
      Examples/UICatalog/Scenarios/ColorPicker.cs
  11. 13 13
      Examples/UICatalog/Scenarios/DynamicMenuBar.cs
  12. 4 4
      Examples/UICatalog/Scenarios/Editor.cs
  13. 3 3
      Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentEditor.cs
  14. 3 3
      Examples/UICatalog/Scenarios/EditorsAndHelpers/AllViewsView.cs
  15. 4 4
      Examples/UICatalog/Scenarios/EditorsAndHelpers/BorderEditor.cs
  16. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/ExpanderButton.cs
  17. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/MarginEditor.cs
  18. 4 4
      Examples/UICatalog/Scenarios/EditorsAndHelpers/SchemeViewer.cs
  19. 1 1
      Examples/UICatalog/Scenarios/EditorsAndHelpers/ThemeViewer.cs
  20. 24 24
      Examples/UICatalog/Scenarios/EditorsAndHelpers/ViewportSettingsEditor.cs
  21. 3 3
      Examples/UICatalog/Scenarios/Images.cs
  22. 8 8
      Examples/UICatalog/Scenarios/ListViewWithSelection.cs
  23. 159 102
      Examples/UICatalog/Scenarios/Mouse.cs
  24. 2 2
      Examples/UICatalog/Scenarios/Navigation.cs
  25. 8 8
      Examples/UICatalog/Scenarios/PosAlignDemo.cs
  26. 1 1
      Examples/UICatalog/Scenarios/ProgressBarStyles.cs
  27. 11 11
      Examples/UICatalog/Scenarios/ScrollBarDemo.cs
  28. 4 4
      Examples/UICatalog/Scenarios/Scrolling.cs
  29. 1 1
      Examples/UICatalog/Scenarios/ShadowStyles.cs
  30. 8 8
      Examples/UICatalog/Scenarios/Shortcuts.cs
  31. 2 2
      Examples/UICatalog/Scenarios/SpinnerStyles.cs
  32. 2 2
      Examples/UICatalog/Scenarios/TextAlignmentAndDirection.cs
  33. 1 1
      Examples/UICatalog/Scenarios/TextEffectsScenario.cs
  34. 2 2
      Examples/UICatalog/Scenarios/TextFormatterDemo.cs
  35. 7 7
      Examples/UICatalog/Scenarios/TextInputControls.cs
  36. 13 4
      Examples/UICatalog/Scenarios/TextStyles.cs
  37. 13 13
      Examples/UICatalog/Scenarios/Themes.cs
  38. 1 1
      Examples/UICatalog/Scenarios/TrueColors.cs
  39. 1 1
      Examples/UICatalog/Scenarios/ViewportSettings.cs
  40. 1 1
      Examples/UICatalog/UICatalog.cs
  41. 9 9
      Examples/UICatalog/UICatalogTop.cs
  42. 56 0
      Terminal.Gui/App/CWP/CWPEventHelper.cs
  43. 102 0
      Terminal.Gui/App/CWP/CWPPropertyHelper.cs
  44. 129 0
      Terminal.Gui/App/CWP/CWPWorkflowHelper.cs
  45. 7 6
      Terminal.Gui/App/CWP/CancelEventArgs.cs
  46. 22 0
      Terminal.Gui/App/CWP/EventArgs.cs
  47. 45 0
      Terminal.Gui/App/CWP/ResultEventArgs.cs
  48. 39 0
      Terminal.Gui/App/CWP/ValueChangedEventArgs.cs
  49. 44 0
      Terminal.Gui/App/CWP/ValueChangingEventArgs.cs
  50. 12 0
      Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs
  51. 1 1
      Terminal.Gui/Configuration/SourceGenerationContext.cs
  52. 2 2
      Terminal.Gui/Configuration/ThemeManager.cs
  53. 0 12
      Terminal.Gui/Drawing/Color/ColorEventArgs.cs
  54. 1 1
      Terminal.Gui/Drawing/Scheme.cs
  55. 0 21
      Terminal.Gui/Drawing/SchemeEventArgs.cs
  56. 1 1
      Terminal.Gui/Drawing/VisualRole.cs
  57. 54 21
      Terminal.Gui/Drawing/VisualRoleEventArgs.cs
  58. 1 1
      Terminal.Gui/Drivers/V2/MainLoop.cs
  59. 11 7
      Terminal.Gui/Drivers/WindowsDriver/WindowsDriver.cs
  60. 121 131
      Terminal.Gui/README.md
  61. 0 21
      Terminal.Gui/Text/StringPropertyEventArgs.cs
  62. 2 3
      Terminal.Gui/ViewBase/Adornment/Adornment.cs
  63. 4 3
      Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs
  64. 30 18
      Terminal.Gui/ViewBase/Adornment/Border.cs
  65. 21 23
      Terminal.Gui/ViewBase/Adornment/Margin.cs
  66. 35 0
      Terminal.Gui/ViewBase/DrawAdornmentsEventArgs.cs
  67. 0 18
      Terminal.Gui/ViewBase/EventArgs.cs
  68. 0 31
      Terminal.Gui/ViewBase/HighlightStyle.cs
  69. 39 0
      Terminal.Gui/ViewBase/MouseState.cs
  70. 2 0
      Terminal.Gui/ViewBase/Navigation/FocusEventArgs.cs
  71. 32 0
      Terminal.Gui/ViewBase/Orientation/OrientationHelper.cs
  72. 2 2
      Terminal.Gui/ViewBase/View.Command.cs
  73. 13 10
      Terminal.Gui/ViewBase/View.Drawing.Attribute.cs
  74. 199 103
      Terminal.Gui/ViewBase/View.Drawing.Scheme.cs
  75. 1 1
      Terminal.Gui/ViewBase/View.Drawing.cs
  76. 100 132
      Terminal.Gui/ViewBase/View.Mouse.cs
  77. 3 0
      Terminal.Gui/ViewBase/View.Navigation.cs
  78. 2 2
      Terminal.Gui/ViewBase/View.ScrollBars.cs
  79. 6 33
      Terminal.Gui/Views/Button.cs
  80. 2 5
      Terminal.Gui/Views/CharMap/CharMap.cs
  81. 14 14
      Terminal.Gui/Views/CheckBox.cs
  82. 2 2
      Terminal.Gui/Views/Color/ColorPicker.16.cs
  83. 1 1
      Terminal.Gui/Views/Color/ColorPicker.cs
  84. 3 3
      Terminal.Gui/Views/ComboBox.cs
  85. 1 0
      Terminal.Gui/Views/FileDialog.cs
  86. 8 8
      Terminal.Gui/Views/FlagSelector.cs
  87. 1 1
      Terminal.Gui/Views/Label.cs
  88. 2 2
      Terminal.Gui/Views/Menu/MenuBarv2.cs
  89. 8 8
      Terminal.Gui/Views/OptionSelector.cs
  90. 4 4
      Terminal.Gui/Views/ScrollBar/ScrollBar.cs
  91. 1 1
      Terminal.Gui/Views/ScrollBar/ScrollSlider.cs
  92. 10 10
      Terminal.Gui/Views/Shortcut.cs
  93. 9 8
      Terminal.Gui/Views/TextInput/DateField.cs
  94. 13 10
      Terminal.Gui/Views/TextInput/TextField.cs
  95. 9 9
      Terminal.Gui/Views/TextInput/TimeField.cs
  96. 1 0
      Terminal.Gui/Views/View.cs
  97. 1 1
      Terminal.Gui/Views/Wizard/Wizard.cs
  98. 2 0
      Terminal.sln.DotSettings
  99. 2 2
      Tests/IntegrationTests/UICatalog/ScenarioTests.cs
  100. 3 3
      Tests/StressTests/ScenariosStressTests.cs

+ 4 - 2
.editorconfig

@@ -34,6 +34,8 @@ csharp_space_between_method_call_empty_parameter_list_parentheses = false
 csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
 csharp_space_between_parentheses = false
 csharp_space_between_square_brackets = false
+csharp_style_var_elsewhere = false:suggestion
+csharp_style_var_when_type_is_apparent = false:suggestion
 dotnet_diagnostic.bc40000.severity = warning
 dotnet_diagnostic.bc400005.severity = warning
 dotnet_diagnostic.bc40008.severity = warning
@@ -545,7 +547,7 @@ resharper_formatter_tags_enabled = false
 resharper_format_leading_spaces_decl = false
 resharper_for_built_in_types = use_var_when_evident
 resharper_for_other_types = use_explicit_type
-resharper_for_simple_types = use_var_when_evident
+resharper_for_simple_types = use_explicit_type
 resharper_ignore_space_preservation = false
 resharper_include_prefix_comment_in_indent = false
 resharper_indent_anonymous_method_block = true
@@ -864,7 +866,7 @@ resharper_arrange_default_value_when_type_evident_highlighting = suggestion
 resharper_arrange_default_value_when_type_not_evident_highlighting = suggestion
 resharper_arrange_local_function_body_highlighting = warning
 resharper_arrange_method_or_operator_body_highlighting = hint
-resharper_arrange_null_checking_pattern_highlighting = error
+resharper_arrange_null_checking_pattern_highlighting = hint
 resharper_arrange_object_creation_when_type_evident_highlighting = suggestion
 resharper_arrange_object_creation_when_type_not_evident_highlighting = warning
 resharper_arrange_redundant_parentheses_highlighting = warning

+ 4 - 30
CONTRIBUTING.md

@@ -10,8 +10,8 @@ We welcome contributions from the community. See [Issues](https://github.com/gui
 
 Terminal.Gui uses the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branching model. 
 
-* The `v1_release_` and `v2_release` branches are always stable, and always matches the most recently released Nuget package.
-* The `v1__develop` and `v2_develop` branches are where new development and bug-fixes happen. `v2_develop` is the default Github branch.
+* The `v1_release` and `v2_release` branches are always stable, and always match the most recently released Nuget package.
+* The `v1_develop` and `v2_develop` branches are where new development and bug-fixes happen. `v2_develop` is the default Github branch.
 
 ### Forking Terminal.Gui
 
@@ -141,34 +141,8 @@ Great care has been provided thus far in ensuring **Terminal.Gui** has great [AP
 
 ### Defining Events
 
-The [Microsoft .NET Framework Design Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/) provides these guidelines for defining events:
-
-> Events always refer to some action, either one that is happening or one that has occurred. Therefore, as with methods, events are named with verbs, and verb tense is used to indicate the time when the event is raised.
->
-> ✔️ DO name events with a verb or a verb phrase.
-> 
-> Examples include Clicked, Painting, DroppedDown, and so on.
-> 
-> ✔️ DO give events names with a concept of before and after, using the present and past tenses.
-> 
-> For example, a close event that is raised before a window is closed would be called Closing, and one that is raised after the window is closed would be called Closed.
-> 
-> ❌ DO NOT use "Before" or "After" prefixes or postfixes to indicate pre- and post-events. Use present and past tenses as just described.
-> 
-> ✔️ DO name event handlers (delegates used as types of events) with the "EventHandler" suffix, as shown in the following example:
-> 
-> ✔️ DO name event argument classes with the "EventArgs" suffix.
-
-1. We follow the naming guidelines provided in https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-type-members?redirectedfrom=MSDN
-2. We use the `event EventHandler<T>` idiom.
-3. For public APIs, the class that can raise the event will implement:
-   - A `virtual` event raising function, named as `OnEventToRaise`. Typical implementations will simply do a `EventToRaise?.Invoke(this, eventArgs)`.
-   - An `event` as in `public event EventHandler<EventArgs> EventToRaise`
-   - Consumers of the event can do `theobject.EventToRaise += (sender, args) => {};`
-   - Sub-classes of the class implementing `EventToRaise` can override `OnEventToRaise` as needed.
-4. Where possible, a subclass of `EventArgs` should be provided and the old and new state should be included. By doing this, event handler methods do not have to query the sender for state.
-
-See also: https://www.codeproject.com../docs/20550/C-Event-Implementation-Fundamentals-Best-Practices
+See https://gui-cs.github.io/Terminal.GuiV2Docs/docs/events.html
+
 
 ### Defining new `View` classes
 

+ 2 - 2
Examples/UICatalog/Resources/config.json

@@ -136,7 +136,7 @@
     {
       "UI Catalog Theme": {
         "Window.DefaultShadow": "Transparent",
-        "CheckBox.DefaultHighlightStyle": "Hover, Pressed, PressedOutside",
+        "CheckBox.DefaultHighlightStates": "In, Pressed, PressedOutside",
         "MessageBox.DefaultButtonAlignment": "Start",
         "StatusBar.DefaultSeparatorLineStyle": "Single",
         "Dialog.DefaultMinimumWidth": 80,
@@ -149,7 +149,7 @@
         "Button.DefaultShadow": "Transparent",
         "FrameView.DefaultBorderStyle": "Double",
         "MessageBox.DefaultMinimumHeight": 0,
-        "Button.DefaultHighlightStyle": "Hover, Pressed",
+        "Button.DefaultHighlightStates": "In, Pressed",
         "Menuv2.DefaultBorderStyle": "Heavy",
         "MenuBarv2.DefaultBorderStyle": "Heavy",
         "Schemes": [

+ 2 - 2
Examples/UICatalog/Scenario.cs

@@ -181,7 +181,7 @@ public class Scenario : IDisposable
 
     private void OnApplicationOnInitializedChanged (object? s, EventArgs<bool> a)
     {
-        if (a.CurrentValue)
+        if (a.Value)
         {
             lock (_timeoutLock!)
             {
@@ -196,7 +196,7 @@ public class Scenario : IDisposable
                 cd.Refreshed += (sender, args) =>
                                                  {
                                                      BenchmarkResults.RefreshedCount++;
-                                                     if (args.CurrentValue)
+                                                     if (args.Value)
                                                      {
                                                          BenchmarkResults.UpdatedCount++;
                                                      }

+ 2 - 2
Examples/UICatalog/Scenarios/Adornments.cs

@@ -51,7 +51,7 @@ public class Adornments : Scenario
                                                              {
                                                                  Normal = new (
                                                                                color.SuperView.GetAttributeForRole (VisualRole.Normal).Foreground,
-                                                                               e.CurrentValue,
+                                                                               e.Result,
                                                                                color.SuperView.GetAttributeForRole (VisualRole.Normal).Style
                                                                               )
                                                              });
@@ -130,7 +130,7 @@ public class Adornments : Scenario
                                       Y = 1,
                                       Text = "_Button in Padding Y = 1",
                                       CanFocus = true,
-                                      HighlightStyle = HighlightStyle.None,
+                                      HighlightStates = MouseState.None,
                                   };
                                   btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
                                   btnButtonInPadding.BorderStyle = LineStyle.Dashed;

+ 2 - 2
Examples/UICatalog/Scenarios/Arrangement.cs

@@ -223,9 +223,9 @@ public class Arrangement : Scenario
 
         return;
 
-        void ColorPickerColorChanged (object sender, ColorEventArgs e)
+        void ColorPickerColorChanged (object sender, ResultEventArgs<Color> e)
         {
-            testFrame.SetScheme (testFrame.GetScheme () with { Normal = new (testFrame.GetAttributeForRole (VisualRole.Normal).Foreground, e.CurrentValue) });
+            testFrame.SetScheme (testFrame.GetScheme () with { Normal = new (testFrame.GetAttributeForRole (VisualRole.Normal).Foreground, e.Result) });
         }
     }
 

+ 8 - 8
Examples/UICatalog/Scenarios/Bars.cs

@@ -415,7 +415,7 @@ public class Bars : Scenario
             Title = "_File",
             HelpText = "File Menu",
             Key = Key.D0.WithAlt,
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = MouseState.In
         };
 
         var editMenuBarItem = new Shortcut
@@ -423,7 +423,7 @@ public class Bars : Scenario
             Title = "_Edit",
             HelpText = "Edit Menu",
             Key = Key.D1.WithAlt,
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = MouseState.In
         };
 
         var helpMenuBarItem = new Shortcut
@@ -431,7 +431,7 @@ public class Bars : Scenario
             Title = "_Help",
             HelpText = "Halp Menu",
             Key = Key.D2.WithAlt,
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = MouseState.In
         };
 
         bar.Add (fileMenuBarItem, editMenuBarItem, helpMenuBarItem);
@@ -445,7 +445,7 @@ public class Bars : Scenario
             Title = "Z_igzag",
             Key = Key.I.WithCtrl,
             Text = "Gonna zig zag",
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = MouseState.In
         };
 
         var shortcut2 = new Shortcut
@@ -453,7 +453,7 @@ public class Bars : Scenario
             Title = "Za_G",
             Text = "Gonna zag",
             Key = Key.G.WithAlt,
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = MouseState.In
         };
 
         var shortcut3 = new Shortcut
@@ -461,7 +461,7 @@ public class Bars : Scenario
             Title = "_Three",
             Text = "The 3rd item",
             Key = Key.D3.WithAlt,
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = MouseState.In
         };
 
         var line = new Line ()
@@ -475,13 +475,13 @@ public class Bars : Scenario
             Title = "_Four",
             Text = "Below the line",
             Key = Key.D3.WithAlt,
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = MouseState.In
         };
 
         shortcut4.CommandView = new CheckBox ()
         {
             Title = shortcut4.Title,
-            HighlightStyle = HighlightStyle.None,
+            HighlightStates = MouseState.None,
             CanFocus = false
         };
         // This ensures the checkbox state toggles when the hotkey of Title is pressed.

+ 1 - 0
Examples/UICatalog/Scenarios/Buttons.cs

@@ -415,6 +415,7 @@ public class Buttons : Scenario
 
         var repeatButton = new Button
         {
+            Id = "repeatButton",
             X = Pos.Right (label) + 1,
             Y = Pos.Top (label),
             Title = $"Accept Co_unt: {acceptCount}",

+ 3 - 3
Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs

@@ -68,13 +68,13 @@ public class CharacterMap : Scenario
 
         _charMap.SelectedCodePointChanged += (sender, args) =>
                                              {
-                                                 if (Rune.IsValid (args.CurrentValue))
+                                                 if (Rune.IsValid (args.Value))
                                                  {
-                                                     jumpEdit.Text = ((Rune)args.CurrentValue).ToString ();
+                                                     jumpEdit.Text = ((Rune)args.Value).ToString ();
                                                  }
                                                  else
                                                  {
-                                                     jumpEdit.Text = $"U+{args.CurrentValue:x5}";
+                                                     jumpEdit.Text = $"U+{args.Value:x5}";
                                                  }
                                              };
 

+ 6 - 6
Examples/UICatalog/Scenarios/ColorPicker.cs

@@ -190,9 +190,9 @@ public class ColorPickers : Scenario
 
         cbShowTextFields.CheckedStateChanging += (_, e) =>
                                                 {
-                                                    foregroundColorPicker.Style.ShowTextFields = e.NewValue == CheckState.Checked;
+                                                    foregroundColorPicker.Style.ShowTextFields = e.Result == CheckState.Checked;
                                                     foregroundColorPicker.ApplyStyleChanges ();
-                                                    backgroundColorPicker.Style.ShowTextFields = e.NewValue == CheckState.Checked;
+                                                    backgroundColorPicker.Style.ShowTextFields = e.Result == CheckState.Checked;
                                                     backgroundColorPicker.ApplyStyleChanges ();
                                                 };
         app.Add (cbShowTextFields);
@@ -209,9 +209,9 @@ public class ColorPickers : Scenario
 
         cbShowName.CheckedStateChanging += (_, e) =>
                                            {
-                                               foregroundColorPicker.Style.ShowColorName = e.NewValue == CheckState.Checked;
+                                               foregroundColorPicker.Style.ShowColorName = e.Result == CheckState.Checked;
                                                foregroundColorPicker.ApplyStyleChanges ();
-                                               backgroundColorPicker.Style.ShowColorName = e.NewValue == CheckState.Checked;
+                                               backgroundColorPicker.Style.ShowColorName = e.Result == CheckState.Checked;
                                                backgroundColorPicker.ApplyStyleChanges ();
                                            };
         app.Add (cbShowName);
@@ -226,7 +226,7 @@ public class ColorPickers : Scenario
     }
 
     /// <summary>Fired when background color is changed.</summary>
-    private void BackgroundColor_ColorChanged (object sender, EventArgs e)
+    private void BackgroundColor_ColorChanged (object sender, ResultEventArgs<Color> e)
     {
         UpdateColorLabel (_backgroundColorLabel,
                           backgroundColorPicker.Visible ?
@@ -237,7 +237,7 @@ public class ColorPickers : Scenario
     }
 
     /// <summary>Fired when foreground color is changed.</summary>
-    private void ForegroundColor_ColorChanged (object sender, EventArgs e)
+    private void ForegroundColor_ColorChanged (object sender, ResultEventArgs<Color> e)
     {
         UpdateColorLabel (_foregroundColorLabel,
                           foregroundColorPicker.Visible ?

+ 13 - 13
Examples/UICatalog/Scenarios/DynamicMenuBar.cs

@@ -142,9 +142,9 @@ public class DynamicMenuBar : Scenario
 
             TextHotKey.TextChanging += (s, e) =>
                                        {
-                                           if (!string.IsNullOrEmpty (e.NewValue) && char.IsLower (e.NewValue [0]))
+                                           if (!string.IsNullOrEmpty (e.Result) && char.IsLower (e.Result [0]))
                                            {
-                                               e.NewValue = e.NewValue.ToUpper ();
+                                               e.Result = e.Result.ToUpper ();
                                            }
                                        };
             TextHotKey.TextChanged += (s, _) => TextHotKey.SelectAll ();
@@ -208,20 +208,20 @@ public class DynamicMenuBar : Scenario
 
             CkbIsTopLevel.CheckedStateChanging += (s, e) =>
                                      {
-                                         if ((_menuItem != null && _menuItem.Parent != null && e.NewValue == CheckState.Checked)
-                                             || (_menuItem == null && _hasParent && e.NewValue == CheckState.Checked))
+                                         if ((_menuItem != null && _menuItem.Parent != null && e.Result == CheckState.Checked)
+                                             || (_menuItem == null && _hasParent && e.Result == CheckState.Checked))
                                          {
                                              MessageBox.ErrorQuery (
                                                                     "Invalid IsTopLevel",
                                                                     "Only menu bar can have top level menu item!",
                                                                     "Ok"
                                                                    );
-                                             e.Cancel = true;
+                                             e.Handled = true;
 
                                              return;
                                          }
 
-                                         if (e.NewValue == CheckState.Checked)
+                                         if (e.Result == CheckState.Checked)
                                          {
                                              CkbSubMenu.CheckedState = CheckState.UnChecked;
                                              CkbSubMenu.SetNeedsDraw ();
@@ -243,13 +243,13 @@ public class DynamicMenuBar : Scenario
                                              TextAction.Text = "";
 
                                              TextShortcutKey.Enabled =
-                                                 e.NewValue == CheckState.Checked && CkbSubMenu.CheckedState == CheckState.UnChecked;
+                                                 e.Result == CheckState.Checked && CkbSubMenu.CheckedState == CheckState.UnChecked;
                                          }
                                      };
 
             CkbSubMenu.CheckedStateChanged += (s, e) =>
                                   {
-                                      if (e.CurrentValue == CheckState.Checked)
+                                      if (e.Value == CheckState.Checked)
                                       {
                                           CkbIsTopLevel.CheckedState = CheckState.UnChecked;
                                           CkbIsTopLevel.SetNeedsDraw ();
@@ -275,7 +275,7 @@ public class DynamicMenuBar : Scenario
                                           if (_hasParent)
                                           {
                                               TextShortcutKey.Enabled = CkbIsTopLevel.CheckedState == CheckState.UnChecked
-                                                                     && e.CurrentValue == CheckState.UnChecked;
+                                                                     && e.Value == CheckState.UnChecked;
                                           }
                                       }
                                   };
@@ -284,7 +284,7 @@ public class DynamicMenuBar : Scenario
                                     {
                                         if (_menuItem != null)
                                         {
-                                            _menuItem.AllowNullChecked = e.CurrentValue == CheckState.Checked;
+                                            _menuItem.AllowNullChecked = e.Value == CheckState.Checked;
                                         }
                                     };
 
@@ -792,13 +792,13 @@ public class DynamicMenuBar : Scenario
 
             txtDelimiter.TextChanging += (s, e) =>
                                           {
-                                              if (!string.IsNullOrEmpty (e.NewValue))
+                                              if (!string.IsNullOrEmpty (e.Result))
                                               {
-                                                  Key.Separator = e.NewValue.ToRunes () [0];
+                                                  Key.Separator = e.Result.ToRunes () [0];
                                               }
                                               else
                                               {
-                                                  e.Cancel = true;
+                                                  e.Handled = true;
                                                   txtDelimiter.SelectAll ();
                                               }
                                           };

+ 4 - 4
Examples/UICatalog/Scenarios/Editor.cs

@@ -901,14 +901,14 @@ public class Editor : Scenario
         {
             X = 0, Y = Pos.Top (txtToFind) + 2, CheckedState = _matchCase ? CheckState.Checked : CheckState.UnChecked, Text = "Match c_ase"
         };
-        ckbMatchCase.CheckedStateChanging += (s, e) => _matchCase = e.NewValue == CheckState.Checked;
+        ckbMatchCase.CheckedStateChanging += (s, e) => _matchCase = e.Result == CheckState.Checked;
         d.Add (ckbMatchCase);
 
         var ckbMatchWholeWord = new CheckBox
         {
             X = 0, Y = Pos.Top (ckbMatchCase) + 1, CheckedState = _matchWholeWord ? CheckState.Checked : CheckState.UnChecked, Text = "Match _whole word"
         };
-        ckbMatchWholeWord.CheckedStateChanging += (s, e) => _matchWholeWord = e.NewValue == CheckState.Checked;
+        ckbMatchWholeWord.CheckedStateChanging += (s, e) => _matchWholeWord = e.Result == CheckState.Checked;
         d.Add (ckbMatchWholeWord);
         return d;
     }
@@ -1159,14 +1159,14 @@ public class Editor : Scenario
         {
             X = 0, Y = Pos.Top (txtToFind) + 2, CheckedState = _matchCase ? CheckState.Checked : CheckState.UnChecked, Text = "Match c_ase"
         };
-        ckbMatchCase.CheckedStateChanging += (s, e) => _matchCase = e.NewValue == CheckState.Checked;
+        ckbMatchCase.CheckedStateChanging += (s, e) => _matchCase = e.Result == CheckState.Checked;
         d.Add (ckbMatchCase);
 
         var ckbMatchWholeWord = new CheckBox
         {
             X = 0, Y = Pos.Top (ckbMatchCase) + 1, CheckedState = _matchWholeWord ? CheckState.Checked : CheckState.UnChecked, Text = "Match _whole word"
         };
-        ckbMatchWholeWord.CheckedStateChanging += (s, e) => _matchWholeWord = e.NewValue == CheckState.Checked;
+        ckbMatchWholeWord.CheckedStateChanging += (s, e) => _matchWholeWord = e.Result == CheckState.Checked;
         d.Add (ckbMatchWholeWord);
 
         return d;

+ 3 - 3
Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentEditor.cs

@@ -170,7 +170,7 @@ public class AdornmentEditor : EditorBase
 
         _diagThicknessCheckBox.CheckedStateChanging += (s, e) =>
                                                        {
-                                                           if (e.NewValue == CheckState.Checked)
+                                                           if (e.Result == CheckState.Checked)
                                                            {
                                                                AdornmentToEdit!.Diagnostics |= ViewDiagnosticFlags.Thickness;
                                                            }
@@ -196,7 +196,7 @@ public class AdornmentEditor : EditorBase
 
         _diagRulerCheckBox.CheckedStateChanging += (s, e) =>
                                                    {
-                                                       if (e.NewValue == CheckState.Checked)
+                                                       if (e.Result == CheckState.Checked)
                                                        {
                                                            AdornmentToEdit!.Diagnostics |= ViewDiagnosticFlags.Ruler;
                                                        }
@@ -210,7 +210,7 @@ public class AdornmentEditor : EditorBase
         _diagRulerCheckBox.Y = Pos.Bottom (_diagThicknessCheckBox);
     }
 
-    private EventHandler<ColorEventArgs> ColorPickerColorChanged ()
+    private EventHandler<ResultEventArgs<Color>> ColorPickerColorChanged ()
     {
         return (o, a) =>
                {

+ 3 - 3
Examples/UICatalog/Scenarios/EditorsAndHelpers/AllViewsView.cs

@@ -1,4 +1,4 @@
-
+#nullable enable
 namespace UICatalog.Scenarios;
 
 public class AllViewsView : View
@@ -80,7 +80,7 @@ public class AllViewsView : View
 
             if (view is { })
             {
-                FrameView? frame = new ()
+                FrameView frame = new ()
                 {
                     CanFocus = true,
                     Title = type.Name,
@@ -181,7 +181,7 @@ public class AllViewsView : View
             view.Height = MAX_VIEW_FRAME_HEIGHT - 2;
         }
 
-        if (!view.Width.Has<DimAuto> (out _))
+        if (!view.Width!.Has<DimAuto> (out _))
         {
             view.Width = Dim.Fill ();
         }

+ 4 - 4
Examples/UICatalog/Scenarios/EditorsAndHelpers/BorderEditor.cs

@@ -91,9 +91,9 @@ public class BorderEditor : AdornmentEditor
             SetNeedsLayout ();
         }
 
-        void OnCkbTitleOnToggle (object? _, CancelEventArgs<CheckState> args)
+        void OnCkbTitleOnToggle (object? _, ResultEventArgs<CheckState> args)
         {
-            if (args.NewValue == CheckState.Checked)
+            if (args.Result == CheckState.Checked)
 
             {
                 ((Border)AdornmentToEdit!).Settings |= BorderSettings.Title;
@@ -105,9 +105,9 @@ public class BorderEditor : AdornmentEditor
             }
         }
 
-        void OnCkbGradientOnToggle (object? _, CancelEventArgs<CheckState> args)
+        void OnCkbGradientOnToggle (object? _, ResultEventArgs<CheckState> args)
         {
-            if (args.NewValue == CheckState.Checked)
+            if (args.Result == CheckState.Checked)
 
             {
                 ((Border)AdornmentToEdit!).Settings |= BorderSettings.Gradient;

+ 1 - 1
Examples/UICatalog/Scenarios/EditorsAndHelpers/ExpanderButton.cs

@@ -43,7 +43,7 @@ public class ExpanderButton : Button
 
         Orientation = Orientation.Vertical;
 
-        HighlightStyle = HighlightStyle.None;
+        HighlightStates = Terminal.Gui.ViewBase.MouseState.None;
 
         Initialized += ExpanderButton_Initialized;
 

+ 1 - 1
Examples/UICatalog/Scenarios/EditorsAndHelpers/MarginEditor.cs

@@ -81,7 +81,7 @@ public class MarginEditor : AdornmentEditor
 
         _flagSelectorTransparent.ValueChanged += (_, args) =>
                                                  {
-                                                     ((Margin)AdornmentToEdit!).ViewportSettings = (ViewportSettingsFlags)args.CurrentValue!;
+                                                     ((Margin)AdornmentToEdit!).ViewportSettings = (ViewportSettingsFlags)args.Value!;
                                                  };
 
 

+ 4 - 4
Examples/UICatalog/Scenarios/EditorsAndHelpers/SchemeViewer.cs

@@ -32,15 +32,15 @@ public class SchemeViewer : FrameView
     }
 
     /// <inheritdoc/>
-    protected override bool OnSettingSchemeName (in string? currentName, ref string? newName)
+    protected override bool OnSchemeNameChanging (ValueChangingEventArgs<string?> args)
     {
-        Title = newName ?? "null";
+        Title = args.NewValue ?? "null";
 
         foreach (VisualRoleViewer v in SubViews.OfType<VisualRoleViewer> ())
         {
-            v.SchemeName = newName;
+            v.SchemeName = args.NewValue;
         }
 
-        return base.OnSettingSchemeName (in currentName, ref newName);
+        return base.OnSchemeNameChanging (args);
     }
 }

+ 1 - 1
Examples/UICatalog/Scenarios/EditorsAndHelpers/ThemeViewer.cs

@@ -106,7 +106,7 @@ public class ThemeViewer : FrameView
         }
     }
 
-    private void OnThemeManagerOnThemeChanged (object? _, StringPropertyEventArgs args) { Title = args.NewString!; }
+    private void OnThemeManagerOnThemeChanged (object? _, EventArgs<string> args) { Title = args.Value!; }
 
     protected override void Dispose (bool disposing)
     {

+ 24 - 24
Examples/UICatalog/Scenarios/EditorsAndHelpers/ViewportSettingsEditor.cs

@@ -115,9 +115,9 @@ public sealed class ViewportSettingsEditor : EditorBase
 
         Add (_cbAllowXGreaterThanContentWidth);
 
-        void AllowNegativeXToggle (object? sender, CancelEventArgs<CheckState> e)
+        void AllowNegativeXToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.AllowNegativeX;
             }
@@ -127,9 +127,9 @@ public sealed class ViewportSettingsEditor : EditorBase
             }
         }
 
-        void AllowXGreaterThanContentWidthToggle (object? sender, CancelEventArgs<CheckState> e)
+        void AllowXGreaterThanContentWidthToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.AllowXGreaterThanContentWidth;
             }
@@ -153,9 +153,9 @@ public sealed class ViewportSettingsEditor : EditorBase
 
         Add (_cbAllowYGreaterThanContentHeight);
 
-        void AllowNegativeYToggle (object? sender, CancelEventArgs<CheckState> e)
+        void AllowNegativeYToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.AllowNegativeY;
             }
@@ -165,9 +165,9 @@ public sealed class ViewportSettingsEditor : EditorBase
             }
         }
 
-        void AllowYGreaterThanContentHeightToggle (object? sender, CancelEventArgs<CheckState> e)
+        void AllowYGreaterThanContentHeightToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.AllowYGreaterThanContentHeight;
             }
@@ -243,9 +243,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbClearContentOnly.CheckedStateChanging += ClearContentOnlyToggle;
 
-        void ClearContentOnlyToggle (object? sender, CancelEventArgs<CheckState> e)
+        void ClearContentOnlyToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.ClearContentOnly;
             }
@@ -264,9 +264,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbClipContentOnly.CheckedStateChanging += ClipContentOnlyToggle;
 
-        void ClipContentOnlyToggle (object? sender, CancelEventArgs<CheckState> e)
+        void ClipContentOnlyToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.ClipContentOnly;
             }
@@ -285,9 +285,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbTransparent.CheckedStateChanging += TransparentToggle;
 
-        void TransparentToggle (object? sender, CancelEventArgs<CheckState> e)
+        void TransparentToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.Transparent;
             }
@@ -306,9 +306,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbTransparentMouse.CheckedStateChanging += TransparentMouseToggle;
 
-        void TransparentMouseToggle (object? sender, CancelEventArgs<CheckState> e)
+        void TransparentMouseToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            if (e.NewValue == CheckState.Checked)
+            if (e.Result == CheckState.Checked)
             {
                 ViewToEdit!.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.TransparentMouse;
             }
@@ -327,9 +327,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbVerticalScrollBar.CheckedStateChanging += VerticalScrollBarToggle;
 
-        void VerticalScrollBarToggle (object? sender, CancelEventArgs<CheckState> e)
+        void VerticalScrollBarToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            ViewToEdit!.VerticalScrollBar.Visible = e.NewValue == CheckState.Checked;
+            ViewToEdit!.VerticalScrollBar.Visible = e.Result == CheckState.Checked;
         }
 
         _cbAutoShowVerticalScrollBar = new ()
@@ -341,9 +341,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbAutoShowVerticalScrollBar.CheckedStateChanging += AutoShowVerticalScrollBarToggle;
 
-        void AutoShowVerticalScrollBarToggle (object? sender, CancelEventArgs<CheckState> e)
+        void AutoShowVerticalScrollBarToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            ViewToEdit!.VerticalScrollBar.AutoShow = e.NewValue == CheckState.Checked;
+            ViewToEdit!.VerticalScrollBar.AutoShow = e.Result == CheckState.Checked;
         }
 
         _cbHorizontalScrollBar = new ()
@@ -355,9 +355,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbHorizontalScrollBar.CheckedStateChanging += HorizontalScrollBarToggle;
 
-        void HorizontalScrollBarToggle (object? sender, CancelEventArgs<CheckState> e)
+        void HorizontalScrollBarToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            ViewToEdit!.HorizontalScrollBar.Visible = e.NewValue == CheckState.Checked;
+            ViewToEdit!.HorizontalScrollBar.Visible = e.Result == CheckState.Checked;
         }
 
         _cbAutoShowHorizontalScrollBar = new ()
@@ -369,9 +369,9 @@ public sealed class ViewportSettingsEditor : EditorBase
         };
         _cbAutoShowHorizontalScrollBar.CheckedStateChanging += AutoShowHorizontalScrollBarToggle;
 
-        void AutoShowHorizontalScrollBarToggle (object? sender, CancelEventArgs<CheckState> e)
+        void AutoShowHorizontalScrollBarToggle (object? sender, ResultEventArgs<CheckState> e)
         {
-            ViewToEdit!.HorizontalScrollBar.AutoShow = e.NewValue == CheckState.Checked;
+            ViewToEdit!.HorizontalScrollBar.AutoShow = e.Result == CheckState.Checked;
         }
 
         Add (

+ 3 - 3
Examples/UICatalog/Scenarios/Images.cs

@@ -111,8 +111,8 @@ public class Images : Scenario
 
         _cbSupportsSixel.CheckedStateChanging += (s, e) =>
                                                  {
-                                                     _sixelSupportResult.IsSupported = e.NewValue == CheckState.Checked;
-                                                     SetupSixelSupported (e.NewValue == CheckState.Checked);
+                                                     _sixelSupportResult.IsSupported = e.Result == CheckState.Checked;
+                                                     SetupSixelSupported (e.Result == CheckState.Checked);
                                                      ApplyShowTabViewHack ();
                                                  };
 
@@ -126,7 +126,7 @@ public class Images : Scenario
             Enabled = canTrueColor,
             Text = "Use true color"
         };
-        cbUseTrueColor.CheckedStateChanging += (_, evt) => Application.Force16Colors = evt.NewValue == CheckState.UnChecked;
+        cbUseTrueColor.CheckedStateChanging += (_, evt) => Application.Force16Colors = evt.Result == CheckState.UnChecked;
         _win.Add (cbUseTrueColor);
 
         var btnOpenImage = new Button { X = Pos.Right (cbUseTrueColor) + 2, Y = 0, Text = "Open Image" };

+ 8 - 8
Examples/UICatalog/Scenarios/ListViewWithSelection.cs

@@ -123,9 +123,9 @@ public class ListViewWithSelection : Scenario
         Application.Shutdown ();
     }
 
-    private void CustomRenderCB_Toggle (object sender, CancelEventArgs<CheckState> stateEventArgs)
+    private void CustomRenderCB_Toggle (object sender, ResultEventArgs<CheckState> stateEventArgs)
     {
-        if (stateEventArgs.CurrentValue == CheckState.Checked)
+        if (stateEventArgs.Result == CheckState.Checked)
         {
             _listView.SetSource (_scenarios);
         }
@@ -137,23 +137,23 @@ public class ListViewWithSelection : Scenario
         _appWindow.SetNeedsDraw ();
     }
 
-    private void AllowsMarkingCB_Toggle (object sender, [NotNull] CancelEventArgs<CheckState> stateEventArgs)
+    private void AllowsMarkingCB_Toggle (object sender, [NotNull] ResultEventArgs<CheckState> stateEventArgs)
     {
-        _listView.AllowsMarking = stateEventArgs.NewValue == CheckState.Checked;
+        _listView.AllowsMarking = stateEventArgs.Result == CheckState.Checked;
         _allowMultipleCb.Enabled = _listView.AllowsMarking;
         _appWindow.SetNeedsDraw ();
     }
 
-    private void AllowsMultipleSelectionCB_Toggle (object sender, [NotNull] CancelEventArgs<CheckState> stateEventArgs)
+    private void AllowsMultipleSelectionCB_Toggle (object sender, [NotNull] ResultEventArgs<CheckState> stateEventArgs)
     {
-        _listView.AllowsMultipleSelection = stateEventArgs.NewValue == CheckState.Checked;
+        _listView.AllowsMultipleSelection = stateEventArgs.Result == CheckState.Checked;
         _appWindow.SetNeedsDraw ();
     }
 
 
-    private void AllowYGreaterThanContentHeightCB_Toggle (object sender, [NotNull] CancelEventArgs<CheckState> stateEventArgs)
+    private void AllowYGreaterThanContentHeightCB_Toggle (object sender, [NotNull] ResultEventArgs<CheckState> stateEventArgs)
     {
-        if (stateEventArgs.NewValue == CheckState.Checked)
+        if (stateEventArgs.Result == CheckState.Checked)
         {
             _listView.ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.AllowYGreaterThanContentHeight;
         }

+ 159 - 102
Examples/UICatalog/Scenarios/Mouse.cs

@@ -1,11 +1,8 @@
-using System;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Linq;
+using System.Collections.ObjectModel;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Mouse", "Demonstrates how to capture mouse events")]
+[ScenarioMetadata ("Mouse", "Demonstrates Mouse Events and States")]
 [ScenarioCategory ("Mouse and Keyboard")]
 public class Mouse : Scenario
 {
@@ -15,6 +12,7 @@ public class Mouse : Scenario
 
         Window win = new ()
         {
+            Id = "win",
             Title = GetQuitKeyAndName ()
         };
 
@@ -73,104 +71,151 @@ public class Mouse : Scenario
 
         win.Add (cbWantContinuousPresses);
 
-        CheckBox cbHighlightOnPress = new ()
+        CheckBox cbHighlightOnPressed = new ()
         {
             X = Pos.Right (filterSlider),
             Y = Pos.Bottom (cbWantContinuousPresses),
-            Title = "_Highlight on Press"
+            Title = "_Highlight on Pressed"
         };
 
-        win.Add (cbHighlightOnPress);
+        win.Add (cbHighlightOnPressed);
+
+        CheckBox cbHighlightOnPressedOutside = new ()
+        {
+            X = Pos.Right (filterSlider),
+            Y = Pos.Bottom (cbHighlightOnPressed),
+            Title = "_Highlight on PressedOutside"
+        };
+
+        win.Add (cbHighlightOnPressedOutside);
 
         var demo = new MouseEventDemoView
         {
+            Id = "demo",
             X = Pos.Right (filterSlider),
-            Y = Pos.Bottom (cbHighlightOnPress),
+            Y = Pos.Bottom (cbHighlightOnPressedOutside),
             Width = Dim.Fill (),
             Height = 15,
-            Title = "Enter/Leave Demo",
+            Title = "Enter/Leave Demo"
         };
 
-        demo.Padding.Initialized += DemoPaddingOnInitialized;
+        demo.Padding!.Initialized += DemoPaddingOnInitialized;
 
         void DemoPaddingOnInitialized (object o, EventArgs eventArgs)
         {
-            demo.Padding.Add (
-                              new MouseEventDemoView ()
-                              {
-                                  X = 0,
-                                  Y = 0,
-                                  Width = Dim.Fill (),
-                                  Height = Dim.Func (() => demo.Padding.Thickness.Top),
-                                  Title = "inPadding",
-                                  Id = "inPadding"
-                              });
+            demo.Padding!.Add (
+                               new MouseEventDemoView
+                               {
+                                   X = 0,
+                                   Y = 0,
+                                   Width = Dim.Fill (),
+                                   Height = Dim.Func (() => demo.Padding.Thickness.Top),
+                                   Title = "inPadding",
+                                   Id = "inPadding"
+                               });
             demo.Padding.Thickness = demo.Padding.Thickness with { Top = 5 };
         }
 
-        View sub1 = new MouseEventDemoView ()
+        View sub1 = new MouseEventDemoView
         {
             X = 0,
             Y = 0,
             Width = Dim.Percent (20),
             Height = Dim.Fill (),
             Title = "sub1",
-            Id = "sub1",
+            Id = "sub1"
         };
         demo.Add (sub1);
 
-        demo.Add (
-                  new MouseEventDemoView ()
-                  {
-                      X = Pos.Right (sub1) - 4,
-                      Y = Pos.Top (sub1) + 1,
-                      Width = Dim.Percent (20),
-                      Height = Dim.Fill (1),
-                      Title = "sub2",
-                      Id = "sub2",
-                  });
+        View sub2 = new MouseEventDemoView
+        {
+            X = Pos.Right (sub1) - 4,
+            Y = Pos.Top (sub1) + 1,
+            Width = Dim.Percent (20),
+            Height = Dim.Fill (1),
+            Title = "sub2",
+            Id = "sub2"
+        };
+
+        demo.Add (sub2);
 
         win.Add (demo);
 
-        cbHighlightOnPress.CheckedState = demo.HighlightStyle == (HighlightStyle.Pressed | HighlightStyle.PressedOutside) ? CheckState.Checked : CheckState.UnChecked;
-
-        // BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/3753
-        cbHighlightOnPress.CheckedStateChanging += (s, e) =>
-                                                   {
-                                                       if (e.NewValue == CheckState.Checked)
-                                                       {
-                                                           demo.HighlightStyle = HighlightStyle.Pressed | HighlightStyle.PressedOutside;
-                                                       }
-                                                       else
-                                                       {
-                                                           demo.HighlightStyle = HighlightStyle.None;
-                                                       }
-
-                                                       foreach (View subview in demo.SubViews)
-                                                       {
-                                                           if (e.NewValue == CheckState.Checked)
-                                                           {
-                                                               subview.HighlightStyle = HighlightStyle.Pressed | HighlightStyle.PressedOutside;
-                                                           }
-                                                           else
-                                                           {
-                                                               subview.HighlightStyle = HighlightStyle.None;
-                                                           }
-                                                       }
-
-                                                       foreach (View subview in demo.Padding.SubViews)
-                                                       {
-                                                           if (e.NewValue == CheckState.Checked)
-                                                           {
-                                                               subview.HighlightStyle = HighlightStyle.Pressed | HighlightStyle.PressedOutside;
-                                                           }
-                                                           else
-                                                           {
-                                                               subview.HighlightStyle = HighlightStyle.None;
-                                                           }
-                                                       }
-
-                                                   };
+        cbHighlightOnPressed.CheckedState = demo.HighlightStates.HasFlag (MouseState.Pressed) ? CheckState.Checked : CheckState.UnChecked;
+
+        cbHighlightOnPressed.CheckedStateChanging += (s, e) =>
+                                                     {
+                                                         if (e.Result == CheckState.Checked)
+                                                         {
+                                                             demo.HighlightStates |= MouseState.Pressed;
+                                                         }
+                                                         else
+                                                         {
+                                                             demo.HighlightStates &= ~MouseState.Pressed;
+                                                         }
+
+                                                         foreach (View subview in demo.SubViews)
+                                                         {
+                                                             if (e.Result == CheckState.Checked)
+                                                             {
+                                                                 subview.HighlightStates |= MouseState.Pressed;
+                                                             }
+                                                             else
+                                                             {
+                                                                 subview.HighlightStates &= ~MouseState.Pressed;
+                                                             }
+                                                         }
+
+                                                         foreach (View subview in demo.Padding.SubViews)
+                                                         {
+                                                             if (e.Result == CheckState.Checked)
+                                                             {
+                                                                 subview.HighlightStates |= MouseState.Pressed;
+                                                             }
+                                                             else
+                                                             {
+                                                                 subview.HighlightStates &= ~MouseState.Pressed;
+                                                             }
+                                                         }
+                                                     };
+
+        cbHighlightOnPressedOutside.CheckedState = demo.HighlightStates.HasFlag (MouseState.PressedOutside) ? CheckState.Checked : CheckState.UnChecked;
+
+        cbHighlightOnPressedOutside.CheckedStateChanging += (s, e) =>
+                                                            {
+                                                                if (e.Result == CheckState.Checked)
+                                                                {
+                                                                    demo.HighlightStates |= MouseState.PressedOutside;
+                                                                }
+                                                                else
+                                                                {
+                                                                    demo.HighlightStates &= ~MouseState.PressedOutside;
+                                                                }
+
+                                                                foreach (View subview in demo.SubViews)
+                                                                {
+                                                                    if (e.Result == CheckState.Checked)
+                                                                    {
+                                                                        subview.HighlightStates |= MouseState.PressedOutside;
+                                                                    }
+                                                                    else
+                                                                    {
+                                                                        subview.HighlightStates &= ~MouseState.PressedOutside;
+                                                                    }
+                                                                }
+
+                                                                foreach (View subview in demo.Padding.SubViews)
+                                                                {
+                                                                    if (e.Result == CheckState.Checked)
+                                                                    {
+                                                                        subview.HighlightStates |= MouseState.PressedOutside;
+                                                                    }
+                                                                    else
+                                                                    {
+                                                                        subview.HighlightStates &= ~MouseState.PressedOutside;
+                                                                    }
+                                                                }
+                                                            };
 
         cbWantContinuousPresses.CheckedStateChanging += (s, e) =>
                                                         {
@@ -185,10 +230,8 @@ public class Mouse : Scenario
                                                             {
                                                                 subview.WantContinuousButtonPressed = demo.WantContinuousButtonPressed;
                                                             }
-
                                                         };
 
-
         var label = new Label
         {
             Text = "_App Events:",
@@ -241,12 +284,12 @@ public class Mouse : Scenario
         win.Add (label, winLog);
 
         clearButton.Accepting += (s, e) =>
-                              {
-                                  appLogList.Clear ();
-                                  appLog.SetSource (appLogList);
-                                  winLogList.Clear ();
-                                  winLog.SetSource (winLogList);
-                              };
+                                 {
+                                     appLogList.Clear ();
+                                     appLog.SetSource (appLogList);
+                                     winLogList.Clear ();
+                                     winLog.SetSource (winLogList);
+                                 };
 
         win.MouseEvent += (sender, a) =>
                           {
@@ -277,42 +320,56 @@ public class Mouse : Scenario
             CanFocus = true;
             Id = "mouseEventDemoView";
 
-            Padding!.Thickness = new Thickness (1, 1, 1, 1);
-
             Initialized += OnInitialized;
 
+            MouseLeave += (s, e) => { Text = "Leave"; };
+            MouseEnter += (s, e) => { Text = "Enter"; };
+
+            return;
+
             void OnInitialized (object sender, EventArgs e)
             {
                 TextAlignment = Alignment.Center;
                 VerticalTextAlignment = Alignment.Center;
 
-                Padding!.SetScheme (new Scheme (new Attribute (Color.Black)));
+                Padding!.Thickness = new (1, 1, 1, 1);
+                Padding!.SetScheme (new (new Attribute (Color.Black)));
+                Padding.Id = $"{Id}.Padding";
 
-                Padding.MouseEnter += PaddingOnMouseEnter;
-                Padding.MouseLeave += PaddingOnMouseLeave;
+                Border!.Thickness = new (1);
+                Border.LineStyle = LineStyle.Rounded;
+                Border.Id = $"{Id}.Border";
+
+                MouseStateChanged += (_, args) =>
+                                     {
+                                         if (args.Value.HasFlag (MouseState.PressedOutside))
+                                         {
+                                             Border.LineStyle = LineStyle.Dotted;
+                                         }
+                                         else
+                                         {
+                                             Border.LineStyle = LineStyle.Single;
+                                         }
+
+                                         SetNeedsDraw ();
+                                     };
+            }
+        }
 
-                void PaddingOnMouseEnter (object o, CancelEventArgs e)
+        /// <inheritdoc/>
+        protected override bool OnGettingAttributeForRole (in VisualRole role, ref Attribute currentAttribute)
+        {
+            if (role == VisualRole.Normal)
+            {
+                if (MouseState.HasFlag (MouseState.Pressed) && HighlightStates.HasFlag (MouseState.Pressed))
                 {
-                    Padding.SchemeName = "Error";
-                }
+                    currentAttribute = currentAttribute with { Background = currentAttribute.Foreground.GetBrighterColor () };
 
-                void PaddingOnMouseLeave (object o, EventArgs e)
-                {
-                    Padding.SchemeName = "Dialog";
+                    return true;
                 }
-
-                Border!.Thickness = new Thickness (1);
-                Border.LineStyle = LineStyle.Rounded;
             }
 
-            MouseLeave += (s, e) =>
-                          {
-                              Text = "Leave";
-                          };
-            MouseEnter += (s, e) =>
-                          {
-                              Text = "Enter";
-                          };
+            return base.OnGettingAttributeForRole (in role, ref currentAttribute);
         }
     }
 }

+ 2 - 2
Examples/UICatalog/Scenarios/Navigation.cs

@@ -220,9 +220,9 @@ public class Navigation : Scenario
 
         return;
 
-        void ColorPicker_ColorChanged (object sender, ColorEventArgs e)
+        void ColorPicker_ColorChanged (object sender, ResultEventArgs<Color> e)
         {
-            testFrame.SetScheme (testFrame.GetScheme () with { Normal = new (testFrame.GetAttributeForRole (VisualRole.Normal).Foreground, e.CurrentValue) });
+            testFrame.SetScheme (testFrame.GetScheme () with { Normal = new (testFrame.GetAttributeForRole (VisualRole.Normal).Foreground, e.Result) });
         }
     }
 

+ 8 - 8
Examples/UICatalog/Scenarios/PosAlignDemo.cs

@@ -101,14 +101,14 @@ public sealed class PosAlignDemo : Scenario
                                       {
                                           if (dimension == Dimension.Width)
                                           {
-                                              _horizAligner.AlignmentModes = e.NewValue == CheckState.Checked
+                                              _horizAligner.AlignmentModes = e.Result == CheckState.Checked
                                                                                  ? _horizAligner.AlignmentModes | AlignmentModes.EndToStart
                                                                                  : _horizAligner.AlignmentModes & ~AlignmentModes.EndToStart;
                                               UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
                                           }
                                           else
                                           {
-                                              _vertAligner.AlignmentModes = e.NewValue == CheckState.Checked
+                                              _vertAligner.AlignmentModes = e.Result == CheckState.Checked
                                                                                 ? _vertAligner.AlignmentModes | AlignmentModes.EndToStart
                                                                                 : _vertAligner.AlignmentModes & ~AlignmentModes.EndToStart;
                                               UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
@@ -139,14 +139,14 @@ public sealed class PosAlignDemo : Scenario
                                      {
                                          if (dimension == Dimension.Width)
                                          {
-                                             _horizAligner.AlignmentModes = e.NewValue == CheckState.Checked
+                                             _horizAligner.AlignmentModes = e.Result == CheckState.Checked
                                                      ? _horizAligner.AlignmentModes | AlignmentModes.IgnoreFirstOrLast
                                                      : _horizAligner.AlignmentModes & ~AlignmentModes.IgnoreFirstOrLast;
                                              UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
                                          }
                                          else
                                          {
-                                             _vertAligner.AlignmentModes = e.NewValue == CheckState.Checked
+                                             _vertAligner.AlignmentModes = e.Result == CheckState.Checked
                                                                                ? _vertAligner.AlignmentModes | AlignmentModes.IgnoreFirstOrLast
                                                                                : _vertAligner.AlignmentModes & ~AlignmentModes.IgnoreFirstOrLast;
                                              UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
@@ -177,14 +177,14 @@ public sealed class PosAlignDemo : Scenario
                                          {
                                              if (dimension == Dimension.Width)
                                              {
-                                                 _horizAligner.AlignmentModes = e.NewValue == CheckState.Checked
+                                                 _horizAligner.AlignmentModes = e.Result == CheckState.Checked
                                                                                     ? _horizAligner.AlignmentModes | AlignmentModes.AddSpaceBetweenItems
                                                                                     : _horizAligner.AlignmentModes & ~AlignmentModes.AddSpaceBetweenItems;
                                                  UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
                                              }
                                              else
                                              {
-                                                 _vertAligner.AlignmentModes = e.NewValue == CheckState.Checked
+                                                 _vertAligner.AlignmentModes = e.Result == CheckState.Checked
                                                                                    ? _vertAligner.AlignmentModes | AlignmentModes.AddSpaceBetweenItems
                                                                                    : _vertAligner.AlignmentModes & ~AlignmentModes.AddSpaceBetweenItems;
                                                  UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
@@ -214,12 +214,12 @@ public sealed class PosAlignDemo : Scenario
                           {
                               if (dimension == Dimension.Width)
                               {
-                                  _leftMargin = e.NewValue == CheckState.Checked ? 1 : 0;
+                                  _leftMargin = e.Result == CheckState.Checked ? 1 : 0;
                                   UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
                               }
                               else
                               {
-                                  _topMargin = e.NewValue == CheckState.Checked ? 1 : 0;
+                                  _topMargin = e.Result == CheckState.Checked ? 1 : 0;
                                   UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
                               }
                           };

+ 1 - 1
Examples/UICatalog/Scenarios/ProgressBarStyles.cs

@@ -268,7 +268,7 @@ public class ProgressBarStyles : Scenario
         ckbBidirectional.CheckedStateChanging += (s, e) =>
                                    {
                                        marqueesBlocksPB.BidirectionalMarquee =
-                                                                  marqueesContinuousPB.BidirectionalMarquee = e.NewValue == CheckState.Checked;
+                                                                  marqueesContinuousPB.BidirectionalMarquee = e.Result == CheckState.Checked;
                                    };
 
 

+ 11 - 11
Examples/UICatalog/Scenarios/ScrollBarDemo.cs

@@ -274,7 +274,7 @@ public class ScrollBarDemo : Scenario
             Text = $"_AutoShow",
             CheckedState = scrollBar.AutoShow ? CheckState.Checked : CheckState.UnChecked
         };
-        autoShow.CheckedStateChanging += (s, e) => scrollBar.AutoShow = e.NewValue == CheckState.Checked;
+        autoShow.CheckedStateChanging += (s, e) => scrollBar.AutoShow = e.Result == CheckState.Checked;
         demoFrame.Add (autoShow);
 
         var lblSliderPosition = new Label
@@ -352,33 +352,33 @@ public class ScrollBarDemo : Scenario
         {
             scrollBar.ScrollableContentSizeChanged += (s, e) =>
                                   {
-                                      eventLog.Log ($"SizeChanged: {e.CurrentValue}");
+                                      eventLog.Log ($"SizeChanged: {e.Value}");
 
-                                      if (scrollContentSize.Value != e.CurrentValue)
+                                      if (scrollContentSize.Value != e.Value)
                                       {
-                                          scrollContentSize.Value = e.CurrentValue;
+                                          scrollContentSize.Value = e.Value;
                                       }
                                   };
 
             scrollBar.SliderPositionChanged += (s, e) =>
                                             {
-                                                eventLog.Log ($"SliderPositionChanged: {e.CurrentValue}");
+                                                eventLog.Log ($"SliderPositionChanged: {e.Value}");
                                                 eventLog.Log ($"  Position: {scrollBar.Position}");
-                                                scrollSliderPosition.Text = e.CurrentValue.ToString ();
+                                                scrollSliderPosition.Text = e.Value.ToString ();
                                             };
 
             scrollBar.Scrolled += (s, e) =>
                                {
-                                   eventLog.Log ($"Scrolled: {e.CurrentValue}");
+                                   eventLog.Log ($"Scrolled: {e.Value}");
                                    eventLog.Log ($"  SliderPosition: {scrollBar.GetSliderPosition ()}");
-                                   scrolled.Text = e.CurrentValue.ToString ();
+                                   scrolled.Text = e.Value.ToString ();
                                };
 
             scrollBar.PositionChanged += (s, e) =>
                                              {
-                                                 eventLog.Log ($"PositionChanged: {e.CurrentValue}");
-                                                 scrollPosition.Value = e.CurrentValue;
-                                                 controlledList.Viewport = controlledList.Viewport with { Y = e.CurrentValue };
+                                                 eventLog.Log ($"PositionChanged: {e.Value}");
+                                                 scrollPosition.Value = e.Value;
+                                                 controlledList.Viewport = controlledList.Viewport with { Y = e.Value };
                                              };
 
 

+ 4 - 4
Examples/UICatalog/Scenarios/Scrolling.cs

@@ -53,7 +53,7 @@ public class Scrolling : Scenario
             CheckedState = demoView.HorizontalScrollBar.Visible ? CheckState.Checked : CheckState.UnChecked
         };
         app.Add (hCheckBox);
-        hCheckBox.CheckedStateChanged += (sender, args) => { demoView.HorizontalScrollBar.Visible = args.CurrentValue == CheckState.Checked; };
+        hCheckBox.CheckedStateChanged += (sender, args) => { demoView.HorizontalScrollBar.Visible = args.Value == CheckState.Checked; };
 
         //// NOTE: This call to EnableScrollBar is technically not needed because the reference
         //// NOTE: to demoView.HorizontalScrollBar below will cause it to be lazy created.
@@ -67,7 +67,7 @@ public class Scrolling : Scenario
             CheckedState = demoView.VerticalScrollBar.Visible ? CheckState.Checked : CheckState.UnChecked
         };
         app.Add (vCheckBox);
-        vCheckBox.CheckedStateChanged += (sender, args) => { demoView.VerticalScrollBar.Visible = args.CurrentValue == CheckState.Checked; };
+        vCheckBox.CheckedStateChanged += (sender, args) => { demoView.VerticalScrollBar.Visible = args.Value == CheckState.Checked; };
 
         var ahCheckBox = new CheckBox
         {
@@ -79,8 +79,8 @@ public class Scrolling : Scenario
 
         ahCheckBox.CheckedStateChanging += (s, e) =>
                                            {
-                                               demoView.HorizontalScrollBar.AutoShow = e.NewValue == CheckState.Checked;
-                                               demoView.VerticalScrollBar.AutoShow = e.NewValue == CheckState.Checked;
+                                               demoView.HorizontalScrollBar.AutoShow = e.Result == CheckState.Checked;
+                                               demoView.VerticalScrollBar.AutoShow = e.Result == CheckState.Checked;
                                            };
         app.Add (ahCheckBox);
 

+ 1 - 1
Examples/UICatalog/Scenarios/ShadowStyles.cs

@@ -82,7 +82,7 @@ public class ShadowStyles : Scenario
         colorPicker.ColorChanged += (sender, args) =>
                                     {
                                         var normal = app.GetScheme ().Normal;
-                                        app.SetScheme (app.GetScheme() with {Normal = new Attribute(normal.Foreground, args.CurrentValue)});
+                                        app.SetScheme (app.GetScheme() with {Normal = new Attribute(normal.Foreground, args.Result)});
                                     };
         app.Add (button, colorPicker);
 

+ 8 - 8
Examples/UICatalog/Scenarios/Shortcuts.cs

@@ -64,7 +64,7 @@ public class Shortcuts : Scenario
             {
                 Text = "_Align Keys",
                 CanFocus = false,
-                HighlightStyle = HighlightStyle.None
+                HighlightStates = MouseState.None
             },
             Key = Key.F5.WithCtrl.WithAlt.WithShift
         };
@@ -85,7 +85,7 @@ public class Shortcuts : Scenario
                                                                                        v => v is Shortcut { Width: not DimAbsolute });
                                                                                   IEnumerable<View> enumerable = toAlign as View [] ?? toAlign.ToArray ();
 
-                                                                                  if (e.NewValue == CheckState.Checked)
+                                                                                  if (e.Result == CheckState.Checked)
                                                                                   {
                                                                                       max = (from Shortcut? peer in enumerable
                                                                                              select peer.Key.ToString ().GetColumns ()).Prepend (max)
@@ -118,7 +118,7 @@ public class Shortcuts : Scenario
             {
                 Text = "Command _First",
                 CanFocus = false,
-                HighlightStyle = HighlightStyle.None
+                HighlightStates = MouseState.None
             },
             Key = Key.F.WithCtrl
         };
@@ -143,7 +143,7 @@ public class Shortcuts : Scenario
                                                                                      {
                                                                                          var peer = (Shortcut)view;
 
-                                                                                         if (e.NewValue == CheckState.Checked)
+                                                                                         if (e.Result == CheckState.Checked)
                                                                                          {
                                                                                              peer.AlignmentModes &= ~AlignmentModes.EndToStart;
                                                                                          }
@@ -181,7 +181,7 @@ public class Shortcuts : Scenario
                                                                                  {
                                                                                      if (peer.CanFocus)
                                                                                      {
-                                                                                         peer.CommandView.CanFocus = e.NewValue == CheckState.Checked;
+                                                                                         peer.CommandView.CanFocus = e.Result == CheckState.Checked;
                                                                                      }
                                                                                  }
                                                                              }
@@ -213,7 +213,7 @@ public class Shortcuts : Scenario
             {
                 Title = "_Button",
                 ShadowStyle = ShadowStyle.None,
-                HighlightStyle = HighlightStyle.None
+                HighlightStates = MouseState.None
             },
             Key = Key.K
         };
@@ -449,7 +449,7 @@ public class Shortcuts : Scenario
                                 {
                                     if (o is { })
                                     {
-                                        eventSource.Add ($"ColorChanged: {o.GetType ().Name} - {args.CurrentValue}");
+                                        eventSource.Add ($"ColorChanged: {o.GetType ().Name} - {args.Result}");
                                         eventLog.MoveDown ();
 
                                         Application.Top.SetScheme (
@@ -457,7 +457,7 @@ public class Shortcuts : Scenario
                                                                    {
                                                                        Normal = new (
                                                                                      Application.Top!.GetAttributeForRole (VisualRole.Normal).Foreground,
-                                                                                     args.CurrentValue,
+                                                                                     args.Result,
                                                                                      Application.Top!.GetAttributeForRole (VisualRole.Normal).Style)
                                                                    });
                                     }

+ 2 - 2
Examples/UICatalog/Scenarios/SpinnerStyles.cs

@@ -162,9 +162,9 @@ public class SpinnerViewStyles : Scenario
                                           }
                                       };
 
-        ckbReverse.CheckedStateChanging += (s, e) => { spinner.SpinReverse = e.NewValue == CheckState.Checked; };
+        ckbReverse.CheckedStateChanging += (s, e) => { spinner.SpinReverse = e.Result == CheckState.Checked; };
 
-        ckbBounce.CheckedStateChanging += (s, e) => { spinner.SpinBounce = e.NewValue == CheckState.Checked; };
+        ckbBounce.CheckedStateChanging += (s, e) => { spinner.SpinBounce = e.Result == CheckState.Checked; };
 
         app.Unloaded += App_Unloaded;
 

+ 2 - 2
Examples/UICatalog/Scenarios/TextAlignmentAndDirection.cs

@@ -501,7 +501,7 @@ public class TextAlignmentAndDirection : Scenario
             Enabled = false
         };
 
-        justifyCheckbox.CheckedStateChanging += (s, e) => ToggleJustify (e.NewValue != CheckState.Checked);
+        justifyCheckbox.CheckedStateChanging += (s, e) => ToggleJustify (e.Result != CheckState.Checked);
 
         justifyOptions.SelectedItemChanged += (s, e) => { ToggleJustify (false, true); };
 
@@ -521,7 +521,7 @@ public class TextAlignmentAndDirection : Scenario
 
         wrapCheckbox.CheckedStateChanging += (s, e) =>
                                 {
-                                    if (e.CurrentValue == CheckState.Checked)
+                                    if (e.Result == CheckState.Checked)
                                     {
                                         foreach (View t in multiLineLabels)
                                         {

+ 1 - 1
Examples/UICatalog/Scenarios/TextEffectsScenario.cs

@@ -56,7 +56,7 @@ public class TextEffectsScenario : Scenario
 
         cbLooping.CheckedStateChanging += (s, e) =>
                             {
-                                _loopingGradient = e.NewValue == CheckState.Checked;
+                                _loopingGradient = e.Result == CheckState.Checked;
                                 SetupGradientLineCanvas (w, w.Frame.Size);
                             };
 

+ 2 - 2
Examples/UICatalog/Scenarios/TextFormatterDemo.cs

@@ -124,8 +124,8 @@ public class TextFormatterDemo : Scenario
                                    {
                                        for (int i = 0; i < alignments.Count; i++)
                                        {
-                                           singleLines [i].Text = e.CurrentValue == CheckState.Checked ? text : unicode;
-                                           multipleLines [i].Text = e.CurrentValue == CheckState.Checked ? text : unicode;
+                                           singleLines [i].Text = e.Result == CheckState.Checked ? text : unicode;
+                                           multipleLines [i].Text = e.Result == CheckState.Checked ? text : unicode;
                                        }
                                    };
 

+ 7 - 7
Examples/UICatalog/Scenarios/TextInputControls.cs

@@ -33,9 +33,9 @@ public class TextInputControls : Scenario
         textField.Autocomplete.SuggestionGenerator = singleWordGenerator;
         textField.TextChanging += TextFieldTextChanging;
 
-        void TextFieldTextChanging (object sender, CancelEventArgs<string> e)
+        void TextFieldTextChanging (object sender, ResultEventArgs<string> e)
         {
-            singleWordGenerator.AllSuggestions = Regex.Matches (e.NewValue, "\\w+")
+            singleWordGenerator.AllSuggestions = Regex.Matches (e.Result, "\\w+")
                                                       .Select (s => s.Value)
                                                       .Distinct ()
                                                       .ToList ();
@@ -121,7 +121,7 @@ public class TextInputControls : Scenario
         {
             X = Pos.Left (textView), Y = Pos.Bottom (textView), CheckedState = textView.ReadOnly ? CheckState.Checked : CheckState.UnChecked, Text = "Read_Only"
         };
-        chxReadOnly.CheckedStateChanging += (sender, args) => textView.ReadOnly = args.NewValue == CheckState.Checked;
+        chxReadOnly.CheckedStateChanging += (sender, args) => textView.ReadOnly = args.Result == CheckState.Checked;
         win.Add (chxReadOnly);
 
         // By default TextView is a multi-line control. It can be forced to 
@@ -139,7 +139,7 @@ public class TextInputControls : Scenario
             CheckedState = textView.WordWrap ? CheckState.Checked : CheckState.UnChecked,
             Text = "_Word Wrap"
         };
-        chxWordWrap.CheckedStateChanging += (s, e) => textView.WordWrap = e.NewValue == CheckState.Checked;
+        chxWordWrap.CheckedStateChanging += (s, e) => textView.WordWrap = e.Result == CheckState.Checked;
         win.Add (chxWordWrap);
 
         // TextView captures Tabs (so users can enter /t into text) by default;
@@ -155,7 +155,7 @@ public class TextInputControls : Scenario
 
         chxMultiline.CheckedStateChanging += (s, e) =>
                                 {
-                                    textView.Multiline = e.NewValue == CheckState.Checked;
+                                    textView.Multiline = e.Result == CheckState.Checked;
 
                                     if (!textView.Multiline && chxWordWrap.CheckedState == CheckState.Checked)
                                     {
@@ -173,7 +173,7 @@ public class TextInputControls : Scenario
 
         chxCaptureTabs.CheckedStateChanging += (s, e) =>
                                   {
-                                      if (e.NewValue == CheckState.Checked)
+                                      if (e.Result == CheckState.Checked)
                                       {
                                           textView.KeyBindings.Add (keyTab, Command.Tab);
                                           textView.KeyBindings.Add (keyBackTab, Command.BackTab);
@@ -184,7 +184,7 @@ public class TextInputControls : Scenario
                                           textView.KeyBindings.Remove (keyBackTab);
                                       }
 
-                                      textView.AllowsTab = e.NewValue == CheckState.Checked;
+                                      textView.AllowsTab = e.Result == CheckState.Checked;
                                   };
         win.Add (chxCaptureTabs);
 

+ 13 - 4
Examples/UICatalog/Scenarios/TextStyles.cs

@@ -81,8 +81,13 @@ public sealed class TestStyles : Scenario
                                                   {
                                                       return;
                                                   }
-                                                  args.NewValue = args.NewValue with { Style = style };
-                                                  args.Cancel = true;
+
+                                                  if (args.Result is { })
+                                                  {
+                                                      args.Result = args.Result.Value with { Style = style };
+                                                  }
+
+                                                  args.Handled = true;
                                               };
 
             appWindow.Add (button);
@@ -125,8 +130,12 @@ public sealed class TestStyles : Scenario
             };
             button.GettingAttributeForRole += (_, args) =>
                                               {
-                                                  args.NewValue = args.NewValue with { Style = combination };
-                                                  args.Cancel = true;
+                                                  if (args.Result is { })
+                                                  {
+                                                      args.Result = args.Result.Value with { Style = combination };
+                                                  }
+
+                                                  args.Handled = true;
                                               };
             appWindow.Add (button);
         }

+ 13 - 13
Examples/UICatalog/Scenarios/Themes.cs

@@ -125,26 +125,26 @@ public sealed class Themes : Scenario
 
         viewListView.SelectedItem = 0;
 
-        themeViewer.SettingSchemeName += (sender, args) =>
-                                         {
-                                             if (_view is { })
-                                             {
-                                                 Application.Top!.SchemeName = args.NewString;
+        themeViewer.SchemeNameChanging += (sender, args) =>
+                                          {
+                                              if (_view is { })
+                                              {
+                                                  Application.Top!.SchemeName = args.NewValue;
 
-                                                 if (_view.HasScheme)
-                                                 {
-                                                     _view.SetScheme (null);
-                                                 }
+                                                  if (_view.HasScheme)
+                                                  {
+                                                      _view.SetScheme (null);
+                                                  }
 
-                                                 _view.SchemeName = args.NewString;
-                                             }
-                                         };
+                                                  _view.SchemeName = args.NewValue;
+                                              }
+                                          };
 
         AllViewsView? allViewsView = null;
 
         allViewsCheckBox.CheckedStateChanged += (sender, args) =>
                                                 {
-                                                    if (args.CurrentValue == CheckState.Checked)
+                                                    if (args.Value == CheckState.Checked)
                                                     {
                                                         viewListView.Visible = false;
                                                         appWindow.Remove (viewFrame);

+ 1 - 1
Examples/UICatalog/Scenarios/TrueColors.cs

@@ -46,7 +46,7 @@ public class TrueColors : Scenario
             Enabled = canTrueColor,
             Text = "Force 16 colors"
         };
-        cbUseTrueColor.CheckedStateChanging += (_, evt) => { Application.Force16Colors = evt.NewValue == CheckState.Checked; };
+        cbUseTrueColor.CheckedStateChanging += (_, evt) => { Application.Force16Colors = evt.Result == CheckState.Checked; };
         app.Add (cbUseTrueColor);
 
         y += 2;

+ 1 - 1
Examples/UICatalog/Scenarios/ViewportSettings.cs

@@ -143,7 +143,7 @@ public class ViewportSettings : Scenario
                                                                          {
                                                                              Normal = new (
                                                                                            colorPicker.SuperView.GetAttributeForRole (VisualRole.Normal).Foreground,
-                                                                                           e.CurrentValue
+                                                                                           e.Result
                                                                                           )
                                                                          });
                                     };

+ 1 - 1
Examples/UICatalog/UICatalog.cs

@@ -406,7 +406,7 @@ public class UICatalog
 
             void ApplicationOnInitializedChanged (object? sender, EventArgs<bool> e)
             {
-                if (e.CurrentValue)
+                if (e.Value)
                 {
                     sw.Start ();
                 }

+ 9 - 9
Examples/UICatalog/UICatalogTop.cs

@@ -168,9 +168,9 @@ public class UICatalogTop : Toplevel
 
             _force16ColorsMenuItemCb.CheckedStateChanged += (sender, args) =>
             {
-                Application.Force16Colors = args.CurrentValue == CheckState.Checked;
+                Application.Force16Colors = args.Value == CheckState.Checked;
 
-                _force16ColorsShortcutCb!.CheckedState = args.CurrentValue;
+                _force16ColorsShortcutCb!.CheckedState = args.Value;
                 Application.LayoutAndDraw ();
             };
 
@@ -186,7 +186,7 @@ public class UICatalogTop : Toplevel
             {
                 _themesRg = new ()
                 {
-                    HighlightStyle = HighlightStyle.None,
+                    HighlightStates = Terminal.Gui.ViewBase.MouseState.None,
                 };
 
                 _themesRg.SelectedItemChanged += (_, args) =>
@@ -210,7 +210,7 @@ public class UICatalogTop : Toplevel
 
                 _topSchemeRg = new ()
                 {
-                    HighlightStyle = HighlightStyle.None,
+                    HighlightStates = Terminal.Gui.ViewBase.MouseState.None,
                 };
 
                 _topSchemeRg.SelectedItemChanged += (_, args) =>
@@ -261,7 +261,7 @@ public class UICatalogTop : Toplevel
             {
                 CanFocus = true,
                 Styles = FlagSelectorStyles.ShowNone,
-                HighlightStyle = HighlightStyle.None,
+                HighlightStates = Terminal.Gui.ViewBase.MouseState.None,
             };
             _diagnosticFlagsSelector.UsedHotKeys.Add (Key.D);
             _diagnosticFlagsSelector.AssignHotKeysToCheckBoxes = true;
@@ -287,7 +287,7 @@ public class UICatalogTop : Toplevel
                 CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked
             };
 
-            _disableMouseCb.CheckedStateChanged += (_, args) => { Application.IsMouseDisabled = args.CurrentValue == CheckState.Checked; };
+            _disableMouseCb.CheckedStateChanged += (_, args) => { Application.IsMouseDisabled = args.Value == CheckState.Checked; };
 
             menuItems.Add (
                            new MenuItemv2
@@ -310,7 +310,7 @@ public class UICatalogTop : Toplevel
                 AssignHotKeysToCheckBoxes = true,
                 Options = Enum.GetNames<LogLevel> (),
                 SelectedItem = logLevels.ToList ().IndexOf (Enum.Parse<LogLevel> (UICatalog.Options.DebugLogLevel)),
-                HighlightStyle = HighlightStyle.Hover
+                HighlightStates = Terminal.Gui.ViewBase.MouseState.In
             };
 
             _logLevelRg.SelectedItemChanged += (_, args) =>
@@ -634,8 +634,8 @@ public class UICatalogTop : Toplevel
 
         _force16ColorsShortcutCb.CheckedStateChanging += (sender, args) =>
         {
-            Application.Force16Colors = args.NewValue == CheckState.Checked;
-            _force16ColorsMenuItemCb!.CheckedState = args.NewValue;
+            Application.Force16Colors = args.Result == CheckState.Checked;
+            _force16ColorsMenuItemCb!.CheckedState = args.Result;
             Application.LayoutAndDraw ();
         };
 

+ 56 - 0
Terminal.Gui/App/CWP/CWPEventHelper.cs

@@ -0,0 +1,56 @@
+#nullable enable
+namespace Terminal.Gui.App;
+
+using System;
+
+
+/// <summary>
+///     Provides helper methods for executing event-driven workflows in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     <para>
+///         Used for workflows where an event is raised to allow cancellation or customization of a result,
+///         such as in <see cref="Application.RaiseKeyDownEvent"/>. The <see cref="Execute{T}"/> method invokes an
+///         event handler and returns whether the operation was handled, supporting result production
+///         scenarios with <see cref="ResultEventArgs{T}"/>.
+///     </para>
+/// </remarks>
+/// <seealso cref="ResultEventArgs{T}"/>
+public static class CWPEventHelper
+{
+    /// <summary>
+    ///     Executes an event-driven CWP workflow by raising an event.
+    /// </summary>
+    /// <typeparam name="T">The type of the result in the event arguments.</typeparam>
+    /// <param name="eventHandler">The event handler to invoke, or null if no handler is subscribed.</param>
+    /// <param name="args">The event arguments, containing a result and handled status.</param>
+    /// <returns>True if the event was handled, false otherwise.</returns>
+    /// <exception cref="ArgumentNullException">Thrown if <paramref name="args"/> is null.</exception>
+    /// <example>
+    ///     <code>
+    ///         EventHandler&lt;ResultEventArgs&lt;Key&gt;&gt;? keyDownHandler = (sender, args) =>
+    ///         {
+    ///             if (args.Result?.KeyCode == KeyCode.Q | KeyCode.CtrlMask)
+    ///             {
+    ///                 args.Handled = true;
+    ///             }
+    ///         };
+    ///         ResultEventArgs&lt;Key&gt; args = new(new Key(KeyCode.Q | KeyCode.CtrlMask));
+    ///         bool handled = CWPEventHelper.Execute(keyDownHandler, args);
+    ///     </code>
+    /// </example>
+    public static bool Execute<T> (
+        EventHandler<ResultEventArgs<T>>? eventHandler,
+        ResultEventArgs<T> args)
+    {
+        ArgumentNullException.ThrowIfNull (args);
+
+        if (eventHandler == null)
+        {
+            return false;
+        }
+
+        eventHandler.Invoke (null, args);
+        return args.Handled;
+    }
+}

+ 102 - 0
Terminal.Gui/App/CWP/CWPPropertyHelper.cs

@@ -0,0 +1,102 @@
+namespace Terminal.Gui.App;
+
+#nullable enable
+
+/// <summary>
+///     Provides helper methods for executing property change workflows in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     <para>
+///         Used for workflows where a property value is modified, such as in <see cref="OrientationHelper"/> or
+///         <see cref="View.SchemeName"/>, allowing pre- and post-change events to customize or cancel the change.
+///     </para>
+/// </remarks>
+/// <seealso cref="ValueChangingEventArgs{T}"/>
+/// <seealso cref="ValueChangedEventArgs{T}"/>
+public static class CWPPropertyHelper
+{
+    /// <summary>
+    ///     Executes a CWP workflow for a property change, with pre- and post-change events.
+    /// </summary>
+    /// <typeparam name="T">
+    ///     The type of the property value, which may be a nullable reference type (e.g., <see cref="string"/>
+    ///     ?).
+    /// </typeparam>
+    /// <param name="currentValue">The current property value, which may be null for nullable types.</param>
+    /// <param name="newValue">The proposed new property value, which may be null for nullable types.</param>
+    /// <param name="onChanging">The virtual method invoked before the change, returning true to cancel.</param>
+    /// <param name="changingEvent">The pre-change event raised to allow modification or cancellation.</param>
+    /// <param name="onChanged">The virtual method invoked after the change.</param>
+    /// <param name="changedEvent">The post-change event raised to notify of the completed change.</param>
+    /// <param name="finalValue">
+    ///     The final value after the workflow, reflecting any modifications, which may be null for
+    ///     nullable types.
+    /// </param>
+    /// <returns>True if the property was changed, false if cancelled.</returns>
+    /// <exception cref="InvalidOperationException">
+    ///     Thrown if <see cref="ValueChangingEventArgs{T}.NewValue"/> is null for non-nullable reference types after the
+    ///     workflow.
+    /// </exception>
+    /// <example>
+    ///     <code>
+    ///         string? current = null;
+    ///         string? proposed = "Base";
+    ///         Func&lt;ValueChangingEventArgs&lt;string?&gt;, bool&gt; onChanging = args =&gt; false;
+    ///         EventHandler&lt;ValueChangingEventArgs&lt;string?&gt;&gt;? changingEvent = null;
+    ///         Action&lt;ValueChangedEventArgs&lt;string?&gt;&gt;? onChanged = args =&gt;
+    ///             Console.WriteLine($"SchemeName changed to {args.NewValue ?? "none"}.");
+    ///         EventHandler&lt;ValueChangedEventArgs&lt;string?&gt;&gt;? changedEvent = null;
+    ///         bool changed = CWPPropertyHelper.ChangeProperty(
+    ///             current, proposed, onChanging, changingEvent, onChanged, changedEvent, out string? final);
+    ///     </code>
+    /// </example>
+    public static bool ChangeProperty<T> (
+        T currentValue,
+        T newValue,
+        Func<ValueChangingEventArgs<T>, bool> onChanging,
+        EventHandler<ValueChangingEventArgs<T>>? changingEvent,
+        Action<ValueChangedEventArgs<T>>? onChanged,
+        EventHandler<ValueChangedEventArgs<T>>? changedEvent,
+        out T finalValue
+    )
+    {
+        if (EqualityComparer<T>.Default.Equals (currentValue, newValue))
+        {
+            finalValue = currentValue;
+
+            return false;
+        }
+
+        ValueChangingEventArgs<T> args = new (currentValue, newValue);
+        bool cancelled = onChanging (args) || args.Handled;
+
+        if (cancelled)
+        {
+            finalValue = currentValue;
+
+            return false;
+        }
+
+        changingEvent?.Invoke (null, args);
+
+        if (args.Handled)
+        {
+            finalValue = currentValue;
+
+            return false;
+        }
+
+        // Validate NewValue for non-nullable reference types
+        if (args.NewValue is null && !typeof (T).IsValueType && !Nullable.GetUnderlyingType (typeof (T))?.IsValueType == true)
+        {
+            throw new InvalidOperationException ("NewValue cannot be null for non-nullable reference types.");
+        }
+
+        finalValue = args.NewValue;
+        ValueChangedEventArgs<T> changedArgs = new (currentValue, finalValue);
+        onChanged?.Invoke (changedArgs);
+        changedEvent?.Invoke (null, changedArgs);
+
+        return true;
+    }
+}

+ 129 - 0
Terminal.Gui/App/CWP/CWPWorkflowHelper.cs

@@ -0,0 +1,129 @@
+#nullable enable
+namespace Terminal.Gui.App;
+
+using System;
+
+
+/// <summary>
+///     Provides helper methods for executing single-phase and result-producing workflows in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     <para>
+///         Used for workflows that allow customization or cancellation, such as command execution
+///         (e.g., <see cref="View.RaiseAccepting"/>) or scheme resolution (e.g., <see cref="View.GetScheme"/>).
+///         The <see cref="Execute{T}"/> method handles workflows without results, while
+///         <see cref="ExecuteWithResult{TResult}"/> handles workflows producing results.
+///     </para>
+/// </remarks>
+/// <seealso cref="ResultEventArgs{T}"/>
+public static class CWPWorkflowHelper
+{
+    /// <summary>
+    ///     Executes a single-phase CWP workflow with a virtual method, event, and optional default action.
+    /// </summary>
+    /// <typeparam name="T">The type of the result in the event arguments.</typeparam>
+    /// <param name="onMethod">The virtual method invoked first, returning true to mark the workflow as handled.</param>
+    /// <param name="eventHandler">The event handler to invoke, or null if no handlers are subscribed.</param>
+    /// <param name="args">The event arguments containing a result and handled status.</param>
+    /// <param name="defaultAction">The default action to execute if the workflow is not handled, or null if none.</param>
+    /// <returns>True if the workflow was handled, false if not, or null if no event handlers are subscribed.</returns>
+    /// <exception cref="ArgumentNullException">
+    ///     Thrown if <paramref name="onMethod"/> or <paramref name="args"/> is null.
+    /// </exception>
+    /// <example>
+    ///     <code>
+    ///         ResultEventArgs&lt;bool&gt; args = new();
+    ///         Func&lt;ResultEventArgs&lt;bool&gt;, bool&gt; onAccepting = _ =&gt; false;
+    ///         EventHandler&lt;ResultEventArgs&lt;bool&gt;&gt;? acceptingHandler = null;
+    ///         Action? defaultAction = () =&gt; args.Result = true;
+    ///         bool? handled = CWPWorkflowHelper.Execute(onAccepting, acceptingHandler, args, defaultAction);
+    ///     </code>
+    /// </example>
+    public static bool? Execute<T> (
+        Func<ResultEventArgs<T>, bool> onMethod,
+        EventHandler<ResultEventArgs<T>>? eventHandler,
+        ResultEventArgs<T> args,
+        Action? defaultAction = null)
+    {
+        ArgumentNullException.ThrowIfNull (onMethod);
+        ArgumentNullException.ThrowIfNull (args);
+
+        bool handled = onMethod (args) || args.Handled;
+        if (handled)
+        {
+            return true;
+        }
+
+        eventHandler?.Invoke (null, args);
+        if (args.Handled)
+        {
+            return true;
+        }
+
+        if (defaultAction is {})
+        {
+            defaultAction ();
+            return true;
+        }
+
+        return eventHandler is null ? null : false;
+    }
+
+    /// <summary>
+    ///     Executes a CWP workflow that produces a result, suitable for methods like <see cref="View.GetScheme"/>.
+    /// </summary>
+    /// <typeparam name="TResult">The type of the result, which may be a nullable reference type (e.g., <see cref="Scheme"/>?).</typeparam>
+    /// <param name="onMethod">The virtual method invoked first, returning true to mark the workflow as handled.</param>
+    /// <param name="eventHandler">The event handler to invoke, or null if no handlers are subscribed.</param>
+    /// <param name="args">The event arguments containing a result and handled status.</param>
+    /// <param name="defaultAction">The default action that produces the result if the workflow is not handled.</param>
+    /// <returns>The result from the event arguments or the default action.</returns>
+    /// <exception cref="ArgumentNullException">
+    ///     Thrown if <paramref name="onMethod"/>, <paramref name="args"/>, or <paramref name="defaultAction"/> is null.
+    /// </exception>
+    /// <exception cref="InvalidOperationException">
+    ///     Thrown if <see cref="ResultEventArgs{T}.Result"/> is null for non-nullable reference types when <see cref="ResultEventArgs{T}.Handled"/> is true.
+    /// </exception>
+    /// <example>
+    ///     <code>
+    ///         ResultEventArgs&lt;Scheme?&gt; args = new();
+    ///         Func&lt;ResultEventArgs&lt;Scheme?&gt;, bool&gt; onGettingScheme = _ =&gt; false;
+    ///         EventHandler&lt;ResultEventArgs&lt;Scheme?&gt;&gt;? gettingSchemeHandler = null;
+    ///         Func&lt;Scheme&gt; defaultAction = () =&gt; SchemeManager.GetScheme("Base");
+    ///         Scheme scheme = CWPWorkflowHelper.ExecuteWithResult(onGettingScheme, gettingSchemeHandler, args, defaultAction);
+    ///     </code>
+    /// </example>
+    public static TResult ExecuteWithResult<TResult> (
+        Func<ResultEventArgs<TResult>, bool> onMethod,
+        EventHandler<ResultEventArgs<TResult>>? eventHandler,
+        ResultEventArgs<TResult> args,
+        Func<TResult> defaultAction)
+    {
+        ArgumentNullException.ThrowIfNull (onMethod);
+        ArgumentNullException.ThrowIfNull (args);
+        ArgumentNullException.ThrowIfNull (defaultAction);
+
+        bool handled = onMethod (args) || args.Handled;
+        if (handled)
+        {
+            if (args.Result is null && !typeof (TResult).IsValueType && !Nullable.GetUnderlyingType (typeof (TResult))?.IsValueType == true)
+            {
+                throw new InvalidOperationException ("Result cannot be null for non-nullable reference types when Handled is true.");
+            }
+            return args.Result!;
+        }
+
+        eventHandler?.Invoke (null, args);
+
+        if (!args.Handled)
+        {
+            return defaultAction ();
+        }
+
+        if (args.Result is null && !typeof (TResult).IsValueType && !Nullable.GetUnderlyingType (typeof (TResult))?.IsValueType == true)
+        {
+            throw new InvalidOperationException ("Result cannot be null for non-nullable reference types when Handled is true.");
+        }
+        return args.Result!;
+    }
+}

+ 7 - 6
Terminal.Gui/ViewBase/CancelEventArgs.cs → Terminal.Gui/App/CWP/CancelEventArgs.cs

@@ -1,19 +1,20 @@
 #nullable enable
 using System.ComponentModel;
 
-namespace Terminal.Gui.ViewBase;
+namespace Terminal.Gui.App;
 
 #pragma warning disable CS1711
 
 /// <summary>
-///     <see cref="EventArgs"/> for events that convey changes to a property of type <typeparamref name="T"/>.
+///      Provides data for events that can be cancelled without a changeable result in a cancellable workflow in the Cancellable Work Pattern (CWP).
 /// </summary>
-/// <typeparam name="T">The type of the value that was part of the change being canceled.</typeparam>
 /// <remarks>
-///     Events that use this class can be cancellable. Where applicable, the <see cref="CancelEventArgs.Cancel"/> property
-///     should be set to
-///     <see langword="true"/> to prevent the state change from occurring.
+///     Used for workflows where a change (e.g., a simple property change) can be cancelled, but the
+///     value being changed is not directly modified by the event handlers.
 /// </remarks>
+/// <typeparam name="T">The type of the value that is being changed.</typeparam>
+/// <seealso cref="ValueChangingEventArgs{T}"/>
+/// <seealso cref="ResultEventArgs{T}"/>
 public class CancelEventArgs<T> : CancelEventArgs where T : notnull
 {
     /// <summary>Initializes a new instance of the <see cref="CancelEventArgs{T}"/> class.</summary>

+ 22 - 0
Terminal.Gui/App/CWP/EventArgs.cs

@@ -0,0 +1,22 @@
+#nullable enable
+namespace Terminal.Gui.App;
+
+#pragma warning disable CS1711
+/// <summary>
+///    Provides data for events that convey the current value of a property or other value in a cancellable workflow (CWP).
+/// </summary>
+/// <remarks>
+///     Used for workflows where the current value of a property or value is being conveyed, such as
+///     when a property has been changed.
+/// </remarks>
+/// <typeparam name="T">The type of the value.</typeparam>
+public class EventArgs<T> : EventArgs /*where T : notnull*/
+{
+    /// <summary>Initializes a new instance of the <see cref="EventArgs{T}"/> class.</summary>
+    /// <param name="currentValue">The current value of the property.</param>
+    /// <typeparam name="T">The type of the value.</typeparam>
+    public EventArgs (in T currentValue) { Value = currentValue; }
+
+    /// <summary>The current value of the property.</summary>
+    public T Value { get; }
+}

+ 45 - 0
Terminal.Gui/App/CWP/ResultEventArgs.cs

@@ -0,0 +1,45 @@
+#nullable enable
+namespace Terminal.Gui.App;
+
+using System;
+
+#pragma warning disable CS1711
+
+/// <summary>
+///     Provides data for events that produce a result in a cancellable workflow in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     Used for workflows where a result (e.g., <see cref="Command"/> outcome, <see cref="Attribute"/> resolution) is
+///     being produced or cancelled, such as for methods like <see cref="View.GetAttributeForRole"/>.
+/// </remarks>
+/// <typeparam name="T">The type of the result.</typeparam>
+/// <seealso cref="CancelEventArgs{T}"/>
+/// <seealso cref="ValueChangingEventArgs{T}"/>
+public class ResultEventArgs<T>
+{
+    /// <summary>
+    ///     Gets or sets the result of the operation, which may be null if no result is provided.
+    /// </summary>
+    public T? Result { get; set; }
+
+    /// <summary>
+    ///     Gets or sets a value indicating whether the operation has been handled.
+    ///     If true, the operation is considered handled and may use the provided result.
+    /// </summary>
+    public bool Handled { get; set; }
+
+    /// <summary>
+    ///     Initializes a new instance of the <see cref="ResultEventArgs{T}"/> class with no initial result.
+    /// </summary>
+    public ResultEventArgs () { }
+
+    /// <summary>
+    ///     Initializes a new instance of the <see cref="ResultEventArgs{T}"/> class with an initial result.
+    /// </summary>
+    /// <param name="result">The initial result, which may be null for optional outcomes.</param>
+    public ResultEventArgs (T? result)
+    {
+        Result = result;
+    }
+}
+#pragma warning restore CS1711

+ 39 - 0
Terminal.Gui/App/CWP/ValueChangedEventArgs.cs

@@ -0,0 +1,39 @@
+#nullable enable
+namespace Terminal.Gui.App;
+
+/// <summary>
+///     Provides data for events that notify of a completed property change in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     <para>
+///         Used in post-change events raised by <see cref="CWPPropertyHelper.ChangeProperty{T}"/> to notify
+///         subscribers of a property change, such as in <see cref="OrientationHelper"/> when the
+///         <see cref="Orientation"/> property is updated or <see cref="View.SchemeName"/> when the scheme name changes.
+///     </para>
+/// </remarks>
+/// <typeparam name="T">The type of the property value, which may be a nullable reference type (e.g., <see cref="string"/>?).</typeparam>
+/// <seealso cref="ValueChangingEventArgs{T}"/>
+/// <seealso cref="CWPPropertyHelper"/>
+public class ValueChangedEventArgs<T>
+{
+    /// <summary>
+    ///     Gets the value before the change, which may be null for nullable types.
+    /// </summary>
+    public T OldValue { get; }
+
+    /// <summary>
+    ///     Gets the value after the change, which may be null for nullable types.
+    /// </summary>
+    public T NewValue { get; }
+
+    /// <summary>
+    ///     Initializes a new instance of the <see cref="ValueChangedEventArgs{T}"/> class.
+    /// </summary>
+    /// <param name="oldValue">The value before the change, which may be null for nullable types.</param>
+    /// <param name="newValue">The value after the change, which may be null for nullable types.</param>
+    public ValueChangedEventArgs (T oldValue, T newValue)
+    {
+        OldValue = oldValue;
+        NewValue = newValue;
+    }
+}

+ 44 - 0
Terminal.Gui/App/CWP/ValueChangingEventArgs.cs

@@ -0,0 +1,44 @@
+#nullable enable
+namespace Terminal.Gui.App;
+
+/// <summary>
+///     Provides data for events that allow modification or cancellation of a property change in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     <para>
+///         Used in pre-change events raised by <see cref="CWPPropertyHelper.ChangeProperty{T}"/> to allow handlers to
+///         modify the proposed value or cancel the change, such as for <see cref="View.SchemeName"/> or
+///         <see cref="OrientationHelper"/>.
+///     </para>
+/// </remarks>
+/// <typeparam name="T">The type of the property value, which may be a nullable reference type (e.g., <see cref="string"/>?).</typeparam>
+/// <seealso cref="ValueChangedEventArgs{T}"/>
+/// <seealso cref="CWPPropertyHelper"/>
+public class ValueChangingEventArgs<T>
+{
+    /// <summary>
+    ///     Gets the current value before the change.
+    /// </summary>
+    public T CurrentValue { get; }
+
+    /// <summary>
+    ///     Gets or sets the proposed new value, which can be modified by event handlers.
+    /// </summary>
+    public T NewValue { get; set; }
+
+    /// <summary>
+    ///     Gets or sets a value indicating whether the change has been handled. If true, the change is cancelled.
+    /// </summary>
+    public bool Handled { get; set; }
+
+    /// <summary>
+    ///     Initializes a new instance of the <see cref="ValueChangingEventArgs{T}"/> class.
+    /// </summary>
+    /// <param name="currentValue">The current value before the change, which may be null for nullable types.</param>
+    /// <param name="newValue">The proposed new value, which may be null for nullable types.</param>
+    public ValueChangingEventArgs (T currentValue, T newValue)
+    {
+        CurrentValue = currentValue;
+        NewValue = newValue;
+    }
+}

+ 12 - 0
Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs

@@ -9,3 +9,15 @@ public class ConfigurationManagerEventArgs : EventArgs
     public ConfigurationManagerEventArgs () { }
 }
 
+
+//public class ConfigurationLoadEventArgs : ResultEventArgs<SettingsScope>
+//{
+//    public ConfigLocations Location { get; }
+//    public string? Path { get; }
+
+//    public ConfigurationLoadEventArgs (ConfigLocations location, string? path)
+//    {
+//        Location = location;
+//        Path = path;
+//    }
+//}

+ 1 - 1
Terminal.Gui/Configuration/SourceGenerationContext.cs

@@ -24,7 +24,7 @@ namespace Terminal.Gui.Configuration;
 [JsonSerializable (typeof (AlignmentModes))]
 [JsonSerializable (typeof (LineStyle))]
 [JsonSerializable (typeof (ShadowStyle))]
-[JsonSerializable (typeof (HighlightStyle))]
+[JsonSerializable (typeof (MouseState))]
 [JsonSerializable (typeof (TextStyle))]
 [JsonSerializable (typeof (Dictionary<ColorName16, string>))]
 [JsonSerializable (typeof (Dictionary<string, Color>))]

+ 2 - 2
Terminal.Gui/Configuration/ThemeManager.cs

@@ -296,12 +296,12 @@ public static class ThemeManager
     internal static void OnThemeChanged (string previousThemeName, string newThemeName)
     {
         Logging.Debug ($"Themes.OnThemeChanged({previousThemeName}) -> {Theme}");
-        StringPropertyEventArgs args = new StringPropertyEventArgs (in previousThemeName, ref newThemeName!);
+        EventArgs<string> args = new (newThemeName);
         ThemeChanged?.Invoke (null, args);
     }
 
     /// <summary>Raised when the selected theme has changed.</summary>
-    public static event EventHandler<StringPropertyEventArgs>? ThemeChanged;
+    public static event EventHandler<EventArgs<string>>? ThemeChanged;
 
     /// <summary>
     ///     Validates all themes in the <see cref="Themes"/> dictionary.

+ 0 - 12
Terminal.Gui/Drawing/Color/ColorEventArgs.cs

@@ -1,12 +0,0 @@
-#nullable enable
-
-
-namespace Terminal.Gui.Drawing;
-
-/// <summary>Event arguments for the <see cref="Color"/> events.</summary>
-public class ColorEventArgs : EventArgs<Color>
-{
-    /// <summary>Initializes a new instance of <see cref="ColorEventArgs"/>
-    /// <paramref name="newColor"/>The value that is being changed to.</summary>
-    public ColorEventArgs (Color newColor) :base(newColor) { }
-}

+ 1 - 1
Terminal.Gui/Drawing/Scheme.cs

@@ -493,7 +493,7 @@ public record Scheme : IEqualityOperators<Scheme, Scheme, bool>
     private readonly Attribute? _highlight;
 
     /// <summary>
-    ///     The visual role for elements that are highlighted (e.g., when the mouse is hovering over a <see cref="Button"/>).
+    ///     The visual role for elements that are highlighted (e.g., when the mouse is inside a <see cref="Button"/>).
     ///     If not explicitly set, will be a derived value. See the description for <see cref="Scheme"/> for details on the
     ///     algorithm used.
     /// </summary>

+ 0 - 21
Terminal.Gui/Drawing/SchemeEventArgs.cs

@@ -1,21 +0,0 @@
-#nullable enable
-using System.ComponentModel;
-
-namespace Terminal.Gui.Drawing;
-
-/// <summary>Event args for draw events</summary>
-public class SchemeEventArgs : CancelEventArgs
-{
-    /// <summary>Creates a new instance of the <see cref="SchemeEventArgs"/> class.</summary>
-    public SchemeEventArgs (in Scheme? currentScheme, ref Scheme? newScheme)
-    {
-        CurrentScheme = currentScheme;
-        NewScheme = newScheme;
-    }
-
-    /// <summary>Gets the View's current <see cref="Scheme"/>.</summary>
-    public Scheme? CurrentScheme { get; }
-
-    /// <summary>Gets or sets the View's new <see cref="Scheme"/>.</summary>
-    public Scheme? NewScheme { get; set;  }
-}

+ 1 - 1
Terminal.Gui/Drawing/VisualRole.cs

@@ -43,7 +43,7 @@ public enum VisualRole
     HotActive,
 
     /// <summary>
-    ///     The visual role for elements that are highlighted (e.g., when the mouse is hovering over a <see cref="Button"/>).
+    ///     The visual role for elements that are highlighted (e.g., when the mouse is inside over a <see cref="Button"/>).
     /// </summary>
     Highlight,
 

+ 54 - 21
Terminal.Gui/Drawing/VisualRoleEventArgs.cs

@@ -1,30 +1,63 @@
 #nullable enable
-
 namespace Terminal.Gui.Drawing;
 
-/// <summary>Args for events that relate <see cref="VisualRole"/>.</summary>
-public class VisualRoleEventArgs : CancelEventArgs<Attribute>
-{
-    /// <inheritdoc/>
-    public VisualRoleEventArgs (in VisualRole role, ref readonly Attribute currentValue, ref Attribute newValue, bool cancel = false) : base (
-                                                                                                                                              in currentValue,
-                                                                                                                                              ref newValue,
-                                                                                                                                              cancel)
-    {
-        Role = role;
-    }
+using System;
 
-    /// <inheritdoc/>
-    protected VisualRoleEventArgs (in VisualRole role, ref readonly Attribute currentValue, ref Attribute newValue) : base (currentValue, newValue)
-    {
-        Role = role;
-    }
+#pragma warning disable CS1711
 
-    /// <inheritdoc/>
-    public VisualRoleEventArgs (in VisualRole role, ref Attribute newValue) : base (default (Attribute), newValue) { Role = role; }
+/// <summary>
+///     Provides data for cancellable workflow events that resolve an <see cref="Attribute"/> for a specific
+///     <see cref="VisualRole"/> in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     <para>
+///         Used in events like <see cref="View.GettingAttributeForRole"/> to allow customization or cancellation
+///         of attribute resolution for a <see cref="VisualRole"/>, such as determining the appearance of a
+///         <see cref="View"/> based on its state (e.g., focused, disabled).
+///     </para>
+///     <para>
+///         Inherits from <see cref="ResultEventArgs{T}"/> with <c>T = <see cref="Attribute"/></c>, providing a
+///         cancellable result workflow where event handlers can supply a custom <see cref="Attribute"/> or mark
+///         the operation as handled.
+///     </para>
+/// </remarks>
+/// <typeparam name="T">The type of the result, constrained to <see cref="Attribute"/>.</typeparam>
+/// <example>
+///     <code>
+///         View view = new();
+///         view.GettingAttributeForRole += (sender, args) =>
+///         {
+///             if (args.Role == VisualRole.Focus)
+///             {
+///                 args.Result = new Attribute(Color.BrightCyan, Color.Black);
+///                 args.Handled = true;
+///             }
+///         };
+///         Attribute attribute = view.GetAttributeForRole(VisualRole.Focus);
+///     </code>
+/// </example>
+/// <seealso cref="ResultEventArgs{T}"/>
+/// <seealso cref="VisualRole"/>
+/// <seealso cref="Attribute"/>
+/// <seealso cref="View.GetAttributeForRole"/>
+public class VisualRoleEventArgs : ResultEventArgs<Attribute?>
+{
+    /// <summary>
+    ///     Gets the <see cref="VisualRole"/> for which an <see cref="Attribute"/> is being resolved.
+    /// </summary>
+    public VisualRole Role { get; }
 
     /// <summary>
-    ///     The <see cref="VisualRole"/> that is being set.
+    ///     Initializes a new instance of the <see cref="VisualRoleEventArgs"/> class with the specified
+    ///     <see cref="VisualRole"/> and initial <see cref="Attribute"/> result.
     /// </summary>
-    public VisualRole Role { get; set; }
+    /// <param name="role">The <see cref="VisualRole"/> for which the attribute is being resolved.</param>
+    /// <param name="result">The initial attribute result, which may be null if no result is provided.</param>
+    public VisualRoleEventArgs (in VisualRole role, Attribute? result)
+        : base (result)
+    {
+        Role = role;
+    }
 }
+
+#pragma warning restore CS1711

+ 1 - 1
Terminal.Gui/Drivers/V2/MainLoop.cs

@@ -184,7 +184,7 @@ public class MainLoop<T> : IMainLoop<T>
 
         if (v.NeedsDraw || v.NeedsLayout)
         {
-            Logging.Trace ($"{v.GetType ().Name} triggered redraw (NeedsDraw={v.NeedsDraw} NeedsLayout={v.NeedsLayout}) ");
+           // Logging.Trace ($"{v.GetType ().Name} triggered redraw (NeedsDraw={v.NeedsDraw} NeedsLayout={v.NeedsLayout}) ");
 
             return true;
         }

+ 11 - 7
Terminal.Gui/Drivers/WindowsDriver/WindowsDriver.cs

@@ -921,17 +921,21 @@ internal class WindowsDriver : ConsoleDriver
             }
             await Task.Delay (delay);
 
-            var me = new MouseEventArgs
-            {
-                ScreenPosition = _pointMove,
-                Flags = mouseFlag
-            };
-
             //Debug.WriteLine($"ProcessContinuousButtonPressedAsync: {view}");
             if (_isButtonPressed && (mouseFlag & MouseFlags.ReportMousePosition) == 0)
             {
+                Point pointMove = _pointMove;
                 // TODO: This makes IConsoleDriver dependent on Application, which is not ideal. This should be moved to Application.
-                Application.Invoke (() => OnMouseEvent (me));
+                Application.Invoke (() =>
+                                    {
+                                        var me = new MouseEventArgs
+                                        {
+                                            ScreenPosition = pointMove,
+                                            Position = pointMove,
+                                            Flags = mouseFlag
+                                        };
+                                        OnMouseEvent (me);
+                                    });
             }
         }
     }

+ 121 - 131
Terminal.Gui/README.md

@@ -1,170 +1,160 @@
 # Terminal.Gui Project
 
-All files required to build the **Terminal.Gui** library (and NuGet package).
+**Terminal.Gui** is a cross-platform UI toolkit for creating console-based graphical user interfaces in .NET. This repository contains all files required to build the **Terminal.Gui** library and NuGet package, enabling developers to create rich terminal applications with ease.
 
-## Project Folder Structure
-
-- `\` - The root folder contains the source code for the library.
-	- `Terminal.Gui.sln` - The Visual Studio solution
-	- `Application\` - The core `Application` logic, including `Application.cs`, which is is a `static` class that provides the base 'application engine', `RunState`, and `MainLoop`.
-
-- `ConsoleDrivers\`
-	- `IConsoleDriver.cs` - Definition for the Console Driver API.
-	- Source files for the three `IConsoleDriver`-based drivers: .NET: `NetDriver`, Unix & Mac: `UnixDriver`, and Windows: `WindowsDriver`.
-
-- `Configuration\` - Classes related the `ConfigurationManager`.
-
-- `Clipboard\` - Classes related to clipboard access.
-
-- `Input\` - Classes relating to keyboard and mouse input. 
-	- `Events.cs` - Defines keyboard and mouse-related structs & classes. 
-	- etc...
-
-- `Text\` - Classes related to text processing
-
-- `Drawing\` - Classes related to drawing 
-
-- `View\` - The `View` class heirarchy, not including any sub-classes
-	- `View.cs` - The base class for non-modal visual elements such as controls.
-	- `Layout\`	
-		- `PosDim.cs` - Implements *Computed Layout* system. These classes have deep dependencies on `View`.
-
-- `Views\` - Sub-classes of `View` 
-	- `Toplevel` - Derived from `View`, the base class for modal visual elements such as top-level windows and dialogs. Supports the concept of `MenuBar` and `StatusBar`.
-	- `Window` - Derived from `TopLevel`; implements Toplevel views with a visible frame and Title.
-	- `Dialog` -
-	- etc...
-
-- `FileServcies/` - File services classes.
-
-## Version numbers
-
-Version info for Terminal.Gui is managed by [gitversion](https://gitversion.net).
+## Project Overview
 
-Install `gitversion`:
+**Terminal.Gui** provides a comprehensive framework for building interactive console applications with support for keyboard and mouse input, customizable views, and a robust event system. It is designed to work across Windows, macOS, and Linux, leveraging platform-specific console capabilities where available.
 
-```powershell
-dotnet tool install --global GitVersion.Tool
-dotnet-gitversion
-```
-
-The project version (the nuget package and in `Terminal.Gui.dll`) is determined from the latest `git tag`. 
-
-The format of version numbers is `vmajor.minor.patch.build.height` and follows the [Semantic Versioning](https://semver.org/) rules.
-
-To define a new version (e.g. with a higher `major`, `minor`, `patch`, or `build` value) tag a commit using `git tag`:
-
-```powershell
-git tag v1.3.4-beta.5 -a -m "Release v1.3.4 Beta 5"
-dotnet-gitversion /updateprojectfiles
-dotnet build -c Release
-```
+## Project Folder Structure
 
-**DO NOT COMMIT AFTER USING `/updateprojectfiles`!**
+- `\` - The root folder contains the core solution and project files for the library.
+	- `Terminal.Gui.sln` - The Visual Studio solution file for the project.
+	- `Terminal.Gui.csproj` - The project file defining build configurations and dependencies.
+	- `App\` - Contains the core `Application` logic, including `Application.cs`, a `static` class that serves as the base 'application engine', managing `RunState` and `MainLoop`.
 
-Doing so will update the `.csproj` files in your branch with version info, which we do not want.
+- `Configuration\` - Classes related to the `ConfigurationManager` for handling application settings.
 
-## Publishing a Release of Terminal.Gui
+- `Drivers\` - Contains the console driver implementations:
+	- `IConsoleDriver.cs` - Defines the Console Driver API.
+	- Driver implementations for .NET (`NetDriver`), Unix & macOS (`UnixDriver`), and Windows (`WindowsDriver`).
 
-First, use the [Semantic Versioning](https://semver.org/) rules.to determine the new verison number. 
+- `Drawing\` - Classes related to rendering graphical elements in the console.
 
-Given a version number MAJOR.MINOR.PATCH, increment the:
+- `FileServices\` - Utility classes for file operations and services.
 
-* MAJOR version when you make incompatible API changes
-* MINOR version when you add functionality in a backwards compatible manner
-* PATCH version when you make backwards compatible bug fixes
+- `Input\` - Classes handling keyboard and mouse input:
+	- `Events.cs` - Defines structs and classes for keyboard and mouse events.
 
-Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
+- `Resources\` - Assets and resources used by the library.
 
-To release a new version (e.g. with a higher `major`, `minor`, or `patch` value) tag a commit using `git tag` and then push that tag directly to the `main` branch on `github.com/gui-cs/Terminal.Gui` (`upstream`).
+- `Text\` - Classes for text processing and formatting.
 
-The `tag` must be of the form `v<major>.<minor>.<patch>`, e.g. `v2.3.4`.
+- `View\` - Core `View` class hierarchy (excluding specific sub-classes):
+	- `View.cs` - The base class for non-modal visual elements such as controls.
+	- Related subdirectories for layout and positioning logic.
 
-`patch` can indicate pre-release or not (e.g. `pre`, `beta`, `rc`, etc...). 
+- `ViewBase\` - Base classes and utilities for views.
 
-### 1) Verify the `develop` branch is ready for release
+- `Views\` - Specific sub-classes of `View`:
+	- `Toplevel` - Base class for modal visual elements like top-level windows and dialogs, supporting `MenuBar` and `StatusBar`.
+	- `Window` - Implements framed top-level views with titles.
+	- `Dialog` - Specialized windows for user interaction.
+	- Other specialized view classes.
 
-* Ensure everything is committed and pushed to the `develop` branch
-* Ensure your local `develop` branch is up-to-date with `upstream/develop`
+## Showcase
 
-### 2) Create a pull request for the release in the `develop` branch
+See the [Showcase](docs/showcase.md) to find independent applications and examples built with Terminal.Gui.
 
-The PR title should be of the form "Release v2.3.4"
+## Getting Started
 
-```powershell
-git checkout develop
-git pull upstream develop
-git checkout -b v2_3_4
-git add .
-git commit -m "Release v2.3.4"
-git push
-```
+For instructions on how to start using **Terminal.Gui**, refer to the [Getting Started Guide](https://gui-cs.github.io/Terminal.Gui/docs/getting-started.html) in our documentation.
 
-Go to the link printed by `git push` and fill out the Pull Request.
+## Documentation
 
-### 3) On github.com, verify the build action worked on your fork, then merge the PR
+Comprehensive documentation for **Terminal.Gui** is available at [gui-cs.github.io/Terminal.Gui](https://gui-cs.github.io/Terminal.Gui). Key resources include:
+- [Events Deep Dive](https://gui-cs.github.io/Terminal.Gui/docs/events.html) - Detailed guide on event handling and the Cancellable Work Pattern.
+- [View Documentation](https://gui-cs.github.io/Terminal.Gui/docs/View.html) - Information on creating and customizing views.
+- [Keyboard Handling](https://gui-cs.github.io/Terminal.Gui/docs/keyboard.html) - Guide to managing keyboard input.
+- [Mouse Support](https://gui-cs.github.io/Terminal.Gui/docs/mouse.html) - Details on implementing mouse interactions.
+- [Showcase](https://gui-cs.github.io/Terminal.Gui/docs/showcase.html) - A collection of applications and examples built with Terminal.Gui.
 
-### 4) Pull the merged `develop` from `upstream`
+For information on generating and updating the API documentation locally, refer to the [DocFX README](../docfx/README.md) in the `docfx` folder.
 
-```powershell
-git checkout develop
-git pull upstream develop
-```
+## Versioning
 
-### 5) Merge `develop` into `main`
+Version information for Terminal.Gui is managed by [gitversion](https://gitversion.net). To install `gitversion`:
 
 ```powershell
-git checkout main
-git pull upstream main
-git merge develop
+dotnet tool install --global GitVersion.Tool
+dotnet-gitversion
 ```
 
-Fix any merge errors.
+The project version (used in the NuGet package and `Terminal.Gui.dll`) is determined from the latest `git tag`. The format of version numbers is `major.minor.patch.build.height` and follows [Semantic Versioning](https://semver.org/) rules.
 
-### 6) Create a new annotated tag for the release on `main`
+To define a new version, tag a commit using `git tag`:
 
 ```powershell
-git tag v2.3.4 -a -m "Release v2.3.4"
-```       
-
-### 7) Push the new tag to `main` on `upstream`
-
-```powershell
-git push --atomic upstream main v2.3.4
-```       
-
-*See https://stackoverflow.com/a/3745250/297526*
-
-### 8) Monitor Github Actions to ensure the Nuget publishing worked.
-
-https://github.com/gui-cs/Terminal.Gui/actions
-
-### 9) Check Nuget to see the new package version (wait a few minutes) 
-https://www.nuget.org/packages/Terminal.Gui
-
-### 10) Add a new Release in Github: https://github.com/gui-cs/Terminal.Gui/releases
-
-Generate release notes with the list of PRs since the last release.
-
-### 11) Update the `develop` branch with the new version
-
-```powershell
-git checkout develop
-git pull upstream develop
-git merge main
-git push upstream develop
+git tag v1.3.4-beta.5 -a -m "Release v1.3.4 Beta 5"
+dotnet-gitversion /updateprojectfiles
+dotnet build -c Release
 ```
 
-## Nuget
+**DO NOT COMMIT AFTER USING `/updateprojectfiles`!** Doing so will update the `.csproj` files in your branch with version info, which we do not want.
 
-https://www.nuget.org/packages/Terminal.Gui
-
-When a new version tag is defined and merged into `main`, a Nuget package will be generated by a Github Action.
-
-If the version is pre-release (includes a hyphen, e.g. `1.3.4-beta.5`) the Nuget package will be tagged as pre-release.
+## Publishing a Release of Terminal.Gui
 
-Miguel & Tig can hide defunct/old Nuget packages.
+To release a new version, follow these steps based on [Semantic Versioning](https://semver.org/) rules:
+
+- **MAJOR** version for incompatible API changes.
+- **MINOR** version for backwards-compatible functionality additions.
+- **PATCH** version for backwards-compatible bug fixes.
+
+### Steps for Release:
+
+1. **Verify the `develop` branch is ready for release**:
+	- Ensure all changes are committed and pushed to the `develop` branch.
+	- Ensure your local `develop` branch is up-to-date with `upstream/develop`.
+
+2. **Create a pull request for the release in the `develop` branch**:
+	- Title the PR as "Release vX.Y.Z".
+	```powershell
+	git checkout develop
+	git pull upstream develop
+	git checkout -b vX_Y_Z
+	git add .
+	git commit -m "Release vX.Y.Z"
+	git push
+	```
+	- Go to the link printed by `git push` and fill out the Pull Request.
+
+3. **On github.com, verify the build action worked on your fork, then merge the PR**.
+
+4. **Pull the merged `develop` from `upstream`**:
+	```powershell
+	git checkout develop
+	git pull upstream develop
+	```
+
+5. **Merge `develop` into `main`**:
+	```powershell
+	git checkout main
+	git pull upstream main
+	git merge develop
+	```
+	- Fix any merge errors.
+
+6. **Create a new annotated tag for the release on `main`**:
+	```powershell
+	git tag vX.Y.Z -a -m "Release vX.Y.Z"
+	```
+
+7. **Push the new tag to `main` on `upstream`**:
+	```powershell
+	git push --atomic upstream main vX.Y.Z
+	```
+
+8. **Monitor Github Actions to ensure the NuGet publishing worked**:
+	- Check [GitHub Actions](https://github.com/gui-cs/Terminal.Gui/actions).
+
+9. **Check NuGet to see the new package version (wait a few minutes)**:
+	- Visit [NuGet Package](https://www.nuget.org/packages/Terminal.Gui).
+
+10. **Add a new Release in Github**:
+	- Go to [GitHub Releases](https://github.com/gui-cs/Terminal.Gui/releases) and generate release notes with the list of PRs since the last release.
+
+11. **Update the `develop` branch with the new version**:
+	```powershell
+	git checkout develop
+	git pull upstream develop
+	git merge main
+	git push upstream develop
+	```
+
+## NuGet
+
+The official NuGet package for Terminal.Gui is available at [https://www.nuget.org/packages/Terminal.Gui](https://www.nuget.org/packages/Terminal.Gui). When a new version tag is defined and merged into `main`, a NuGet package is automatically generated by a GitHub Action. Pre-release versions (e.g., `1.3.4-beta.5`) are tagged as pre-release on NuGet.
 
 ## Contributing
 
-See [CONTRIBUTING.md](https://github.com/gui-cs/Terminal.Gui/blob/master/CONTRIBUTING.md).
+We welcome contributions from the community. For detailed guidelines on how to contribute, including coding style, unit tests, and pull request processes, please refer to [CONTRIBUTING.md](https://github.com/gui-cs/Terminal.Gui/blob/master/CONTRIBUTING.md).

+ 0 - 21
Terminal.Gui/Text/StringPropertyEventArgs.cs

@@ -1,21 +0,0 @@
-#nullable enable
-using System.ComponentModel;
-
-namespace Terminal.Gui.Text;
-
-/// <summary>Event args for <see langword="string"/> type property events</summary>
-public class StringPropertyEventArgs : CancelEventArgs
-{
-    /// <summary>Creates a new instance of the <see cref="StringPropertyEventArgs"/> class.</summary>
-    public StringPropertyEventArgs (in string? currentString, ref string? newString)
-    {
-        CurrentString = currentString;
-        NewString = newString;
-    }
-
-    /// <summary>Gets the current <see cref="String"/>.</summary>
-    public string? CurrentString { get; }
-
-    /// <summary>Gets or sets the new <see cref="String"/>.</summary>
-    public string? NewString { get; set;  }
-}

+ 2 - 3
Terminal.Gui/ViewBase/Adornment/Adornment.cs

@@ -95,13 +95,12 @@ public class Adornment : View, IDesignable
         return true;
     }
 
-    /// <param name="scheme"></param>
     /// <inheritdoc />
-    protected override bool OnSettingScheme (in Scheme? scheme)
+    protected override bool OnSettingScheme (ValueChangingEventArgs<Scheme?> args)
     {
         Parent?.SetNeedsDraw ();
 
-        _scheme = scheme;
+        _scheme = args.NewValue;
         return false;
     }
 

+ 4 - 3
Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs

@@ -35,6 +35,8 @@ public partial class Border
             return false;
         }
 
+        MouseState |= MouseState.Pressed;
+
         // Add Commands and KeyBindings - Note it's ok these get added each time. KeyBindings are cleared in EndArrange()
         AddArrangeModeKeyBindings ();
 
@@ -425,6 +427,8 @@ public partial class Border
         // Debug.Assert (_arranging != ViewArrangement.Fixed);
         Arranging = ViewArrangement.Fixed;
 
+        MouseState &= ~MouseState.Pressed;
+
         Application.MouseEvent -= ApplicationOnMouseEvent;
 
         if (Application.MouseGrabView == this && _dragPosition.HasValue)
@@ -496,8 +500,6 @@ public partial class Border
                 _dragPosition = mouseEvent.Position;
                 Application.GrabMouse (this);
 
-                SetPressedHighlight (HighlightStyle);
-
                 // Determine the mode based on where the click occurred
                 ViewArrangement arrangeMode = DetermineArrangeModeFromClick ();
                 EnterArrangeMode (arrangeMode);
@@ -522,7 +524,6 @@ public partial class Border
         {
             _dragPosition = null;
             Application.UngrabMouse ();
-            SetPressedHighlight (HighlightStyle.None);
 
             EndArrangeMode ();
 

+ 30 - 18
Terminal.Gui/ViewBase/Adornment/Border.cs

@@ -53,14 +53,10 @@ public partial class Border : Adornment
         Application.GrabbingMouse += Application_GrabbingMouse;
         Application.UnGrabbingMouse += Application_UnGrabbingMouse;
 
-        HighlightStyle |= HighlightStyle.Pressed;
-
         ThicknessChanged += OnThicknessChanged;
     }
 
-
     // TODO: Move DrawIndicator out of Border and into View
-
     private void OnThicknessChanged (object? sender, EventArgs e)
     {
         if (IsInitialized)
@@ -117,7 +113,15 @@ public partial class Border : Adornment
     {
         base.BeginInit ();
 
+        if (Parent is null)
+        {
+            return;
+        }
+
         ShowHideDrawIndicator ();
+
+        HighlightStates |= (Parent.Arrangement != ViewArrangement.Fixed ? MouseState.Pressed : MouseState.None);
+
 #if SUBVIEW_BASED_BORDER
         if (Parent is { })
         {
@@ -275,6 +279,7 @@ public partial class Border : Adornment
 
         LineStyle lineStyle = LineStyle;
 
+
         if (Settings.FastHasFlags (BorderSettings.Title))
         {
             if (Thickness.Top == 2)
@@ -332,9 +337,16 @@ public partial class Border : Adornment
             bool drawBottom = Thickness.Bottom > 0 && Frame.Width > 1 && Frame.Height > 1;
             bool drawRight = Thickness.Right > 0 && (Frame.Height > 1 || Thickness.Top == 0);
 
-            Attribute prevAttr = Driver?.GetAttribute () ?? Attribute.Default;
+            //Attribute prevAttr = Driver?.GetAttribute () ?? Attribute.Default;
+
+            Attribute normalAttribute = GetAttributeForRole (VisualRole.Normal);
+
+            if (MouseState.HasFlag (MouseState.Pressed))
+            {
+                normalAttribute = GetAttributeForRole (VisualRole.Highlight);
+            }
 
-            SetAttributeForRole (VisualRole.Normal);
+            SetAttribute (normalAttribute);
 
             if (drawTop)
             {
@@ -348,7 +360,7 @@ public partial class Border : Adornment
                                  borderBounds.Width,
                                  Orientation.Horizontal,
                                  lineStyle,
-                                 Driver?.GetAttribute ()
+                                 normalAttribute
                                 );
                 }
                 else
@@ -363,7 +375,7 @@ public partial class Border : Adornment
                                      Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                      Orientation.Horizontal,
                                      lineStyle,
-                                     Driver?.GetAttribute ()
+                                     normalAttribute
                                     );
                     }
 
@@ -377,7 +389,7 @@ public partial class Border : Adornment
                                      Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                      Orientation.Horizontal,
                                      lineStyle,
-                                     Driver?.GetAttribute ()
+                                     normalAttribute
                                     );
 
                         lc?.AddLine (
@@ -385,7 +397,7 @@ public partial class Border : Adornment
                                      Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                      Orientation.Horizontal,
                                      lineStyle,
-                                     Driver?.GetAttribute ()
+                                     normalAttribute
                                     );
                     }
 
@@ -396,7 +408,7 @@ public partial class Border : Adornment
                                  2,
                                  Orientation.Horizontal,
                                  lineStyle,
-                                 Driver?.GetAttribute ()
+                                 normalAttribute
                                 );
 
                     // Add a vert line for ╔╡
@@ -405,7 +417,7 @@ public partial class Border : Adornment
                                  titleBarsLength,
                                  Orientation.Vertical,
                                  LineStyle.Single,
-                                 Driver?.GetAttribute ()
+                                 normalAttribute
                                 );
 
                     // Add a vert line for ╞
@@ -420,7 +432,7 @@ public partial class Border : Adornment
                                  titleBarsLength,
                                  Orientation.Vertical,
                                  LineStyle.Single,
-                                 Driver?.GetAttribute ()
+                                 normalAttribute
                                 );
 
                     // Add the right hand line for ╞═════╗
@@ -435,7 +447,7 @@ public partial class Border : Adornment
                                  borderBounds.Width - Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
                                  Orientation.Horizontal,
                                  lineStyle,
-                                 Driver?.GetAttribute ()
+                                 normalAttribute
                                 );
                 }
             }
@@ -449,7 +461,7 @@ public partial class Border : Adornment
                              sideLineLength,
                              Orientation.Vertical,
                              lineStyle,
-                             Driver?.GetAttribute ()
+                             normalAttribute
                             );
             }
 #endif
@@ -461,7 +473,7 @@ public partial class Border : Adornment
                              borderBounds.Width,
                              Orientation.Horizontal,
                              lineStyle,
-                             Driver?.GetAttribute ()
+                             normalAttribute
                             );
             }
 
@@ -472,11 +484,11 @@ public partial class Border : Adornment
                              sideLineLength,
                              Orientation.Vertical,
                              lineStyle,
-                             Driver?.GetAttribute ()
+                             normalAttribute
                             );
             }
 
-            SetAttribute (prevAttr);
+            // SetAttribute (prevAttr);
 
             // TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler
             if (Diagnostics.HasFlag (ViewDiagnosticFlags.Ruler))

+ 21 - 23
Terminal.Gui/ViewBase/Adornment/Margin.cs

@@ -1,5 +1,6 @@
 #nullable enable
 
+using System.Runtime.InteropServices;
 
 namespace Terminal.Gui.ViewBase;
 
@@ -32,11 +33,6 @@ public class Margin : Adornment
     /// <inheritdoc/>
     public Margin (View parent) : base (parent)
     {
-        /* Do nothing; View.CreateAdornment requires a constructor that takes a parent */
-
-        // BUGBUG: We should not set HighlightStyle.Pressed here, but wherever it is actually needed
-        // HighlightStyle |= HighlightStyle.Pressed;
-        Highlight += Margin_Highlight;
         SubViewLayout += Margin_LayoutStarted;
 
         // Margin should not be focusable
@@ -81,7 +77,7 @@ public class Margin : Adornment
         {
             var view = stack.Pop ();
 
-            if (view.Margin?.GetCachedClip() != null)
+            if (view.Margin?.GetCachedClip () != null)
             {
                 view.Margin.NeedsDraw = true;
                 Region? saved = GetClip ();
@@ -113,15 +109,9 @@ public class Margin : Adornment
         }
 
         ShadowStyle = base.ShadowStyle;
-    }
 
-    ///// <inheritdoc />
-    //protected override bool OnGettingScheme (out Scheme? scheme)
-    //{
-    //    scheme = Parent?.SuperView?.GetScheme () ?? SchemeManager.GetScheme (Schemes.Base);
-
-    //    return true;
-    //}
+        Parent.MouseStateChanged += OnParentOnMouseStateChanged;
+    }
 
     /// <inheritdoc/>
     protected override bool OnClearingViewport ()
@@ -153,12 +143,12 @@ public class Margin : Adornment
     /// <inheritdoc />
     protected override bool OnDrawingText ()
     {
-        return ViewportSettings.HasFlag(ViewportSettingsFlags.Transparent);
+        return ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent);
     }
 
     #region Shadow
 
-    private bool _pressed;
+    // private bool _pressed;
     private ShadowView? _bottomShadow;
     private ShadowView? _rightShadow;
 
@@ -228,14 +218,22 @@ public class Margin : Adornment
         set => base.ShadowStyle = SetShadow (value);
     }
 
-    private void Margin_Highlight (object? sender, CancelEventArgs<HighlightStyle> e)
+    private void OnParentOnMouseStateChanged (object? sender, EventArgs<MouseState> args)
     {
-        if (Thickness == Thickness.Empty || ShadowStyle == ShadowStyle.None)
+        if (sender is not View parent || Thickness == Thickness.Empty || ShadowStyle == ShadowStyle.None)
         {
             return;
         }
 
-        if (_pressed && e.NewValue == HighlightStyle.None)
+        bool pressed = args.Value.HasFlag (MouseState.Pressed) && parent.HighlightStates.HasFlag(MouseState.Pressed);
+        bool pressedOutside = args.Value.HasFlag (MouseState.PressedOutside) && parent.HighlightStates.HasFlag (MouseState.PressedOutside); ;
+
+        if (pressedOutside)
+        {
+            pressed = false;
+        }
+
+        if (MouseState.HasFlag (MouseState.Pressed) && !pressed)
         {
             // If the view is pressed and the highlight is being removed, move the shadow back.
             // Note, for visual effects reasons, we only move horizontally.
@@ -256,14 +254,14 @@ public class Margin : Adornment
                 _bottomShadow.Visible = true;
             }
 
-            _pressed = false;
+            MouseState &= ~MouseState.Pressed;
 
             return;
         }
 
-        if (!_pressed && e.NewValue.HasFlag (HighlightStyle.Pressed))
+        if (!MouseState.HasFlag (MouseState.Pressed) && pressed)
         {
-            // If the view is not pressed and we want highlight move the shadow
+            // If the view is not pressed, and we want highlight move the shadow
             // Note, for visual effects reasons, we only move horizontally.
             // TODO: Add a setting or flag that lets the view move vertically as well.
             Thickness = new (
@@ -271,7 +269,7 @@ public class Margin : Adornment
                              Thickness.Top + PRESS_MOVE_VERTICAL,
                              Thickness.Right - PRESS_MOVE_HORIZONTAL,
                              Thickness.Bottom - PRESS_MOVE_VERTICAL);
-            _pressed = true;
+            MouseState |= MouseState.Pressed;
 
             if (_rightShadow is { })
             {

+ 35 - 0
Terminal.Gui/ViewBase/DrawAdornmentsEventArgs.cs

@@ -0,0 +1,35 @@
+#nullable enable
+namespace Terminal.Gui.ViewBase;
+
+/// <summary>
+///     Provides data for events that allow cancellation of adornment drawing in the Cancellable Work Pattern (CWP).
+/// </summary>
+/// <remarks>
+///     <para>
+///         Used in events raised by <see cref="View.DoDrawAdornments"/> to allow handlers to cancel the drawing
+///         of <see cref="View.Margin"/>, <see cref="View.Border"/>, and <see cref="View.Padding"/> adornments.
+///     </para>
+/// </remarks>
+/// <seealso cref="View.DrawAdornments"/>
+/// <seealso cref="CWPEventHelper"/>
+public class DrawAdornmentsEventArgs
+{
+    /// <summary>
+    ///     Gets the draw context for tracking drawn regions, or null if not tracking.
+    /// </summary>
+    public DrawContext? Context { get; }
+
+    /// <summary>
+    ///     Gets or sets a value indicating whether the adornment drawing is handled. If true, drawing is cancelled.
+    /// </summary>
+    public bool Handled { get; set; }
+
+    /// <summary>
+    ///     Initializes a new instance of the <see cref="DrawAdornmentsEventArgs"/> class.
+    /// </summary>
+    /// <param name="context">The draw context, or null if not tracking.</param>
+    public DrawAdornmentsEventArgs (DrawContext? context)
+    {
+        Context = context;
+    }
+}

+ 0 - 18
Terminal.Gui/ViewBase/EventArgs.cs

@@ -1,18 +0,0 @@
-#nullable enable
-namespace Terminal.Gui.ViewBase;
-
-#pragma warning disable CS1711
-/// <summary>
-///     <see cref="EventArgs"/> for events that convey changes to a property of type <typeparamref name="T"/>.
-/// </summary>
-/// <typeparam name="T">The type of the value that was part of the change being canceled.</typeparam>
-public class EventArgs<T> : EventArgs where T : notnull
-{
-    /// <summary>Initializes a new instance of the <see cref="EventArgs{T}"/> class.</summary>
-    /// <param name="currentValue">The current value of the property.</param>
-    /// <typeparam name="T">The type of the value.</typeparam>
-    public EventArgs (in T currentValue) { CurrentValue = currentValue; }
-
-    /// <summary>The current value of the property.</summary>
-    public T CurrentValue { get; }
-}

+ 0 - 31
Terminal.Gui/ViewBase/HighlightStyle.cs

@@ -1,31 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace Terminal.Gui.ViewBase;
-
-/// <summary>
-///     Describes the highlight style of a view when the mouse is over it.
-/// </summary>
-[JsonConverter (typeof (JsonStringEnumConverter<HighlightStyle>))]
-[Flags]
-public enum HighlightStyle
-{
-    /// <summary>
-    ///     No highlight.
-    /// </summary>
-    None = 0,
-
-    /// <summary>
-    ///     The mouse is hovering over the view (but not pressed). See <see cref="View.MouseEnter"/>.
-    /// </summary>
-    Hover = 1,
-
-    /// <summary>
-    ///     The mouse is pressed within the <see cref="View.Viewport"/>.
-    /// </summary>
-    Pressed = 2,
-
-    /// <summary>
-    ///     The mouse is pressed but moved outside the <see cref="View.Viewport"/>.
-    /// </summary>
-    PressedOutside = 4
-}

+ 39 - 0
Terminal.Gui/ViewBase/MouseState.cs

@@ -0,0 +1,39 @@
+using System.Text.Json.Serialization;
+
+namespace Terminal.Gui.ViewBase;
+
+/// <summary>
+///     Used to describe the state of the mouse in relation to a <see cref="View"/> (<see cref="View.MouseState"/>) and to
+///     specify visual effects,
+///     such as highlighting a button when the mouse is over it or changing the appearance of a view when the mouse is
+///     pressed (<see cref="View.HighlightStates"/>).
+/// </summary>
+/// <seealso cref="View.MouseState"/>
+/// <seealso cref="View.HighlightStates"/>
+[JsonConverter (typeof (JsonStringEnumConverter<MouseState>))]
+[Flags]
+public enum MouseState
+{
+    /// <summary>
+    ///     No mouse interaction with the view is occurring.
+    /// </summary>
+    None = 0,
+
+    /// <summary>
+    ///     The mouse is in the <see cref="View.Viewport"/> (but not pressed). Set between the <see cref="View.MouseEnter"/>
+    ///     and <see cref="View.MouseLeave"/> events.
+    /// </summary>
+    In = 1,
+
+    /// <summary>
+    ///     The mouse is in the <see cref="View.Viewport"/> and is pressed.
+    /// </summary>
+    Pressed = 2,
+
+    /// <summary>
+    ///     The mouse is outside the <see cref="View.Viewport"/> and is pressed. If
+    ///     <see cref="View.WantContinuousButtonPressed"/> is true,
+    ///     this flag is ignored so that the view remains in the pressed state until the mouse is released.
+    /// </summary>
+    PressedOutside = 4
+}

+ 2 - 0
Terminal.Gui/ViewBase/Navigation/FocusEventArgs.cs

@@ -1,5 +1,7 @@
 namespace Terminal.Gui.ViewBase;
 
+// TODO: CWP: FocusChanging should use an event arg type derived from ResultEventArgs<bool> so that its more obvious
+// TODO: the result can be changed.
 /// <summary>The event arguments for <see cref="View.HasFocus"/> events.</summary>
 public class HasFocusEventArgs : CancelEventArgs<bool>
 {

+ 32 - 0
Terminal.Gui/ViewBase/Orientation/OrientationHelper.cs

@@ -1,6 +1,8 @@
 #nullable enable
 namespace Terminal.Gui.ViewBase;
 
+
+
 /// <summary>
 ///     Helper class for implementing <see cref="IOrientation"/>.
 /// </summary>
@@ -135,3 +137,33 @@ public class OrientationHelper
     /// </remarks>
     public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
 }
+
+
+//public class OrientationHelper
+//{
+//    private Orientation _orientation;
+
+//    public Orientation Orientation
+//    {
+//        get => _orientation;
+//        set
+//        {
+//            CWPPropertyHelper.ChangeProperty (
+//                                              currentValue: _orientation,
+//                                              newValue: ref value,
+//                                              onChanging: args => OnOrientationChanging (args),
+//                                              changingEvent: OrientationChanging,
+//                                              onChanged: args => OnOrientationChanged (args),
+//                                              changedEvent: OrientationChanged
+//                                             );
+//            _orientation = value;
+//        }
+//    }
+
+//    public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
+//    public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
+
+//    protected virtual bool OnOrientationChanging (CancelEventArgs<Orientation> args) => false;
+//    protected virtual void OnOrientationChanged (EventArgs<Orientation> args) { }
+//}
+

+ 2 - 2
Terminal.Gui/ViewBase/View.Command.cs

@@ -219,7 +219,7 @@ public partial class View // Command APIs
     /// </returns>
     protected bool? RaiseSelecting (ICommandContext? ctx)
     {
-        Logging.Debug ($"{Title} ({ctx?.Source?.Title})");
+        //Logging.Debug ($"{Title} ({ctx?.Source?.Title})");
         CommandEventArgs args = new () { Context = ctx };
 
         // Best practice is to invoke the virtual method first.
@@ -266,7 +266,7 @@ public partial class View // Command APIs
     protected bool? RaiseHandlingHotKey ()
     {
         CommandEventArgs args = new () { Context = new CommandContext<KeyBinding> { Command = Command.HotKey } };
-        Logging.Debug ($"{Title} ({args.Context?.Source?.Title})");
+        //Logging.Debug ($"{Title} ({args.Context?.Source?.Title})");
 
         // Best practice is to invoke the virtual method first.
         // This allows derived classes to handle the event and potentially cancel it.

+ 13 - 10
Terminal.Gui/ViewBase/View.Drawing.Attribute.cs

@@ -12,21 +12,21 @@ public partial class View
     public Attribute GetCurrentAttribute () { return Driver?.GetAttribute () ?? Attribute.Default; }
 
     /// <summary>
-    ///     Gets the <see cref="Attribute"/> associated with a specified <see cref="Drawing.VisualRole"/>
-    ///     from the <see cref="Drawing.Scheme"/>.
+    ///     Gets the <see cref="Attribute"/> associated with a specified <see cref="VisualRole"/>
+    ///     from the <see cref="Scheme"/>.
     ///     <para>
     ///         Raises <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>
     ///         which can cancel the default behavior, and optionally change the attribute in the event args.
     ///     </para>
     ///     <para>
-    ///     If <see cref="Enabled"/> is <see langword="false"/>, <see cref="Drawing.VisualRole.Disabled"/>
+    ///     If <see cref="Enabled"/> is <see langword="false"/>, <see cref="VisualRole.Disabled"/>
     ///     will be used instead of <paramref name="role"></paramref>.
     ///     To override this behavior use  <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>
     ///     to cancel the method, and return a different attribute.
     ///     </para>
     ///     <para>
-    ///     If <see cref="HighlightStyle"/> is not <see cref="HighlightStyle.None"/> and <see cref="MouseHovering"/> is <see langword="true"/>,
-    ///     the <see cref="Drawing.VisualRole.Highlight"/> will be used instead of <paramref name="role"/>.
+    ///     If <see cref="HighlightStates"/> is not <see cref="MouseState.None"/> and <see cref="MouseState"/> is <see cref="MouseState.In"/>
+    ///     the <see cref="VisualRole.Highlight"/> will be used instead of <paramref name="role"/>.
     ///     To override this behavior use  <see cref="OnGettingAttributeForRole"/>/<see cref="GettingAttributeForRole"/>
     ///     to cancel the method, and return a different attribute.
     ///     </para>
@@ -43,18 +43,21 @@ public partial class View
             return schemeAttribute;
         }
 
-        VisualRoleEventArgs args = new (role, newValue: ref schemeAttribute, currentValue: ref schemeAttribute);
+        VisualRoleEventArgs args = new (role, result: schemeAttribute);
         GettingAttributeForRole?.Invoke (this, args);
 
-        if (args.Cancel)
+        if (args is { Handled: true, Result: { } })
         {
             // A handler may have changed the attribute
-            return args.NewValue;
+            return args.Result.Value;
         }
 
-        if (HighlightStyle != HighlightStyle.None)
+        if (role != VisualRole.Disabled && HighlightStates != MouseState.None)
         {
-            if (MouseHovering && HighlightStyle.HasFlag (HighlightStyle.Hover) && role != VisualRole.Highlight && role != VisualRole.Disabled)
+            // The default behavior for HighlightStates of MouseState.Over is to use the Highlight role
+            if (((HighlightStates.HasFlag (MouseState.In) && MouseState.HasFlag (MouseState.In))
+                 || (HighlightStates.HasFlag (MouseState.Pressed) && MouseState.HasFlag (MouseState.Pressed)))
+                 && role != VisualRole.Highlight && !HasFocus)
             {
                 schemeAttribute = GetAttributeForRole (VisualRole.Highlight);
             }

+ 199 - 103
Terminal.Gui/ViewBase/View.Drawing.Scheme.cs

@@ -8,53 +8,96 @@ public partial class View
     private string? _schemeName;
 
     /// <summary>
-    ///     Gets or sets the name of the Scheme to use for this View. If set, it will override the scheme inherited from the
-    ///     SuperView. If a Scheme was explicitly set (<see cref="HasScheme"/> is <see langword="true"/>),
-    ///     this property will be ignored.
+    ///     Gets or sets the name of the scheme to use for this <see cref="View"/>. If set, it overrides the scheme
+    ///     inherited from the <see cref="SuperView"/>. If a scheme was explicitly set (<see cref="HasScheme"/> is
+    ///     true), this property is ignored.
     /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Setting this property raises pre- and post-change events via <see cref="CWPPropertyHelper"/>,
+    ///         allowing customization or cancellation of the change. The <see cref="SchemeNameChanging"/> event
+    ///         is raised before the change, and <see cref="SchemeNameChanged"/> is raised after.
+    ///     </para>
+    /// </remarks>
+    /// <value>The scheme name, or null if no scheme name is set.</value>
+    /// <seealso cref="SchemeNameChanging"/>
+    /// <seealso cref="SchemeNameChanged"/>
     public string? SchemeName
     {
         get => _schemeName;
         set
         {
-            if (_schemeName == value)
-            {
-                return;
-            }
+            bool changed = CWPPropertyHelper.ChangeProperty (
+                _schemeName,
+                value,
+                OnSchemeNameChanging,
+                SchemeNameChanging,
+                OnSchemeNameChanged,
+                SchemeNameChanged,
+                out string? finalValue);
 
-            if (OnSettingSchemeName (in _schemeName, ref value))
+            if (changed)
             {
-                _schemeName = value;
-                return;
+                _schemeName = finalValue;
             }
+        }
+    }
 
-            StringPropertyEventArgs args = new (in _schemeName, ref value);
-            SettingSchemeName?.Invoke (this, args);
-
-            if (args.Cancel)
-            {
-                _schemeName = args.NewString;
-
-                return;
-            }
+    /// <summary>
+    ///     Called before the <see cref="SchemeName"/> property changes, allowing subclasses to cancel or modify the change.
+    /// </summary>
+    /// <param name="args">The event arguments containing the current and proposed new scheme name.</param>
+    /// <returns>True to cancel the change, false to proceed.</returns>
+    protected virtual bool OnSchemeNameChanging (ValueChangingEventArgs<string?> args)
+    {
+        return false;
+    }
 
-            _schemeName = value;
-        }
+    /// <summary>
+    ///     Called after the <see cref="SchemeName"/> property changes, allowing subclasses to react to the change.
+    /// </summary>
+    /// <param name="args">The event arguments containing the old and new scheme name.</param>
+    protected virtual void OnSchemeNameChanged (ValueChangedEventArgs<string?> args)
+    {
     }
 
     /// <summary>
-    ///     Called when the <see cref="Scheme"/> for the View is to be set.
+    ///     Raised before the <see cref="SchemeName"/> property changes, allowing handlers to modify or cancel the change.
     /// </summary>
-    /// <param name="currentName"></param>
-    /// <param name="newName"></param>
-    /// <returns><see langword="true"/> to stop default behavior.</returns>
-    protected virtual bool OnSettingSchemeName (in string? currentName, ref string? newName) { return false; }
+    /// <remarks>
+    ///     Set <see cref="ValueChangingEventArgs{T}.Handled"/> to true to cancel the change or modify
+    ///     <see cref="ValueChangingEventArgs{T}.NewValue"/> to adjust the proposed value.
+    /// </remarks>
+    /// <example>
+    ///     <code>
+    ///         view.SchemeNameChanging += (sender, args) =>
+    ///         {
+    ///             if (args.NewValue == "InvalidScheme")
+    ///             {
+    ///                 args.Handled = true;
+    ///                 Console.WriteLine("Invalid scheme name cancelled.");
+    ///             }
+    ///         };
+    ///     </code>
+    /// </example>
+    public event EventHandler<ValueChangingEventArgs<string?>>? SchemeNameChanging;
 
-    /// <summary>Raised when the <see cref="Scheme"/> for the View is to be set.</summary>
-    /// <returns>
-    ///     Set <see cref="CancelEventArgs.Cancel"/> to <see langword="true"/> to stop default behavior.
-    /// </returns>
-    public event EventHandler<StringPropertyEventArgs>? SettingSchemeName;
+    /// <summary>
+    ///     Raised after the <see cref="SchemeName"/> property changes, notifying handlers of the completed change.
+    /// </summary>
+    /// <remarks>
+    ///     Provides the old and new scheme name via <see cref="ValueChangedEventArgs{T}.OldValue"/> and
+    ///     <see cref="ValueChangedEventArgs{T}.NewValue"/>, which may be null.
+    /// </remarks>
+    /// <example>
+    ///     <code>
+    ///         view.SchemeNameChanged += (sender, args) =>
+    ///         {
+    ///             Console.WriteLine($"SchemeName changed from {args.OldValue ?? "none"} to {args.NewValue ?? "none"}.");
+    ///         };
+    ///     </code>
+    /// </example>
+    public event EventHandler<ValueChangedEventArgs<string?>>? SchemeNameChanged;
 
     // Both holds the set Scheme and is used to determine if a Scheme has been set or not
     private Scheme? _scheme;
@@ -66,112 +109,165 @@ public partial class View
     public bool HasScheme => _scheme is { };
 
     /// <summary>
-    ///     Gets the Scheme for the View. If the Scheme has not been explicitly set (see <see cref="HasScheme"/>), gets
-    ///     <see cref="SuperView"/>'s Scheme.
+    ///     Gets the scheme for the <see cref="View"/>. If the scheme has not been explicitly set
+    ///     (see <see cref="HasScheme"/>), gets the <see cref="SuperView"/>'s scheme or falls back to the base scheme.
     /// </summary>
-    /// <returns></returns>
+    /// <returns>The resolved scheme, never null.</returns>
+    /// <remarks>
+    ///     <para>
+    ///         This method uses the Cancellable Work Pattern (CWP) via <see cref="CWPWorkflowHelper.ExecuteWithResult{TResult}"/>
+    ///         to allow customization or cancellation of scheme resolution through the <see cref="OnGettingScheme"/> method
+    ///         and <see cref="GettingScheme"/> event.
+    ///     </para>
+    /// </remarks>
+    /// <example>
+    ///     <code>
+    ///         view.GettingScheme += (sender, args) =>
+    ///         {
+    ///             args.Result = SchemeManager.GetScheme("Custom");
+    ///             args.Handled = true;
+    ///         };
+    ///         Scheme scheme = view.GetScheme();
+    ///     </code>
+    /// </example>
     public Scheme GetScheme ()
     {
-        if (OnGettingScheme (out Scheme? newScheme))
-        {
-            return newScheme!;
-        }
+        ResultEventArgs<Scheme?> args = new ();
 
-        var args = new SchemeEventArgs (in _scheme, ref newScheme);
-        GettingScheme?.Invoke (this, args);
+        return CWPWorkflowHelper.ExecuteWithResult (
+                                                    onMethod: args =>
+                                                              {
+                                                                  bool cancelled = OnGettingScheme (out Scheme? newScheme);
+                                                                  args.Result = newScheme;
+                                                                  return cancelled;
+                                                              },
+                                                    eventHandler: GettingScheme,
+                                                    args,
+                                                    DefaultAction);
 
-        if (args.Cancel)
+        Scheme DefaultAction ()
         {
-            return args.NewScheme!;
-        }
+            if (!HasScheme && !string.IsNullOrEmpty (SchemeName))
+            {
+                return SchemeManager.GetScheme (SchemeName);
+            }
 
-        if (!HasScheme && !string.IsNullOrEmpty (SchemeName))
-        {
-            return SchemeManager.GetScheme (SchemeName);
-        }
+            if (!HasScheme)
+            {
+                return SuperView?.GetScheme () ?? SchemeManager.GetScheme (Schemes.Base);
+            }
 
-        if (!HasScheme)
-        {
-            return SuperView?.GetScheme () ?? SchemeManager.GetScheme (Schemes.Base);
+            return _scheme!;
         }
-
-        return _scheme!;
     }
 
     /// <summary>
-    ///     Called when the <see cref="Scheme"/> for the View is being retrieved. Overrides can return <see langword="true"/>
-    ///     to
-    ///     stop further processing and optionally set <paramref name="scheme"/> to a different value.
+    ///     Called when the <see cref="Scheme"/> for the <see cref="View"/> is being retrieved. Subclasses can return
+    ///     true to stop further processing and optionally set <paramref name="scheme"/> to a different value.
     /// </summary>
-    /// <returns><see langword="true"/> to stop default behavior.</returns>
+    /// <param name="scheme">The scheme to use, or null to continue processing.</param>
+    /// <returns>True to stop default behavior, false to proceed.</returns>
     protected virtual bool OnGettingScheme (out Scheme? scheme)
     {
         scheme = null;
-
         return false;
     }
 
     /// <summary>
-    ///     Raised when the <see cref="Scheme"/> for the View is being retrieved. Overrides can return <see langword="true"/>
-    ///     to
-    ///     stop further processing and optionally set the <see cref="Scheme"/> in the event args to a different value.
+    ///     Raised when the <see cref="Scheme"/> for the <see cref="View"/> is being retrieved. Handlers can set
+    ///     <see cref="ResultEventArgs{T}.Handled"/> to true to stop further processing and optionally set
+    ///     <see cref="ResultEventArgs{T}.Result"/> to a different value.
     /// </summary>
-    /// <returns>
-    ///     Set `Cancel` to <see langword="true"/> to stop default behavior.
-    /// </returns>
-    public event EventHandler<SchemeEventArgs>? GettingScheme;
+    public event EventHandler<ResultEventArgs<Scheme?>>? GettingScheme;
+
 
     /// <summary>
-    ///     Sets the Scheme for the View. Raises <see cref="SettingScheme"/> event before setting the scheme.
+    ///     Sets the scheme for the <see cref="View"/>, marking it as explicitly set.
     /// </summary>
-    /// <param name="scheme">
-    ///     The scheme to set. If <see langword="null"/> <see cref="HasScheme"/> will be
-    ///     <see langword="false"/>.
-    /// </param>
-    /// <returns><see langword="true"/> if the scheme was set.</returns>
+    /// <param name="scheme">The scheme to set, or null to clear the explicit scheme.</param>
+    /// <returns>True if the scheme was set, false if unchanged or cancelled.</returns>
+    /// <remarks>
+    ///     <para>
+    ///         This method uses the Cancellable Work Pattern (CWP) via <see cref="CWPPropertyHelper.ChangeProperty{T}"/>
+    ///         to allow customization or cancellation of the scheme change through the <see cref="OnSettingScheme"/> method
+    ///         and <see cref="SchemeChanging"/> event. The <see cref="SchemeChanged"/> event is raised after a successful change.
+    ///     </para>
+    ///     <para>
+    ///         If set to null, <see cref="HasScheme"/> will be false, and the view will inherit the scheme from its
+    ///         <see cref="SuperView"/> or fall back to the base scheme.
+    ///     </para>
+    /// </remarks>
+    /// <example>
+    ///     <code>
+    ///         view.SchemeChanging += (sender, args) =>
+    ///         {
+    ///             if (args.NewValue is null)
+    ///             {
+    ///                 args.Handled = true;
+    ///                 Console.WriteLine("Null scheme cancelled.");
+    ///             }
+    ///         };
+    ///         view.SchemeChanged += (sender, args) =>
+    ///         {
+    ///             Console.WriteLine($"Scheme changed to {args.NewValue?.Name ?? "none"}.");
+    ///         };
+    ///         bool set = view.SetScheme(SchemeManager.GetScheme("Base"));
+    ///     </code>
+    /// </example>
     public bool SetScheme (Scheme? scheme)
     {
-        if (_scheme == scheme)
-        {
-            return false;
-        }
-
-        if (OnSettingScheme (in scheme))
-        {
-            return false;
-        }
+        bool changed = CWPPropertyHelper.ChangeProperty (
+            _scheme,
+            scheme,
+            OnSettingScheme,
+            SchemeChanging,
+            OnSchemeChanged,
+            SchemeChanged,
+            out Scheme? finalValue);
 
-        var args = new CancelEventArgs ();
-        SettingScheme?.Invoke (this, args);
-
-        if (args.Cancel)
+        if (changed)
         {
-            return false;
+            _scheme = finalValue;
+            return true;
         }
+        return false;
+    }
 
-        _scheme = scheme;
-
-        // BUGBUG: This should be in Border.cs somehow
-        if (Border is { } && Border.LineStyle != LineStyle.None && Border.HasScheme)
-        {
-            Border.SetScheme (_scheme);
-        }
+    /// <summary>
+    ///     Called before the scheme is set, allowing subclasses to cancel or modify the change.
+    /// </summary>
+    /// <param name="args">The event arguments containing the current and proposed new scheme.</param>
+    /// <returns>True to cancel the change, false to proceed.</returns>
+    protected virtual bool OnSettingScheme (ValueChangingEventArgs<Scheme?> args)
+    {
+        return false;
+    }
 
+    /// <summary>
+    ///     Called after the scheme is set, allowing subclasses to react to the change.
+    /// </summary>
+    /// <param name="args">The event arguments containing the old and new scheme.</param>
+    protected virtual void OnSchemeChanged (ValueChangedEventArgs<Scheme?> args)
+    {
         SetNeedsDraw ();
-
-        return true;
     }
 
     /// <summary>
-    ///     Called when the <see cref="Scheme"/> for the View is to be set.
+    ///     Raised before the scheme is set, allowing handlers to modify or cancel the change.
     /// </summary>
-    /// <param name="scheme"></param>
-    /// <returns><see langword="true"/> to stop default behavior.</returns>
-    protected virtual bool OnSettingScheme (in Scheme? scheme) { return false; }
-
-    /// <summary>Raised when the <see cref="Scheme"/> for the View is to be set.</summary>
-    /// <returns>
-    ///     Set <see cref="CancelEventArgs.Cancel"/> to <see langword="true"/> to stop default behavior.
-    /// </returns>
-    public event EventHandler<CancelEventArgs>? SettingScheme;
+    /// <remarks>
+    ///     Set <see cref="ValueChangingEventArgs{T}.Handled"/> to true to cancel the change or modify
+    ///     <see cref="ValueChangingEventArgs{T}.NewValue"/> to adjust the proposed scheme.
+    /// </remarks>
+    public event EventHandler<ValueChangingEventArgs<Scheme?>>? SchemeChanging;
+
+    /// <summary>
+    ///     Raised after the scheme is set, notifying handlers of the completed change.
+    /// </summary>
+    /// <remarks>
+    ///     Provides the old and new scheme via <see cref="ValueChangedEventArgs{T}.OldValue"/> and
+    ///     <see cref="ValueChangedEventArgs{T}.NewValue"/>, which may be null.
+    /// </remarks>
+    public event EventHandler<ValueChangedEventArgs<Scheme?>>? SchemeChanged;
+
 }

+ 1 - 1
Terminal.Gui/ViewBase/View.Drawing.cs

@@ -164,7 +164,7 @@ public partial class View // Drawing APIs
         }
     }
 
-    private void DoDrawAdornments (Region? originalClip)
+    internal void DoDrawAdornments (Region? originalClip)
     {
         if (this is Adornment)
         {

+ 100 - 132
Terminal.Gui/ViewBase/View.Mouse.cs

@@ -46,12 +46,6 @@ public partial class View // Mouse APIs
 
     #region MouseEnterLeave
 
-    /// <summary>
-    ///     Gets whether the mouse is currently hovering over the View's <see cref="Viewport"/>. Is <see langword="true"/> after
-    ///     <see cref="MouseEnter"/> has been raised, and before <see cref="MouseLeave"/> is raised.
-    /// </summary>
-    public bool MouseHovering { get; internal set; }
-
     /// <summary>
     ///     INTERNAL Called by <see cref="Application.RaiseMouseEvent"/> when the mouse moves over the View's
     ///     <see cref="Frame"/>.
@@ -86,9 +80,9 @@ public partial class View // Mouse APIs
             return true;
         }
 
-        MouseHovering = true;
+        MouseState |= MouseState.In;
 
-        if (HighlightStyle != HighlightStyle.None)
+        if (HighlightStates != MouseState.None)
         {
             SetNeedsDraw ();
         }
@@ -96,36 +90,6 @@ public partial class View // Mouse APIs
         return false;
     }
 
-    /// <summary>
-    ///     Gets the <see cref="Drawing.Scheme"/> to use when the view is highlighted. The highlight colorscheme
-    ///     is based on the current <see cref="Drawing.Scheme"/>, using <see cref="Color.GetBrighterColor"/>.
-    /// </summary>
-    /// <remarks>The highlight scheme.</remarks>
-    public Scheme GetHighlightScheme ()
-    {
-        Scheme cs = GetScheme ();
-
-        return cs with
-        {
-            Normal = new (
-                          GetAttributeForRole (VisualRole.Normal).Foreground.GetBrighterColor (),
-                          GetAttributeForRole (VisualRole.Normal).Background,
-                          GetAttributeForRole (VisualRole.Normal).Style),
-            HotNormal = new (
-                             GetAttributeForRole (VisualRole.HotNormal).Foreground.GetBrighterColor (),
-                             GetAttributeForRole (VisualRole.HotNormal).Background,
-                             GetAttributeForRole (VisualRole.HotNormal).Style),
-            Focus = new (
-                         GetAttributeForRole (VisualRole.Focus).Foreground.GetBrighterColor (),
-                         GetAttributeForRole (VisualRole.Focus).Background,
-                         GetAttributeForRole (VisualRole.Focus).Style),
-            HotFocus = new (
-                            GetAttributeForRole (VisualRole.HotFocus).Foreground.GetBrighterColor (),
-                            GetAttributeForRole (VisualRole.HotFocus).Background,
-                            GetAttributeForRole (VisualRole.HotFocus).Style)
-        };
-    }
-
     /// <summary>
     ///     Called when the mouse moves over the View's <see cref="Frame"/> and no other non-SubView occludes it.
     ///     <see cref="MouseLeave"/> will
@@ -143,7 +107,7 @@ public partial class View // Mouse APIs
     ///         Adornments receive MouseEnter/Leave events when the mouse is over the Adornment's <see cref="Thickness"/>.
     ///     </para>
     ///     <para>
-    ///         See <see cref="SetPressedHighlight"/> for more information.
+    ///         See <see cref="MouseState"/> for more information.
     ///     </para>
     /// </remarks>
     /// <param name="eventArgs"></param>
@@ -174,7 +138,7 @@ public partial class View // Mouse APIs
     ///         prevents Views higher in the visible hierarchy from receiving Enter/Leave events.
     ///     </para>
     ///     <para>
-    ///         See <see cref="SetPressedHighlight"/> for more information.
+    ///         See <see cref="MouseState"/> for more information.
     ///     </para>
     /// </remarks>
     public event EventHandler<CancelEventArgs>? MouseEnter;
@@ -192,7 +156,7 @@ public partial class View // Mouse APIs
     ///         Adornments receive MouseEnter/Leave events when the mouse is over the Adornment's <see cref="Thickness"/>.
     ///     </para>
     ///     <para>
-    ///         See <see cref="SetPressedHighlight"/> for more information.
+    ///         See <see cref="MouseState"/> for more information.
     ///     </para>
     /// </remarks>
     internal void NewMouseLeaveEvent ()
@@ -204,9 +168,11 @@ public partial class View // Mouse APIs
 
         MouseLeave?.Invoke (this, EventArgs.Empty);
 
-        MouseHovering = false;
+        MouseState &= ~MouseState.In;
+
+        // TODO: Should we also MouseState &= ~MouseState.Pressed; ??
 
-        if (HighlightStyle != HighlightStyle.None)
+        if (HighlightStates != MouseState.None)
         {
             SetNeedsDraw ();
         }
@@ -220,7 +186,7 @@ public partial class View // Mouse APIs
     ///         Adornments receive MouseEnter/Leave events when the mouse is over the Adornment's <see cref="Thickness"/>.
     ///     </para>
     ///     <para>
-    ///         See <see cref="SetPressedHighlight"/> for more information.
+    ///         See <see cref="MouseState"/> for more information.
     ///     </para>
     /// </remarks>
     protected virtual void OnMouseLeave () { }
@@ -233,7 +199,7 @@ public partial class View // Mouse APIs
     ///         Adornments receive MouseEnter/Leave events when the mouse is over the Adornment's <see cref="Thickness"/>.
     ///     </para>
     ///     <para>
-    ///         See <see cref="SetPressedHighlight"/> for more information.
+    ///         See <see cref="MouseState"/> for more information.
     ///     </para>
     /// </remarks>
     public event EventHandler? MouseLeave;
@@ -242,8 +208,13 @@ public partial class View // Mouse APIs
 
     #region Low Level Mouse Events
 
-    /// <summary>Gets or sets whether the <see cref="View"/> wants continuous button pressed events.</summary>
-    public virtual bool WantContinuousButtonPressed { get; set; }
+    /// <summary>
+    ///     Gets or sets whether the <see cref="View"/> wants continuous button pressed events. When set to
+    ///     <see langword="true"/>,
+    ///     and the user presses and holds the mouse button, <see cref="NewMouseEvent"/> will be
+    ///     repeatedly called with the same <see cref="MouseFlags"/> for as long as the mouse button remains pressed.
+    /// </summary>
+    public bool WantContinuousButtonPressed { get; set; }
 
     /// <summary>Gets or sets whether the <see cref="View"/> wants mouse position reports.</summary>
     /// <value><see langword="true"/> if mouse position reports are wanted; otherwise, <see langword="false"/>.</value>
@@ -263,13 +234,9 @@ public partial class View // Mouse APIs
     ///         mouse buttons was clicked, the <see cref="RaiseMouseClickEvent"/>/<see cref="MouseClick"/> event will be raised
     ///     </para>
     ///     <para>
-    ///         See <see cref="SetPressedHighlight"/> for more information.
-    ///     </para>
-    ///     <para>
-    ///         If <see cref="WantContinuousButtonPressed"/> is <see langword="true"/>, the <see cref="RaiseMouseEvent"/>/
-    ///         <see cref="MouseEvent"/> event
-    ///         will be raised on any new mouse event where <see cref="MouseEventArgs.Flags"/> indicates a button
-    ///         is pressed.
+    ///         If <see cref="WantContinuousButtonPressed"/> is <see langword="true"/>, and the user presses and holds the
+    ///         mouse button, <see cref="NewMouseEvent"/> will be repeatedly called with the same <see cref="MouseFlags"/> for
+    ///         as long as the mouse button remains pressed.
     ///     </para>
     /// </remarks>
     /// <param name="mouseEvent"></param>
@@ -300,7 +267,7 @@ public partial class View // Mouse APIs
         }
 
         // Post-Conditions
-        if (HighlightStyle != HighlightStyle.None || WantContinuousButtonPressed)
+        if (HighlightStates != MouseState.None || WantContinuousButtonPressed)
         {
             if (WhenGrabbedHandlePressed (mouseEvent))
             {
@@ -318,7 +285,7 @@ public partial class View // Mouse APIs
             }
         }
 
-        // We get here if the view did not handle the mouse event via OnMouseEvent/MouseEvent and
+        // We get here if the view did not handle the mouse event via OnMouseEvent/MouseEvent, and
         // it did not handle the press/release/clicked events via HandlePress/HandleRelease/HandleClicked
         if (mouseEvent.IsSingleDoubleOrTripleClicked)
         {
@@ -375,7 +342,7 @@ public partial class View // Mouse APIs
     /// <summary>
     ///     INTERNAL For cases where the view is grabbed and the mouse is clicked, this method handles the released event
     ///     (typically
-    ///     when <see cref="WantContinuousButtonPressed"/> or <see cref="HighlightStyle"/> are set).
+    ///     when <see cref="WantContinuousButtonPressed"/> or <see cref="HighlightStates"/> are set).
     /// </summary>
     /// <remarks>
     ///     Marked internal just to support unit tests
@@ -390,7 +357,9 @@ public partial class View // Mouse APIs
         {
             if (Application.MouseGrabView == this)
             {
-                SetPressedHighlight (HighlightStyle.None);
+                //Logging.Debug ($"{Id} - {MouseState}");
+                MouseState &= ~MouseState.Pressed;
+                MouseState &= ~MouseState.PressedOutside;
             }
 
             return mouseEvent.Handled = true;
@@ -402,7 +371,7 @@ public partial class View // Mouse APIs
     /// <summary>
     ///     INTERNAL For cases where the view is grabbed and the mouse is clicked, this method handles the released event
     ///     (typically
-    ///     when <see cref="WantContinuousButtonPressed"/> or <see cref="HighlightStyle"/> are set).
+    ///     when <see cref="WantContinuousButtonPressed"/> or <see cref="HighlightStates"/> are set).
     /// </summary>
     /// <remarks>
     ///     <para>
@@ -433,19 +402,26 @@ public partial class View // Mouse APIs
 
             if (Viewport.Contains (mouseEvent.Position))
             {
-                if (this is not Adornment
-                    && SetPressedHighlight (HighlightStyle.HasFlag (HighlightStyle.Pressed) ? HighlightStyle.Pressed : HighlightStyle.None))
+                //Logging.Debug ($"{Id} - Inside Viewport: {MouseState}");
+                // The mouse is inside.
+                if (HighlightStates.HasFlag (MouseState.Pressed))
                 {
-                    return true;
+                    MouseState |= MouseState.Pressed;
                 }
+
+                // Always clear PressedOutside when the mouse is pressed inside the Viewport
+                MouseState &= ~MouseState.PressedOutside;
             }
-            else
-            {
-                if (this is not Adornment
-                    && SetPressedHighlight (HighlightStyle.HasFlag (HighlightStyle.PressedOutside) ? HighlightStyle.PressedOutside : HighlightStyle.None))
 
+            if (!Viewport.Contains (mouseEvent.Position))
+            {
+                // Logging.Debug ($"{Id} - Outside Viewport: {MouseState}");
+                // The mouse is outside.
+                // When WantContinuousButtonPressed is set we want to keep the mouse state as pressed (e.g. a repeating button).
+                // This shows the user that the button is doing something, even if the mouse is outside the Viewport.
+                if (HighlightStates.HasFlag (MouseState.PressedOutside) && !WantContinuousButtonPressed)
                 {
-                    return true;
+                    MouseState |= MouseState.PressedOutside;
                 }
             }
 
@@ -486,7 +462,6 @@ public partial class View // Mouse APIs
         }
 
         // Cancellable event
-
         if (OnMouseClick (args) || args.Handled)
         {
             return args.Handled;
@@ -540,7 +515,7 @@ public partial class View // Mouse APIs
     /// <summary>
     ///     INTERNAL For cases where the view is grabbed and the mouse is clicked, this method handles the click event
     ///     (typically
-    ///     when <see cref="WantContinuousButtonPressed"/> or <see cref="HighlightStyle"/> are set).
+    ///     when <see cref="WantContinuousButtonPressed"/> or <see cref="HighlightStates"/> are set).
     /// </summary>
     /// <remarks>
     ///     Marked internal just to support unit tests
@@ -556,10 +531,10 @@ public partial class View // Mouse APIs
             // We're grabbed. Clicked event comes after the last Release. This is our signal to ungrab
             Application.UngrabMouse ();
 
-            if (SetPressedHighlight (HighlightStyle.None))
-            {
-                return true;
-            }
+            // TODO: Prove we need to unset MouseState.Pressed and MouseState.PressedOutside here
+            // TODO: There may be perf gains if we don't unset these flags here
+            MouseState &= ~MouseState.Pressed;
+            MouseState &= ~MouseState.PressedOutside;
 
             // If mouse is still in bounds, generate a click
             if (!WantMousePositionReports && Viewport.Contains (mouseEvent.Position))
@@ -626,90 +601,83 @@ public partial class View // Mouse APIs
 
     #endregion Mouse Wheel Events
 
-    #region Highlight Handling
+    #region MouseState Handling
 
+    private MouseState _mouseState;
 
     /// <summary>
-    ///     Gets or sets whether the <see cref="View"/> will be highlighted visually by mouse interaction.
+    ///     Gets the state of the mouse relative to the View. When changed, the <see cref="MouseStateChanged"/>/
+    ///     <see cref="OnMouseStateChanged"/>
+    ///     event will be raised.
     /// </summary>
-    public HighlightStyle HighlightStyle { get; set; }
-
-    /// <summary>
-    ///     INTERNAL Raises the <see cref="Highlight"/> event. Returns <see langword="true"/> if the event was handled,
-    ///     <see langword="false"/> otherwise.
-    /// </summary>
-    /// <param name="args"></param>
-    /// <returns></returns>
-    private bool RaiseHighlight (CancelEventArgs<HighlightStyle> args)
+    public MouseState MouseState
     {
-        if (OnHighlight (args))
+        get => _mouseState;
+        internal set
         {
-            return true;
-        }
-
-        Highlight?.Invoke (this, args);
+            if (_mouseState == value)
+            {
+                return;
+            }
 
-        return args.Cancel;
-    }
+            EventArgs<MouseState> args = new (value);
 
-    /// <summary>
-    ///     Called when the view is to be highlighted. The <see cref="HighlightStyle"/> passed in the event indicates the
-    ///     highlight style that will be applied. The view can modify the highlight style by setting the
-    ///     <see cref="CancelEventArgs{T}.NewValue"/> property.
-    /// </summary>
-    /// <param name="args">
-    ///     Set the <see cref="CancelEventArgs{T}.NewValue"/> property to <see langword="true"/>, to cancel, indicating custom
-    ///     highlighting.
-    /// </param>
-    /// <returns><see langword="true"/>, to cancel, indicating custom highlighting.</returns>
-    protected virtual bool OnHighlight (CancelEventArgs<HighlightStyle> args) { return false; }
+            RaiseMouseStateChanged (args);
 
-    /// <summary>
-    ///     Raised when the view is to be highlighted. The <see cref="HighlightStyle"/> passed in the event indicates the
-    ///     highlight style that will be applied. The view can modify the highlight style by setting the
-    ///     <see cref="CancelEventArgs{T}.NewValue"/> property.
-    ///     Set to <see langword="true"/>, to cancel, indicating custom highlighting.
-    /// </summary>
-    public event EventHandler<CancelEventArgs<HighlightStyle>>? Highlight;
+            _mouseState = value;
+        }
+    }
 
     /// <summary>
-    ///     INTERNAL Enables the highlight for the view when the mouse is pressed. Called from OnMouseEvent.
+    ///     Gets or sets which <see cref="MouseState"/> changes should cause the View to change its appearance.
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         Set <see cref="HighlightStyle"/> to <see cref="HighlightStyle.Pressed"/> and/or
-    ///         <see cref="HighlightStyle.PressedOutside"/> to enable.
+    ///         <see cref="MouseState.In"/> is set by default, which means the View will be highlighted when the
+    ///         mouse is over it. The default behavior of <see cref="SetAttributeForRole"/>
+    ///         is to use the <see cref="Drawing.VisualRole.Highlight"/> role for the highlight Attribute.
     ///     </para>
     ///     <para>
-    ///         Calls <see cref="OnHighlight"/> and raises the <see cref="Highlight"/> event.
+    ///         <see cref="MouseState.Pressed"/> means the View will be highlighted when the mouse is pressed over it.
+    ///         <see cref="Border"/>'s default behavior is to use
+    ///         the <see cref="VisualRole.Highlight"/> role when the Border is pressed for Arrangement.
+    ///         <see cref="Margin"/>'s default behavior, when shadows are enabled, is to move the shadow providing
+    ///         a pressed effect.
     ///     </para>
     ///     <para>
-    ///         Marked internal just to support unit tests
+    ///         <see cref="MouseState.PressedOutside"/> means the View will be highlighted when the mouse was pressed
+    ///         inside it and then moved outside of it, unless <see cref="WantContinuousButtonPressed"/> is set to
+    ///         <see langword="true"/>, in which case the flag has no effect.
     ///     </para>
     /// </remarks>
-    /// <returns><see langword="true"/>, if the Highlight event was handled, <see langword="false"/> otherwise.</returns>
-    internal bool SetPressedHighlight (HighlightStyle newHighlightStyle)
-    {
-        // TODO: Make the highlight colors configurable
-        if (!CanFocus)
-        {
-            return false;
-        }
+    public MouseState HighlightStates { get; set; }
 
-        HighlightStyle copy = HighlightStyle;
-        CancelEventArgs<HighlightStyle> args = new (ref copy, ref newHighlightStyle);
+    /// <summary>
+    ///     INTERNAL Raises the <see cref="MouseStateChanged"/> event.
+    /// </summary>
+    /// <param name="args"></param>
+    private void RaiseMouseStateChanged (EventArgs<MouseState> args)
+    {
+        //Logging.Debug ($"{Id} - {args.Value} -> {args.Value}");
 
-        if (RaiseHighlight (args) || args.Cancel)
-        {
-            return true;
-        }
+        OnMouseStateChanged (args);
 
-        // For 3D Pressed Style - Note we don't care about canceling the event here
-        Margin?.RaiseHighlight (args);
-        return args.Cancel;
+        MouseStateChanged?.Invoke (this, args);
     }
 
-    #endregion Highlight Handling
+    /// <summary>
+    ///     Called when <see cref="MouseState"/> has changed, indicating the View should be highlighted or not. The <see cref="MouseState"/> passed in the event
+    ///     indicates the highlight style that will be applied.
+    /// </summary>
+    protected virtual void OnMouseStateChanged (EventArgs<MouseState> args) { }
+
+    /// <summary>
+    ///     RaisedCalled when <see cref="MouseState"/> has changed, indicating the View should be highlighted or not. The <see cref="MouseState"/> passed in the event
+    ///     indicates the highlight style that will be applied.
+    /// </summary>
+    public event EventHandler<EventArgs<MouseState>>? MouseStateChanged;
+
+    #endregion MouseState Handling
 
     private void DisposeMouse () { }
 }

+ 3 - 0
Terminal.Gui/ViewBase/View.Navigation.cs

@@ -637,6 +637,8 @@ public partial class View // Focus and cross-view navigation management (TabStop
         return (true, false);
     }
 
+    // TODO: CWP: FocusChanging should use an event arg type derived from ResultEventArgs<bool> so that its more obvious
+    // TODO: the result can be changed.
     private bool RaiseFocusChanging (bool currentHasFocus, bool newHasFocus, View? currentFocused, View? newFocused)
     {
         Debug.Assert (currentFocused is null || currentFocused is { HasFocus: true });
@@ -882,6 +884,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
         SetNeedsDraw ();
     }
 
+    // TODO: CWP: FocusChanged should not be using event args derived from CancelEventArgs, as it is not cancellable.
     private void RaiseFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
     {
         // If we are the most focused view, we need to set the focused view in Application.Navigation

+ 2 - 2
Terminal.Gui/ViewBase/View.ScrollBars.cs

@@ -139,7 +139,7 @@ public partial class View
                                      {
                                          Viewport = Viewport with
                                          {
-                                             Y = Math.Min (args.CurrentValue, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize)
+                                             Y = Math.Min (args.Value, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize)
                                          };
                                      };
 
@@ -160,7 +160,7 @@ public partial class View
                                      {
                                          Viewport = Viewport with
                                          {
-                                             X = Math.Min (args.CurrentValue, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize)
+                                             X = Math.Min (args.Value, scrollBar.ScrollableContentSize - scrollBar.VisibleContentSize)
                                          };
                                      };
 

+ 6 - 33
Terminal.Gui/Views/Button.cs

@@ -39,13 +39,13 @@ public class Button : View, IDesignable
     ///     Gets or sets the default Highlight Style.
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static HighlightStyle DefaultHighlightStyle { get; set; } = HighlightStyle.Pressed | HighlightStyle.Hover;
+    public static MouseState DefaultHighlightStates { get; set; } = MouseState.In | MouseState.Pressed | MouseState.PressedOutside;
 
     /// <summary>Initializes a new instance of <see cref="Button"/>.</summary>
     public Button ()
     {
-        TextAlignment = Alignment.Center;
-        VerticalTextAlignment = Alignment.Center;
+        base.TextAlignment = Alignment.Center;
+        base.VerticalTextAlignment = Alignment.Center;
 
         _leftBracket = Glyphs.LeftBracket;
         _rightBracket = Glyphs.RightBracket;
@@ -67,8 +67,8 @@ public class Button : View, IDesignable
         TitleChanged += Button_TitleChanged;
         MouseClick += Button_MouseClick;
 
-        ShadowStyle = DefaultShadow;
-        HighlightStyle = DefaultHighlightStyle;
+        base.ShadowStyle = DefaultShadow;
+        HighlightStates = DefaultHighlightStates;
     }
 
     private bool? HandleHotKeyCommand (ICommandContext commandContext)
@@ -99,33 +99,6 @@ public class Button : View, IDesignable
 
         return false;
     }
-
-    private bool _wantContinuousButtonPressed;
-
-    /// <inheritdoc/>
-    public override bool WantContinuousButtonPressed
-    {
-        get => _wantContinuousButtonPressed;
-        set
-        {
-            if (value == _wantContinuousButtonPressed)
-            {
-                return;
-            }
-
-            _wantContinuousButtonPressed = value;
-
-            if (_wantContinuousButtonPressed)
-            {
-                HighlightStyle |= HighlightStyle.PressedOutside;
-            }
-            else
-            {
-                HighlightStyle &= ~HighlightStyle.PressedOutside;
-            }
-        }
-    }
-
     private void Button_MouseClick (object sender, MouseEventArgs e)
     {
         if (e.Handled)
@@ -139,7 +112,7 @@ public class Button : View, IDesignable
 
     private void Button_TitleChanged (object sender, EventArgs<string> e)
     {
-        base.Text = e.CurrentValue;
+        base.Text = e.Value;
         TextFormatter.HotKeySpecifier = HotKeySpecifier;
     }
 

+ 2 - 5
Terminal.Gui/Views/CharMap/CharMap.cs

@@ -106,10 +106,10 @@ public class CharMap : View, IDesignable
     {
         if (e.Role != VisualRole.Focus && e.Role != VisualRole.Active)
         {
-            e.NewValue = GetAttributeForRole (HasFocus ? VisualRole.Focus : VisualRole.Active);
+            e.Result = GetAttributeForRole (HasFocus ? VisualRole.Focus : VisualRole.Active);
         }
 
-        e.Cancel = true;
+        e.Handled = true;
     }
 
     private bool? Move (ICommandContext? commandContext, int cpOffset)
@@ -442,9 +442,6 @@ public class CharMap : View, IDesignable
 
     #region Mouse Handling
 
-    // TODO: Use this to demonstrate using a popover to show glyph info on hover
-    // public event EventHandler<ListViewItemEventArgs>? Hover;
-
     private bool? HandleSelectCommand (ICommandContext? commandContext)
     {
         Point position = GetCursor (SelectedCodePoint);

+ 14 - 14
Terminal.Gui/Views/CheckBox.cs

@@ -14,7 +14,7 @@ public class CheckBox : View
     ///     Gets or sets the default Highlight Style.
     /// </summary>
     [ConfigurationProperty (Scope = typeof (ThemeScope))]
-    public static HighlightStyle DefaultHighlightStyle { get; set; } = HighlightStyle.PressedOutside | HighlightStyle.Pressed | HighlightStyle.Hover;
+    public static MouseState DefaultHighlightStates { get; set; } = MouseState.PressedOutside | MouseState.Pressed | MouseState.In;
 
     /// <summary>
     ///     Initializes a new instance of <see cref="CheckBox"/>.
@@ -46,7 +46,7 @@ public class CheckBox : View
 
         TitleChanged += Checkbox_TitleChanged;
 
-        HighlightStyle = DefaultHighlightStyle;
+        HighlightStates = DefaultHighlightStates;
     }
 
     private bool? AdvanceAndSelect (ICommandContext? commandContext)
@@ -68,7 +68,7 @@ public class CheckBox : View
 
     private void Checkbox_TitleChanged (object? sender, EventArgs<string> e)
     {
-        base.Text = e.CurrentValue;
+        base.Text = e.Value;
         TextFormatter.HotKeySpecifier = HotKeySpecifier;
     }
 
@@ -152,7 +152,7 @@ public class CheckBox : View
             return null;
         }
 
-        CancelEventArgs<CheckState> e = new (in _checkedState, ref value);
+        ResultEventArgs<CheckState> e = new (value);
 
         if (OnCheckedStateChanging (e))
         {
@@ -161,9 +161,9 @@ public class CheckBox : View
 
         CheckedStateChanging?.Invoke (this, e);
 
-        if (e.Cancel)
+        if (e.Handled)
         {
-            return e.Cancel;
+            return e.Handled;
         }
 
         _checkedState = value;
@@ -184,7 +184,7 @@ public class CheckBox : View
     ///         The state change can be cancelled by setting the args.Cancel to <see langword="true"/>.
     ///     </para>
     /// </remarks>
-    protected virtual bool OnCheckedStateChanging (CancelEventArgs<CheckState> args) { return false; }
+    protected virtual bool OnCheckedStateChanging (ResultEventArgs<CheckState> args) { return false; }
 
     /// <summary>Raised when the <see cref="CheckBox"/> state is changing.</summary>
     /// <remarks>
@@ -192,7 +192,7 @@ public class CheckBox : View
     ///         This event can be cancelled. If cancelled, the <see cref="CheckBox"/> will not change its state.
     ///     </para>
     /// </remarks>
-    public event EventHandler<CancelEventArgs<CheckState>>? CheckedStateChanging;
+    public event EventHandler<ResultEventArgs<CheckState>>? CheckedStateChanging;
 
     /// <summary>Called when the <see cref="CheckBox"/> state has changed.</summary>
     protected virtual void OnCheckedStateChanged (EventArgs<CheckState> args) { }
@@ -221,32 +221,32 @@ public class CheckBox : View
     public bool? AdvanceCheckState ()
     {
         CheckState oldValue = CheckedState;
-        CancelEventArgs<CheckState> e = new (in _checkedState, ref oldValue);
+        ResultEventArgs<CheckState> e = new (oldValue);
 
         switch (CheckedState)
         {
             case CheckState.None:
-                e.NewValue = CheckState.Checked;
+                e.Result = CheckState.Checked;
 
                 break;
             case CheckState.Checked:
-                e.NewValue = CheckState.UnChecked;
+                e.Result = CheckState.UnChecked;
 
                 break;
             case CheckState.UnChecked:
                 if (AllowCheckStateNone)
                 {
-                    e.NewValue = CheckState.None;
+                    e.Result = CheckState.None;
                 }
                 else
                 {
-                    e.NewValue = CheckState.Checked;
+                    e.Result = CheckState.Checked;
                 }
 
                 break;
         }
 
-        bool? cancelled = ChangeCheckedState (e.NewValue);
+        bool? cancelled = ChangeCheckedState (e.Result);
 
         return cancelled;
     }

+ 2 - 2
Terminal.Gui/Views/Color/ColorPicker.16.cs

@@ -53,7 +53,7 @@ public class ColorPicker16 : View
     }
 
     /// <summary>Fired when a color is picked.</summary>
-    public event EventHandler<ColorEventArgs>? ColorChanged;
+    public event EventHandler<ResultEventArgs<Color>>? ColorChanged;
 
     /// <summary>Cursor for the selected color.</summary>
     public Point Cursor
@@ -280,7 +280,7 @@ public class ColorPicker16 : View
 
     private void SetInitialProperties ()
     {
-        HighlightStyle = HighlightStyle.PressedOutside | HighlightStyle.Pressed;
+        HighlightStates = ViewBase.MouseState.PressedOutside | ViewBase.MouseState.Pressed;
 
         CanFocus = true;
         AddCommands ();

+ 1 - 1
Terminal.Gui/Views/Color/ColorPicker.cs

@@ -96,7 +96,7 @@ public partial class ColorPicker : View, IDesignable
     /// <summary>
     ///     Fired when color is changed.
     /// </summary>
-    public event EventHandler<ColorEventArgs>? ColorChanged;
+    public event EventHandler<ResultEventArgs<Color>>? ColorChanged;
 
     /// <inheritdoc/>
     protected override bool OnDrawingContent ()

+ 3 - 3
Terminal.Gui/Views/ComboBox.cs

@@ -111,10 +111,10 @@ public class ComboBox : View, IDesignable
     }
 
     /// <inheritdoc />
-    protected override bool OnSettingScheme (in Scheme scheme)
+    protected override bool OnSettingScheme (ValueChangingEventArgs<Scheme?> args)
     {
-        _listview.SetScheme(scheme);
-        return base.OnSettingScheme (in scheme);
+        _listview.SetScheme(args.NewValue);
+        return base.OnSettingScheme (args);
     }
 
     /// <summary>Gets or sets if the drop-down list can be hide with a button click event.</summary>

+ 1 - 0
Terminal.Gui/Views/FileDialog.cs

@@ -0,0 +1 @@
+ 

+ 8 - 8
Terminal.Gui/Views/FlagSelector.cs

@@ -307,7 +307,7 @@ public class FlagSelector : View, IOrientation, IDesignable
             Title = nameWithHotKey,
             Id = name,
             Data = flag,
-            HighlightStyle = HighlightStyle.Hover
+            HighlightStates = ViewBase.MouseState.In
         };
 
         checkbox.GettingAttributeForRole += (_, e) =>
@@ -320,36 +320,36 @@ public class FlagSelector : View, IOrientation, IDesignable
                                            switch (e.Role)
                                            {
                                                case VisualRole.Normal:
-                                                   e.Cancel = true;
+                                                   e.Handled = true;
 
                                                    if (!HasFocus)
                                                    {
-                                                       e.NewValue = GetAttributeForRole (VisualRole.Focus);
+                                                       e.Result = GetAttributeForRole (VisualRole.Focus);
                                                    }
                                                    else
                                                    {
                                                        // If _scheme was set, it's because of Hover
                                                        if (checkbox.HasScheme)
                                                        {
-                                                           e.NewValue = checkbox.GetAttributeForRole (VisualRole.Normal);
+                                                           e.Result = checkbox.GetAttributeForRole (VisualRole.Normal);
                                                        }
                                                        else
                                                        {
-                                                           e.NewValue = GetAttributeForRole (VisualRole.Normal);
+                                                           e.Result = GetAttributeForRole (VisualRole.Normal);
                                                        }
                                                    }
 
                                                    break;
 
                                                case VisualRole.HotNormal:
-                                                   e.Cancel = true;
+                                                   e.Handled = true;
                                                    if (!HasFocus)
                                                    {
-                                                       e.NewValue = GetAttributeForRole (VisualRole.HotFocus);
+                                                       e.Result = GetAttributeForRole (VisualRole.HotFocus);
                                                    }
                                                    else
                                                    {
-                                                       e.NewValue = GetAttributeForRole (VisualRole.HotNormal);
+                                                       e.Result = GetAttributeForRole (VisualRole.HotNormal);
                                                    }
 
                                                    break;

+ 1 - 1
Terminal.Gui/Views/Label.cs

@@ -40,7 +40,7 @@ public class Label : View, IDesignable
 
     private void Label_TitleChanged (object sender, EventArgs<string> e)
     {
-        base.Text = e.CurrentValue;
+        base.Text = e.Value;
         TextFormatter.HotKeySpecifier = HotKeySpecifier;
     }
 

+ 2 - 2
Terminal.Gui/Views/Menu/MenuBarv2.cs

@@ -198,7 +198,7 @@ public class MenuBarv2 : Menuv2, IDesignable
     {
         if (sender is MenuBarItemv2 mbi)
         {
-            if (e.CurrentValue)
+            if (e.Value)
             {
                 Active = true;
             }
@@ -541,7 +541,7 @@ public class MenuBarv2 : Menuv2, IDesignable
                                                      {
                                                          Normal = new (
                                                                        GetAttributeForRole (VisualRole.Normal).Foreground,
-                                                                       args.CurrentValue,
+                                                                       args.Result,
                                                                        GetAttributeForRole (VisualRole.Normal).Style)
                                                      });
                                       };

+ 8 - 8
Terminal.Gui/Views/OptionSelector.cs

@@ -179,7 +179,7 @@ public class OptionSelector : View, IOrientation, IDesignable
             Title = nameWithHotKey,
             Id = name,
             Data = index,
-            //HighlightStyle = HighlightStyle.Hover,
+            //HighlightStates = HighlightStates.Hover,
             RadioStyle = true
         };
 
@@ -193,37 +193,37 @@ public class OptionSelector : View, IOrientation, IDesignable
             switch (e.Role)
             {
                 case VisualRole.Normal:
-                    e.Cancel = true;
+                    e.Handled = true;
 
                     if (!HasFocus)
                     {
-                        e.NewValue = GetAttributeForRole (VisualRole.Focus);
+                        e.Result = GetAttributeForRole (VisualRole.Focus);
                     }
                     else
                     {
                         // If _scheme was set, it's because of Hover
                         if (checkbox.HasScheme)
                         {
-                            e.NewValue = checkbox.GetAttributeForRole(VisualRole.Normal);
+                            e.Result = checkbox.GetAttributeForRole(VisualRole.Normal);
                         }
                         else
                         {
-                            e.NewValue = GetAttributeForRole (VisualRole.Normal);
+                            e.Result = GetAttributeForRole (VisualRole.Normal);
                         }
                     }
 
                     break;
 
                 case VisualRole.HotNormal:
-                    e.Cancel = true;
+                    e.Handled = true;
 
                     if (!HasFocus)
                     {
-                        e.NewValue = GetAttributeForRole (VisualRole.HotFocus);
+                        e.Result = GetAttributeForRole (VisualRole.HotFocus);
                     }
                     else
                     {
-                        e.NewValue = GetAttributeForRole (VisualRole.HotNormal);
+                        e.Result = GetAttributeForRole (VisualRole.HotNormal);
                     }
 
                     break;

+ 4 - 4
Terminal.Gui/Views/ScrollBar/ScrollBar.cs

@@ -434,7 +434,7 @@ public class ScrollBar : View, IOrientation, IDesignable
             return;
         }
 
-        RaiseSliderPositionChangeEvents (_sliderPosition, e.CurrentValue);
+        RaiseSliderPositionChangeEvents (_sliderPosition, e.Value);
     }
 
     private void SliderOnScroll (object? sender, EventArgs<int> e)
@@ -446,14 +446,14 @@ public class ScrollBar : View, IOrientation, IDesignable
 
         int calculatedSliderPos = CalculateSliderPositionFromContentPosition (
                                                                               _position,
-                                                                              e.CurrentValue >= 0 ? NavigationDirection.Forward : NavigationDirection.Backward);
+                                                                              e.Value >= 0 ? NavigationDirection.Forward : NavigationDirection.Backward);
 
         if (calculatedSliderPos == _sliderPosition)
         {
             return;
         }
 
-        int sliderScrolledAmount = e.CurrentValue;
+        int sliderScrolledAmount = e.Value;
         int calculatedPosition = CalculatePositionFromSliderPosition (calculatedSliderPos + sliderScrolledAmount);
 
         Position = calculatedPosition;
@@ -610,7 +610,7 @@ public class ScrollBar : View, IOrientation, IDesignable
     {
         OrientationChanged += (sender, args) =>
                               {
-                                  if (args.CurrentValue == Orientation.Vertical)
+                                  if (args.Value == Orientation.Vertical)
                                   {
                                       Width = 1;
                                       Height = Dim.Fill ();

+ 1 - 1
Terminal.Gui/Views/ScrollBar/ScrollSlider.cs

@@ -26,7 +26,7 @@ public class ScrollSlider : View, IOrientation, IDesignable
 
         OnOrientationChanged (Orientation);
 
-        HighlightStyle = HighlightStyle.Hover;
+        HighlightStates = ViewBase.MouseState.In;
     }
 
     #region IOrientation members

+ 10 - 10
Terminal.Gui/Views/Shortcut.cs

@@ -60,7 +60,7 @@ public class Shortcut : View, IOrientation, IDesignable
     /// <param name="helpText">The help text to display.</param>
     public Shortcut (Key key, string? commandText, Action? action, string? helpText = null)
     {
-        HighlightStyle = HighlightStyle.None;
+        HighlightStates = ViewBase.MouseState.None;
         CanFocus = true;
 
         if (Border is { })
@@ -481,7 +481,7 @@ public class Shortcut : View, IOrientation, IDesignable
         CommandView.VerticalTextAlignment = Alignment.Center;
         CommandView.TextAlignment = Alignment.Start;
         CommandView.TextFormatter.WordWrap = false;
-        //CommandView.HighlightStyle = HighlightStyle.None;
+        //CommandView.HighlightStates = HighlightStates.None;
         CommandView.GettingAttributeForRole += SubViewOnGettingAttributeForRole;
     }
 
@@ -492,16 +492,16 @@ public class Shortcut : View, IOrientation, IDesignable
             case VisualRole.Normal:
                 if (HasFocus)
                 {
-                    e.Cancel = true;
-                    e.NewValue = GetAttributeForRole (VisualRole.Focus);
+                    e.Handled = true;
+                    e.Result = GetAttributeForRole (VisualRole.Focus);
                 }
                 break;
 
             case VisualRole.HotNormal:
                 if (HasFocus)
                 {
-                    e.Cancel = true;
-                    e.NewValue = GetAttributeForRole (VisualRole.HotFocus);
+                    e.Handled = true;
+                    e.Result = GetAttributeForRole (VisualRole.HotFocus);
                 }
                 break;
         }
@@ -547,7 +547,7 @@ public class Shortcut : View, IOrientation, IDesignable
         HelpView.VerticalTextAlignment = Alignment.Center;
         HelpView.TextAlignment = Alignment.Start;
         HelpView.TextFormatter.WordWrap = false;
-        HelpView.HighlightStyle = HighlightStyle.None;
+        HelpView.HighlightStates = ViewBase.MouseState.None;
 
         HelpView.GettingAttributeForRole += SubViewOnGettingAttributeForRole;
     }
@@ -681,14 +681,14 @@ public class Shortcut : View, IOrientation, IDesignable
         KeyView.TextAlignment = Alignment.End;
         KeyView.VerticalTextAlignment = Alignment.Center;
         KeyView.KeyBindings.Clear ();
-        KeyView.HighlightStyle = HighlightStyle.None;
+        KeyView.HighlightStates = ViewBase.MouseState.None;
 
         KeyView.GettingAttributeForRole += (sender, args) =>
                                            {
                                                if (args.Role == VisualRole.Normal)
                                                {
-                                                   args.NewValue = SuperView?.GetAttributeForRole (HasFocus ? VisualRole.HotFocus : VisualRole.HotNormal) ?? Attribute.Default;
-                                                   args.Cancel = true;
+                                                   args.Result = SuperView?.GetAttributeForRole (HasFocus ? VisualRole.HotFocus : VisualRole.HotNormal) ?? Attribute.Default;
+                                                   args.Handled = true;
                                                }
                                            };
         KeyView.ClearingViewport += (sender, args) =>

+ 9 - 8
Terminal.Gui/Views/TextInput/DateField.cs

@@ -184,15 +184,15 @@ public class DateField : TextField
         }
     }
 
-    private void DateField_Changing (object sender, CancelEventArgs<string> e)
+    private void OnTextChanging (object sender, ResultEventArgs<string> e)
     {
         try
         {
             var spaces = 0;
 
-            for (var i = 0; i < e.NewValue.Length; i++)
+            for (var i = 0; i < e.Result.Length; i++)
             {
-                if (e.NewValue [i] == ' ')
+                if (e.Result [i] == ' ')
                 {
                     spaces++;
                 }
@@ -203,21 +203,22 @@ public class DateField : TextField
             }
 
             spaces += FormatLength;
-            string trimmedText = e.NewValue [..spaces];
+            string trimmedText = e.Result [..spaces];
             spaces -= FormatLength;
             trimmedText = trimmedText.Replace (new string (' ', spaces), " ");
             var date = Convert.ToDateTime (trimmedText).ToString (_format.Trim ());
 
-            if ($" {date}" != e.NewValue)
+            if ($" {date}" != e.Result)
             {
-                e.NewValue = $" {date}".Replace (RightToLeftMark, "");
+                // Change the date format to match the current culture
+                e.Result = $" {date}".Replace (RightToLeftMark, "");
             }
 
             AdjCursorPosition (CursorPosition);
         }
         catch (Exception)
         {
-            e.Cancel = true;
+            e.Handled = true;
         }
     }
 
@@ -375,7 +376,7 @@ public class DateField : TextField
         _separator = GetDataSeparator (Culture.DateTimeFormat.DateSeparator);
         Date = date;
         CursorPosition = 1;
-        TextChanging += DateField_Changing;
+        TextChanging += OnTextChanging;
 
         // Things this view knows how to do
         AddCommand (

+ 13 - 10
Terminal.Gui/Views/TextInput/TextField.cs

@@ -518,10 +518,10 @@ public class TextField : View, IDesignable
             }
 
             string newText = value.Replace ("\t", "").Split ("\n") [0];
-            CancelEventArgs<string> args = new (ref oldText, ref newText);
-            OnTextChanging (args);
+            ResultEventArgs<string> args = new (newText);
+            RaiseTextChanging (args);
 
-            if (args.Cancel)
+            if (args.Handled)
             {
                 if (_cursorPosition > _text.Count)
                 {
@@ -534,7 +534,7 @@ public class TextField : View, IDesignable
             ClearAllSelection ();
 
             // Note we use NewValue here; TextChanging subscribers may have changed it
-            _text = args.NewValue.EnumerateRunes ().ToList ();
+            _text = args.Result.EnumerateRunes ().ToList ();
 
             if (!Secret && !_historyText.IsFromHistory)
             {
@@ -1067,16 +1067,21 @@ public class TextField : View, IDesignable
         return true;
     }
 
-    /// <summary>Virtual method that invoke the <see cref="TextChanging"/> event if it's defined.</summary>
+    /// <summary>Raises the <see cref="TextChanging"/> event, enabling canceling the change or adjusting the text.</summary>
     /// <param name="args">The event arguments.</param>
-    /// <returns><see langword="true"/> if the event was cancelled.</returns>
-    public bool OnTextChanging (CancelEventArgs<string> args)
+    /// <returns><see langword="true"/> if the event was cancelled or the text was adjusted by the event.</returns>
+    public bool RaiseTextChanging (ResultEventArgs<string> args)
     {
+        // TODO: CWP: Add an OnTextChanging protected virtual method that can be overridden to handle text changing events.
+
         TextChanging?.Invoke (this, args);
 
-        return args.Cancel;
+        return args.Handled;
     }
 
+    /// <summary>Raised before <see cref="Text"/> changes. The change can be canceled the text adjusted.</summary>
+    public event EventHandler<ResultEventArgs<string>> TextChanging;
+
     /// <summary>Paste the selected text from the clipboard.</summary>
     public virtual void Paste ()
     {
@@ -1167,8 +1172,6 @@ public class TextField : View, IDesignable
     ///// </summary>
     //public event EventHandler<StateEventArgs<string>> TextChanged;
 
-    /// <summary>Changing event, raised before the <see cref="Text"/> changes and can be canceled or changing the new text.</summary>
-    public event EventHandler<CancelEventArgs<string>> TextChanging;
 
     /// <summary>Undoes the latest changes.</summary>
     public void Undo ()

+ 9 - 9
Terminal.Gui/Views/TextInput/TimeField.cs

@@ -432,15 +432,15 @@ public class TimeField : TextField
         return true;
     }
 
-    private void TextField_TextChanging (object sender, CancelEventArgs<string> e)
+    private void TextField_TextChanging (object sender, ResultEventArgs<string> e)
     {
         try
         {
             var spaces = 0;
 
-            for (var i = 0; i < e.NewValue.Length; i++)
+            for (var i = 0; i < e.Result.Length; i++)
             {
-                if (e.NewValue [i] == ' ')
+                if (e.Result [i] == ' ')
                 {
                     spaces++;
                 }
@@ -451,31 +451,31 @@ public class TimeField : TextField
             }
 
             spaces += FieldLength;
-            string trimmedText = e.NewValue [..spaces];
+            string trimmedText = e.Result [..spaces];
             spaces -= FieldLength;
             trimmedText = trimmedText.Replace (new string (' ', spaces), " ");
 
-            if (trimmedText != e.NewValue)
+            if (trimmedText != e.Result)
             {
-                e.NewValue = trimmedText;
+                e.Result = trimmedText;
             }
 
             if (!TimeSpan.TryParseExact (
-                                         e.NewValue.Trim (),
+                                         e.Result.Trim (),
                                          Format.Trim (),
                                          CultureInfo.CurrentCulture,
                                          TimeSpanStyles.None,
                                          out TimeSpan result
                                         ))
             {
-                e.Cancel = true;
+                e.Handled = true;
             }
 
             AdjCursorPosition (CursorPosition);
         }
         catch (Exception)
         {
-            e.Cancel = true;
+            e.Handled = true;
         }
     }
 }

+ 1 - 0
Terminal.Gui/Views/View.cs

@@ -0,0 +1 @@
+ 

+ 1 - 1
Terminal.Gui/Views/Wizard/Wizard.cs

@@ -563,7 +563,7 @@ public class Wizard : Dialog
     {
         if (string.IsNullOrEmpty (_wizardTitle))
         {
-            _wizardTitle = e.CurrentValue;
+            _wizardTitle = e.Value;
         }
     }
 }

+ 2 - 0
Terminal.sln.DotSettings

@@ -381,6 +381,7 @@
 	<s:Boolean x:Key="/Default/CodeStyle/EditorConfig/EnableEditorConfigSupport/@EntryValue">False</s:Boolean>
 	<s:Boolean x:Key="/Default/CodeStyle/EditorConfig/ShowEditorConfigStatusBarIndicator/@EntryValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/CodeStyle/EditorConfig/SyncToVisualStudio/@EntryValue">True</s:Boolean>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CWP/@EntryIndexedValue">CWP</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LL/@EntryIndexedValue">LL</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LR/@EntryIndexedValue">LR</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
@@ -411,6 +412,7 @@
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
 	<s:Int64 x:Key="/Default/Environment/UnitTesting/ParallelProcessesCount/@EntryValue">5</s:Int64>
+	<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=Attribute_0020attribute/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Gainsboro/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Gonek/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Guppie/@EntryIndexedValue">True</s:Boolean>

+ 2 - 2
Tests/IntegrationTests/UICatalog/ScenarioTests.cs

@@ -87,7 +87,7 @@ public class ScenarioTests : TestsAllViews
 
         void OnApplicationOnInitializedChanged (object? s, EventArgs<bool> a)
         {
-            if (a.CurrentValue)
+            if (a.Value)
             {
                 Application.Iteration += OnApplicationOnIteration;
                 initialized = true;
@@ -103,7 +103,7 @@ public class ScenarioTests : TestsAllViews
                 shutdownGracefully = true;
             }
 
-            _output.WriteLine ($"Initialized == {a.CurrentValue}; shutdownGracefully == {shutdownGracefully}.");
+            _output.WriteLine ($"Initialized == {a.Value}; shutdownGracefully == {shutdownGracefully}.");
         }
 
         // If the scenario doesn't close within abortTime ms, this will force it to quit

+ 3 - 3
Tests/StressTests/ScenariosStressTests.cs

@@ -90,7 +90,7 @@ public class ScenariosStressTests : TestsAllViews
 
         void OnApplicationOnInitializedChanged (object? s, EventArgs<bool> a)
         {
-            if (a.CurrentValue)
+            if (a.Value)
             {
                 lock (_timeoutLock)
                 {
@@ -106,7 +106,7 @@ public class ScenariosStressTests : TestsAllViews
                                      {
                                          refreshedCount++;
 
-                                         if (args.CurrentValue)
+                                         if (args.Value)
                                          {
                                              updatedCount++;
                                          }
@@ -124,7 +124,7 @@ public class ScenariosStressTests : TestsAllViews
                 stopwatch!.Stop ();
             }
 
-            _output.WriteLine ($"Initialized == {a.CurrentValue}");
+            _output.WriteLine ($"Initialized == {a.Value}");
         }
 
         void OnApplicationOnIteration (object? s, IterationEventArgs a)

部分文件因为文件数量过多而无法显示