diff --git a/mRemoteNGTests/Properties/Resources.Designer.cs b/mRemoteNGTests/Properties/Resources.Designer.cs
index 2f759968..48157bac 100644
--- a/mRemoteNGTests/Properties/Resources.Designer.cs
+++ b/mRemoteNGTests/Properties/Resources.Designer.cs
@@ -329,6 +329,16 @@ namespace mRemoteNGTests.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap TestImage {
+ get {
+ object obj = ResourceManager.GetObject("TestImage", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized string similar to Version: 1.75.6164.27544
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
diff --git a/mRemoteNGTests/Properties/Resources.resx b/mRemoteNGTests/Properties/Resources.resx
index 902712d2..93d4db1f 100644
--- a/mRemoteNGTests/Properties/Resources.resx
+++ b/mRemoteNGTests/Properties/Resources.resx
@@ -154,6 +154,9 @@
..\Resources\dev-update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
+
+ ..\Resources\TestImage.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
..\Resources\test_puttyConnectionManager_database.dat;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16
diff --git a/mRemoteNGTests/Resources/TestImage.bmp b/mRemoteNGTests/Resources/TestImage.bmp
new file mode 100644
index 00000000..745429ef
Binary files /dev/null and b/mRemoteNGTests/Resources/TestImage.bmp differ
diff --git a/mRemoteNGTests/UI/DisplayPropertiesTests.cs b/mRemoteNGTests/UI/DisplayPropertiesTests.cs
new file mode 100644
index 00000000..124fb093
--- /dev/null
+++ b/mRemoteNGTests/UI/DisplayPropertiesTests.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Drawing;
+using mRemoteNG.UI;
+using mRemoteNG.UI.GraphicsUtilities;
+using mRemoteNGTests.Properties;
+using NSubstitute;
+using NUnit.Framework;
+
+namespace mRemoteNGTests.UI
+{
+ public class DisplayPropertiesTests
+ {
+ [Test]
+ public void ScaleHeightReturnsValueScaledByHeightScalingFactor()
+ {
+ var graphics = Substitute.For();
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(4, 2));
+ var sut = new DisplayProperties(graphics);
+
+ var initialValue = 10;
+ var scaledValue = sut.ScaleHeight(initialValue);
+
+ Assert.That(scaledValue, Is.EqualTo(sut.ResolutionScalingFactor.Height * initialValue));
+ }
+
+ [Test]
+ public void ScaleWidthReturnsValueScaledByWidthScalingFactor()
+ {
+ var graphics = Substitute.For();
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(4, 2));
+ var sut = new DisplayProperties(graphics);
+
+ var initialValue = 10;
+ var scaledValue = sut.ScaleWidth(initialValue);
+
+ Assert.That(scaledValue, Is.EqualTo(sut.ResolutionScalingFactor.Width * initialValue));
+ }
+
+ [Test]
+ public void ScaleSizeReturnsNewSizeWithCorrectlyScaledHeight()
+ {
+ var graphics = Substitute.For();
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(4, 2));
+ var sut = new DisplayProperties(graphics);
+
+ var initialValue = new Size(12, 16);
+ var scaledValue = sut.ScaleSize(initialValue);
+
+ Assert.That(scaledValue.Height, Is.EqualTo(sut.ResolutionScalingFactor.Height * initialValue.Height));
+ }
+
+ [Test]
+ public void ScaleSizeReturnsNewSizeWithCorrectlyScaledWidth()
+ {
+ var graphics = Substitute.For();
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(4, 2));
+ var sut = new DisplayProperties(graphics);
+
+ var initialValue = new Size(12, 16);
+ var scaledValue = sut.ScaleSize(initialValue);
+
+ Assert.That(scaledValue.Width, Is.EqualTo(sut.ResolutionScalingFactor.Width * initialValue.Width));
+ }
+
+ [Test]
+ public void ScaleImageReturnsNewImageWithCorrectlyScaledHeight()
+ {
+ var graphics = Substitute.For();
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(4, 2));
+ var sut = new DisplayProperties(graphics);
+
+ var initialValue = Resources.TestImage;
+ var scaledValue = sut.ScaleImage(initialValue);
+
+ Assert.That(scaledValue.Height, Is.EqualTo(sut.ResolutionScalingFactor.Height * initialValue.Height));
+ }
+
+ [Test]
+ public void ScaleImageReturnsNewImageWithCorrectlyScaledWidth()
+ {
+ var graphics = Substitute.For();
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(4, 2));
+ var sut = new DisplayProperties(graphics);
+
+ var initialValue = Resources.TestImage;
+ var scaledValue = sut.ScaleImage(initialValue);
+
+ Assert.That(scaledValue.Width, Is.EqualTo(sut.ResolutionScalingFactor.Width * initialValue.Width));
+ }
+
+ [Test]
+ public void ResolutionScalingFactorAlwaysReturnsMostUpdatedValue()
+ {
+ var graphics = Substitute.For();
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(4, 4));
+ var sut = new DisplayProperties(graphics);
+
+ graphics.GetResolutionScalingFactor().Returns(new SizeF(8, 8));
+ Assert.That(sut.ResolutionScalingFactor.Width, Is.EqualTo(8));
+ }
+
+ [Test]
+ public void AttemptingToScaleANullImageWillThrowAnException()
+ {
+ var sut = new DisplayProperties(Substitute.For());
+ Assert.Throws(() => sut.ScaleImage((Image)null));
+ }
+
+ [Test]
+ public void AttemptingToScaleANullIconWillThrowAnException()
+ {
+ var sut = new DisplayProperties(Substitute.For());
+ Assert.Throws(() => sut.ScaleImage((Icon)null));
+ }
+
+ [Test]
+ public void AttemptingToCallConstructorWithNullGraphicsProviderWillThrow()
+ {
+ // ReSharper disable once ObjectCreationAsStatement
+ Assert.Throws(() => new DisplayProperties(null));
+ }
+ }
+}
diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj
index 61485194..84511745 100644
--- a/mRemoteNGTests/mRemoteNGTests.csproj
+++ b/mRemoteNGTests/mRemoteNGTests.csproj
@@ -231,6 +231,7 @@
TextBoxExtensionsTestForm.cs
+
@@ -295,6 +296,7 @@
+
diff --git a/mRemoteV1/UI/DisplayProperties.cs b/mRemoteV1/UI/DisplayProperties.cs
index 18cff4be..dae5ee06 100644
--- a/mRemoteV1/UI/DisplayProperties.cs
+++ b/mRemoteV1/UI/DisplayProperties.cs
@@ -2,16 +2,35 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
-using System.Windows.Forms;
+using mRemoteNG.Tools;
+using mRemoteNG.UI.GraphicsUtilities;
namespace mRemoteNG.UI
{
public class DisplayProperties
{
- // Dpi of a 'normal' definition screen
- private const int BaselineDpi = 96;
+ private readonly IGraphicsProvider _graphicsProvider;
- public SizeF ResolutionScalingFactor { get; } = GetResolutionScalingFactor();
+ public SizeF ResolutionScalingFactor => _graphicsProvider.GetResolutionScalingFactor();
+
+ ///
+ /// Creates a new instance with the default
+ /// of type
+ ///
+ public DisplayProperties()
+ : this(new GdiPlusGraphicsProvider())
+ {
+ }
+
+ ///
+ /// Creates a new instance with the given
+ /// .
+ ///
+ ///
+ public DisplayProperties(IGraphicsProvider graphicsProvider)
+ {
+ _graphicsProvider = graphicsProvider.ThrowIfNull(nameof(graphicsProvider));
+ }
///
/// Scale the given nominal width value by the
@@ -28,7 +47,7 @@ namespace mRemoteNG.UI
///
public int ScaleHeight(float height)
{
- return CalculateScaledValue(height, ResolutionScalingFactor.Width);
+ return CalculateScaledValue(height, ResolutionScalingFactor.Height);
}
///
@@ -52,6 +71,9 @@ namespace mRemoteNG.UI
///
public Bitmap ScaleImage(Image image)
{
+ if (image == null)
+ throw new ArgumentNullException(nameof(image));
+
var width = ScaleWidth(image.Width);
var height = ScaleHeight(image.Height);
var destRect = new Rectangle(0, 0, width, height);
@@ -79,6 +101,9 @@ namespace mRemoteNG.UI
public Bitmap ScaleImage(Icon icon)
{
+ if (icon == null)
+ throw new ArgumentNullException(nameof(icon));
+
return ScaleImage(icon.ToBitmap());
}
@@ -90,13 +115,5 @@ namespace mRemoteNG.UI
{
return (int)Math.Round(value * scalingValue);
}
-
- private static SizeF GetResolutionScalingFactor()
- {
- using (var g = new Form().CreateGraphics())
- {
- return new SizeF(g.DpiX/BaselineDpi, g.DpiY / BaselineDpi);
- }
- }
}
}
diff --git a/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs b/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs
new file mode 100644
index 00000000..d6fdc481
--- /dev/null
+++ b/mRemoteV1/UI/GraphicsUtilities/GdiPlusGraphicsProvider.cs
@@ -0,0 +1,22 @@
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace mRemoteNG.UI.GraphicsUtilities
+{
+ ///
+ /// Gets environment graphics information using the Windows GDI+ API.
+ ///
+ public class GdiPlusGraphicsProvider : IGraphicsProvider
+ {
+ // Dpi of a 'normal' definition screen
+ private const int BaselineDpi = 96;
+
+ public SizeF GetResolutionScalingFactor()
+ {
+ using (var g = new Form().CreateGraphics())
+ {
+ return new SizeF(g.DpiX / BaselineDpi, g.DpiY / BaselineDpi);
+ }
+ }
+ }
+}
diff --git a/mRemoteV1/UI/GraphicsUtilities/IGraphicsProvider.cs b/mRemoteV1/UI/GraphicsUtilities/IGraphicsProvider.cs
new file mode 100644
index 00000000..918a5b7e
--- /dev/null
+++ b/mRemoteV1/UI/GraphicsUtilities/IGraphicsProvider.cs
@@ -0,0 +1,9 @@
+using System.Drawing;
+
+namespace mRemoteNG.UI.GraphicsUtilities
+{
+ public interface IGraphicsProvider
+ {
+ SizeF GetResolutionScalingFactor();
+ }
+}
diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj
index e12c42ab..085f7eb8 100644
--- a/mRemoteV1/mRemoteV1.csproj
+++ b/mRemoteV1/mRemoteV1.csproj
@@ -664,6 +664,8 @@
UnhandledExceptionWindow.cs
+
+
Component