Skip to content

Commit 8a7b56b

Browse files
Merge pull request #35 from RuntimeRascal/copilot/change-clear-canvas-hotkey
Change Clear Canvas hotkey to Delete with confirmation modal
2 parents 7bf4260 + a347d23 commit 8a7b56b

12 files changed

Lines changed: 390 additions & 46 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,25 @@ 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.14
10+
11+
### Added
12+
- **Clear Canvas Confirmation Modal**
13+
- Press `Delete` while drawing mode is active to open a Yes/No confirmation before clearing the canvas
14+
- While the modal is open, drawing and tool switching are disabled; closing the modal restores the previous tool
15+
16+
### Changed
17+
- **Clear Canvas Hotkey**
18+
- Clear canvas hotkey changed from `R` to `Delete`
19+
- `Delete` is suppressed while drawing mode is active to prevent deleting content in underlying apps
20+
- **UI + Docs**
21+
- Updated overlay hint text and Help shortcuts to reference `Delete`
22+
- Updated `docs/KEY_LEGEND.md`
23+
24+
### Fixed
25+
- Updated `ClearCanvasFeatureTests` to reflect the new `Delete` hotkey + confirmation flow
26+
27+
928
## v1.0.13
1029

1130
### 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.13</Version>
3+
<Version Condition="'$(Version)' == ''">1.0.14</Version>
44
<OutputName>GhostDrawSetup-$(Version)</OutputName>
55
<OutputType>Package</OutputType>
66
<Platform>x64</Platform>

Src/GhostDraw/App.xaml.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,9 @@ private void OnClearCanvasPressed(object? sender, EventArgs e)
246246
{
247247
try
248248
{
249-
// Only clear canvas if drawing mode is active
250-
if (_drawingManager?.IsDrawingMode == true)
251-
{
252-
_logger?.LogInformation("R pressed - clearing canvas");
253-
_drawingManager?.ClearCanvas();
254-
}
249+
// Delete key pressed - show confirmation modal (hook already checks drawing mode is active)
250+
_logger?.LogInformation("Delete pressed - requesting clear canvas confirmation");
251+
_drawingManager?.RequestClearCanvas();
255252
}
256253
catch (Exception ex)
257254
{

Src/GhostDraw/Core/GlobalKeyboardHook.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class GlobalKeyboardHook : IDisposable
1212

1313
// Only keep VK_ESCAPE constant (emergency exit)
1414
private const int VK_ESCAPE = 0x1B; // 27
15-
private const int VK_R = 0x52; // 82 - 'R' key for clear canvas
15+
private const int VK_DELETE = 0x2E; // 46 - 'Delete' key for clear canvas
1616
private const int VK_L = 0x4C; // 76 - 'L' key for line tool
1717
private const int VK_P = 0x50; // 80 - 'P' key for pen tool
1818
private const int VK_E = 0x45; // 69 - 'E' key for eraser tool
@@ -216,11 +216,19 @@ private nint HookCallback(int nCode, nint wParam, nint lParam)
216216
EscapePressed?.Invoke(this, EventArgs.Empty);
217217
}
218218

219-
// Check for R key press (clear canvas)
220-
if (vkCode == VK_R && isKeyDown)
219+
// Check for Delete key press (clear canvas - only when drawing mode is active)
220+
if ((vkCode == VK_DELETE) && isKeyDown && _isDrawingModeActive)
221221
{
222-
_logger.LogDebug("R key pressed - clear canvas request");
222+
_logger.LogDebug("Delete key pressed - clear canvas confirmation request");
223223
ClearCanvasPressed?.Invoke(this, EventArgs.Empty);
224+
225+
// INTENTIONAL: Suppress Delete key when drawing mode is active to prevent deleting
226+
// content in underlying apps. This is different from other tool keys (P, L, E, etc.)
227+
// which are less likely to cause data loss in underlying applications.
228+
// The Delete key is specifically suppressed as per requirements to avoid accidental
229+
// deletion in text editors or other apps while the overlay is active.
230+
shouldSuppressKey = true;
231+
_logger.LogDebug("Delete key suppressed - drawing mode is active");
224232
}
225233

226234
// Check for L key press (line tool)

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.13</Version>
11+
<Version>1.0.14</Version>
1212
<EnableWindowsTargeting>true</EnableWindowsTargeting>
1313
</PropertyGroup>
1414

Src/GhostDraw/Managers/DrawingManager.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,25 +386,37 @@ public void ToggleHelp()
386386
}
387387

