Skip to content

Latest commit

 

History

History
866 lines (676 loc) · 33.4 KB

File metadata and controls

866 lines (676 loc) · 33.4 KB

Interactive Editor - Architecture Recommendations

Date: December 5, 2025
Last Updated: December 11, 2025
Scope: Phase 2+ development (phase-agnostic architectural decisions)
Context: Phase 1 interactive editor completed successfully. This document outlines architectural considerations for ongoing development.


Critical Update: Baseline Storage Architecture ✅ COMPLETE (December 11, 2025)

Executive Summary

Status: ✅ Completed in v2.1.2

Problem: Index-based baseline storage was fragile and caused critical undo bugs in v2.1.1.

Solution: Migrated to time-keyed dictionary storage.

Results:

  • ✅ Prevents entire class of index-related bugs
  • ✅ Simplified insert/delete operations (5 dict ops vs 12 array ops)
  • ✅ Made corruption impossible (separate data structure from model)
  • ✅ All tests passing

Detailed Documentation: See architecture/baseline_storage_refactoring.md


Critical Update: GUI Flexibility Architecture (December 10, 2025)

Executive Summary

Decision: Migrate to QDockWidget-based architecture for GUI panels to support Phase 3 (M2 integration) and beyond.

Rationale:

  • Phase 3 adds M2 (partner perspective) requiring dual-perspective visualization
  • Space constraints: Cannot double horizontal space for separate M1/M2 panels
  • Solution: Overlay M1 and M2 on same graphs with active/inactive visual states
  • Future features (statistics, help, analysis) need flexible workspace management

Impact: This is foundational infrastructure, not optional. Without flexible GUI architecture:

  • ❌ M2 integration will be cramped and unusable on laptop screens
  • ❌ Future instrumentation panels cannot be added/removed/resized
  • ❌ Professional workflow (multi-monitor, custom layouts) not supported

GUI Flexibility Requirements

Core Needs:

  1. Resizable panels - User control over primitive/trajectory panel sizes
  2. Movable panels - Drag panels to rearrange workspace
  3. Hideable panels - Show/hide panels based on current task
  4. Detachable panels - Undock to separate windows for multi-monitor setups
  5. Layout persistence - Save/restore user's custom workspace configuration

Future Extensibility:

  • Statistics panel (bond metrics, trajectory analysis)
  • Debug instrumentation panel (solver diagnostics)
  • Help/documentation panel (context-sensitive guidance)
  • Analysis window (Phase 4 - separate synchronized window)

M2 Integration Architecture (Phase 3)

Challenge: Adding M2 (partner perspective) would require double the horizontal space if implemented as separate panels.

Solution: Overlay Visualization

Concept:

  • M1 and M2 share the same primitive and gamma_self graphs
  • One perspective is "active" (editable), one is "inactive" (read-only context)
  • Visual differentiation through line styles, opacity, and marker states
  • Perspective switcher (radio buttons) controls which perspective is active

Visual Design:

State Line Style Marker Style Opacity Interactivity Color Indicator
Active Bold (width=2) Solid fill 1.0 Draggable Red glow
Inactive Thin/Dashed (width=1) Hollow 0.4 Read-only Grey

