diff --git a/src/Eto.Mac/SDConversions.cs b/src/Eto.Mac/SDConversions.cs
index 1cd213ced4..8f6380deef 100644
--- a/src/Eto.Mac/SDConversions.cs
+++ b/src/Eto.Mac/SDConversions.cs
@@ -99,6 +99,11 @@ public static sd.PointF ToSD (this PointF point)
return new sd.PointF (point.X, point.Y);
}
+ public static sd.Point ToSDPoint (this PointF point)
+ {
+ return new sd.Point ((int)point.X, (int)point.Y);
+ }
+
internal static sd.PointF[] ToSD (this PointF[] points)
{
var result = new sd.PointF[points.Length];
diff --git a/src/Eto.WinForms/Win32.dpi.cs b/src/Eto.WinForms/Win32.dpi.cs
index 679af4b3a1..7f6427e882 100644
--- a/src/Eto.WinForms/Win32.dpi.cs
+++ b/src/Eto.WinForms/Win32.dpi.cs
@@ -59,12 +59,12 @@ public static Eto.Drawing.Point LogicalToScreen(this Eto.Drawing.PointF point, E
{
screen = screen ?? Eto.Forms.Screen.FromPoint(point);
var sdscreen = ScreenHandler.GetControl(screen);
+ var location = sdscreen.GetLogicalLocation();
var pixelSize = sdscreen.GetLogicalPixelSize(usePerMonitor);
- var location = sdscreen.GetBounds().Location;
- var screenBounds = screen.Bounds;
+ var sdscreenBounds = usePerMonitor ? sdscreen.GetBounds() : sdscreen.Bounds.ToEto();
- var x = location.X + (point.X - screenBounds.X) * pixelSize;
- var y = location.Y + (point.Y - screenBounds.Y) * pixelSize;
+ var x = sdscreenBounds.X + (point.X - location.X) * pixelSize;
+ var y = sdscreenBounds.Y + (point.Y - location.Y) * pixelSize;
return Drawing.Point.Round(new Drawing.PointF(x, y));
}
@@ -76,10 +76,10 @@ public static Eto.Drawing.PointF ScreenToLogical(this Eto.Drawing.Point point, s
public static Eto.Drawing.PointF ScreenToLogical(this sd.Point point, swf.Screen sdscreen = null, bool usePerMonitor = true)
{
- sdscreen = sdscreen ?? swf.Screen.FromPoint(point);
+ sdscreen ??= swf.Screen.FromPoint(point);
var location = sdscreen.GetLogicalLocation();
var pixelSize = sdscreen.GetLogicalPixelSize(usePerMonitor);
- var sdscreenBounds = sdscreen.GetBounds();
+ var sdscreenBounds = usePerMonitor ? sdscreen.GetBounds() : sdscreen.Bounds.ToEto();
var x = location.X + (point.X - sdscreenBounds.X) / pixelSize;
var y = location.Y + (point.Y - sdscreenBounds.Y) / pixelSize;
@@ -93,10 +93,10 @@ public static Eto.Drawing.RectangleF ScreenToLogical(this Eto.Drawing.Rectangle
sdscreen = sdscreen ?? swf.Screen.FromPoint(rect.Location.ToSD());
var location = sdscreen.GetLogicalLocation();
var pixelSize = sdscreen.GetLogicalPixelSize(usePerMonitor);
- var screenBounds = sdscreen.GetBounds();
+ var sdscreenBounds = usePerMonitor ? sdscreen.GetBounds() : sdscreen.Bounds.ToEto();
return new Eto.Drawing.RectangleF(
- location.X + (rect.X - screenBounds.X) / pixelSize,
- location.Y + (rect.Y - screenBounds.Y) / pixelSize,
+ location.X + (rect.X - sdscreenBounds.X) / pixelSize,
+ location.Y + (rect.Y - sdscreenBounds.Y) / pixelSize,
rect.Width / pixelSize,
rect.Height / pixelSize
);
diff --git a/src/Eto.WinForms/WinConversions.shared.cs b/src/Eto.WinForms/WinConversions.shared.cs
index ce67ee6f64..7434b1968e 100644
--- a/src/Eto.WinForms/WinConversions.shared.cs
+++ b/src/Eto.WinForms/WinConversions.shared.cs
@@ -59,76 +59,6 @@ public static sd.Color ToSD(this Color color)
return sd.Color.FromArgb((byte)(color.A * 255), (byte)(color.R * 255), (byte)(color.G * 255), (byte)(color.B * 255));
}
- public static Point ToEto(this sd.Point point)
- {
- return new Point(point.X, point.Y);
- }
-
- public static PointF ToEto(this sd.PointF point)
- {
- return new PointF(point.X, point.Y);
- }
-
- public static sd.PointF ToSD(this PointF point)
- {
- return new sd.PointF(point.X, point.Y);
- }
-
- public static sd.Point ToSDPoint(this PointF point)
- {
- return new sd.Point((int)point.X, (int)point.Y);
- }
-
- public static Size ToEto(this sd.Size size)
- {
- return new Size(size.Width, size.Height);
- }
-
- public static sd.Size ToSD(this Size size)
- {
- return new sd.Size(size.Width, size.Height);
- }
-
- public static Size ToEtoF(this sd.SizeF size)
- {
- return new Size((int)size.Width, (int)size.Height);
- }
-
- public static SizeF ToEto(this sd.SizeF size)
- {
- return new SizeF(size.Width, size.Height);
- }
-
- public static sd.SizeF ToSD(this SizeF size)
- {
- return new sd.SizeF(size.Width, size.Height);
- }
-
- public static Rectangle ToEto(this sd.Rectangle rect)
- {
- return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
- }
-
- public static RectangleF ToEto(this sd.RectangleF rect)
- {
- return new RectangleF(rect.X, rect.Y, rect.Width, rect.Height);
- }
-
- public static sd.Rectangle ToSD(this Rectangle rect)
- {
- return new sd.Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
- }
-
- public static sd.RectangleF ToSD(this RectangleF rect)
- {
- return new sd.RectangleF(rect.X, rect.Y, rect.Width, rect.Height);
- }
-
- public static sd.Rectangle ToSDRectangle(this RectangleF rect)
- {
- return new sd.Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
- }
-
internal static sd.Point[] ToSD(this Point[] points)
{
var result =
diff --git a/src/Eto.Wpf/WpfHelpers.cs b/src/Eto.Wpf/WpfHelpers.cs
old mode 100644
new mode 100755
index f206f24050..9d3c39842a
--- a/src/Eto.Wpf/WpfHelpers.cs
+++ b/src/Eto.Wpf/WpfHelpers.cs
@@ -83,5 +83,33 @@ public static Window ToEtoWindow(IntPtr windowHandle)
return null;
return new Form(new HwndFormHandler(windowHandle));
}
+
+ ///
+ /// Converts a System.Drawing.Point in screen coordinates to an Eto point in screen coordinates.
+ ///
+ /// A point in Windows Forms/win32 screen coordinates.
+ /// A point in Eto screen coordinates.
+ public static PointF ToEtoScreen(this sd.Point point, swf.Screen sdscreen = null, bool perMonitor = false) => Win32.ScreenToLogical(point, sdscreen, perMonitor);
+
+ public static RectangleF ToEtoScreen(this sd.Rectangle rect, swf.Screen sdscreen = null, bool perMonitor = false)
+ {
+ var topLeft = ToEtoScreen(rect.Location, sdscreen, perMonitor);
+ var bottomRight = ToEtoScreen(new sd.Point(rect.X + rect.Width, rect.Y + rect.Height), sdscreen, perMonitor);
+ return new RectangleF(topLeft, new SizeF(bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y));
+ }
+
+ ///
+ /// Converts a point in Eto screen coordinates to a point in Windows Forms/win32 screen coordinates.
+ ///
+ /// A point in Eto screen coordinates.
+ /// A point in Windows Forms/win32 screen coordinates.
+ public static Point ToNativeScreen(this PointF point, Screen screen = null, bool perMonitor = false) => Win32.LogicalToScreen(point, screen, perMonitor);
+ public static Rectangle ToNativeScreen(this RectangleF rect, Screen screen = null, bool perMonitor = false)
+ {
+ var topLeft = rect.TopLeft.ToNativeScreen(screen, perMonitor);
+ var bottomRight = rect.BottomRight.ToNativeScreen(screen, perMonitor);
+ return new Rectangle(topLeft, new Size(bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y));
+ }
+
}
}
\ No newline at end of file
diff --git a/test/Eto.Test.Wpf/UnitTests/ScreenToClientTests.cs b/test/Eto.Test.Wpf/UnitTests/ScreenToClientTests.cs
new file mode 100755
index 0000000000..d191edf770
--- /dev/null
+++ b/test/Eto.Test.Wpf/UnitTests/ScreenToClientTests.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Eto.Test.UnitTests;
+using NUnit.Framework;
+using swf = System.Windows.Forms;
+using sd = System.Drawing;
+
+namespace Eto.Test.Wpf.UnitTests
+{
+ [TestFixture]
+ public class ScreenToClientTests : TestBase
+ {
+
+ class NonActivatingForm : swf.Form
+ {
+ protected override bool ShowWithoutActivation => true;
+ }
+
+ [Test, ManualTest]
+ public void ScreenLocationsShouldBeCorrect()
+ {
+ var mre = new ManualResetEvent(false);
+ Invoke(() =>
+ {
+ var wfwindows = new List();
+ var windows = new List();
+
+ void CreateWindow(Rectangle rect)
+ {
+ var window = new Form
+ {
+ ShowActivated = false,
+ ShowInTaskbar = false,
+ Minimizable = false,
+ Maximizable = false,
+ Bounds = rect,
+ Content = TableLayout.AutoSized("Click to dismiss", centered: true)
+ };
+ window.MouseDown += (sender, e) =>
+ {
+ foreach (var w in windows)
+ {
+ w.Close();
+ }
+ foreach (var w in wfwindows)
+ {
+ w.Close();
+ }
+ mre.Set();
+ };
+ window.Show();
+ windows.Add(window);
+
+ bool perMonitor = true;
+
+ var sdrect = WpfHelpers.ToNativeScreen(rect, window.Screen, perMonitor: perMonitor).ToSD();
+
+ var wfwindow = new NonActivatingForm
+ {
+ Bounds = sdrect,
+ ShowInTaskbar = false,
+ MinimizeBox = false,
+ MaximizeBox = false,
+ StartPosition = swf.FormStartPosition.Manual,
+ BackColor = sd.Color.Blue
+ };
+ wfwindow.Controls.Add(new swf.Label { Text = "Move me", Dock = swf.DockStyle.Fill, ForeColor = sd.Color.White });
+ wfwindow.LocationChanged += (sender, e) =>
+ {
+ var loc = wfwindow.RectangleToScreen(wfwindow.ClientRectangle);
+ window.Bounds = (Rectangle)WpfHelpers.ToEtoScreen(loc, swf.Screen.FromControl(wfwindow), perMonitor: perMonitor);
+ };
+ wfwindow.SizeChanged += (sender, e) =>
+ {
+ var loc = wfwindow.RectangleToScreen(wfwindow.ClientRectangle);
+ window.Bounds = (Rectangle)WpfHelpers.ToEtoScreen(loc, swf.Screen.FromControl(wfwindow), perMonitor: perMonitor);
+ };
+ wfwindow.Show();
+ wfwindows.Add(wfwindow);
+
+ }
+
+ foreach (var screen in Screen.Screens)
+ {
+ var bounds = (Rectangle)screen.WorkingArea;
+ var size = new Size(200, 200);
+ CreateWindow(new Rectangle(bounds.TopLeft, size));
+ CreateWindow(new Rectangle(bounds.TopRight - new Size(size.Width, 0), size));
+ CreateWindow(new Rectangle(bounds.BottomLeft - new Size(0, size.Height), size));
+ CreateWindow(new Rectangle(bounds.BottomRight - size, size));
+ }
+ });
+ mre.WaitOne();
+ }
+
+ }
+}
\ No newline at end of file