# Cancellable Work Pattern (CWP) Analysis Report ## Executive Summary This report analyzes all instances of the Cancellable Work Pattern (CWP) in the Terminal.Gui codebase to assess the potential impact of reversing the calling order from: - **Current**: Virtual method first → Event second - **Proposed**: Event first → Virtual method second ## Background The CWP pattern currently calls the virtual method (`OnXxx`) before invoking the event (`Xxx`). This gives inherited code (via override) priority over external code (via event subscription). Issue #3714 raises concerns about this order, particularly for mouse events where external code cannot prevent events from reaching overridden methods in views. ## Analysis Methodology 1. Identified all `protected virtual bool OnXxx` methods in Terminal.Gui 2. Located their corresponding event invocations 3. Analyzed the calling context and dependencies 4. Assessed impact of order reversal ## Detailed Analysis ### 1. Mouse Events #### 1.1 OnMouseEvent / MouseEvent **File**: `Terminal.Gui/ViewBase/View.Mouse.cs:348` **Calling Context**: ```csharp public bool RaiseMouseEvent (MouseEventArgs mouseEvent) { if (OnMouseEvent (mouseEvent) || mouseEvent.Handled) { return true; } MouseEvent?.Invoke (this, mouseEvent); return mouseEvent.Handled; } ``` **Current Order**: `OnMouseEvent` → `MouseEvent` **Impact Analysis**: - **HIGH IMPACT**: This is the primary mouse event handler - **Problem**: Views like `Slider` that override `OnMouseEvent` cannot be prevented from handling mouse events by external code - **Dependencies**: Many views override `OnMouseEvent` expecting priority - **Reversing Order Would**: - Allow external code to cancel before view's override processes - Break existing assumptions in views that expect first access - Require review of all `OnMouseEvent` overrides #### 1.2 OnMouseClick / MouseClick **File**: `Terminal.Gui/ViewBase/View.Mouse.cs:515` **Calling Context**: ```csharp protected bool RaiseMouseClickEvent (MouseEventArgs args) { if (OnMouseClick (args) || args.Handled) { return args.Handled; } MouseClick?.Invoke (this, args); // ... } ``` **Current Order**: `OnMouseClick` → `MouseClick` **Impact Analysis**: - **HIGH IMPACT**: Same issue as `OnMouseEvent` - **Problem**: External code cannot prevent clicks from reaching view's override - **Reversing Order Would**: - Enable external mouse click prevention - Consistent with `OnMouseEvent` changes - Requires coordination with all click handlers #### 1.3 OnMouseEnter / MouseEnter **File**: `Terminal.Gui/ViewBase/View.Mouse.cs:125` **Calling Context**: ```csharp internal bool? NewMouseEnterEvent (CancelEventArgs eventArgs) { if (OnMouseEnter (eventArgs)) { return true; } MouseEnter?.Invoke (this, eventArgs); // ... } ``` **Current Order**: `OnMouseEnter` → `MouseEnter` **Impact Analysis**: - **MEDIUM IMPACT**: Less commonly overridden - **Reversing Order Would**: - Allow external code to prevent enter notifications - Minimal breaking changes expected #### 1.4 OnMouseWheel / MouseWheel **File**: `Terminal.Gui/ViewBase/View.Mouse.cs:610` **Calling Context**: ```csharp protected bool RaiseMouseWheelEvent (MouseEventArgs args) { if (OnMouseWheel (args) || args.Handled) { return args.Handled; } MouseWheel?.Invoke (this, args); // ... } ``` **Current Order**: `OnMouseWheel` → `MouseWheel` **Impact Analysis**: - **MEDIUM IMPACT**: Wheel handling is specific - **Reversing Order Would**: - Enable external scroll prevention - Useful for modal dialogs or locked views ### 2. Keyboard Events #### 2.1 OnKeyDown / KeyDown **File**: `Terminal.Gui/ViewBase/View.Keyboard.cs:367` **Calling Context**: ```csharp public bool NewKeyDownEvent (Key k) { if (OnKeyDown (k) || k.Handled) { return true; } KeyDown?.Invoke (this, k); return k.Handled; } ``` **Current Order**: `OnKeyDown` → `KeyDown` **Impact Analysis**: - **HIGH IMPACT**: Core keyboard input handling - **Dependencies**: Many views override for input processing - **Reversing Order Would**: - Allow external key interception before view processing - Could break views expecting first access to keys - Major behavioral change for input handling #### 2.2 OnKeyDownNotHandled / KeyDownNotHandled **File**: `Terminal.Gui/ViewBase/View.Keyboard.cs:399` **Current Order**: `OnKeyDownNotHandled` → `KeyDownNotHandled` **Impact Analysis**: - **LOW IMPACT**: Secondary handler for unhandled keys - **Reversing Order Would**: - Minor change, already handles unhandled keys - Low risk #### 2.3 OnKeyUp / KeyUp **File**: `Terminal.Gui/ViewBase/View.Keyboard.cs` (implementation in NewKeyUpEvent) **Current Order**: `OnKeyUp` → `KeyUp` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: Less commonly used than KeyDown - **Reversing Order Would**: - Enable external key-up prevention - Lower risk than KeyDown ### 3. Command Events #### 3.1 OnAccepting / Accepting **File**: `Terminal.Gui/ViewBase/View.Command.cs:190` **Impact Analysis**: - **MEDIUM-HIGH IMPACT**: Core command pattern - **Used by**: CheckBox, RadioGroup, Button, etc. - **Reversing Order Would**: - Allow external cancellation before view logic - May break views expecting to set state first #### 3.2 OnSelecting / Selecting **File**: `Terminal.Gui/ViewBase/View.Command.cs:245` **Impact Analysis**: - **MEDIUM IMPACT**: Selection behavior - **Reversing Order Would**: - Enable external selection control - Useful for validation scenarios #### 3.3 OnHandlingHotKey / HandlingHotKey **File**: `Terminal.Gui/ViewBase/View.Command.cs:291` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: HotKey processing - **Reversing Order Would**: - Allow hotkey override by external code - Could be useful for dynamic hotkey management #### 3.4 OnCommandNotBound / CommandNotBound **File**: `Terminal.Gui/ViewBase/View.Command.cs:93` **Impact Analysis**: - **LOW IMPACT**: Fallback for unmapped commands - **Reversing Order Would**: - Minor impact, handles unbound commands ### 4. Drawing Events #### 4.1 Drawing Pipeline Events **Files**: `Terminal.Gui/ViewBase/View.Drawing.cs` - `OnDrawingAdornments` / `DrawingAdornments` - `OnClearingViewport` / `ClearingViewport` - `OnDrawingText` / `DrawingText` - `OnDrawingContent` / `DrawingContent` - `OnDrawingSubViews` / `DrawingSubViews` - `OnRenderingLineCanvas` / `RenderingLineCanvas` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: Rendering customization - **Reversing Order Would**: - Allow external drawing interception - Useful for debugging/tracing - Lower risk as drawing is less state-dependent ### 5. Navigation Events #### 5.1 OnAdvancingFocus / AdvancingFocus **File**: `Terminal.Gui/ViewBase/View.Navigation.cs:208` **Impact Analysis**: - **MEDIUM-HIGH IMPACT**: Focus management - **Reversing Order Would**: - Allow external focus control - Could break focus flow expectations #### 5.2 OnHasFocusChanging / HasFocusChanging **File**: `Terminal.Gui/ViewBase/View.Navigation.cs:717` **Impact Analysis**: - **MEDIUM-HIGH IMPACT**: Focus state management - **Reversing Order Would**: - Enable external focus validation - Useful for preventing focus changes ### 6. Property Change Events #### 6.1 OnSchemeNameChanging / SchemeNameChanging **File**: `Terminal.Gui/ViewBase/View.Drawing.Scheme.cs:51` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: Scheme change validation - **Uses**: `CWPPropertyHelper` - **Reversing Order Would**: - Allow external scheme validation - Low risk #### 6.2 OnGettingScheme / GettingScheme **File**: `Terminal.Gui/ViewBase/View.Drawing.Scheme.cs:170` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: Scheme resolution - **Reversing Order Would**: - Allow external scheme override - Useful for theming #### 6.3 OnSettingScheme / SettingScheme **File**: `Terminal.Gui/ViewBase/View.Drawing.Scheme.cs:241` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: Scheme application - **Reversing Order Would**: - Enable external scheme interception - Low risk #### 6.4 OnVisibleChanging / VisibleChanging **File**: `Terminal.Gui/ViewBase/View.cs:382` **Impact Analysis**: - **MEDIUM IMPACT**: Visibility state management - **Reversing Order Would**: - Allow external visibility control - Could affect layout calculations #### 6.5 OnOrientationChanging (commented out) **File**: `Terminal.Gui/ViewBase/Orientation/OrientationHelper.cs:166` **Impact Analysis**: - **N/A**: Currently commented out - **Note**: OrientationHelper uses callback pattern ### 7. View-Specific Events #### 7.1 OnCellActivated (TableView) **File**: `Terminal.Gui/Views/TableView/TableView.cs:1277` **Impact Analysis**: - **LOW IMPACT**: TableView-specific - **Reversing Order Would**: - Allow external cell activation control - Isolated to TableView #### 7.2 OnPositionChanging (ScrollBar, ScrollSlider) **Files**: - `Terminal.Gui/Views/ScrollBar/ScrollBar.cs:375` - `Terminal.Gui/Views/ScrollBar/ScrollSlider.cs:245` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: Scrollbar-specific - **Reversing Order Would**: - Enable external scroll validation - Useful for scroll constraints #### 7.3 OnCheckedStateChanging (CheckBox) **File**: `Terminal.Gui/Views/CheckBox.cs:187` **Impact Analysis**: - **LOW-MEDIUM IMPACT**: CheckBox state management - **Reversing Order Would**: - Allow external state validation - Useful for validation logic ### 8. Other Events #### 8.1 OnBorderStyleChanged **File**: `Terminal.Gui/ViewBase/View.Adornments.cs:162` **Impact Analysis**: - **LOW IMPACT**: Border styling - **Reversing Order Would**: - Enable external border control - Minimal risk #### 8.2 OnMouseIsHeldDownTick (MouseHeldDown) **File**: `Terminal.Gui/ViewBase/MouseHeldDown.cs:71` **Impact Analysis**: - **LOW IMPACT**: Continuous mouse press - **Reversing Order Would**: - Allow external hold-down control - Minimal risk #### 8.3 OnGettingAttributeForRole **File**: `Terminal.Gui/ViewBase/View.Drawing.Attribute.cs:78` **Impact Analysis**: - **LOW IMPACT**: Attribute resolution - **Reversing Order Would**: - Enable external attribute override - Useful for accessibility ## Summary Statistics **Total CWP Implementations Found**: 33 **By Impact Level**: - **HIGH IMPACT**: 3 (Mouse/Keyboard core events) - **MEDIUM-HIGH IMPACT**: 4 (Commands, Navigation) - **MEDIUM IMPACT**: 8 (Various UI events) - **LOW-MEDIUM IMPACT**: 10 (Property changes, view-specific) - **LOW IMPACT**: 8 (Specialized/rare events) ## Code Dependencies on Current Order ### Tests That Validate Order Located in `Tests/UnitTestsParallelizable/View/Orientation/OrientationTests.cs`: ```csharp [Fact] public void OrientationChanging_VirtualMethodCalledBeforeEvent() { // Test explicitly validates virtual method is called before event } [Fact] public void OrientationChanged_VirtualMethodCalledBeforeEvent() { // Test explicitly validates virtual method is called before event } ``` **Impact**: These tests will FAIL if order is reversed - they explicitly test current behavior. ### Views With Override Dependencies Based on code search, many views override these methods and may depend on being called first: - `Slider.OnMouseEvent` - Core issue from #3714 - Various views override `OnKeyDown` for input handling - Command handlers in Button, CheckBox, RadioGroup - Custom drawing in various views ## Recommendations ### Option 1: Reverse Order Globally **Pros**: - Solves #3714 completely - Consistent pattern across all events - External code gets priority (looser coupling) **Cons**: - MAJOR BREAKING CHANGE - Requires updating all views that override CWP methods - Extensive testing required - May break user code **Effort**: HIGH (4-6 weeks) **Risk**: HIGH ### Option 2: Add "Before" Events **Pros**: - Non-breaking - Explicit control for when needed - Gradual migration path **Cons**: - More API surface - Complexity in naming/documentation - Two patterns coexist **Effort**: MEDIUM (2-3 weeks) **Risk**: LOW ### Option 3: Add `IgnoreMouse` Property **Pros**: - Minimal change - Solves immediate #3714 issue - No breaking changes **Cons**: - Band-aid solution - Doesn't address root cause - Only solves mouse issue **Effort**: LOW (1 week) **Risk**: VERY LOW ### Option 4: Reverse Order for Mouse Events Only **Pros**: - Solves #3714 - Limited scope reduces risk - Mouse is primary concern **Cons**: - Inconsistent pattern - Still breaking for mouse overrides - Confusion with different orders **Effort**: MEDIUM (2 weeks) **Risk**: MEDIUM ## Conclusion The analysis reveals that reversing CWP order globally would be a **significant breaking change** affecting 33+ event pairs across the codebase. The **highest impact** would be on: 1. **Mouse events** (OnMouseEvent, OnMouseClick) - direct issue #3714 2. **Keyboard events** (OnKeyDown) - core input handling 3. **Command events** (OnAccepting, OnSelecting) - state management 4. **Navigation events** (OnAdvancingFocus, OnHasFocusChanging) - focus flow **Recommended Approach**: - **Short-term**: Option 3 (IgnoreMouse property) or Option 2 (Before events for mouse only) - **Long-term**: Consider Option 2 with gradual migration, or accept current design as intentional The current design prioritizes **inheritance over composition**, which may be appropriate for a UI framework where tight coupling through inheritance is common. However, it limits external control, which is the root cause of #3714. ## Next Steps 1. Review this analysis with maintainers 2. Decide on approach based on project priorities 3. If proceeding with order reversal: - Create comprehensive test plan - Update all affected views - Update documentation - Provide migration guide 4. If proceeding with alternative: - Implement chosen solution - Update documentation with rationale - Add examples for working around current limitation