Architecture
This document describes the internal architecture of SlicerMouseMaster.
System Overview
┌─────────────────────────────────────────────────────────────────┐
│ Qt Application │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ MouseMasterEventHandler │ │
│ │ (Application-level Qt event filter) │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Platform │ │ Preset │ │ Action │ │
│ │ Adapter │ │ Manager │ │ Registry │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ │ │ │ │
│ └────────────────────┼────────────────────┘ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Mouse Profile│ │
│ │ (dataclass) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Event Flow
When a user presses a mouse button:
User Button Press
│
▼
Qt Application (eventFilter)
│
▼
MouseMasterEventHandler.eventFilter()
├── Normalize button via PlatformAdapter
├── Get current Slicer module context
├── Look up binding: context-specific → default
├── Execute action via ActionRegistry
└── Return True (consumed) or False (pass-through)
Key Classes
MouseMaster/MouseMaster.py
MouseMaster: Slicer module registration and metadata
MouseMasterWidget: Qt widget for UI setup and user interaction
MouseMasterLogic: Business logic coordinator
MouseMasterLib/EventHandler.py
The core of MouseMaster. Implements a Qt application-level event filter that intercepts mouse button events.
class MouseMasterEventHandler(QObject):
def eventFilter(self, obj, event):
if event.type() == QEvent.MouseButtonPress:
button = event.button()
# Normalize and execute mapped action
return self.handleButton(button)
return False
MouseMasterLib/MouseProfile.py
Data classes for mouse definitions:
MouseButton: Single button definition (id, name, Qt code, remappable)
MouseFeatures: Optional features (horizontal scroll, thumb wheel)
MouseProfile: Complete mouse definition with all buttons
MouseMasterLib/PresetManager.py
Handles preset loading, saving, and management:
Mapping: Single button-to-action mapping
Preset: Complete preset with mappings and context overrides
PresetManager: CRUD operations for presets
MouseMasterLib/ActionRegistry.py
Singleton registry of executable actions:
registry = ActionRegistry.get_instance()
registry.register("my_action", MyActionHandler(), category="custom")
registry.execute("my_action", parameters={})
MouseMasterLib/PlatformAdapter.py
Cross-platform button code normalization:
adapter = PlatformAdapter.get_instance()
normalized = adapter.normalize_button(qt_button_code)
Data Formats
Mouse Definition JSON
Located in Resources/MouseDefinitions/:
{
"id": "logitech_mx_master_3s",
"name": "Logitech MX Master 3S",
"vendor": "Logitech",
"vendorId": "0x46D",
"productIds": ["0x4082", "0xB023"],
"buttons": [
{
"id": "left",
"name": "Left Click",
"qtButton": 1,
"remappable": false
},
{
"id": "back",
"name": "Back",
"qtButton": 8,
"remappable": true,
"defaultAction": "undo"
}
],
"features": {
"horizontalScroll": true,
"thumbWheel": true
}
}
Preset JSON
Located in presets/:
{
"id": "segmentation_workflow",
"name": "Segmentation Workflow",
"version": "1.0",
"mouseId": "logitech_mx_master_3s",
"mappings": {
"back": {"action": "slicer_action", "actionId": "undo"},
"forward": {"action": "slicer_action", "actionId": "redo"}
},
"contextMappings": {
"SegmentEditor": {
"back": {"action": "segment_previous"},
"forward": {"action": "segment_next"}
}
}
}
Design Decisions
Key architectural decisions are documented in Architecture Decision Records (ADRs):
Architecture Decision Records - Full list of ADRs
Important decisions:
Qt event filter over VTK observers for broader coverage
JSON presets for human-readable, shareable configurations
Platform adapters to abstract OS differences
Singleton registries for actions and adapters