diff --git a/.github/workflows/01_build_test_publish.yaml b/.github/workflows/01_build_test_publish.yaml index 52d80a8..e4ead8d 100644 --- a/.github/workflows/01_build_test_publish.yaml +++ b/.github/workflows/01_build_test_publish.yaml @@ -67,6 +67,13 @@ jobs: name: FancyMouse-v0.0.0-preview path: .build/app + - name: upload test images + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-images + path: ./src/FancyMouse.UnitTests + #- name: dotnet tool jb inspectcode # working-directory: ${{ env.BUILD_PATH }} # run: | diff --git a/src/FancyMouse.UnitTests/Common/Helpers/DrawingHelperTests.cs b/src/FancyMouse.UnitTests/Common/Helpers/DrawingHelperTests.cs index 0e6074f..91af60b 100644 --- a/src/FancyMouse.UnitTests/Common/Helpers/DrawingHelperTests.cs +++ b/src/FancyMouse.UnitTests/Common/Helpers/DrawingHelperTests.cs @@ -1,4 +1,5 @@ using System.Drawing; +using System.Drawing.Imaging; using System.Reflection; using FancyMouse.Common.Helpers; using FancyMouse.Common.Imaging; @@ -44,12 +45,12 @@ public static IEnumerable GetTestCases() { new TestCase( previewStyle: AppSettings.DefaultSettings.PreviewStyle, - screens: new() + screens: new List() { - new RectangleInfo(0, 0, 500, 500), - new RectangleInfo(500, 0, 500, 500), - new RectangleInfo(500, 500, 500, 500), - new RectangleInfo(0, 500, 500, 500), + new(0, 0, 500, 500), + new(500, 0, 500, 500), + new(500, 500, 500, 500), + new(0, 500, 500, 500), }, activatedLocation: new(x: 50, y: 50), desktopImageFilename: "Common/Helpers/_test-4grid-desktop.png", @@ -60,10 +61,10 @@ public static IEnumerable GetTestCases() { new TestCase( previewStyle: AppSettings.DefaultSettings.PreviewStyle, - screens: new() + screens: new List() { - new RectangleInfo(5120, 349, 1920, 1080), - new RectangleInfo(0, 0, 5120, 1440), + new(5120, 349, 1920, 1080), + new(0, 0, 5120, 1440), }, activatedLocation: new(x: 50, y: 50), desktopImageFilename: "Common/Helpers/_test-win11-desktop.png", @@ -86,9 +87,17 @@ public void RunTestCases(TestCase data) var imageCopyService = new StaticImageRegionCopyService(desktopImage); using var actual = DrawingHelper.RenderPreview(previewLayout, imageCopyService); + // save the actual image so we can pick it up as a build artifact + var actualFilename = Path.GetFileNameWithoutExtension(data.ExpectedImageFilename) + "_actual" + Path.GetExtension(data.ExpectedImageFilename); + actual.Save(actualFilename, ImageFormat.Png); + // load the expected image var expected = GetPreviewLayoutTests.LoadImageResource(data.ExpectedImageFilename); + // save the actual image so we can pick it up as a build artifact + var expectedFilename = Path.GetFileNameWithoutExtension(data.ExpectedImageFilename) + "_expected" + Path.GetExtension(data.ExpectedImageFilename); + expected.Save(expectedFilename, ImageFormat.Png); + // compare the images var screens = System.Windows.Forms.Screen.AllScreens; AssertImagesEqual(expected, actual); @@ -106,7 +115,7 @@ private static Bitmap LoadImageResource(string filename) } var stream = assembly.GetManifestResourceStream(resourceName) - ?? throw new InvalidOperationException(); + ?? throw new InvalidOperationException(); var image = (Bitmap)Image.FromStream(stream); return image; } diff --git a/src/FancyMouse.UnitTests/Common/Helpers/LayoutHelperTests.cs b/src/FancyMouse.UnitTests/Common/Helpers/LayoutHelperTests.cs index 5882539..1bb8b5b 100644 --- a/src/FancyMouse.UnitTests/Common/Helpers/LayoutHelperTests.cs +++ b/src/FancyMouse.UnitTests/Common/Helpers/LayoutHelperTests.cs @@ -113,18 +113,19 @@ public TestCase(PreviewStyle previewStyle, List screens, PointInf this.ExpectedResult = expectedResult; } - public PreviewStyle PreviewStyle { get; set; } + public PreviewStyle PreviewStyle { get; } - public List Screens { get; set; } + public List Screens { get; } - public PointInfo ActivatedLocation { get; set; } + public PointInfo ActivatedLocation { get; } - public PreviewLayout ExpectedResult { get; set; } + public PreviewLayout ExpectedResult { get; } } public static IEnumerable GetTestCases() { - // happy path - 50% scaling, *has* preview borders but *no* screenshot borders + // happy path - single screen with 50% scaling, + // *has* a preview borders but *no* screenshot borders // // +----------------+ // | | @@ -180,7 +181,8 @@ public static IEnumerable GetTestCases() }); yield return new object[] { new TestCase(previewStyle, screens, activatedLocation, previewLayout) }; - // happy path - 50% scaling, *no* preview borders but *has* screenshot borders + // happy path - single screen with 50% scaling, + // *no* preview borders but *has* screenshot borders // // +----------------+ // | | diff --git a/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-desktop.png b/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-desktop.png index c0e11f8..b874606 100644 Binary files a/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-desktop.png and b/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-desktop.png differ diff --git a/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-expected.png b/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-expected.png index 707cdbd..9d4b161 100644 Binary files a/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-expected.png and b/src/FancyMouse.UnitTests/Common/Helpers/_test-win11-expected.png differ diff --git a/src/FancyMouse/Common/Helpers/DrawingHelper.cs b/src/FancyMouse/Common/Helpers/DrawingHelper.cs index d44863b..18138b0 100644 --- a/src/FancyMouse/Common/Helpers/DrawingHelper.cs +++ b/src/FancyMouse/Common/Helpers/DrawingHelper.cs @@ -49,12 +49,12 @@ public static Bitmap RenderPreview( previewGraphics, previewLayout.PreviewStyle.ScreenStyle, screenshotBounds); } - var imageUpdated = false; + var refreshRequired = false; var placeholdersDrawn = false; for (var i = 0; i < sourceScreens.Count; i++) { imageCopyService.CopyImageRegion(previewGraphics, sourceScreens[i], targetScreens[i].ContentBounds); - imageUpdated = true; + refreshRequired = true; // show the placeholder images and show the form if it looks like it might take // a while to capture the remaining screenshot images (but only if there are any) @@ -71,11 +71,11 @@ public static Bitmap RenderPreview( } previewImageUpdatedCallback?.Invoke(); - imageUpdated = false; + refreshRequired = false; } } - if (imageUpdated) + if (refreshRequired) { previewImageUpdatedCallback?.Invoke(); } @@ -92,7 +92,7 @@ private static void DrawRaisedBorder( Graphics graphics, BoxStyle boxStyle, BoxBounds boxBounds) { var borderStyle = boxStyle.BorderStyle; - if ((borderStyle.Horizontal == 0) && (borderStyle.Vertical == 0)) + if ((borderStyle.Horizontal == 0) || (borderStyle.Vertical == 0)) { return; } diff --git a/src/FancyMouse/Common/Helpers/LayoutHelper.cs b/src/FancyMouse/Common/Helpers/LayoutHelper.cs index a3944f0..3643046 100644 --- a/src/FancyMouse/Common/Helpers/LayoutHelper.cs +++ b/src/FancyMouse/Common/Helpers/LayoutHelper.cs @@ -18,17 +18,16 @@ public static PreviewLayout GetPreviewLayout( } var builder = new PreviewLayout.Builder(); + builder.Screens = screens.ToList(); // calculate the bounding rectangle for the virtual screen - var virtualScreen = LayoutHelper.GetCombinedScreenBounds(screens); - builder.VirtualScreen = virtualScreen; - builder.Screens = screens; + builder.VirtualScreen = LayoutHelper.GetCombinedScreenBounds(builder.Screens); // find the screen that contains the activated location - this is the // one we'll show the preview form on - var activatedScreen = screens.Single( + var activatedScreen = builder.Screens.Single( screen => screen.Contains(activatedLocation)); - builder.ActivatedScreenIndex = screens.IndexOf(activatedScreen); + builder.ActivatedScreenIndex = builder.Screens.IndexOf(activatedScreen); // work out the maximum allowed size of the preview form: // * can't be bigger than the activated screen @@ -43,11 +42,15 @@ public static PreviewLayout GetPreviewLayout( .Shrink(previewStyle.CanvasStyle.BorderStyle) .Shrink(previewStyle.CanvasStyle.PaddingStyle); + // scale the virtual screen to fit inside the content area + var screenScalingRatio = builder.VirtualScreen.Size + .ScaleToFitRatio(maxContentSize); + // work out the actual size of the "content area" by scaling the virtual screen // to fit inside the maximum content area while maintaining its aspect ration. // we'll also offset it to allow for any margins, borders and padding - var contentBounds = virtualScreen.Size - .ScaleToFit(maxContentSize) + var contentBounds = builder.VirtualScreen.Size + .Scale(screenScalingRatio) .Floor() .PlaceAt(0, 0) .Offset(previewStyle.CanvasStyle.MarginStyle.Left, previewStyle.CanvasStyle.MarginStyle.Top) @@ -69,18 +72,13 @@ public static PreviewLayout GetPreviewLayout( .Clamp(activatedScreen); builder.FormBounds = formBounds; - // get the scaling factor to draw screenshot images at by scaling the - // virtual screen to fit inside the preview content bounds - var scalingRatio = builder.VirtualScreen.Size - .ScaleToFitRatio(contentBounds.Size); - // now calculate the positions of each of the screenshot images on the preview - builder.ScreenshotBounds = screens + builder.ScreenshotBounds = builder.Screens .Select( screen => LayoutHelper.GetBoxBoundsFromOuterBounds( screen - .Offset(virtualScreen.Location.ToSize().Invert()) - .Scale(scalingRatio) + .Offset(builder.VirtualScreen.Location.ToSize().Invert()) + .Scale(screenScalingRatio) .Offset(builder.PreviewBounds.ContentBounds.Location.ToSize()) .Truncate(), previewStyle.ScreenStyle)) diff --git a/src/FancyMouse/Common/Models/Drawing/BoxBounds.cs b/src/FancyMouse/Common/Models/Drawing/BoxBounds.cs index 9903375..82d141d 100644 --- a/src/FancyMouse/Common/Models/Drawing/BoxBounds.cs +++ b/src/FancyMouse/Common/Models/Drawing/BoxBounds.cs @@ -22,7 +22,7 @@ public sealed class BoxBounds */ - public BoxBounds( + internal BoxBounds( RectangleInfo outerBounds, RectangleInfo marginBounds, RectangleInfo borderBounds, diff --git a/src/FancyMouse/Common/Models/Drawing/SizeInfo.cs b/src/FancyMouse/Common/Models/Drawing/SizeInfo.cs index f5c16f3..89da740 100644 --- a/src/FancyMouse/Common/Models/Drawing/SizeInfo.cs +++ b/src/FancyMouse/Common/Models/Drawing/SizeInfo.cs @@ -65,6 +65,10 @@ public SizeInfo Intersect(SizeInfo size) public SizeInfo Invert() => new(-this.Width, -this.Height); + public SizeInfo Scale(decimal scalingFactor) => new( + this.Width * scalingFactor, + this.Height * scalingFactor); + public SizeInfo Shrink(BorderStyle border) => new(this.Width - border.Horizontal, this.Height - border.Vertical); diff --git a/src/FancyMouse/Common/Models/Layout/PreviewLayout.cs b/src/FancyMouse/Common/Models/Layout/PreviewLayout.cs index e8153e3..1918640 100644 --- a/src/FancyMouse/Common/Models/Layout/PreviewLayout.cs +++ b/src/FancyMouse/Common/Models/Layout/PreviewLayout.cs @@ -10,7 +10,7 @@ public sealed class Builder { public Builder() { - this.Screens = new List(); + this.Screens = new(); this.ScreenshotBounds = new(); } @@ -26,7 +26,7 @@ public RectangleInfo? VirtualScreen set; } - public IList Screens + public List Screens { get; set; @@ -72,7 +72,7 @@ public PreviewLayout Build() public PreviewLayout( PreviewStyle previewStyle, RectangleInfo virtualScreen, - IList screens, + List screens, int activatedScreenIndex, RectangleInfo formBounds, BoxBounds previewBounds, diff --git a/src/FancyMouse/UI/FancyMouseForm.cs b/src/FancyMouse/UI/FancyMouseForm.cs index cf597fb..42da162 100644 --- a/src/FancyMouse/UI/FancyMouseForm.cs +++ b/src/FancyMouse/UI/FancyMouseForm.cs @@ -252,6 +252,10 @@ private void OnPreviewImageUpdated() { if (!this.Visible) { + // we seem to need to turn off topmost and then re-enable it again + // when we show the form, otherwise it doesn't always get shown topmost... + this.TopMost = false; + this.TopMost = true; this.Show(); }