From b26cb077e35e99f85d8c1846efeb332e648060c6 Mon Sep 17 00:00:00 2001 From: Alex Maitland Date: Sat, 16 Mar 2024 08:03:16 +1000 Subject: [PATCH] WPF - Fixed Html Dropdown positioning when near bottom of screen (Cleanup) (#4759) * WPF - Popup Mouse Transform - Refactor and performance improvements - WPF Example - Enable popup transform by default Issue #2820 --- .../Views/BrowserTabView.xaml.cs | 3 ++ CefSharp.Wpf/ChromiumWebBrowser.cs | 39 ++++++--------- .../Experimental/ExperimentalExtensions.cs | 12 +++++ CefSharp.Wpf/IMouseAdjustor.cs | 15 ------ .../Internals/IMousePositionTransform.cs | 14 ++++++ ...eAdjustor.cs => MousePositionTransform.cs} | 48 ++++--------------- .../Internals/NoOpMousePositionTransform.cs | 21 ++++++++ 7 files changed, 74 insertions(+), 78 deletions(-) create mode 100644 CefSharp.Wpf/Experimental/ExperimentalExtensions.cs delete mode 100644 CefSharp.Wpf/IMouseAdjustor.cs create mode 100644 CefSharp.Wpf/Internals/IMousePositionTransform.cs rename CefSharp.Wpf/Internals/{MouseAdjustor.cs => MousePositionTransform.cs} (76%) create mode 100644 CefSharp.Wpf/Internals/NoOpMousePositionTransform.cs diff --git a/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs b/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs index 367bdc5377..a45b06c96e 100644 --- a/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs +++ b/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs @@ -16,6 +16,7 @@ using CefSharp.Fluent; using CefSharp.Wpf.Example.Handlers; using CefSharp.Wpf.Example.ViewModels; +using CefSharp.Wpf.Experimental; using CefSharp.Wpf.Experimental.Accessibility; namespace CefSharp.Wpf.Example.Views @@ -31,6 +32,8 @@ public BrowserTabView() DataContextChanged += OnDataContextChanged; + browser.UsePopupMouseTransform(); + //browser.BrowserSettings.BackgroundColor = Cef.ColorSetARGB(0, 255, 255, 255); //Please remove the comments below to use the Experimental WpfImeKeyboardHandler. diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 12b157521e..d3a00d9134 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -140,11 +140,6 @@ public partial class ChromiumWebBrowser : Control, IRenderWebBrowser, IWpfWebBro /// private static bool DesignMode; - /// - /// The class that coordinates the positioning of the dropdown if wanted. - /// - private IMouseAdjustor mouseAdjustor; - // https://github.com/chromiumembedded/cef/issues/3427 private bool resizeHackIgnoreOnPaint; private Structs.Size? resizeHackSize; @@ -155,6 +150,11 @@ public partial class ChromiumWebBrowser : Control, IRenderWebBrowser, IWpfWebBro /// private bool initialFocus; + /// + /// The class that coordinates the positioning of the dropdown if wanted. + /// + internal IMousePositionTransform MousePositionTransform { get; set; } + /// /// When enabled the browser will resize by 1px when it becomes visible to workaround /// the upstream issue @@ -489,14 +489,6 @@ public ChromiumWebBrowser() { NoInliningConstructor(); } - - bool adjust = true; - - if (adjust) - this.mouseAdjustor = new MouseAdjustor(); - - else - this.mouseAdjustor = new NoMouseAdjustor(); } /// @@ -626,6 +618,7 @@ private void NoInliningConstructor() PresentationSource.AddSourceChangedHandler(this, PresentationSourceChangedHandler); MenuHandler = new ContextMenuHandler(); + MousePositionTransform = new NoOpMousePositionTransform(); UseLayoutRounding = true; } @@ -1053,7 +1046,7 @@ protected virtual void OnPopupShow(bool isOpen) UiThreadRunAsync(() => { popupImage.Visibility = isOpen ? Visibility.Visible : Visibility.Hidden; - mouseAdjustor.OnPopupShow(isOpen); + MousePositionTransform.OnPopupShow(isOpen); }); } @@ -2125,7 +2118,7 @@ private void SetPopupSizeAndPositionImpl(Rect rect) popupImage.Width = rect.Width; popupImage.Height = rect.Height; - Point point = this.mouseAdjustor.UpdatePopupSizeAndPosition(rect, this.viewRect); + var point = MousePositionTransform.UpdatePopupSizeAndPosition(rect, viewRect); Canvas.SetLeft(popupImage, point.X); Canvas.SetTop(popupImage, point.Y); @@ -2295,8 +2288,8 @@ protected override void OnMouseMove(MouseEventArgs e) var point = e.GetPosition(this); var modifiers = e.GetModifiers(); - var adjustedPoint = mouseAdjustor.GetAdjustedMouseCoords(point); - browser.GetHost().SendMouseMoveEvent(adjustedPoint.X, adjustedPoint.Y, false, modifiers); + MousePositionTransform.TransformMousePoint(ref point); + browser.GetHost().SendMouseMoveEvent((int)point.X, (int)point.Y, false, modifiers); } base.OnMouseMove(e); @@ -2313,11 +2306,11 @@ protected override void OnMouseWheel(MouseWheelEventArgs e) var point = e.GetPosition(this); var modifiers = e.GetModifiers(); var isShiftKeyDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift); - var adjustedPoint = mouseAdjustor.GetAdjustedMouseCoords(point); + MousePositionTransform.TransformMousePoint(ref point); browser.SendMouseWheelEvent( - adjustedPoint.X, - adjustedPoint.Y, + (int)point.X, + (int)point.Y, deltaX: isShiftKeyDown ? e.Delta : 0, deltaY: !isShiftKeyDown ? e.Delta : 0, modifiers: modifiers); @@ -2467,11 +2460,9 @@ private void OnMouseButton(MouseButtonEventArgs e) { clickCount = 1; } - - var adjustedPoint = mouseAdjustor.GetAdjustedMouseCoords(point); - browser.GetHost().SendMouseClickEvent(adjustedPoint.X, adjustedPoint.Y, (MouseButtonType)e.ChangedButton, mouseUp, clickCount, modifiers); - // browser.GetHost().SendMouseClickEvent(mouseTeleport.originalRect.X + mouseTeleport.originalRect.Width, (int)point.Y, (MouseButtonType)e.ChangedButton, mouseUp, clickCount, modifiers); + MousePositionTransform.TransformMousePoint(ref point); + browser.GetHost().SendMouseClickEvent((int)point.X, (int)point.Y, (MouseButtonType)e.ChangedButton, mouseUp, clickCount, modifiers); } e.Handled = true; diff --git a/CefSharp.Wpf/Experimental/ExperimentalExtensions.cs b/CefSharp.Wpf/Experimental/ExperimentalExtensions.cs new file mode 100644 index 0000000000..9e3ee28ca7 --- /dev/null +++ b/CefSharp.Wpf/Experimental/ExperimentalExtensions.cs @@ -0,0 +1,12 @@ +using CefSharp.Wpf.Internals; + +namespace CefSharp.Wpf.Experimental +{ + public static class ExperimentalExtensions + { + public static void UsePopupMouseTransform(this ChromiumWebBrowser chromiumWebBrowser) + { + chromiumWebBrowser.MousePositionTransform = new MousePositionTransform(); + } + } +} diff --git a/CefSharp.Wpf/IMouseAdjustor.cs b/CefSharp.Wpf/IMouseAdjustor.cs deleted file mode 100644 index e8d11d94d9..0000000000 --- a/CefSharp.Wpf/IMouseAdjustor.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using CefSharp.Structs; - -namespace CefSharp.Wpf -{ - /// - /// Implement this interface to control how the mouse-adjustor is used. - /// - public interface IMouseAdjustor : IDisposable - { - System.Windows.Point UpdatePopupSizeAndPosition(Rect originalRect, Rect viewRect); - void OnPopupShow(bool isOpen); - Point GetAdjustedMouseCoords(System.Windows.Point point); - } -} diff --git a/CefSharp.Wpf/Internals/IMousePositionTransform.cs b/CefSharp.Wpf/Internals/IMousePositionTransform.cs new file mode 100644 index 0000000000..4140bcab1f --- /dev/null +++ b/CefSharp.Wpf/Internals/IMousePositionTransform.cs @@ -0,0 +1,14 @@ +using CefSharp.Structs; + +namespace CefSharp.Wpf.Internals +{ + /// + /// Implement this interface to control transform the mouse position + /// + public interface IMousePositionTransform + { + System.Windows.Point UpdatePopupSizeAndPosition(Rect originalRect, Rect viewRect); + void OnPopupShow(bool isOpen); + void TransformMousePoint(ref System.Windows.Point point); + } +} diff --git a/CefSharp.Wpf/Internals/MouseAdjustor.cs b/CefSharp.Wpf/Internals/MousePositionTransform.cs similarity index 76% rename from CefSharp.Wpf/Internals/MouseAdjustor.cs rename to CefSharp.Wpf/Internals/MousePositionTransform.cs index 419855b58a..419bafd692 100644 --- a/CefSharp.Wpf/Internals/MouseAdjustor.cs +++ b/CefSharp.Wpf/Internals/MousePositionTransform.cs @@ -2,28 +2,7 @@ namespace CefSharp.Wpf.Internals { - public class NoMouseAdjustor : IMouseAdjustor - { - public virtual void Dispose() - { - } - - public System.Windows.Point UpdatePopupSizeAndPosition(Rect originalRect, Rect viewRect) - { - return new System.Windows.Point(originalRect.X, originalRect.Y); - } - - public void OnPopupShow(bool isOpen) - { - } - - public Point GetAdjustedMouseCoords(System.Windows.Point point) - { - return new Point((int)point.X, (int)point.Y); - } - } - - public class MouseAdjustor : IMouseAdjustor + public sealed class MousePositionTransform : IMousePositionTransform { /// /// The x-offset. @@ -50,20 +29,13 @@ public class MouseAdjustor : IMouseAdjustor /// private bool isOpen; - /// - /// This method is required for the interface. - /// - public virtual void Dispose() - { - } - /// /// Updates the size and the position of the popup. /// /// /// /// The adjusted point. - public System.Windows.Point UpdatePopupSizeAndPosition(Rect originalRect, Rect viewRect) + System.Windows.Point IMousePositionTransform.UpdatePopupSizeAndPosition(Rect originalRect, Rect viewRect) { int x = originalRect.X, prevX = originalRect.X, @@ -124,7 +96,7 @@ public System.Windows.Point UpdatePopupSizeAndPosition(Rect originalRect, Rect v /// Resets the offsets and original-rect. /// If the popup is open or not. /// - public void OnPopupShow(bool isOpen) + void IMousePositionTransform.OnPopupShow(bool isOpen) { if (!isOpen) { @@ -142,16 +114,14 @@ public void OnPopupShow(bool isOpen) /// Adjusts the mouse-coordinates when the popup is visible. /// /// The original point. - /// The adjusted point if needed, else the original point. - public Point GetAdjustedMouseCoords(System.Windows.Point point) + /// The transformed point if needed, else the original point. + void IMousePositionTransform.TransformMousePoint(ref System.Windows.Point point) { - if (!this.isOpen) - return new Point((int)point.X, (int)point.Y); - - if (!this.IsInsideOriginalRect(point) && IsInsideAdjustedRect(point)) - return new Point((int)point.X + this.xOffset, (int)point.Y + this.yOffset); + if (!isOpen) + return; - return new Point((int)point.X, (int)point.Y); + if (!IsInsideOriginalRect(point) && IsInsideAdjustedRect(point)) + point = new System.Windows.Point((int)point.X + this.xOffset, (int)point.Y + this.yOffset); } /// diff --git a/CefSharp.Wpf/Internals/NoOpMousePositionTransform.cs b/CefSharp.Wpf/Internals/NoOpMousePositionTransform.cs new file mode 100644 index 0000000000..9a271ec6b1 --- /dev/null +++ b/CefSharp.Wpf/Internals/NoOpMousePositionTransform.cs @@ -0,0 +1,21 @@ +using CefSharp.Structs; + +namespace CefSharp.Wpf.Internals +{ + public sealed class NoOpMousePositionTransform : IMousePositionTransform + { + System.Windows.Point IMousePositionTransform.UpdatePopupSizeAndPosition(Rect originalRect, Rect viewRect) + { + return new System.Windows.Point(originalRect.X, originalRect.Y); + } + + void IMousePositionTransform.OnPopupShow(bool isOpen) + { + } + + void IMousePositionTransform.TransformMousePoint(ref System.Windows.Point point) + { + + } + } +}