diff --git a/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs b/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs index 009839a9cb14..5debdcdb9725 100644 --- a/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs +++ b/src/SamplesApp/SamplesApp.UITests/ScreenshotInfo.cs @@ -23,6 +23,11 @@ public ScreenshotInfo(FileInfo file, string stepName) public static implicit operator ScreenshotInfo(FileInfo fi) => new ScreenshotInfo(fi, fi.Name); public Bitmap GetBitmap() => _bitmap ??= new Bitmap(File.FullName); + + public int Width => GetBitmap().Width; + + public int Height => GetBitmap().Height; + public void Dispose() { _bitmap?.Dispose(); diff --git a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs index e9821c6b3bf0..4b753f037b42 100644 --- a/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs +++ b/src/SamplesApp/SamplesApp.UITests/Windows_UI_Xaml_Controls/FlyoutTests/UnoSamples_Tests.Flyout.cs @@ -233,5 +233,20 @@ public void Flyout_Namescope() _app.FastTap(closeButton); } + + [Test] + [AutoRetry] + public void Flyout_ShowAt_Window_Content() + { + Run("UITests.Windows_UI_Xaml_Controls.FlyoutTests.Flyout_ShowAt_Window_Content"); + + var windowButton = _app.Marked("WindowButton"); + + _app.WaitForElement(windowButton); + _app.FastTap(windowButton); + + using var result = TakeScreenshot("Result", ignoreInSnapshotCompare: true); + ImageAssert.HasColorAt(result, result.Width / 2, 150, Color.Red); + } } } diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems index 720969906bb1..0aaa4ca4bfa9 100644 --- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems +++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems @@ -1445,6 +1445,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -5552,6 +5556,9 @@ Flyout_Namescope.xaml + + Flyout_ShowAt_Window_Content.xaml + Flyout_TemplatedParent.xaml diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml new file mode 100644 index 000000000000..052c95e6fe93 --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml.cs new file mode 100644 index 000000000000..9f60c3b24371 --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Flyout/Flyout_ShowAt_Window_Content.xaml.cs @@ -0,0 +1,49 @@ +using Uno.UI.Samples.Controls; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; + +// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 + +namespace UITests.Windows_UI_Xaml_Controls.FlyoutTests +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Sample] + public sealed partial class Flyout_ShowAt_Window_Content : Page + { + public Flyout_ShowAt_Window_Content() + { + this.InitializeComponent(); + } + + private void ButtonButton_Click(object sender, RoutedEventArgs e) + { + Windows.UI.Xaml.Controls.Flyout flyout = new Windows.UI.Xaml.Controls.Flyout(); + flyout.Content = + new Border() + { + Width = 300, + Height = 300, + Background = new SolidColorBrush(Windows.UI.Colors.Red), + }; + + flyout.ShowAt((Button)sender); + } + + private void WindowButton_Click(object sender, RoutedEventArgs e) + { + Windows.UI.Xaml.Controls.Flyout flyout = new Windows.UI.Xaml.Controls.Flyout(); + flyout.Content = + new Border() + { + Width = 300, + Height = 300, + Background = new SolidColorBrush(Windows.UI.Colors.Red), + }; + + flyout.ShowAt(global::Windows.UI.Xaml.Window.Current.Content as FrameworkElement); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs index a21f8e41a038..782189936ae4 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutBase.cs @@ -325,7 +325,10 @@ private protected virtual void ShowAtCore(FrameworkElement placementTarget, Flyo throw new ArgumentException("Invalid flyout position"); } - // UNO TODO: clamp position within contentRect + var visibleBounds = ApplicationView.GetForCurrentView().VisibleBounds; + positionValue = new Point( + positionValue.X.Clamp(visibleBounds.Left, visibleBounds.Right), + positionValue.Y.Clamp(visibleBounds.Top, visibleBounds.Bottom)); SetTargetPosition(positionValue); } diff --git a/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs b/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs index 32a5e0a7b949..e6d1b1cd7f9c 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Popup/PlacementPopupPanel.cs @@ -285,6 +285,48 @@ ref controlYPos { this.Log().LogDebug($"Calculated placement, finalRect={finalRect}"); } + + // Ensure the popup is not positioned fully beyond visible bounds. + // This can happen for example when the user is trying to show a flyout at + // Window.Current.Content - which will match Top position, which would be outside + // the visible bounds (negative Y). + + if (finalRect.Bottom < visibleBounds.Top) + { + finalRect = new Rect( + finalRect.Left, + visibleBounds.Top, + finalRect.Width, + finalRect.Height); + } + + if (finalRect.Top > visibleBounds.Bottom) + { + finalRect = new Rect( + finalRect.Left, + visibleBounds.Bottom - finalRect.Height, + finalRect.Width, + finalRect.Height); + } + + if (finalRect.Right < visibleBounds.Left) + { + finalRect = new Rect( + visibleBounds.Left, + finalRect.Top, + finalRect.Width, + finalRect.Height); + } + + if (finalRect.Left > visibleBounds.Right) + { + finalRect = new Rect( + visibleBounds.Right - finalRect.Width, + finalRect.Top, + finalRect.Width, + finalRect.Height); + } + return finalRect; } diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs index 9fc64caf0a01..916180275c00 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.skia.cs @@ -139,7 +139,7 @@ public void UpdateForeground() internal override void Render(SKSurface surface) { - if (!string.IsNullOrEmpty(_owner.Text)) + if (!string.IsNullOrEmpty(_owner.Text) && Size != default) { UpdateForeground();