Skip to content

Commit

Permalink
Merge pull request #2336 from cwensley/curtis/fix-system-dpi-pointtof…
Browse files Browse the repository at this point in the history
…romscreen

Wpf: Fix PointToScreen/PointFromScreen in system dpi aware mode
  • Loading branch information
cwensley authored Oct 18, 2022
2 parents 4e4525c + 7677e74 commit 8b9f246
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 13 deletions.
38 changes: 32 additions & 6 deletions src/Eto.Wpf/Forms/WpfFrameworkElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -973,11 +973,24 @@ public PointF PointFromScreen(PointF point)
return point;

point = point.LogicalToScreen(Widget.ParentWindow?.Screen);
point = Win32.ExecuteInDpiAwarenessContext(() => ContainerControl.PointFromScreen(point.ToWpf())).ToEto();

if (Win32.IsSystemDpiAware)
{
point = point * Win32.SystemDpi / Win32.GetLogicalPixelSize(SwfScreen);
var logicalPixelSize = Win32.GetLogicalPixelSize(SwfScreen);
var systemDpi = Win32.SystemDpi;

// WPF does not take into account the location of the element in the form..
var rootVisual = ContainerControl.GetVisualParents().OfType<sw.UIElement>().Last();
var location = ContainerControl.TranslatePoint(new sw.Point(0, 0), rootVisual).ToEto();
point -= (location * logicalPixelSize) - (location * systemDpi);

point = Win32.ExecuteInDpiAwarenessContext(() => ContainerControl.PointFromScreen(point.ToWpf())).ToEto();

point = point * systemDpi / logicalPixelSize;
}
else
{
point = Win32.ExecuteInDpiAwarenessContext(() => ContainerControl.PointFromScreen(point.ToWpf())).ToEto();
}
return point;

Expand All @@ -993,13 +1006,26 @@ public PointF PointToScreen(PointF point)
if (presentationSource == null)
return point;

PointF pt;
if (Win32.IsSystemDpiAware)
{
point = point / Win32.SystemDpi * Win32.GetLogicalPixelSize(SwfScreen);
}
var pt = Win32.ExecuteInDpiAwarenessContext(() => ContainerControl.PointToScreen(point.ToWpf()));
var logicalPixelSize = Win32.GetLogicalPixelSize(SwfScreen);
var systemDpi = Win32.SystemDpi;
point = point / systemDpi * logicalPixelSize;

pt = Win32.ExecuteInDpiAwarenessContext(() => ContainerControl.PointToScreen(point.ToWpf())).ToEto();

return pt.ToEtoPoint().ScreenToLogical(SwfScreen);
// WPF does not take into account the location of the element in the form..
var rootVisual = ContainerControl.GetVisualParents().OfType<sw.UIElement>().Last();
var location = ContainerControl.TranslatePoint(new sw.Point(0, 0), rootVisual).ToEto();
pt += (location * logicalPixelSize) - (location * systemDpi);
}
else
{
pt = Win32.ExecuteInDpiAwarenessContext(() => ContainerControl.PointToScreen(point.ToWpf())).ToEto();
}

return Point.Truncate(pt).ScreenToLogical(SwfScreen);
}

public Point Location
Expand Down
58 changes: 51 additions & 7 deletions test/Eto.Test/Sections/Behaviors/ScreenSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class ScreenSection : Scrollable
Label windowPositionLabel;
Label mousePositionLabel;
bool showScreenContent;
PointF? _mousePositionInWindow;

protected bool ShowScreenContent
{
Expand Down Expand Up @@ -159,9 +160,8 @@ Form CreateWindow(string title)

var restoreForm = new Form {
Title = "RestoreForm",
Content = "This form should restore its size and position",
Resizable = true,
ClientSize = new Size(450, 300),
Size = new Size(450, 300),
ShowActivated = false
};
var adjacentForm = new Form
Expand All @@ -173,32 +173,68 @@ Form CreateWindow(string title)
Closeable = false,
Maximizable = false,
Minimizable = false,
Content = new Splitter { Panel1 = new Panel(), Panel2 = new Panel() }
Content = new Panel()
};
var dragPanel = new Drawable { BackgroundColor = Colors.Blue };
var restoreContent = new TableLayout(
new TableRow("This form should restore its size and position"),
new TableRow(
new TableLayout(
new TableRow(new Panel { Size = new Size(100, 100)}),
new TableRow(new Panel { Size = new Size(100, 100)}, dragPanel)
)
));
restoreForm.Content = restoreContent;

dragPanel.Paint += (_, e2) =>
{
var mousePt = dragPanel.PointFromScreen(Mouse.Position);
var mouseRect = new RectangleF(mousePt, SizeF.Empty);
mouseRect.Inflate(6, 6);
e2.Graphics.FillEllipse(Colors.Red, mouseRect);
if (_mousePositionInWindow != null)
{
var otherRect = new RectangleF(dragPanel.PointFromScreen(_mousePositionInWindow.Value), SizeF.Empty);
otherRect.Inflate(3, 3);
e2.Graphics.FillEllipse(Colors.Yellow, otherRect);
}
};
dragPanel.MouseDown += (_, e2) => e2.Handled = true;
dragPanel.MouseMove += (sender2, e2) =>
{
_mousePositionInWindow = dragPanel.PointToScreen(e2.Location);
dragPanel.Invalidate();
// adjacentForm.Location = Point.Round(_mousePositionInWindow.Value);
Invalidate();
};

void SetAdjacentSize()
{
if (adjacentForm == null)
return;
adjacentForm.Location = Point.Round(restoreForm.Content.PointToScreen(restoreForm.Content.Bounds.TopRight));
adjacentForm.Location = Point.Round(restoreForm.Content.PointToScreen(restoreForm.Content.Bounds.BottomRight) - new Size(0, restoreForm.Content.Height));
adjacentForm.Size = new Size(100, restoreForm.Content.Height);
}

RestorePosition(restoreForm);
restoreForm.LocationChanged += (_, __) => { Invalidate(); SetAdjacentSize(); };
restoreForm.SizeChanged += (_, __) => { Invalidate(); SetAdjacentSize(); };
RestorePosition(restoreForm);
restoreForm.Closing += (_, __) => { SavePosition(restoreForm); adjacentForm.Close(); adjacentForm = null; };
restoreForm.Shown += (_, __) =>
{
SetAdjacentSize();
adjacentForm?.Show();
};
restoreForm.Show();
// SetAdjacentSize();

cornerWindows.Add(restoreForm);

cornerWindows.Add(adjacentForm);

return;

int i = 0;
foreach (var screen in Screen.Screens)
{
Expand Down Expand Up @@ -344,11 +380,19 @@ void DrawWindow(Window window)
}
}
var mousePosition = Mouse.Position * scale + offset;
var mouseRect = new RectangleF(mousePosition, SizeF.Empty);
mouseRect.Inflate(2, 2);
mouseRect.Inflate(3, 3);
pe.Graphics.FillEllipse(Colors.Red, mouseRect);
if (_mousePositionInWindow != null)
{
var mousePositionInWindow = _mousePositionInWindow.Value * scale + offset;
var mouseInWindowRect = new RectangleF(mousePositionInWindow, SizeF.Empty);
mouseInWindowRect.Inflate(2, 2);
pe.Graphics.FillEllipse(Colors.Yellow, mouseInWindowRect);
}
};
return screenLayoutDrawable;
}
Expand Down

0 comments on commit 8b9f246

Please sign in to comment.