388388
/// <summary>
389-
/// Clears the canvas while keeping drawing mode active
389+
/// Requests to clear the canvas - shows confirmation modal first
390390
/// </summary>
391-
public void ClearCanvas()
391+
public void RequestClearCanvas()
392392
{
393393
try
394394
{
395395
if (_overlayWindow.IsVisible)
396396
{
397-
_logger.LogInformation("Clearing canvas (R key)");
398-
_overlayWindow.ClearCanvas();
397+
_logger.LogInformation("Requesting clear canvas confirmation (Delete key)");
398+
399+
// Show confirmation modal with callbacks
400+
_overlayWindow.ShowClearCanvasConfirmation(
401+
onConfirm: () =>
402+
{
403+
_logger.LogInformation("Clear canvas confirmed - clearing");
404+
_overlayWindow.ClearCanvas();
405+
},
406+
onCancel: () =>
407+
{
408+
_logger.LogInformation("Clear canvas canceled - no action");
409+
}
410+
);
399411
}
400412
else
401413
{
402-
_logger.LogDebug("ClearCanvas ignored - overlay not visible");
414+
_logger.LogDebug("RequestClearCanvas ignored - overlay not visible");
403415
}
404416
}
405417
catch (Exception ex)
406418
{
407-
_logger.LogError(ex, "Failed to clear canvas");
419+
_logger.LogError(ex, "Failed to request clear canvas");
408420
// Don't re-throw - not critical
409421
}
410422
}

Src/GhostDraw/Views/IOverlayWindow.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,11 @@ public interface IOverlayWindow
3535
/// Undoes the last drawing action
3636
/// </summary>
3737
void UndoLastAction();
38+
39+
/// <summary>
40+
/// Shows the clear canvas confirmation modal
41+
/// </summary>
42+
/// <param name="onConfirm">Action to call when user confirms (clicks Yes)</param>
43+
/// <param name="onCancel">Action to call when user cancels (clicks No or closes modal)</param>
44+
void ShowClearCanvasConfirmation(Action onConfirm, Action onCancel);
3845
}

Src/GhostDraw/Views/OverlayWindow.xaml

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
<TextBlock FontFamily="Segoe UI"
8989
FontSize="16"
9090
Foreground="#B0B0B0"
91-
Text="Press R to clear canvas | ESC to exit"/>
91+
Text="Press Delete to clear canvas | ESC to exit"/>
9292
</Border>
9393

9494
<!-- Screenshot Saved Toast (top-center of screen, cyberpunk style) -->
@@ -117,6 +117,115 @@
117117
Text="📸 Screenshot Saved!"/>
118118
</Border>
119119

