Skip to content

Commit 1b0deda

Browse files
committed
feat: activation and tool change hint popup center bottom screen that fades away.
1 parent 425d8ec commit 1b0deda

6 files changed

Lines changed: 121 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- **Windows Store Package**
1212
- Added windows store package project and publish first version to windows store.
1313
- Added new custom splash screen.
14+
- Add activation and tool change hint popup center bottom screen that fades away.
1415

1516
### Changed
1617
- Versioning semantics to 4-part
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using GhostDraw.Core;
5+
6+
namespace GhostDraw.Helpers;
7+
8+
/// <summary>
9+
/// Builds the user-facing text shown in the drawing mode hint popup.
10+
/// </summary>
11+
public static class DrawingModeHintMessageBuilder
12+
{
13+
public static string Build(DrawTool activeTool, IReadOnlyList<int> hotkeyKeys, bool isLockMode)
14+
{
15+
var toolName = GetToolDisplayName(activeTool);
16+
var hotkeyDisplayName = VirtualKeyHelper.GetCombinationDisplayName(hotkeyKeys?.ToList() ?? new List<int>());
17+
var exitInstruction = isLockMode
18+
? $"Press Esc or {hotkeyDisplayName} to exit draw mode"
19+
: $"Press Esc or release {hotkeyDisplayName} to exit draw mode";
20+
21+
return string.Join(Environment.NewLine,
22+
$"Current tool: {toolName}",
23+
"Press F1 for help",
24+
"Press Delete to clear canvas",
25+
exitInstruction);
26+
}
27+
28+
private static string GetToolDisplayName(DrawTool tool) => tool switch
29+
{
30+
DrawTool.Pen => "Pen",
31+
DrawTool.Line => "Line",
32+
DrawTool.Arrow => "Arrow",
33+
DrawTool.Eraser => "Eraser",
34+
DrawTool.Rectangle => "Rectangle",
35+
DrawTool.Circle => "Circle",
36+
DrawTool.Text => "Text",
37+
_ => tool.ToString()
38+
};
39+
}

Src/GhostDraw/Views/OverlayWindow.xaml.cs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ public partial class OverlayWindow : Window, IOverlayWindow
2020
private readonly DrawingHistory _drawingHistory;
2121
private bool _isDrawing = false;
2222
private bool _isHelpVisible = false;
23+
private bool _hasShownDrawingHint = false;
24+
private DateTimeOffset _lastDrawingHintShownAt = DateTimeOffset.MinValue;
25+
private static readonly TimeSpan DrawingHintDebounce = TimeSpan.FromMilliseconds(400);
2326

2427
// Tool instances
2528
private readonly PenTool _penTool;
@@ -190,6 +193,8 @@ public void EnableDrawing()
190193
ClearDrawing();
191194

192195
_isDrawing = true;
196+
_hasShownDrawingHint = false;
197+
_lastDrawingHintShownAt = DateTimeOffset.MinValue;
193198

