diff --git a/Terminal.Gui/App/Popovers/Popover.cs b/Terminal.Gui/App/Popovers/Popover.cs
index 0a2f323445..eec4d7ff4f 100644
--- a/Terminal.Gui/App/Popovers/Popover.cs
+++ b/Terminal.Gui/App/Popovers/Popover.cs
@@ -350,6 +350,19 @@ protected override void OnVisibleChanged ()
base.OnVisibleChanged (); // PopoverImpl handles Hide
}
+ ///
+ protected override void OnFrameChanged (in Rectangle frame)
+ {
+ base.OnFrameChanged (in frame);
+
+ if (!Visible || Anchor is null || ContentView is null)
+ {
+ return;
+ }
+
+ SetPosition (anchor: Anchor ());
+ }
+
///
/// Extracts the result from the content view using or .
///
diff --git a/Tests/UnitTestsParallelizable/Application/Popover/Application.PopoverTests.cs b/Tests/UnitTestsParallelizable/Application/Popover/Application.PopoverTests.cs
index dc4cd38a3c..efd9d15537 100644
--- a/Tests/UnitTestsParallelizable/Application/Popover/Application.PopoverTests.cs
+++ b/Tests/UnitTestsParallelizable/Application/Popover/Application.PopoverTests.cs
@@ -250,12 +250,50 @@ public void Hide_NonActivePopover_DoesNotAffectActivePopover ()
Assert.Equal (initialVisibleState, popover2.Visible);
}
+ // CoPilot - ChatGPT v4
+ [Fact]
+ public void LayoutAndDraw_ScreenResize_LayoutsVisiblePopover ()
+ {
+ // Arrange
+ using IApplication app = Application.Create ();
+ app.Init (DriverRegistry.Names.ANSI);
+ app.Driver!.SetScreenSize (80, 25);
+
+ Runnable top = new () { App = app };
+ SessionToken? token = app.Begin (top);
+
+ PopoverTestClass popover = new ()
+ {
+ App = app,
+ Width = 10,
+ Height = 5
+ };
+ app.Popovers!.Register (popover);
+ app.Popovers.Show (popover);
+
+ app.LayoutAndDraw ();
+ popover.LayoutPassCount = 0;
+
+ app.Driver.SetScreenSize (100, 30);
+
+ // Act
+ app.LayoutAndDraw ();
+
+ // Assert
+ Assert.True (popover.LayoutPassCount > 0);
+
+ app.End (token!);
+ top.Dispose ();
+ }
+
public class PopoverTestClass : View, IPopoverView
{
public List HandledKeys { get; } = [];
public int NewCommandInvokeCount { get; private set; }
+ public int LayoutPassCount { get; set; }
+
public bool HandleNewCommand { get; set; }
///
@@ -342,6 +380,12 @@ protected override bool OnKeyDown (Key key)
return false;
}
+ protected override void OnSubViewLayout (LayoutEventArgs args)
+ {
+ LayoutPassCount++;
+ base.OnSubViewLayout (args);
+ }
+
///
public IRunnable? Owner { get; set; }
diff --git a/Tests/UnitTestsParallelizable/Views/DropDownListTests.cs b/Tests/UnitTestsParallelizable/Views/DropDownListTests.cs
index 45012aea99..680a132fd7 100644
--- a/Tests/UnitTestsParallelizable/Views/DropDownListTests.cs
+++ b/Tests/UnitTestsParallelizable/Views/DropDownListTests.cs
@@ -900,6 +900,120 @@ public void Scrolling_TallDropdown_TopItemsDraw ()
app.End (token!);
}
+ // CoPilot - ChatGPT v4
+ [Fact]
+ public void VisiblePopover_Repositions_WhenTerminalIsResized ()
+ {
+ // Arrange
+ using IApplication app = Application.Create ();
+ app.Init (DriverRegistry.Names.ANSI);
+ app.Driver!.SetScreenSize (40, 15);
+
+ using Runnable top = new ();
+ SessionToken? token = app.Begin (top);
+
+ ObservableCollection items = ["Alpha", "Beta", "Gamma"];
+
+ DropDownList dropdown = new ()
+ {
+ X = Pos.Center (),
+ Y = Pos.Center (),
+ Width = 12,
+ Source = new ListWrapper (items),
+ ReadOnly = true
+ };
+
+ top.Add (dropdown);
+ app.LayoutAndDraw ();
+
+ dropdown.SetFocus ();
+ app.InjectKey (Key.F4);
+ app.LayoutAndDraw ();
+
+ Popover? popover = FindDropDownPopover (app) as Popover;
+ Assert.NotNull (popover);
+ Assert.True (popover.Visible);
+
+ Rectangle initialListFrame = popover.ContentView!.FrameToScreen ();
+ Rectangle initialDropDownFrame = dropdown.FrameToScreen ();
+
+ // Act
+ app.Driver.SetScreenSize (60, 25);
+ app.LayoutAndDraw ();
+
+ // Assert
+ Rectangle resizedListFrame = popover.ContentView.FrameToScreen ();
+ Rectangle resizedDropDownFrame = dropdown.FrameToScreen ();
+
+ Assert.NotEqual (initialDropDownFrame.Location, resizedDropDownFrame.Location);
+ Assert.Equal (resizedDropDownFrame.X, resizedListFrame.X);
+ Assert.Equal (resizedDropDownFrame.Bottom, resizedListFrame.Y);
+ Assert.NotEqual (initialListFrame.Location, resizedListFrame.Location);
+
+ app.End (token!);
+ }
+
+ // CoPilot - ChatGPT v4
+ [Fact]
+ public void VisiblePopover_LayoutsHeight_WhenTerminalIsResized ()
+ {
+ // Arrange
+ using IApplication app = Application.Create ();
+ app.Init (DriverRegistry.Names.ANSI);
+ app.Driver!.SetScreenSize (30, 10);
+
+ using Runnable top = new ();
+ SessionToken? token = app.Begin (top);
+
+ ObservableCollection items =
+ [
+ "Item_00",
+ "Item_01",
+ "Item_02",
+ "Item_03",
+ "Item_04",
+ "Item_05",
+ "Item_06",
+ "Item_07",
+ "Item_08",
+ "Item_09"
+ ];
+
+ DropDownList dropdown = new ()
+ {
+ X = 0,
+ Y = 0,
+ Width = 12,
+ Source = new ListWrapper (items),
+ ReadOnly = true
+ };
+
+ top.Add (dropdown);
+ app.LayoutAndDraw ();
+
+ dropdown.SetFocus ();
+ app.InjectKey (Key.F4);
+ app.LayoutAndDraw ();
+
+ Popover? popover = FindDropDownPopover (app) as Popover;
+ Assert.NotNull (popover);
+ Assert.True (popover.Visible);
+
+ int initialHeight = popover.ContentView!.Frame.Height;
+ Assert.Equal (9, initialHeight);
+
+ // Act
+ app.Driver.SetScreenSize (30, 5);
+ app.LayoutAndDraw ();
+
+ // Assert
+ int resizedHeight = popover.ContentView.Frame.Height;
+ Assert.Equal (4, resizedHeight);
+ Assert.NotEqual (initialHeight, resizedHeight);
+
+ app.End (token!);
+ }
+
// Helper to find the DropDownList popover (excludes the context menu popover)
private static IPopoverView? FindDropDownPopover (IApplication app) => app.Popovers?.Popovers.OfType> ().FirstOrDefault ();
}