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