Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 245 additions & 0 deletions docs/analysis/ISSUE_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
# CWP Order Analysis - Summary for Issue Discussion

## Overview

I've completed a comprehensive analysis of the Cancellable Work Pattern (CWP) order in the Terminal.Gui codebase as requested in this issue. The analysis covers:

1. Every CWP implementation in the codebase
2. Impact assessment of reversing the order
3. Code dependencies on the current order
4. Four solution options with detailed pros/cons
5. Concrete recommendations with implementation plans

## Full Analysis Documents

The complete analysis is available in the repository under `docs/analysis/`:

- **[README.md](../analysis/README.md)** - Overview and navigation guide
- **[cwp_analysis_report.md](../analysis/cwp_analysis_report.md)** - Executive summary with statistics
- **[cwp_detailed_code_analysis.md](../analysis/cwp_detailed_code_analysis.md)** - Technical deep-dive
- **[cwp_recommendations.md](../analysis/cwp_recommendations.md)** - Implementation guidance

## Key Findings

### Scale of CWP Usage

- **33+ CWP event pairs** found across the codebase
- **100+ virtual method overrides** in views that depend on current order
- **3 helper classes** implement the pattern (CWPWorkflowHelper, etc.)
- **Explicit tests** validate current order (OrientationTests)
- **Code comments** document current order as "best practice"

### CWP Categories by Impact

| Impact Level | Count | Examples |
|-------------|-------|----------|
| HIGH | 3 | OnMouseEvent, OnMouseClick, OnKeyDown |
| MEDIUM-HIGH | 4 | OnAccepting, OnSelecting, OnAdvancingFocus, OnHasFocusChanging |
| MEDIUM | 8 | OnMouseWheel, OnMouseEnter, OnKeyUp, various commands |
| LOW-MEDIUM | 10 | Property changes, view-specific events |
| LOW | 8 | Specialized/rare events |

### Dependencies on Current Order

1. **Explicit in Code**: Comments state current order is "best practice"
2. **Explicit in Tests**: Tests verify virtual method called before event
3. **Implicit in Views**: 100+ overrides assume they get first access
4. **Implicit in State Management**: Views update state first, then external code sees updated state

### The Core Problem (Issue #3714)

Views like `Slider` override `OnMouseEvent` and return `true`, preventing external code from ever seeing the event:

```csharp
// What users WANT but CANNOT do today:
slider.MouseEvent += (sender, args) =>
{
if (shouldDisable)
args.Handled = true; // TOO LATE - Slider.OnMouseEvent already handled it
};
```

## Four Solution Options

### Option 1: Reverse Order Globally ⚠️

**Change all 33+ CWP patterns** to call event first, virtual method second.

- **Effort**: 4-6 weeks
- **Risk**: VERY HIGH (major breaking change)
- **Verdict**: ❌ NOT RECOMMENDED unless major version change

**Why Not**: Breaks 100+ view overrides, changes fundamental framework philosophy, requires extensive testing, may break user code.

### Option 2: Add "Before" Events 🎯 RECOMMENDED

**Add new events** (e.g., `BeforeMouseEvent`) that fire before virtual method.

```csharp
// Three-phase pattern:
// 1. BeforeMouseEvent (external pre-processing) ← NEW
// 2. OnMouseEvent (view processing) ← EXISTING
// 3. MouseEvent (external post-processing) ← EXISTING
```

- **Effort**: 2-3 weeks
- **Risk**: LOW (non-breaking, additive only)
- **Verdict**: ✅ **RECOMMENDED**

**Why Yes**: Solves #3714, non-breaking, clear intent, selective application, provides migration path.

### Option 3: Add `MouseInputEnabled` Property 🔧

**Add property** to View to disable mouse handling entirely.

- **Effort**: 1 week
- **Risk**: VERY LOW
- **Verdict**: ⚠️ Band-aid solution, acceptable short-term

**Why Maybe**: Quick fix for immediate issue, but doesn't address root cause or help keyboard/other events.

### Option 4: Reverse Order for Mouse Only 🎯

**Reverse order** for mouse events only, keep keyboard/others unchanged.

- **Effort**: 2 weeks
- **Risk**: MEDIUM (still breaking for mouse)
- **Verdict**: ⚠️ Inconsistent pattern, Option 2 is cleaner

**Why Not**: Creates inconsistency, still breaks mouse event overrides, doesn't help future similar issues.

## Recommended Solution: Option 2

### Implementation Overview