194199
// Initialize active tool based on current settings
195200
var settings = _appSettings.CurrentSettings;
@@ -227,6 +232,8 @@ public void DisableDrawingInternal(bool clearHistory)
227232
{
228233
_logger.LogInformation("?? Drawing disabled");
229234
_isDrawing = false;
235+
_hasShownDrawingHint = false;
236+
_lastDrawingHintShownAt = DateTimeOffset.MinValue;
230237

231238
// Deactivate current tool and cancel any in-progress operations
232239
if (_activeTool != null)
@@ -415,6 +422,11 @@ public void OnToolChanged(DrawTool newTool)
415422
// Update cursor for new tool
416423
UpdateCursor();
417424

425+
if (_isDrawing)
426+
{
427+
ShowDrawingModeHint(fromToolChange: true);
428+
}
429+
418430
_logger.LogInformation("Tool changed to {Tool}", newTool);
419431
}
420432
catch (Exception ex)
@@ -612,12 +624,34 @@ private void HideCanvasClearedToast()
612624
/// <summary>
613625
/// Shows the drawing mode hint with animation (displayed when entering drawing mode)
614626
/// </summary>
615-
private void ShowDrawingModeHint()
627+
private void ShowDrawingModeHint(bool fromToolChange = false)
616628
{
617629
try
618630
{
619-
DrawingModeHint.Show("Press Delete to clear canvas | ESC to exit");
620-
_logger.LogDebug("Drawing mode hint shown");
631+
if (fromToolChange && !_hasShownDrawingHint)
632+
{
633+
// Avoid double-show during initial activation when tool change events fire
634+
return;
635+
}
636+
637+
var now = DateTimeOffset.UtcNow;
638+
if (fromToolChange && (now - _lastDrawingHintShownAt) < DrawingHintDebounce)
639+
{
640+
_logger.LogDebug("Drawing mode hint throttled (from tool change)");
641+
return;
642+
}
643+
644+
var settings = _appSettings.CurrentSettings;
645+
var message = DrawingModeHintMessageBuilder.Build(
646+
settings.ActiveTool,
647+
settings.HotkeyVirtualKeys,
648+
settings.LockDrawingMode);
649+
650+
DrawingModeHint.Show(message);
651+
_hasShownDrawingHint = true;
652+
_lastDrawingHintShownAt = now;
653+
_logger.LogDebug("Drawing mode hint shown with tool {Tool} and hotkey {Hotkey} (LockMode={LockMode})",
654+
settings.ActiveTool, settings.HotkeyDisplayName, settings.LockDrawingMode);
621655
}
622656
catch (Exception ex)
623657
{

Src/GhostDraw/Views/UserControls/DrawingModeHintControl.xaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
FontFamily="Segoe UI"
2626
FontSize="16"
2727
Foreground="#B0B0B0"
28-
Text="Press Delete to clear canvas | ESC to exit"/>
28+
TextAlignment="Center"
29+
TextWrapping="Wrap"
30+
Text="Current tool: Pen&#x0a;Press F1 for help&#x0a;Press Delete to clear canvas&#x0a;Press Esc or hotkey to exit draw mode"/>
2931
</Border>
3032
</UserControl>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using GhostDraw.Core;
3+
using GhostDraw.Helpers;
4+
5+
namespace GhostDraw.Tests;
6+
7+
public class DrawingModeHintMessageBuilderTests
8+
{
9+
[Fact]
10+
public void Build_LockMode_UsesPressHotkeyMessage()
11+
{
12+
var message = DrawingModeHintMessageBuilder.Build(DrawTool.Line, new[] { 0x11, 0x12, 0x58 }, true);
13+
14+
var expected = string.Join(Environment.NewLine,
15+
"Current tool: Line",
16+
"Press F1 for help",
17+
"Press Delete to clear canvas",
18+
"Press Esc or Ctrl + Alt + X to exit draw mode");
19+
20+
Assert.Equal(expected, message);
21+
}
22+
23+
[Fact]
24+
public void Build_HoldMode_UsesReleaseHotkeyMessage()
25+
{
26+
var message = DrawingModeHintMessageBuilder.Build(DrawTool.Text, new[] { 0x10, 0x20 }, false);
27+
28+
var expected = string.Join(Environment.NewLine,
29+
"Current tool: Text",
30+
"Press F1 for help",
31+
"Press Delete to clear canvas",
32+
"Press Esc or release Shift + Space to exit draw mode");
33+
34+
Assert.Equal(expected, message);
35+
}
36+
}

docs/TODO.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@
4646
- [X] openFolderAfterScreenshot default to `true`
4747
- [X] Splash screen uses `docs\hero-orig.png` (WPF splash + MSIX SplashScreen.png)
4848
- [X] Tray about screen update with accurate info
49-
- [ ] Tool change toast bottom center screen fades away
50-
- [ ] Activation toast bottom center screen
51-
- [ ] Show current tool
52-
- [ ] How to exit. Depending on activation hotkey
53-
- [ ] F1 for help
49+
- [X] Tool change toast bottom center screen fades away
50+
- [X] Activation toast bottom center screen
51+
- [X] Show current tool
52+
- [X] How to exit. Depending on activation hotkey
53+
- [X] F1 for help
5454
- [X] Ensure setting dir work in both msi version and win store version
5555
- [X] All project build warnings, messages and errors are resolved
5656
- [ ] All documents updated with correct information. Not needed documents removed.

0 commit comments

Comments
 (0)