- Improved sketching
This commit is contained in:
@@ -257,7 +257,7 @@ def _setup_coordinate_system(self, painter: QPainter):
|
||||
|
||||
### Mode-Based Interaction
|
||||
|
||||
The sketcher supports multiple interaction modes:
|
||||
The sketcher supports multiple interaction modes with robust mode management:
|
||||
|
||||
#### Drawing Modes
|
||||
- `SketchMode.LINE`: Two-point line creation
|
||||
@@ -272,7 +272,80 @@ The sketcher supports multiple interaction modes:
|
||||
- `SketchMode.DISTANCE`: Distance/length constraint
|
||||
|
||||
#### Selection Mode
|
||||
- `SketchMode.NONE`: Selection and manipulation mode
|
||||
- `SketchMode.NONE`: Selection and manipulation mode (enables point dragging)
|
||||
|
||||
### Selection and Deletion System
|
||||
|
||||
The sketcher now includes a comprehensive selection and deletion system that allows users to select and remove elements from the sketch.
|
||||
|
||||
#### Selection Methods
|
||||
|
||||
1. **Single Element Selection**: Click on individual points or lines to select/deselect them
|
||||
2. **Rectangle Selection**: Click and drag to create a selection rectangle for multiple elements
|
||||
3. **Visual Feedback**: Selected elements are highlighted in yellow with increased size
|
||||
|
||||
#### Deletion Methods
|
||||
|
||||
1. **Keyboard Deletion**: Press Delete or Backspace to remove selected elements
|
||||
2. **Proper Cleanup**: Elements are removed from both the sketch and constraint solver
|
||||
3. **Dependency Handling**: Lines are deleted before points to maintain geometric integrity
|
||||
|
||||
#### Implementation Details
|
||||
|
||||
The selection system is implemented through the following components:
|
||||
|
||||
- **Selection Tracking**: `selected_elements` list tracks currently selected elements
|
||||
- **Rectangle Selection**: `selection_rect_start` and `selection_rect_end` track rectangle selection bounds
|
||||
- **Visual Feedback**: Modified drawing methods highlight selected elements in yellow
|
||||
- **Keyboard Support**: `keyPressEvent` handles Delete/Backspace keys
|
||||
- **Deletion Method**: `delete_selected_elements` handles removal of elements from sketch and solver
|
||||
|
||||
#### Selection Workflow
|
||||
|
||||
1. **Default Selection Mode**: The sketcher defaults to selection mode when no drawing tool is active
|
||||
2. **Element Selection**:
|
||||
- Click on points or lines to select/deselect them (they turn yellow)
|
||||
- Click and drag to create a rectangle selection for multiple elements
|
||||
3. **Element Deletion**:
|
||||
- Press Delete or Backspace to remove all selected elements
|
||||
- Elements are removed from both the sketch and constraint solver
|
||||
4. **Visual Feedback**:
|
||||
- Selected elements are highlighted in yellow
|
||||
- Rectangle selection is shown with a yellow dashed border
|
||||
|
||||
#### Constraints Handling
|
||||
|
||||
When elements are deleted:
|
||||
- Lines are removed first to avoid issues with points being used by lines
|
||||
- Points are only removed if they are not used by any remaining lines
|
||||
- The constraint solver is re-run after deletion to update remaining constraints
|
||||
- Proper error handling ensures the UI remains responsive even if solver operations fail
|
||||
|
||||
### Mode Management System
|
||||
|
||||
The mode system has been enhanced to provide intuitive selection and deletion functionality:
|
||||
|
||||
#### Mode Compatibility
|
||||
- Python `None` is automatically converted to `SketchMode.NONE` for backward compatibility
|
||||
- The `set_mode()` method ensures the mode is always a valid `SketchMode` enum value
|
||||
- Mode changes reset all interaction buffers and state
|
||||
|
||||
#### Default Selection Behavior
|
||||
- `SketchMode.NONE` now serves as the default selection mode
|
||||
- When no drawing tool is active, the sketcher is in selection mode by default
|
||||
- Users can click on elements to select/deselect them (they turn yellow)
|
||||
- Users can click and drag to create rectangle selections
|
||||
- Pressing Delete or Backspace removes all selected elements
|
||||
|
||||
#### Right-Click Behavior
|
||||
- Right-clicking **always** exits any active mode and returns to `SketchMode.NONE`
|
||||
- This enables point dragging and prevents unintended geometry creation
|
||||
- The mode reset happens directly in the sketcher, not through main app signals
|
||||
|
||||
#### Point Dragging Safety
|
||||
- Point dragging is **only** enabled when in `SketchMode.NONE` mode
|
||||
- Left-clicks in `NONE` mode check for draggable points first
|
||||
- If no point is found, the click is processed as a selection operation
|
||||
|
||||
### Mouse Event Handling
|
||||
|
||||
@@ -282,14 +355,45 @@ def mousePressEvent(self, event):
|
||||
local_pos = self._viewport_to_local(event.pos())
|
||||
|
||||
if event.button() == Qt.LeftButton:
|
||||
if self.current_mode == SketchMode.NONE:
|
||||
# Check for point dragging
|
||||
point = self.sketch.get_point_near(local_pos)
|
||||
if point:
|
||||
self._start_point_drag(point, local_pos)
|
||||
self._handle_left_click(local_pos)
|
||||
elif event.button() == Qt.RightButton:
|
||||
self._handle_right_click(local_pos)
|
||||
elif event.button() == Qt.MiddleButton:
|
||||
self._start_panning(event.pos())
|
||||
```
|
||||
|
||||
#### Enhanced Left-Click Handler
|
||||
```python
|
||||
def _handle_left_click(self, pos: QPoint):
|
||||
# Safety check for NONE mode (dragging enabled)
|
||||
if self.current_mode == SketchMode.NONE or self.current_mode is None:
|
||||
point = self.sketch.get_point_near(pos, self.snap_settings.snap_distance)
|
||||
if point:
|
||||
self._start_point_drag(point, pos)
|
||||
return
|
||||
else:
|
||||
# Handle drawing modes
|
||||
self._handle_left_click(local_pos)
|
||||
# No point found - ignore click to prevent unintended drawing
|
||||
return
|
||||
|
||||
# Handle active drawing/constraint modes
|
||||
if self.current_mode == SketchMode.LINE:
|
||||
self._handle_line_creation(pos)
|
||||
elif self.current_mode == SketchMode.HORIZONTAL:
|
||||
self._handle_horizontal_constraint(pos)
|
||||
# ... other modes
|
||||
```
|
||||
|
||||
#### Right-Click Mode Reset
|
||||
```python
|
||||
def _handle_right_click(self, pos: QPoint):
|
||||
# Reset interaction state
|
||||
self._reset_interaction_state()
|
||||
|
||||
# Force mode to NONE to enable dragging
|
||||
self.current_mode = SketchMode.NONE
|
||||
|
||||
# Emit signal to inform main app
|
||||
self.constraint_applied.emit()
|
||||
```
|
||||
|
||||
### Point Dragging System
|
||||
@@ -531,7 +635,12 @@ widget.show()
|
||||
|
||||
**Mode Control:**
|
||||
```python
|
||||
# Set drawing modes
|
||||
widget.set_mode(SketchMode.LINE)
|
||||
widget.set_mode(SketchMode.NONE) # Enable selection/dragging
|
||||
widget.set_mode(None) # Also converted to SketchMode.NONE
|
||||
|
||||
# Construction geometry
|
||||
widget.set_construction_mode(True)
|
||||
```
|
||||
|
||||
@@ -624,6 +733,22 @@ widget.sketch_modified.connect(callback)
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Mode Handling Problems
|
||||
**Symptoms**: Unintended line creation when dragging, tools not deactivating properly
|
||||
**Causes**: Mode not properly reset to NONE, Python None vs SketchMode.NONE confusion
|
||||
**Solutions**:
|
||||
- Always right-click to exit active modes
|
||||
- Ensure `set_mode(None)` is converted to `SketchMode.NONE`
|
||||
- Verify mode state after tool deactivation in main app
|
||||
|
||||
#### Point Dragging Issues
|
||||
**Symptoms**: Cannot drag points, dragging creates unwanted lines
|
||||
**Causes**: Mode not set to NONE, safety checks preventing drag detection
|
||||
**Solutions**:
|
||||
- Verify current mode is `SketchMode.NONE` before attempting to drag
|
||||
- Right-click to ensure proper mode exit from drawing tools
|
||||
- Check that point detection threshold is appropriate
|
||||
|
||||
#### Solver Failures
|
||||
**Symptoms**: Constraints not applied, geometry not updating
|
||||
**Causes**: Over-constrained systems, conflicting constraints
|
||||
@@ -690,8 +815,35 @@ Key log messages include:
|
||||
|
||||
---
|
||||
|
||||
## Recent Improvements (2025-08-16)
|
||||
|
||||
### Mode Handling Enhancements
|
||||
|
||||
Significant improvements have been made to the mode management system:
|
||||
|
||||
#### Fixed Issues
|
||||
1. **Unintended Line Creation**: Resolved issue where dragging with line tool deactivated would still create lines
|
||||
2. **Mode Reset Reliability**: Right-click now reliably exits any active mode and returns to NONE
|
||||
3. **Backward Compatibility**: Python `None` mode values are automatically converted to `SketchMode.NONE`
|
||||
4. **Safety Checks**: Added comprehensive checks to prevent drawing operations in NONE mode
|
||||
|
||||
#### Implementation Details
|
||||
- Enhanced `_handle_right_click()` to directly set mode to NONE
|
||||
- Added safety checks in `_handle_left_click()` for NONE mode behavior
|
||||
- Improved `set_mode()` method to handle None input gracefully
|
||||
- Added comprehensive debug logging for mode transitions
|
||||
|
||||
#### Integration Improvements
|
||||
- Fixed main app integration where constraint modes were prematurely reset
|
||||
- Ensured persistent constraint behavior until explicit user cancellation
|
||||
- Maintained UI button state consistency with actual sketcher mode
|
||||
|
||||
These improvements ensure reliable mode transitions and prevent common user frustrations with unintended geometry creation.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The ImprovedSketchWidget provides a robust, extensible foundation for 2D parametric sketching in Fluency CAD. Its architecture separates concerns effectively, uses proven libraries (SolverSpace, PySide6), and provides rich interaction capabilities while maintaining good performance characteristics.
|
||||
|
||||
The system is designed for extensibility - new geometry types, constraint types, and interaction modes can be added following the established patterns. The comprehensive API allows for both direct use and integration with larger CAD systems.
|
||||
|
||||
With the recent mode handling improvements, the sketcher now provides a more reliable and intuitive user experience, with proper separation between drawing modes and selection/manipulation operations.
|
||||
|
||||
Reference in New Issue
Block a user