Add new `BeforeXxx` events that fire BEFORE virtual methods:

```csharp
public partial class View // Mouse APIs
{
public event EventHandler<MouseEventArgs>? BeforeMouseEvent;
public event EventHandler<MouseEventArgs>? BeforeMouseClick;

public bool RaiseMouseEvent(MouseEventArgs mouseEvent)
{
// Phase 1: Before event (NEW) - external pre-processing
BeforeMouseEvent?.Invoke(this, mouseEvent);
if (mouseEvent.Handled)
return true;

// Phase 2: Virtual method (EXISTING) - view processing
if (OnMouseEvent(mouseEvent) || mouseEvent.Handled)
return true;

// Phase 3: After event (EXISTING) - external post-processing
MouseEvent?.Invoke(this, mouseEvent);
return mouseEvent.Handled;
}
}
```

### Usage Example (Solves #3714)

```csharp
var slider = new Slider();

// NOW THIS WORKS!
slider.BeforeMouseEvent += (sender, args) =>
{
if (shouldDisableSlider)
{
args.Handled = true; // Prevents Slider.OnMouseEvent from being called
}
};
```

### Benefits

1. ✅ **Solves #3714**: External code can now prevent views from handling events
2. ✅ **Non-Breaking**: All existing code continues to work
3. ✅ **Clear Intent**: "Before" explicitly means "external pre-processing"
4. ✅ **Selective**: Add to problematic events (mouse, keyboard), not all 33
5. ✅ **Future-Proof**: Provides migration path for v3.0
6. ✅ **Minimal Risk**: Additive only, no changes to existing behavior

### Implementation Checklist

- [ ] Week 1: Add BeforeMouseEvent, BeforeMouseClick, BeforeMouseWheel
- [ ] Week 2: Update documentation (events.md, cancellable-work-pattern.md)
- [ ] Week 3: Add BeforeKeyDown if needed
- [ ] Week 4: Testing and refinement

## Comparison Table

| Aspect | Option 1: Reverse Order | Option 2: Before Events | Option 3: Property | Option 4: Mouse Only |
|--------|------------------------|------------------------|-------------------|---------------------|
| Solves #3714 | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
| Breaking Change | ❌ Major | ✅ None | ✅ None | ⚠️ Medium |
| Consistency | ✅ Perfect | ⚠️ Two patterns | ⚠️ Band-aid | ❌ Inconsistent |
| Effort | ❌ 4-6 weeks | ✅ 2-3 weeks | ✅ 1 week | ⚠️ 2 weeks |
| Risk | ❌ Very High | ✅ Low | ✅ Very Low | ⚠️ Medium |
| Future-Proof | ✅ Yes | ✅ Yes | ❌ No | ⚠️ Partial |
| **Verdict** | ❌ Not Recommended | ✅ **RECOMMENDED** | ⚠️ Short-term only | ⚠️ Option 2 better |

## What About Just Fixing Slider?

**No** - this is a systemic issue affecting 30+ views:
- ListView, TextView, TextField
- TableView, TreeView
- ScrollBar, ScrollSlider
- MenuBar, TabRow
- ColorBar, HexView
- And 20+ more...

Any view that overrides `OnMouseEvent` has the same problem. We need a general solution.

## Design Philosophy Consideration

The current order reflects "inheritance over composition":
- Virtual methods (inheritance) get priority
- Events (composition) get second chance
- Appropriate for tightly-coupled UI framework

The proposed "Before" events enable "composition over inheritance" when needed:
- External code (composition) can prevent via BeforeXxx
- Virtual methods (inheritance) process if not prevented
- Events (composition) observe after processing
- Best of both worlds

## Next Steps

1. **Review** this analysis and recommendation
2. **Decide** on approach (recommend Option 2)
3. **Implement** if proceeding:
- Add BeforeMouseEvent, BeforeMouseClick, BeforeMouseWheel
- Update documentation with three-phase pattern
- Add tests validating new events
- Verify Slider scenario works as expected
4. **Document** decision and rationale

## Questions for Discussion

1. Do we agree Option 2 (Before Events) is the best approach?
2. Should we implement keyboard events at the same time, or mouse-only first?
3. Should we apply this pattern to commands/navigation events, or wait for user requests?
4. What should the naming convention be? (`BeforeXxx`, `PreXxx`, `XxxPre`?)
5. Should we mark old pattern as "legacy" in v3.0, or keep both indefinitely?

## Timeline

If we proceed with **Option 2**:

- **Week 1-2**: Implementation (mouse events)
- **Week 3**: Documentation
- **Week 4**: Testing and refinement
- **Total**: ~1 month to complete solution

## Conclusion

The analysis shows that **reversing CWP order globally would be a major breaking change** affecting 100+ locations. However, **adding "Before" events is a low-risk solution** that achieves the same goal without breaking existing code.

**Recommendation**: Proceed with Option 2 (Add Before Events)

---

For complete technical details, code examples, and implementation specifications, see the full analysis documents in `docs/analysis/`.
126 changes: 126 additions & 0 deletions docs/analysis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Cancellable Work Pattern (CWP) Order Analysis

This directory contains a comprehensive analysis of the Cancellable Work Pattern (CWP) in Terminal.Gui, specifically examining the question of whether to reverse the calling order from "virtual method first, event second" to "event first, virtual method second."

## Documents in This Analysis

### 1. [CWP Analysis Report](cwp_analysis_report.md)
**Executive-level overview** of the analysis with:
- Summary statistics (33+ CWP implementations found)
- Impact assessment by category (mouse, keyboard, commands, etc.)
- Analysis of each CWP implementation
- Risk assessment by impact level
- Four solution options with pros/cons
- Recommendations

**Read this first** for high-level understanding.

### 2. [CWP Detailed Code Analysis](cwp_detailed_code_analysis.md)
**Technical deep-dive** with:
- Code examples of current implementation
- Detailed explanation of Slider mouse event issue (#3714)
- Complete catalog of all CWP implementations
- Analysis of helper classes (CWPWorkflowHelper, etc.)
- Documentation review
- Dependencies on current order
- Breaking change assessment

**Read this second** for technical details.

### 3. [CWP Recommendations](cwp_recommendations.md)
**Implementation guidance** with:
- Detailed comparison of 4 solution options
- Recommended approach (Option 2: Add Before Events)
- Complete implementation specification
- Code examples showing solution
- Migration path
- Testing strategy
- Implementation checklist

**Read this third** for actionable recommendations.

## Quick Summary

### The Issue
External code cannot prevent views (like Slider) from handling events because the virtual method (e.g., `OnMouseEvent`) is called before the event is raised, allowing the view to mark the event as handled before external subscribers see it.

### Analysis Results
- **33+ CWP implementations** found across codebase
- **100+ virtual method overrides** depend on current order
- **HIGH IMPACT** change if order reversed globally
- **Tests explicitly validate** current order
- **Code comments document** current order as "best practice"

### Recommended Solution: **Add "Before" Events** ✅

Instead of changing the existing pattern (breaking change), ADD new events:
- `BeforeMouseEvent`, `BeforeMouseClick`, etc.
- Called BEFORE virtual method
- Allows external code to cancel before view processes
- Non-breaking, additive change
- Solves issue #3714 completely

**Effort**: 2-3 weeks
**Risk**: LOW
**Breaking Changes**: None

### Implementation Example

```csharp
// What users want and NOW CAN DO:
var slider = new Slider();

slider.BeforeMouseEvent += (sender, args) =>
{
if (shouldDisableSlider)
{
args.Handled = true; // Prevents Slider.OnMouseEvent from being called
}
};
```

### Three-Phase Pattern

```
1. BeforeXxx event → External pre-processing (NEW)
2. OnXxx method → View processing (EXISTING)
3. Xxx event → External post-processing (EXISTING)
```

## For Issue Maintainers

This analysis was requested in issue #3714 to:
> "Use the AIs to do an analysis of the entire code base, creating a report of EVERY instance where CWP-style eventing is used and what the potential impact of changing the CWP guidance would be."

The analysis is complete and recommends **Option 2 (Add Before Events)** as the best balance of:
- Solving the issue
- Minimizing risk
- Preserving existing behavior
- Providing migration path

## Next Steps

1. Review analysis and recommendation
2. Decide on approach
3. If proceeding with Option 2:
- Implement BeforeMouseEvent, BeforeMouseClick, BeforeMouseWheel
- Update documentation
- Add tests
- Verify Slider scenario works
4. If proceeding with alternative:
- Document rationale
- Implement chosen solution

## Files Changed During Analysis

- ❌ No production code changed (analysis only)
- ✅ Analysis documents created (this directory)

## Related Issues

- #3714: Cancellable Work Pattern order issue (mouse events)
- #3417: Related mouse event handling issue

## Date of Analysis

Generated: 2024 (exact date in git history)
Loading