Skip to content

Commit 68504b6

Browse files
authored
Merge pull request #620 from TheJoeFin/grab-templates
Grab templates
2 parents c3113ab + 6952739 commit 68504b6

62 files changed

Lines changed: 7768 additions & 889 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Tests/BarcodeUtilitiesTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System.Drawing;
2+
using System.Drawing.Imaging;
3+
using System.IO;
4+
using System.Runtime.InteropServices.WindowsRuntime;
5+
using Text_Grab;
6+
using Text_Grab.Models;
7+
using Text_Grab.Utilities;
8+
using Windows.Storage.Streams;
9+
10+
namespace Tests;
11+
12+
public class BarcodeUtilitiesTests
13+
{
14+
[Fact]
15+
public void TryToReadBarcodes_WithDisposedBitmap_ReturnsEmptyBarcodeOutput()
16+
{
17+
Bitmap disposedBitmap = new(8, 8);
18+
disposedBitmap.Dispose();
19+
20+
OcrOutput result = BarcodeUtilities.TryToReadBarcodes(disposedBitmap);
21+
22+
Assert.Equal(OcrOutputKind.Barcode, result.Kind);
23+
Assert.Equal(string.Empty, result.RawOutput);
24+
}
25+
26+
[Fact]
27+
public async Task GetBitmapFromIRandomAccessStream_ReturnsBitmapIndependentOfSourceStream()
28+
{
29+
using Bitmap sourceBitmap = new(8, 8);
30+
sourceBitmap.SetPixel(0, 0, Color.Red);
31+
32+
using MemoryStream memoryStream = new();
33+
sourceBitmap.Save(memoryStream, ImageFormat.Png);
34+
35+
using InMemoryRandomAccessStream randomAccessStream = new();
36+
_ = await randomAccessStream.WriteAsync(memoryStream.ToArray().AsBuffer());
37+
38+
Bitmap clonedBitmap = ImageMethods.GetBitmapFromIRandomAccessStream(randomAccessStream);
39+
40+
Assert.Equal(8, clonedBitmap.Width);
41+
Assert.Equal(8, clonedBitmap.Height);
42+
Assert.Equal(Color.Red.ToArgb(), clonedBitmap.GetPixel(0, 0).ToArgb());
43+
}
44+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Drawing;
2+
using System.Windows;
3+
using System.Windows.Media;
4+
using Text_Grab.Utilities;
5+
using Point = System.Windows.Point;
6+
7+
namespace Tests;
8+
9+
public class FreeformCaptureUtilitiesTests
10+
{
11+
[WpfFact]
12+
public void GetBounds_RoundsOutwardToIncludeAllPoints()
13+
{
14+
List<Point> points =
15+
[
16+
new(1.2, 2.8),
17+
new(10.1, 4.2),
18+
new(4.6, 9.9)
19+
];
20+
21+
Rect bounds = FreeformCaptureUtilities.GetBounds(points);
22+
23+
Assert.Equal(new Rect(new Point(1, 2), new Point(11, 10)), bounds);
24+
}
25+
26+
[WpfFact]
27+
public void BuildGeometry_CreatesClosedFigure()
28+
{
29+
List<Point> points =
30+
[
31+
new(0, 0),
32+
new(4, 0),
33+
new(4, 4)
34+
];
35+
36+
PathGeometry geometry = FreeformCaptureUtilities.BuildGeometry(points);
37+
38+
Assert.Single(geometry.Figures);
39+
Assert.Equal(points[0], geometry.Figures[0].StartPoint);
40+
Assert.True(geometry.Figures[0].IsClosed);
41+
Assert.Equal(2, geometry.Figures[0].Segments.Count);
42+
}
43+
44+
[WpfFact]
45+
public void CreateMaskedBitmap_WhitensPixelsOutsideThePolygon()
46+
{
47+
using Bitmap sourceBitmap = new(10, 10);
48+
using Graphics graphics = Graphics.FromImage(sourceBitmap);
49+
graphics.Clear(System.Drawing.Color.Black);
50+
51+
using Bitmap maskedBitmap = FreeformCaptureUtilities.CreateMaskedBitmap(
52+
sourceBitmap,
53+
[
54+
new Point(2, 2),
55+
new Point(7, 2),
56+
new Point(7, 7),
57+
new Point(2, 7)
58+
]);
59+
60+
Assert.Equal(System.Drawing.Color.Gray.ToArgb(), maskedBitmap.GetPixel(0, 0).ToArgb());
61+
Assert.Equal(System.Drawing.Color.Black.ToArgb(), maskedBitmap.GetPixel(4, 4).ToArgb());
62+
}
63+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Windows;
2+
using Text_Grab;
3+
using Text_Grab.Models;
4+
5+
namespace Tests;
6+
7+
public class FullscreenCaptureResultTests
8+
{
9+
[Theory]
10+
[InlineData(FsgSelectionStyle.Region, true)]
11+
[InlineData(FsgSelectionStyle.Window, true)]
12+
[InlineData(FsgSelectionStyle.Freeform, false)]
13+
[InlineData(FsgSelectionStyle.AdjustAfter, true)]
14+
public void SupportsTemplateActions_MatchesSelectionStyle(FsgSelectionStyle selectionStyle, bool expected)
15+
{
16+
FullscreenCaptureResult result = new(selectionStyle, Rect.Empty);
17+
18+
Assert.Equal(expected, result.SupportsTemplateActions);
19+
}
20+
21+
[Theory]
22+
[InlineData(FsgSelectionStyle.Region, true)]
23+
[InlineData(FsgSelectionStyle.Window, false)]
24+
[InlineData(FsgSelectionStyle.Freeform, false)]
25+
[InlineData(FsgSelectionStyle.AdjustAfter, true)]
26+
public void SupportsPreviousRegionReplay_MatchesSelectionStyle(FsgSelectionStyle selectionStyle, bool expected)
27+
{
28+
FullscreenCaptureResult result = new(selectionStyle, Rect.Empty);
29+
30+
Assert.Equal(expected, result.SupportsPreviousRegionReplay);
31+
}
32+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using System.Windows.Controls;
2+
using Text_Grab.Models;
3+
using Text_Grab.Views;
4+
using Wpf.Ui.Controls;
5+
using MenuItem = System.Windows.Controls.MenuItem;
6+
7+
namespace Tests;
8+
9+
public class FullscreenGrabPostGrabActionTests
10+
{
11+
[Fact]
12+
public void GetPostGrabActionKey_UsesTemplateIdForTemplateActions()
13+
{
14+
ButtonInfo action = new("Template Action", "ApplyTemplate_Click", SymbolRegular.Apps24, DefaultCheckState.Off)
15+
{
16+
TemplateId = "template-123"
17+
};
18+
19+
string key = FullscreenGrab.GetPostGrabActionKey(action);
20+
21+
Assert.Equal("template:template-123", key);
22+
}
23+
24+
[Fact]
25+
public void GetPostGrabActionKey_FallsBackToButtonTextWhenClickEventMissing()
26+
{
27+
ButtonInfo action = new()
28+
{
29+
ButtonText = "Custom action"
30+
};
31+
32+
string key = FullscreenGrab.GetPostGrabActionKey(action);
33+
34+
Assert.Equal("text:Custom action", key);
35+
}
36+
37+
[WpfFact]
38+
public void GetActionablePostGrabMenuItems_ExcludesUtilityEntriesAndPreservesOrder()
39+
{
40+
ContextMenu contextMenu = new();
41+
MenuItem firstAction = new()
42+
{
43+
Header = "First action",
44+
Tag = new ButtonInfo("First action", "First_Click", SymbolRegular.Apps24, DefaultCheckState.Off)
45+
};
46+
MenuItem utilityItem = new()
47+
{
48+
Header = "Customize",
49+
Tag = "EditPostGrabActions"
50+
};
51+
MenuItem secondAction = new()
52+
{
53+
Header = "Second action",
54+
Tag = new ButtonInfo("Second action", "Second_Click", SymbolRegular.Apps24, DefaultCheckState.Off)
55+
};
56+
57+
contextMenu.Items.Add(firstAction);
58+
contextMenu.Items.Add(new Separator());
59+
contextMenu.Items.Add(utilityItem);
60+
contextMenu.Items.Add(secondAction);
61+
contextMenu.Items.Add(new MenuItem
62+
{
63+
Header = "Close this menu",
64+
Tag = "ClosePostGrabMenu"
65+
});
66+
67+
List<MenuItem> actionableItems = FullscreenGrab.GetActionablePostGrabMenuItems(contextMenu);
68+
69+
Assert.Collection(actionableItems,
70+
item => Assert.Same(firstAction, item),
71+
item => Assert.Same(secondAction, item));
72+
}
73+
74+
[WpfFact]
75+
public void BuildPostGrabActionSnapshot_KeepsChangedTemplateCheckedAndUnchecksOthers()
76+
{
77+
ButtonInfo regularAction = new("Trim each line", "TrimEachLine_Click", SymbolRegular.Apps24, DefaultCheckState.Off);
78+
ButtonInfo firstTemplate = new("Template A", "ApplyTemplate_Click", SymbolRegular.Apps24, DefaultCheckState.Off)
79+
{
80+
TemplateId = "template-a"
81+
};
82+
ButtonInfo secondTemplate = new("Template B", "ApplyTemplate_Click", SymbolRegular.Apps24, DefaultCheckState.Off)
83+
{
84+
TemplateId = "template-b"
85+
};
86+
87+
Dictionary<string, bool> snapshot = FullscreenGrab.BuildPostGrabActionSnapshot(
88+
[
89+
new MenuItem { Tag = regularAction, IsCheckable = true, IsChecked = true },
90+
new MenuItem { Tag = firstTemplate, IsCheckable = true, IsChecked = true },
91+
new MenuItem { Tag = secondTemplate, IsCheckable = true, IsChecked = false }
92+
],
93+
FullscreenGrab.GetPostGrabActionKey(secondTemplate),
94+
true);
95+
96+
Assert.True(snapshot[FullscreenGrab.GetPostGrabActionKey(regularAction)]);
97+
Assert.False(snapshot[FullscreenGrab.GetPostGrabActionKey(firstTemplate)]);
98+
Assert.True(snapshot[FullscreenGrab.GetPostGrabActionKey(secondTemplate)]);
99+
}
100+
101+
[Fact]
102+
public void ShouldPersistLastUsedState_ForForcedSourceAction_ReturnsTrue()
103+
{
104+
ButtonInfo lastUsedAction = new("Remove duplicate lines", "RemoveDuplicateLines_Click", SymbolRegular.Apps24, DefaultCheckState.LastUsed);
105+
106+
bool shouldPersist = FullscreenGrab.ShouldPersistLastUsedState(
107+
lastUsedAction,
108+
previousChecked: true,
109+
isChecked: true,
110+
forcePersistActionKey: FullscreenGrab.GetPostGrabActionKey(lastUsedAction));
111+
112+
Assert.True(shouldPersist);
113+
}
114+
115+
[Fact]
116+
public void ShouldPersistLastUsedState_DoesNotPersistUnchangedNonSourceAction()
117+
{
118+
ButtonInfo lastUsedAction = new("Remove duplicate lines", "RemoveDuplicateLines_Click", SymbolRegular.Apps24, DefaultCheckState.LastUsed);
119+
120+
bool shouldPersist = FullscreenGrab.ShouldPersistLastUsedState(
121+
lastUsedAction,
122+
previousChecked: true,
123+
isChecked: true);
124+
125+
Assert.False(shouldPersist);
126+
}
127+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System.Windows;
2+
using Text_Grab;
3+
using Text_Grab.Models;
4+
using Text_Grab.Views;
5+
6+
namespace Tests;
7+
8+
public class FullscreenGrabSelectionStyleTests
9+
{
10+
[Theory]
11+
[InlineData(FsgSelectionStyle.Window, false, true)]
12+
[InlineData(FsgSelectionStyle.Window, true, true)]
13+
[InlineData(FsgSelectionStyle.Region, true, true)]
14+
[InlineData(FsgSelectionStyle.Region, false, false)]
15+
[InlineData(FsgSelectionStyle.Freeform, false, false)]
16+
[InlineData(FsgSelectionStyle.AdjustAfter, false, false)]
17+
public void ShouldKeepTopToolbarVisible_MatchesSelectionState(
18+
FsgSelectionStyle selectionStyle,
19+
bool isAwaitingAdjustAfterCommit,
20+
bool expected)
21+
{
22+
bool shouldKeepVisible = FullscreenGrab.ShouldKeepTopToolbarVisible(
23+
selectionStyle,
24+
isAwaitingAdjustAfterCommit);
25+
26+
Assert.Equal(expected, shouldKeepVisible);
27+
}
28+
29+
[Theory]
30+
[InlineData(FsgSelectionStyle.Region, true)]
31+
[InlineData(FsgSelectionStyle.Window, false)]
32+
[InlineData(FsgSelectionStyle.Freeform, false)]
33+
[InlineData(FsgSelectionStyle.AdjustAfter, true)]
34+
public void ShouldUseOverlayCutout_MatchesSelectionStyle(FsgSelectionStyle selectionStyle, bool expected)
35+
{
36+
bool shouldUseCutout = FullscreenGrab.ShouldUseOverlayCutout(selectionStyle);
37+
38+
Assert.Equal(expected, shouldUseCutout);
39+
}
40+
41+
[Theory]
42+
[InlineData(FsgSelectionStyle.Region, true)]
43+
[InlineData(FsgSelectionStyle.Window, false)]
44+
[InlineData(FsgSelectionStyle.Freeform, false)]
45+
[InlineData(FsgSelectionStyle.AdjustAfter, true)]
46+
public void ShouldDrawSelectionOutline_MatchesSelectionStyle(FsgSelectionStyle selectionStyle, bool expected)
47+
{
48+
bool shouldDrawOutline = FullscreenGrab.ShouldDrawSelectionOutline(selectionStyle);
49+
50+
Assert.Equal(expected, shouldDrawOutline);
51+
}
52+
53+
[Fact]
54+
public void ShouldCommitWindowSelection_RequiresSameWindowHandleOnMouseUp()
55+
{
56+
WindowSelectionCandidate pressedCandidate = new((nint)1, new Rect(0, 0, 40, 40), "Target", 100);
57+
WindowSelectionCandidate releasedSameCandidate = new((nint)1, new Rect(0, 0, 40, 40), "Target", 100);
58+
WindowSelectionCandidate releasedDifferentCandidate = new((nint)2, new Rect(0, 0, 40, 40), "Other", 200);
59+
60+
Assert.True(FullscreenGrab.ShouldCommitWindowSelection(pressedCandidate, releasedSameCandidate));
61+
Assert.False(FullscreenGrab.ShouldCommitWindowSelection(pressedCandidate, releasedDifferentCandidate));
62+
Assert.False(FullscreenGrab.ShouldCommitWindowSelection(pressedCandidate, null));
63+
Assert.False(FullscreenGrab.ShouldCommitWindowSelection(null, releasedSameCandidate));
64+
}
65+
66+
[Fact]
67+
public void WindowSelectionCandidate_DisplayText_UsesFallbacksWhenMetadataMissing()
68+
{
69+
WindowSelectionCandidate candidate = new((nint)1, new Rect(0, 0, 40, 40), string.Empty, 100);
70+
71+
Assert.Equal("Application", candidate.DisplayAppName);
72+
Assert.Equal("Untitled window", candidate.DisplayTitle);
73+
}
74+
}

0 commit comments

Comments
 (0)