Perspective Switcher:

  • Widget Type: Radio buttons (QRadioButton group)
  • Placement: Toolbar (QToolBar) - recommended for visibility
  • Active State: Red glow (#FF4444 or #E74C3C)
  • Inactive State: Grey (#9E9E9E or #BDBDBD)
  • Keyboard Shortcut: Tab or Space to toggle between M1/M2
  • Label: "Editing: ⦿ M1 ○ M2" (filled circle = active)

Interaction Model:

  • Drag events only affect active perspective
  • Click events (lock/unlock, marker selection) only target active perspective
  • Both perspectives visible simultaneously for context
  • Z-order: Active perspective renders on top (higher z-order)

Benefits:

  • ✅ Saves 50% horizontal space (no separate panels needed)
  • ✅ Maintains context (see both perspectives simultaneously)
  • ✅ Clear focus (one editable, one reference)
  • ✅ Reduces implementation complexity vs. dual-panel system
  • ✅ Natural workflow (toggle between perspectives like layers)

QDockWidget Architecture

Why QDockWidget (not QSplitter):

Feature QSplitter QDockWidget
Resize panels ✅ Yes ✅ Yes
Rearrange panels ❌ No ✅ Yes
Hide/show panels ⚠️ Collapse only ✅ Full hide
Undock to windows ❌ No ✅ Yes
Multi-monitor ❌ Limited ✅ Full support
Tab panels ❌ No ✅ Yes
Layout persistence ⚠️ Manual ✅ Qt automatic
Flexibility ⚠️ Moderate (7/10) ✅ Maximum (10/10)

QDockWidget Features:

  • Users can resize by dragging dividers
  • Users can rearrange by dragging dock title bars
  • Users can hide/show via View menu
  • Users can detach to separate windows (multi-monitor workflows)
  • Users can tab panels together (save space)
  • Qt automatically saves/restores layouts via QSettings
  • Professional application standard (Qt Creator, Visual Studio, etc.)

Implementation Plan:

class InteractiveEditorQt(QMainWindow):
    def __init__(self):
        super().__init__()
        
        # Create dock widgets
        self.primitive_dock = QDockWidget("Primitives", self)
        self.primitive_dock.setWidget(self.primitive_panel)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.primitive_dock)
        
        self.trajectory_dock = QDockWidget("Trajectory (gamma_self)", self)
        self.trajectory_dock.setWidget(self.trajectory_panel)
        self.addDockWidget(Qt.RightDockWidgetArea, self.trajectory_dock)
        
        # Create View menu for show/hide
        view_menu = self.menuBar().addMenu("View")
        view_menu.addAction(self.primitive_dock.toggleViewAction())
        view_menu.addAction(self.trajectory_dock.toggleViewAction())
        
        # Layout persistence
        self.restore_layout()  # QSettings-based

Migration Effort: 3-4 hours

  • Wrap existing panels in QDockWidget containers
  • Add View menu with show/hide actions
  • Implement save/restore layout (Qt provides this)
  • Set sensible defaults (vertical split, equal sizes)

Phase 3 Implementation Timeline

Phase 3.1: QDockWidget Foundation (3-4 hours)

  • ✅ Wrap primitive_panel in QDockWidget
  • ✅ Wrap trajectory_panel in QDockWidget
  • ✅ Add View menu with panel toggles
  • ✅ Implement layout save/restore
  • ✅ Test resize, rearrange, hide/show, undock workflows
  • Result: Current functionality + flexible workspace

Phase 3.2: Perspective Switcher (2 hours)

  • ✅ Create PerspectiveSwitcher widget (QRadioButton group)
  • ✅ Add to toolbar (QToolBar)
  • ✅ Style active=red glow, inactive=grey
  • ✅ Connect to controller.switch_perspective()
  • ✅ Add keyboard shortcut (QShortcut: Tab or Space)
  • Result: Can switch perspectives (M2 rendering not yet implemented)

Phase 3.3: M2 Overlay Rendering (3-4 hours)

  • ✅ Primitive panel renders both M1 and M2 datasets
  • ✅ Apply active/inactive visual styles (opacity, line width, marker fill)
  • ✅ Filter interactions to active perspective only
  • ✅ Trajectory panel shows both trajectories with differentiated styles
  • ✅ Z-order management (active front, inactive back)
  • Result: Full M2 support with overlay UX

Phase 3.4: Data Model Updates (2 hours)

  • ✅ EditorModel tracks both M1 and M2 events
  • ✅ CSV format extended for M2 columns (or separate CSV)
  • ✅ Save/load both perspectives
  • ✅ Observer pattern handles dual-perspective updates
  • Result: Complete M2 data persistence

Total Phase 3 Effort: ~10-12 hours


Future Features Roadmap (Phase 4)

Pop-up Dialogs:

  1. Marker Properties Dialog

    • Trigger: Click primitive marker
    • Content: Event time, primitive value, notes field
    • Actions: Edit value, add/edit notes, delete event
    • Implementation: QDialog with QFormLayout (~2 hours)
  2. Gamma Marker Inspector

    • Trigger: Click gamma_self trajectory marker
    • Content: Time, gamma_self (real, imag), notes
    • Actions: View/edit annotations
    • Implementation: QDialog similar to marker properties (~1 hour)
  3. Settings Dialog

    • Trigger: Edit → Settings menu
    • Content: Weights, colors, layout preferences
    • Actions: Modify configuration, reset to defaults
    • Implementation: QDialog with tabs (QTabWidget) (~3 hours)
  4. Help System

    • Trigger: Help menu or F1 key
    • Content: User guide, keyboard shortcuts, feature explanations
    • Implementation: QTextBrowser or embedded web view (~2 hours)

Additional Dock Panels:

  1. Statistics Panel

    • Content: Bond metrics, trajectory analysis, event counts
    • Updates: Real-time via observer pattern
    • Implementation: QDockWidget with QTableWidget (~3 hours)
  2. Debug Instrumentation Panel

    • Content: Solver diagnostics, cache statistics, performance metrics
    • Toggle: Developer mode only
    • Implementation: QDockWidget with QTreeWidget (~4 hours)

Separate Windows:

  1. Analysis Window (Phase 4)
    • Purpose: Batch analysis, sensitivity studies, scenario comparison
    • Communication: Shared EditorModel + observer pattern
    • Implementation: Separate QMainWindow, synchronized updates (~8 hours)

Inverse Solver (Deferred to Phase 4)

  • Complexity: Very high with M2 (non-unique solutions, constraint satisfaction)
  • UI: Click-and-drag on gamma_self → suggest primitive adjustments
  • Algorithm: Constrained optimization, iterative solver
  • Implementation: ~15-20 hours (research + implementation)

Technical Design Decisions

Observer Pattern Integration:

  • ✅ Already implemented (December 7, 2025)
  • ✅ EditorModel uses ObservableDict for modified_primitives
  • ✅ Controller registers observers for cache invalidation
  • ✅ Ready for M2: Each perspective triggers updates automatically

Shared Model Approach:

  • Single EditorModel instance holds both M1 and M2 data
  • Perspective switcher changes active_perspective property
  • All UI components observe model changes
  • No duplicate model logic or synchronization code needed

Data Persistence:

  • Option A: Extended CSV with M2 columns (time, v_M1, r_M1, ..., v_M2, r_M2, ...)
  • Option B: Separate CSV files (scenario_M1.csv, scenario_M2.csv)
  • Recommendation: Option A for Phase 3 (simpler), Option B if datasets diverge significantly

Visual Rendering Strategy:

  • PyQtGraph supports multiple datasets per plot (addPlot with multiple calls)
  • Use PlotDataItem for each perspective with different pens/brushes
  • Set z-values to control rendering order (active=100, inactive=50)
  • Enable/disable mouse events per PlotDataItem for interaction filtering

Architecture Principles (Do Not Paint Into Corners)

1. Separation of Concerns

  • ✅ Model (data) independent of View (rendering) independent of Controller (logic)
  • ✅ Changes to one component don't cascade to others
  • ✅ Easy to swap UI frameworks if needed (though Qt is future-proof)

2. Observer Pattern for Reactivity

  • ✅ Components subscribe to model changes
  • ✅ Automatic updates eliminate manual synchronization bugs
  • ✅ Scales to unlimited observers (statistics panel, debug panel, analysis window)

3. Flexible Workspace

  • ✅ QDockWidget enables user customization
  • ✅ No hardcoded layouts or fixed panel sizes
  • ✅ Adapts to laptop, wide monitor, dual monitor setups automatically

4. Incremental Feature Addition

  • ✅ Pop-up dialogs add features without consuming main window space
  • ✅ Dock panels can be added/removed without refactoring existing code
  • ✅ Keyboard shortcuts and menu actions provide discoverability

5. Data Format Extensibility

  • ✅ CSV format supports additional columns (M2, notes, metadata)
  • ✅ Backward compatible: Old CSVs load fine (M2 defaults to None)
  • ✅ Forward compatible: New fields ignored by older versions

6. Performance Considerations

  • ✅ PyQtGraph for high-performance plotting (GPU-accelerated)
  • ✅ Debounced updates prevent excessive recomputation
  • ✅ Caching via observer pattern (only recompute when data changes)
  • ✅ Lazy loading for large scenarios (compute trajectories on demand)

7. Testability

  • ✅ Model has unit tests (test_model.py, test_observable.py)
  • ✅ Controller logic testable without GUI
  • ✅ Integration tests via QTest (Qt's testing framework)

Risk Assessment

Low Risk:

  • QDockWidget implementation (standard Qt pattern, well-documented)
  • Perspective switcher (simple widget, straightforward logic)
  • M2 overlay rendering (PyQtGraph supports multiple datasets natively)

Moderate Risk:

  • Z-order and interaction filtering (need careful testing)
  • Layout persistence edge cases (rare Qt bugs, easily worked around)
  • CSV format changes (backward compatibility requires validation)

High Risk (Deferred to Phase 4):

  • Inverse solver (non-unique solutions, algorithm research needed)
  • Analysis window synchronization (complex state management)
  • Large-scale scenario performance (100+ events, need profiling)

Mitigation:

  • Implement QDockWidget foundation first (enables everything else)
  • Test M2 overlay incrementally (M2 data → rendering → interaction)
  • Defer high-risk features until core architecture proven

Success Metrics

Phase 3.1 Success:

  • ✅ User can resize primitive and trajectory panels
  • ✅ User can rearrange panels (drag dock titles)
  • ✅ User can hide/show panels via View menu
  • ✅ User can undock panels to separate windows
  • ✅ Layout persists across editor sessions

Phase 3.2 Success:

  • ✅ Perspective switcher visible in toolbar
  • ✅ Red glow indicates active perspective
  • ✅ Grey indicates inactive perspective
  • ✅ Keyboard shortcut toggles perspectives
  • ✅ No crashes or visual glitches

Phase 3.3 Success:

  • ✅ M1 and M2 render on same graphs
  • ✅ Active perspective bold/solid, inactive thin/faded
  • ✅ Drag only affects active perspective
  • ✅ Click only affects active perspective
  • ✅ Both perspectives visible and distinguishable

Phase 3.4 Success:

  • ✅ Save CSV with both M1 and M2 data
  • ✅ Load CSV and restore both perspectives
  • ✅ Undo/redo works for both perspectives
  • ✅ Observer pattern updates both views automatically

Implementation Status Summary

December 10, 2025:

  • ✅ Phase 2.0 Complete: PySide6 migration, undo/redo (QUndoStack)
  • ✅ Phase 2.1 Complete: Diagnostic "what-if" markers
  • ✅ Observer pattern implemented (automatic cache invalidation)
  • ✅ Configuration system (user preferences via JSON)
  • ✅ Primitives module (single source of truth for metadata)
  • ⏳ Phase 3 Planning: QDockWidget + M2 overlay architecture designed

Current GUI Flexibility: 7/10 (functional but rigid layout)
Target GUI Flexibility: 10/10 (QDockWidget-based, fully flexible workspace)


Current Architecture Assessment

Phase 1 - What Works Well ✅

Strengths:

  • PySide6/PyQtGraph Foundation (Phase 2.0) - Professional Qt framework, high-performance plotting
  • Undo/Redo System (Phase 2.0) - QUndoStack with command pattern, keyboard shortcuts
  • Observer Pattern (Phase 2.1) - Automatic cache invalidation, reactive updates
  • Diagnostic Markers (Phase 2.1) - "What-if" analysis without modifying data
  • Clean MVC separation - Model (EditorModel), View (panels), Controller well separated
  • Centralized constants - editor_constants.py for all magic numbers
  • Utility functions - editor_utils.py with 9 helper methods, ~60 LOC saved
  • Configuration system - User preferences via JSON, backward compatible
  • Primitives module - Single source of truth for primitive metadata
  • Well-tested - 48 unit tests, 100% pass rate
  • Well-documented - Comprehensive user guide and inline comments

Current Stack (December 2025):

  • Python 3.8+ with PySide6 (Qt6) framework
  • PyQtGraph for high-performance plotting
  • QUndoStack for undo/redo
  • CSV-based data persistence with backward compatibility
  • Observer pattern for reactive updates

Phase 1-2 - Known Limitations ⚠️

1. Fixed Layout System

  • Issue: Panels use fixed QVBoxLayout/QHBoxLayout (cannot resize, rearrange, or hide)
  • Impact:
    • Users cannot customize workspace (laptop vs. wide monitor vs. dual monitor)
    • Future panels (statistics, debug, help) have no flexible space
    • M2 integration would require double horizontal space (cramped on small screens)
    • Professional workflows (detach panels, custom layouts) not supported

2. Single Perspective Only

  • Issue: Only M1 (individual perspective) currently supported
  • Impact:
    • Phase 3 will add M2 (partner perspective)
    • Dual perspectives need efficient visualization (cannot double UI width)
    • Need overlay design with active/inactive states

3. Limited Extensibility for Future Features

  • Issue: No architecture for additional panels, dialogs, or windows
  • Impact:
    • Marker properties dialog (edit notes, values) - no clear implementation path
    • Statistics panel - nowhere to place without refactoring layout
    • Help system - no pop-up or side panel support
    • Analysis window (Phase 4) - complex synchronization needed

Phase 2-3 Requirements & Challenges

Completed Phase 2 Features ✅

  1. ✅ PySide6 Migration - Professional Qt framework foundation
  2. ✅ Undo/Redo System - QUndoStack with keyboard shortcuts
  3. ✅ Diagnostic Markers - "What-if" analysis without data modification
  4. ✅ Observer Pattern - Automatic cache invalidation and reactive updates
  5. ✅ Configuration System - User preferences via JSON
  6. ✅ Primitives Module - Centralized primitive metadata

Planned Phase 3 Features (Critical for M2)

  1. ⏳ QDockWidget Architecture (Foundation)

    • Resizable, movable, hideable panels
    • Layout persistence (save/restore user workspace)
    • Multi-monitor support (undock to separate windows)
    • View menu for show/hide controls
  2. ⏳ M2 Integration (Dual-Perspective Support)

    • Overlay visualization (M1 and M2 on same graphs)
    • Perspective switcher (radio buttons with visual feedback)
    • Active/inactive visual states (bold vs. faded)
    • Interaction filtering (drag only affects active perspective)
    • Data model for both perspectives
  3. ⏳ Enhanced Dialogs (Space Management)

    • Marker properties dialog (edit values, add notes)
    • Gamma marker inspector (annotations)
    • Settings dialog (preferences, weights, colors)

Why QDockWidget Is Critical (Not Optional)

Why QDockWidget Is Critical (Not Optional)

Without QDockWidget (Current State):

  • ❌ Fixed layout: Cannot resize, rearrange, or hide panels
  • ❌ M2 space problem: Adding M2 doubles horizontal space → cramped on laptops
  • ❌ Future panels: No space for statistics, debug, help without refactoring
  • ❌ Professional workflows: No multi-monitor, detach, or custom layouts
  • ❌ User flexibility: One-size-fits-all layout doesn't adapt to different setups

With QDockWidget (Phase 3 Target):

  • ✅ Flexible workspace: Users control panel sizes, positions, visibility
  • ✅ M2 overlay: Share same graphs with active/inactive states (space-efficient)
  • ✅ Future-proof: Add statistics, debug, help panels as dockables (no refactoring)
  • ✅ Professional: Standard Qt pattern (Qt Creator, Visual Studio, Blender use this)
  • ✅ Automatic: Qt handles layout persistence, multi-monitor, all edge cases

Bottom Line: QDockWidget is foundational infrastructure for Phase 3+ success. Without it, M2 integration and future features will be constrained and awkward.


Recommendations (Updated December 10, 2025)

✅ Phase 2 Complete: Qt Foundation

Completed Migration:

  • ✅ PySide6 (Qt6) framework - professional GUI foundation
  • ✅ PyQtGraph plotting - high-performance, GPU-accelerated
  • ✅ QUndoStack - discrete undo/redo with keyboard shortcuts
  • ✅ Command pattern - prevents recursive undo bugs
  • ✅ Observer pattern - automatic updates via ObservableDict

Migration Duration: ~7 hours (Phase 2.0 + 2.1)
Risk: Very low (completed successfully)
Benefits:

  • Rich widget library ready for Phase 3 features
  • Performance: PyQtGraph 10-100x faster than matplotlib
  • Professional: Native look/feel, keyboard shortcuts, standard patterns

⏳ Phase 3 Required: QDockWidget + M2

Why QDockWidget Now:

  • Phase 3 Blocker: M2 integration needs flexible workspace
  • Foundation: Enables all future features (statistics, analysis, help)
  • Standard Pattern: Proven Qt approach, well-documented
  • User Demand: Professional users expect resizable/movable panels

Migration Effort: 3-4 hours (see detailed plan in Critical Update section above)
Risk: Low (standard Qt pattern, QDockWidget is mature)
Benefits:

  • Ultimate flexibility (resize, rearrange, hide, undock, tab)
  • M2 overlay becomes feasible (share graphs instead of duplicate panels)
  • Future panels add easily (just create new QDockWidget)
  • Layout persistence automatic (Qt QSettings handles this)

Do Not Consider Alternatives:

  • ❌ QSplitter - Only resizable, not movable/hideable/undockable
  • ❌ Fixed layout - Unacceptable for Phase 3+ (M2, statistics, help)
  • ❌ Custom layout system - Reinventing Qt's wheel (weeks of work, many bugs)

Decision Matrix (Updated)

Feature Phase 1 (Matplotlib) Phase 2 (Qt Fixed Layout) Phase 3 (Qt + QDockWidget)
Phase 1-2 Features ✅ Excellent ✅ Excellent ✅ Excellent
M2 Overlay ❌ Very Difficult ⚠️ Cramped ✅ Space-Efficient
Panel Flexibility ❌ None ❌ Fixed ✅ Full Flexibility
Multi-Monitor ❌ No ❌ No ✅ Yes
Future Panels ❌ Very Difficult ⚠️ Refactor Needed ✅ Trivial to Add
Professional UX ⚠️ Basic ✅ Good ✅ Excellent
Maintainability ⚠️ Limited ✅ Good ✅ Excellent
Layout Persistence ❌ No ❌ No ✅ Automatic
Implementation ✅ Complete ✅ Complete ⏳ 3-4 hours

Legend:

  • ✅ Good/Easy/Complete
  • ⚠️ Moderate/Some Issues
  • ❌ Poor/Very Difficult/Blocker

Specific Recommendations by Component (Updated)

1. Event Management System ✅ COMPLETE (December 6-7, 2025)

Status: QUndoStack implemented (Phase 2.0)

Implementation: Qt's native undo/redo framework

class EditorController:
    def __init__(self, model, view):
        self.undo_stack = QUndoStack()
        
    def move_marker(self, event_idx, primitive_key, new_value):
        """Move marker with undo support."""
        command = MoveMarkerCommand(
            model=self.model,
            event_idx=event_idx,
            primitive_key=primitive_key,
            old_value=old_value,
            new_value=new_value,
            controller=self  # Delegate for trajectory updates
        )
        self.undo_stack.push(command)  # Execute and add to stack

Features:

  • ✅ Discrete undo/redo (each marker edit is separate step)
  • ✅ Keyboard shortcuts (Ctrl+Z undo, Ctrl+Y/Ctrl+Shift+Z redo)
  • ✅ Command pattern prevents recursive undo creation
  • ✅ QUndoStack handles all stack management automatically

Completed: December 6, 2025 (~4 hours in Phase 2.0)

2. Configuration System ✅ IMPLEMENTED (December 6, 2025)

Status: Complete - tools/editor/config.py created

Implementation: User preferences file with JSON format

File: ~/.whenmathprays/editor_config.json

{
  "layout": {
    "margin_left": 0.14,
    "margin_right": 0.02,
    "panel_gap": 0.35,
    "primitive_gauge_x": -0.18
  },
  "weights": {
    "w_v": 1.0,
    "w_r": 1.0,
    "w_f": 1.0,
    "w_a": 1.0,
    "w_S_real": 0.5,
    "w_S_imag": 0.5
  },
  "appearance": {
    "marker_size": 8,
    "line_width": 1.5
  }
}

Features:

  • Falls back to sensible defaults if file doesn't exist (zero breakage)
  • Loads on editor startup, merges with defaults
  • Example config file: docs/editor_config_example.json
  • All LAYOUT values now user-customizable

Completed: December 6, 2025 (~2 hours)

3. GUI Framework ✅ COMPLETE (December 6, 2025)

Status: PySide6 (Qt6) migration complete (Phase 2.0)

Implementation: Full Qt framework with PyQtGraph

from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PySide6.QtCore import Qt
import pyqtgraph as pg

class InteractiveEditorQt(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Interactive Scenario Editor - Phase 2")
        
        # Central widget with layout
        central = QWidget()
        self.setCentralWidget(central)
        layout = QVBoxLayout(central)
        
        # PyQtGraph plots (high performance)
        self.primitive_panel = PrimitivePanelPyQtGraph(model, controller)
        self.trajectory_panel = TrajectoryPanelPyQtGraph(model, controller)
        
        layout.addWidget(self.primitive_panel)
        layout.addWidget(self.trajectory_panel)

Benefits:

  • ✅ Qt6 framework: Professional, mature, feature-rich
  • ✅ PyQtGraph: 10-100x faster than matplotlib (GPU-accelerated)
  • ✅ Ready for QDockWidget (Phase 3)
  • ✅ Native dialogs, menus, keyboard shortcuts
  • ✅ Multi-platform: Windows, Linux, macOS

Completed: December 6, 2025 (~4 hours in Phase 2.0)

4. Primitives Metadata Module ✅ COMPLETE (December 6, 2025)

Status: tools/editor/primitives.py created

Implementation: Single source of truth for primitive definitions

from dataclasses import dataclass

@dataclass(frozen=True)
class PrimitiveInfo:
    key: str           # Short key (v, r, f, a, S)
    name: str          # Full name (Visibility, Resonance, etc.)
    color: str         # Hex color code
    description: str   # Human-readable description

PRIMITIVES = {
    'v': PrimitiveInfo('v', 'Visibility', '#1f77b4', 'How visible/present...'),
    'r': PrimitiveInfo('r', 'Resonance', '#ff7f0e', 'Emotional alignment...'),
    # ... 10 primitives total
}

Benefits:

  • ✅ One place to update primitive names
  • ✅ Includes descriptions for tooltips/help
  • ✅ Self-documenting with metadata
  • ✅ Easy to extend (validation rules, ranges)

Completed: December 6, 2025 (~30 minutes)


Action Items (Updated December 10, 2025)

✅ Completed:

  1. PySide6 Migration (Phase 2.0, December 6) - 4 hours
  2. QUndoStack Undo/Redo (Phase 2.0, December 6) - Included in migration
  3. Diagnostic Markers (Phase 2.1, December 7) - 3 hours
  4. Observer Pattern (December 7) - 2-3 hours
  5. Configuration System (December 6) - 2 hours
  6. Primitives Module (December 6) - 30 minutes
  7. Magic Numbers → Constants (December 7) - 30 minutes
  8. Helper Methods (December 7) - 1-2 hours
  9. Unit Tests (December 7) - 2-3 hours (48 tests, 100% pass)

Total Phase 2 Effort: ~15-16 hours
Code Quality: A+ (9.5/10)
Test Coverage: 100% of new components

⏳ Phase 3 Immediate Priorities (Next):

3.1 QDockWidget Foundation (~3-4 hours) - CRITICAL

  • Wrap primitive_panel in QDockWidget
  • Wrap trajectory_panel in QDockWidget
  • Add View menu with show/hide panel actions
  • Implement layout save/restore (QSettings)
  • Set sensible defaults (vertical split, equal sizes)
  • Test: resize, rearrange, hide/show, undock workflows
  • Deliverable: Current functionality + flexible resizable workspace

3.2 Perspective Switcher (~2 hours)

  • Create PerspectiveSwitcher widget (QRadioButton group styled)
  • Add to toolbar (QToolBar)
  • Style: active=red glow (#FF4444), inactive=grey (#9E9E9E)
  • Connect to controller.switch_perspective()
  • Add keyboard shortcut (QShortcut: Tab or Space)
  • Update status in window title or status bar
  • Deliverable: Can switch perspectives (M2 not rendered yet)

3.3 M2 Overlay Rendering (~3-4 hours)

  • Primitive panel renders both M1 and M2 datasets
  • Apply active/inactive visual styles:
    • Active: line_width=2, opacity=1.0, solid markers, z=100
    • Inactive: line_width=1, opacity=0.4, hollow markers, z=50
  • Filter drag/click events to active perspective only
  • Trajectory panel shows both trajectories with styles
  • Z-order management (active renders on top)
  • Deliverable: Full M2 visualization with overlay UX

3.4 M2 Data Model (~2 hours)

  • EditorModel tracks both M1 and M2 events
  • CSV format extension (columns: time, v_M1, r_M1, ..., v_M2, r_M2, ...)
  • Backward compatible: Load old M1-only CSVs (M2=None)
  • Save/load both perspectives
  • Observer pattern triggers updates for both views
  • Deliverable: Complete M2 data persistence

Total Phase 3 Core: ~10-12 hours

🔮 Phase 4 Future Enhancements (Lower Priority):

Dialogs and Windows:

  • Marker Properties Dialog (edit values, notes) - 2 hours
  • Gamma Marker Inspector (annotations) - 1 hour
  • Settings Dialog (preferences, weights, colors) - 3 hours
  • Help System (user guide, keyboard shortcuts) - 2 hours

Additional Panels:

  • Statistics Panel (bond metrics, trajectory analysis) - 3 hours
  • Debug Instrumentation Panel (solver diagnostics) - 4 hours

Advanced Features:

  • Analysis Window (separate synchronized window) - 8 hours
  • Inverse Solver (drag gamma_self → suggest primitives) - 15-20 hours

Total Phase 4: ~35-40 hours (incremental, as needed)


Conclusion (Updated December 10, 2025)

Phase 1-2 Status:Complete and Excellent

  • PySide6 (Qt6) migration successful
  • QUndoStack provides professional undo/redo
  • Observer pattern enables reactive updates
  • Diagnostic markers add "what-if" analysis capability
  • Code quality: A+ (9.5/10), fully tested (48 tests, 100% pass)

Phase 3 Critical Path: 🎯 QDockWidget Architecture Required

  • Non-negotiable: M2 integration needs flexible workspace
  • Foundation: QDockWidget enables all future features (statistics, help, analysis)
  • Timeline: ~10-12 hours total for QDockWidget + M2 overlay + data model
  • Risk: Low (standard Qt pattern, well-documented, proven approach)

Why QDockWidget Cannot Be Deferred:

  1. Without QDockWidget: M2 doubles horizontal space → cramped on laptops, unusable UX
  2. Without QDockWidget: Future panels (statistics, help, debug) have no space → constant refactoring
  3. Without QDockWidget: Professional workflows (multi-monitor, custom layouts) impossible
  4. With QDockWidget: M2 overlay saves space, flexible workspace, future-proof, professional

Architecture Principles - Do Not Paint Into Corners:

  • Separation of Concerns: Model/View/Controller cleanly separated
  • Observer Pattern: Automatic synchronization, scales to unlimited observers
  • Flexible Workspace: QDockWidget enables user customization, adapts to all setups
  • Incremental Features: Pop-ups and docks add features without refactoring
  • Data Extensibility: CSV supports M2, notes, metadata (backward compatible)
  • Performance: PyQtGraph GPU-accelerated, debounced updates, caching
  • Testability: Unit tests, integration tests (QTest), 100% coverage

Recommendation: Proceed with Phase 3.1 (QDockWidget Foundation) immediately. This is foundational infrastructure, not an optional enhancement. Everything after Phase 3.1 builds on this flexible workspace architecture.


Related Documents:

Questions? See issue tracker for Phase 3 planning or contact development team.


Appendix: Quick Reference

Current Tech Stack (Phase 2)

  • Framework: PySide6 (Qt6)
  • Plotting: PyQtGraph (GPU-accelerated)
  • Undo/Redo: QUndoStack with command pattern
  • Reactivity: Observer pattern (Observable, ObservableDict)
  • Config: JSON-based user preferences (~/.whenmathprays/editor_config.json)
  • Data: CSV with backward compatibility
  • Testing: pytest with 48 tests (100% pass)

Phase 3 Target Stack

  • Everything Above +
  • Layout: QDockWidget (flexible workspace)
  • M2: Overlay visualization with active/inactive states
  • Switcher: QRadioButton group with visual feedback (red/grey)
  • Persistence: QSettings for layout save/restore

Key Design Patterns

  1. MVC: Model (EditorModel), View (panels), Controller (EditorController)
  2. Observer: Observable/ObservableDict for automatic updates
  3. Command: QUndoCommand for undo/redo operations
  4. Dock: QDockWidget for flexible panel management

Visual Design Specs

Element Active Inactive
Line Width 2 1 (or dashed)
Marker Style Solid fill Hollow
Opacity 1.0 0.4
Z-Order 100 (front) 50 (back)
Radio Button Red glow (#FF4444) Grey (#9E9E9E)
Interactivity Draggable Read-only

Implementation Checklist

  • Phase 2.0: PySide6 migration + undo/redo
  • Phase 2.1: Diagnostic "what-if" markers
  • Observer pattern for reactivity
  • Configuration system
  • Code cleanup (constants, helpers, tests)
  • Phase 3.1: QDockWidget foundation (~3-4 hrs)
  • Phase 3.2: Perspective switcher (~2 hrs)
  • Phase 3.3: M2 overlay rendering (~3-4 hrs)
  • Phase 3.4: M2 data model (~2 hrs)