Skip to content

Commit b1142ef

Browse files
Merge pull request #29 from RuntimeRascal/copilot/fix-eraser-tool-functionality
Fix eraser tool for rectangles/circles + add shift modifier for perfect squares
2 parents 321504f + 4f40423 commit b1142ef

File tree

6 files changed

+74
-6
lines changed

6 files changed

+74
-6
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88

9+
## v1.0.11
10+
11+
### Added
12+
- **Rectangle Tool: Shift Modifier for Perfect Squares**
13+
- Hold Shift while drawing rectangles to constrain to perfect squares
14+
- Uses `Math.Min(width, height)` to fit square within dragged bounds
15+
- Works during both preview and finalization
16+
- Consistent with Circle tool's Shift modifier behavior
17+
18+
### Fixed
19+
- **Eraser Tool Now Erases All Shape Types**
20+
- Eraser now properly removes Rectangle shapes
21+
- Eraser now properly removes Circle/Ellipse shapes
22+
- Added bounds intersection detection using `IntersectsWith()` for shape types
23+
- Added NaN guards for `Canvas.GetLeft/GetTop` to handle uninitialized attached properties
24+
- Previously only removed Polylines (pen strokes) and Lines
25+
926
## v1.0.10
1027

1128
### Added

Installer/GhostDraw.Installer.wixproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="WixToolset.Sdk/4.0.5">
22
<PropertyGroup>
3-
<Version Condition="'$(Version)' == ''">1.0.10</Version>
3+
<Version Condition="'$(Version)' == ''">1.0.11</Version>
44
<OutputName>GhostDrawSetup-$(Version)</OutputName>
55
<OutputType>Package</OutputType>
66
<Platform>x64</Platform>

Src/GhostDraw/GhostDraw.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<UseWPF>true</UseWPF>
99
<UseWindowsForms>true</UseWindowsForms>
1010
<ApplicationIcon>Assets\favicon.ico</ApplicationIcon>
11-
<Version>1.0.10</Version>
11+
<Version>1.0.11</Version>
1212
<EnableWindowsTargeting>true</EnableWindowsTargeting>
1313
</PropertyGroup>
1414

Src/GhostDraw/Tools/EraserTool.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,42 @@ private void EraseAtPosition(Point position, Canvas canvas)
136136
}
137137
}
138138
}
139+
else if (element is System.Windows.Shapes.Rectangle rectangle)
140+
{
141+
// Check if eraser intersects with rectangle bounds
142+
double left = Canvas.GetLeft(rectangle);
143+
double top = Canvas.GetTop(rectangle);
144+
145+
// Handle NaN values (shouldn't happen, but be defensive)
146+
if (!double.IsNaN(left) && !double.IsNaN(top) &&
147+
!double.IsNaN(rectangle.Width) && !double.IsNaN(rectangle.Height))
148+
{
149+
Rect shapeRect = new Rect(left, top, rectangle.Width, rectangle.Height);
150+
151+
if (eraserRect.IntersectsWith(shapeRect))
152+
{
153+
shouldErase = true;
154+
}
155+
}
156+
}
157+
else if (element is Ellipse ellipse)
158+
{
159+
// Check if eraser intersects with ellipse bounds
160+
double left = Canvas.GetLeft(ellipse);
161+
double top = Canvas.GetTop(ellipse);
162+
163+
// Handle NaN values (shouldn't happen, but be defensive)
164+
if (!double.IsNaN(left) && !double.IsNaN(top) &&
165+
!double.IsNaN(ellipse.Width) && !double.IsNaN(ellipse.Height))
166+
{
167+
Rect ellipseRect = new Rect(left, top, ellipse.Width, ellipse.Height);
168+
169+
if (eraserRect.IntersectsWith(ellipseRect))
170+
{
171+
shouldErase = true;
172+
}
173+
}
174+
}
139175

140176
if (shouldErase)
141177
{

Src/GhostDraw/Tools/RectangleTool.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ public void OnMouseMove(Point position, Canvas canvas, MouseButtonState leftButt
4242
if (_isCreatingRectangle && _currentRectangle != null && _rectangleStartPoint.HasValue)
4343
{
4444
// Update rectangle dimensions to follow cursor
45-
UpdateRectangle(_rectangleStartPoint.Value, position);
45+
// Check if Shift key is held down for perfect square
46+
bool isShiftPressed = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
47+
UpdateRectangle(_rectangleStartPoint.Value, position, isShiftPressed);
4648
}
4749
}
4850

@@ -117,7 +119,7 @@ private void StartNewRectangle(Point startPoint, Canvas canvas)
117119
_logger.LogInformation("Rectangle started at ({X:F0}, {Y:F0})", startPoint.X, startPoint.Y);
118120
}
119121

120-
private void UpdateRectangle(Point startPoint, Point currentPoint)
122+
private void UpdateRectangle(Point startPoint, Point currentPoint, bool isPerfectSquare = false)
121123
{
122124
if (_currentRectangle == null)
123125
return;
@@ -128,6 +130,17 @@ private void UpdateRectangle(Point startPoint, Point currentPoint)
128130
double width = Math.Abs(currentPoint.X - startPoint.X);
129131
double height = Math.Abs(currentPoint.Y - startPoint.Y);
130132

133+
// If Shift is held, make it a perfect square (width = height = min dimension)
134+
// Note: Uses Math.Min (not Math.Max like CircleTool) so the square fits within
135+
// the dragged bounding box, making the final size more predictable and visible
136+
// to the user as they drag. This matches the behavior specified in the issue.
137+
if (isPerfectSquare)
138+
{
139+
double size = Math.Min(width, height);
140+
width = size;
141+
height = size;
142+
}
143+
131144
Canvas.SetLeft(_currentRectangle, left);
132145
Canvas.SetTop(_currentRectangle, top);
133146
_currentRectangle.Width = width;
@@ -138,7 +151,9 @@ private void FinishRectangle(Point endPoint)
138151
{
139152
if (_currentRectangle != null && _rectangleStartPoint.HasValue)
140153
{
141-
UpdateRectangle(_rectangleStartPoint.Value, endPoint);
154+
// Check if Shift was held on the final click
155+
bool isShiftPressed = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
156+
UpdateRectangle(_rectangleStartPoint.Value, endPoint, isShiftPressed);
142157
_logger.LogInformation("Rectangle finished at ({X:F0}, {Y:F0})", endPoint.X, endPoint.Y);
143158
}
144159

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ghost-draw",
3-
"version": "1.0.10",
3+
"version": "1.0.11",
44
"description": "Draw directly on your screen with a transparent overlay",
55
"repository": {
66
"type": "git",

0 commit comments

Comments
 (0)