120+
<!-- Clear Canvas Confirmation Modal (center of screen, dimmed background) -->
121+
<Grid x:Name="ClearCanvasModalGrid"
122+
Visibility="Collapsed">
123+
<!-- Dimmed background -->
124+
<Border Background="Black" Opacity="0.7"/>
125+
126+
<!-- Modal dialog -->
127+
<Border HorizontalAlignment="Center"
128+
VerticalAlignment="Center"
129+
Padding="40,32"
130+
Background="#0F1419"
131+
BorderBrush="#FF0080"
132+
BorderThickness="2"
133+
CornerRadius="8">
134+
<Border.Effect>
135+
<DropShadowEffect Color="#FF0080"
136+
Opacity="0.8"
137+
BlurRadius="30"
138+
ShadowDepth="0"/>
139+
</Border.Effect>
140+
<StackPanel>
141+
<!-- Question -->
142+
<TextBlock FontFamily="Segoe UI"
143+
FontSize="24"
144+
FontWeight="Bold"
145+
Foreground="#FFFFFF"
146+
Text="Clear canvas?"
147+
HorizontalAlignment="Center"
148+
Margin="0,0,0,24"/>
149+
150+
<!-- Buttons -->
151+
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
152+
<!-- Yes Button -->
153+
<Button x:Name="ClearCanvasYesButton"
154+
Content="Yes"
155+
FontFamily="Segoe UI"
156+
FontSize="18"
157+
FontWeight="Bold"
158+
Padding="32,12"
159+
Margin="0,0,16,0"
160+
Background="#FF0080"
161+
Foreground="#FFFFFF"
162+
BorderThickness="0"
163+
Cursor="Hand"
164+
Click="ClearCanvasYesButton_Click">
165+
<Button.Style>
166+
<Style TargetType="Button">
167+
<Setter Property="Background" Value="#FF0080"/>
168+
<Setter Property="Template">
169+
<Setter.Value>
170+
<ControlTemplate TargetType="Button">
171+
<Border Background="{TemplateBinding Background}"
172+
CornerRadius="4"
173+
Padding="{TemplateBinding Padding}">
174+
<ContentPresenter HorizontalAlignment="Center"
175+
VerticalAlignment="Center"/>
176+
</Border>
177+
</ControlTemplate>
178+
</Setter.Value>
179+
</Setter>
180+
<Style.Triggers>
181+
<Trigger Property="IsMouseOver" Value="True">
182+
<Setter Property="Background" Value="#FF1A99"/>
183+
</Trigger>
184+
</Style.Triggers>
185+
</Style>
186+
</Button.Style>
187+
</Button>
188+
189+
<!-- No Button -->
190+
<Button x:Name="ClearCanvasNoButton"
191+
Content="No"
192+
FontFamily="Segoe UI"
193+
FontSize="18"
194+
FontWeight="Bold"
195+
Padding="32,12"
196+
Background="#404040"
197+
Foreground="#FFFFFF"
198+
BorderThickness="0"
199+
Cursor="Hand"
200+
Click="ClearCanvasNoButton_Click">
201+
<Button.Style>
202+
<Style TargetType="Button">
203+
<Setter Property="Background" Value="#404040"/>
204+
<Setter Property="Template">
205+
<Setter.Value>
206+
<ControlTemplate TargetType="Button">
207+
<Border Background="{TemplateBinding Background}"
208+
CornerRadius="4"
209+
Padding="{TemplateBinding Padding}">
210+
<ContentPresenter HorizontalAlignment="Center"
211+
VerticalAlignment="Center"/>
212+
</Border>
213+
</ControlTemplate>
214+
</Setter.Value>
215+
</Setter>
216+
<Style.Triggers>
217+
<Trigger Property="IsMouseOver" Value="True">
218+
<Setter Property="Background" Value="#505050"/>
219+
</Trigger>
220+
</Style.Triggers>
221+
</Style>
222+
</Button.Style>
223+
</Button>
224+
</StackPanel>
225+
</StackPanel>
226+
</Border>
227+
</Grid>
228+
120229
<!-- Help Popup (center of screen, shows keyboard shortcuts) -->
121230
<Border x:Name="HelpPopupBorder"
122231
HorizontalAlignment="Center"
@@ -270,7 +379,7 @@
270379
FontSize="16"
271380
FontWeight="Bold"
272381
Foreground="#FFAA00"
273-
Text="R"
382+
Text="Delete"
274383
MinWidth="120"
275384
Margin="0,0,16,0"/>
276385
<TextBlock FontFamily="Segoe UI"

0 commit comments

Comments
 (0)