Skip to content

Commit 96fbe8a

Browse files
BDisptig
andauthored
Fixes #5119. Popover isn't recalculating it's position when terminal is resizing (#5120)
* Fixes #5119. Popover isn't recalculating it's position when terminal is resizing * Add one more unit test for popover screen resize * Fix unit test --------- Co-authored-by: Tig <tig@users.noreply.github.com>
1 parent 0410158 commit 96fbe8a

3 files changed

Lines changed: 171 additions & 0 deletions

File tree

Terminal.Gui/App/Popovers/Popover.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,19 @@ protected override void OnVisibleChanged ()
350350
base.OnVisibleChanged (); // PopoverImpl handles Hide
351351
}
352352

353+
/// <inheritdoc />
354+
protected override void OnFrameChanged (in Rectangle frame)
355+
{
356+
base.OnFrameChanged (in frame);
357+
358+
if (!Visible || Anchor is null || ContentView is null)
359+
{
360+
return;
361+
}
362+
363+
SetPosition (anchor: Anchor ());
364+
}
365+
353366
/// <summary>
354367
/// Extracts the result from the content view using <see cref="ResultExtractor"/> or <see cref="IValue{TResult}"/>.
355368
/// </summary>

Tests/UnitTestsParallelizable/Application/Popover/Application.PopoverTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,50 @@ public void Hide_NonActivePopover_DoesNotAffectActivePopover ()
250250
Assert.Equal (initialVisibleState, popover2.Visible);
251251
}
252252

253+
// CoPilot - ChatGPT v4
254+
[Fact]
255+
public void LayoutAndDraw_ScreenResize_LayoutsVisiblePopover ()
256+
{
257+
// Arrange
258+
using IApplication app = Application.Create ();
259+
app.Init (DriverRegistry.Names.ANSI);
260+
app.Driver!.SetScreenSize (80, 25);
261+
262+
Runnable top = new () { App = app };
263+
SessionToken? token = app.Begin (top);
264+
265+
PopoverTestClass popover = new ()
266+
{
267+
App = app,
268+
Width = 10,
269+
Height = 5
270+
};
271+
app.Popovers!.Register (popover);
272+
app.Popovers.Show (popover);
273+
274+
app.LayoutAndDraw ();
275+
popover.LayoutPassCount = 0;
276+
277+
app.Driver.SetScreenSize (100, 30);
278+
279+
// Act
280+
app.LayoutAndDraw ();
281+
282+
// Assert
283+
Assert.True (popover.LayoutPassCount > 0);
284+
285+
app.End (token!);
286+
top.Dispose ();
287+
}
288+
253289
public class PopoverTestClass : View, IPopoverView
254290
{
255291
public List<Key> HandledKeys { get; } = [];
256292

257293
public int NewCommandInvokeCount { get; private set; }
258294

295+
public int LayoutPassCount { get; set; }
296+
259297
public bool HandleNewCommand { get; set; }
260298

261299
/// <summary>
@@ -342,6 +380,12 @@ protected override bool OnKeyDown (Key key)
342380
return false;
343381
}
344382

383+
protected override void OnSubViewLayout (LayoutEventArgs args)
384+
{
385+
LayoutPassCount++;
386+
base.OnSubViewLayout (args);
387+
}
388+
345389
/// <inheritdoc/>
346390
public IRunnable? Owner { get; set; }
347391

Tests/UnitTestsParallelizable/Views/DropDownListTests.cs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,120 @@ public void Scrolling_TallDropdown_TopItemsDraw ()
900900
app.End (token!);
901901
}
902902

903+
// CoPilot - ChatGPT v4
904+
[Fact]
905+
public void VisiblePopover_Repositions_WhenTerminalIsResized ()
906+
{
907+
// Arrange
908+
using IApplication app = Application.Create ();
909+
app.Init (DriverRegistry.Names.ANSI);
910+
app.Driver!.SetScreenSize (40, 15);
911+
912+
using Runnable top = new ();
913+
SessionToken? token = app.Begin (top);
914+
915+
ObservableCollection<string> items = ["Alpha", "Beta", "Gamma"];
916+
917+
DropDownList dropdown = new ()
918+
{
919+
X = Pos.Center (),
920+
Y = Pos.Center (),
921+
Width = 12,
922+
Source = new ListWrapper<string> (items),
923+
ReadOnly = true
924+
};
925+
926+
top.Add (dropdown);
927+
app.LayoutAndDraw ();
928+
929+
dropdown.SetFocus ();
930+
app.InjectKey (Key.F4);
931+
app.LayoutAndDraw ();
932+
933+
Popover<ListView, string?>? popover = FindDropDownPopover (app) as Popover<ListView, string?>;
934+
Assert.NotNull (popover);
935+
Assert.True (popover.Visible);
936+
937+
Rectangle initialListFrame = popover.ContentView!.FrameToScreen ();
938+
Rectangle initialDropDownFrame = dropdown.FrameToScreen ();
939+
940+
// Act
941+
app.Driver.SetScreenSize (60, 25);
942+
app.LayoutAndDraw ();
943+
944+
// Assert
945+
Rectangle resizedListFrame = popover.ContentView.FrameToScreen ();
946+
Rectangle resizedDropDownFrame = dropdown.FrameToScreen ();
947+
948+
Assert.NotEqual (initialDropDownFrame.Location, resizedDropDownFrame.Location);
949+
Assert.Equal (resizedDropDownFrame.X, resizedListFrame.X);
950+
Assert.Equal (resizedDropDownFrame.Bottom, resizedListFrame.Y);
951+
Assert.NotEqual (initialListFrame.Location, resizedListFrame.Location);
952+
953+
app.End (token!);
954+
}
955+
956+
// CoPilot - ChatGPT v4
957+
[Fact]
958+
public void VisiblePopover_LayoutsHeight_WhenTerminalIsResized ()
959+
{
960+
// Arrange
961+
using IApplication app = Application.Create ();
962+
app.Init (DriverRegistry.Names.ANSI);
963+
app.Driver!.SetScreenSize (30, 10);
964+
965+
using Runnable top = new ();
966+
SessionToken? token = app.Begin (top);
967+
968+
ObservableCollection<string> items =
969+
[
970+
"Item_00",
971+
"Item_01",
972+
"Item_02",
973+
"Item_03",
974+
"Item_04",
975+
"Item_05",
976+
"Item_06",
977+
"Item_07",
978+
"Item_08",
979+
"Item_09"
980+
];
981+
982+
DropDownList dropdown = new ()
983+
{
984+
X = 0,
985+
Y = 0,
986+
Width = 12,
987+
Source = new ListWrapper<string> (items),
988+
ReadOnly = true
989+
};
990+
991+
top.Add (dropdown);
992+
app.LayoutAndDraw ();
993+
994+
dropdown.SetFocus ();
995+
app.InjectKey (Key.F4);
996+
app.LayoutAndDraw ();
997+
998+
Popover<ListView, string?>? popover = FindDropDownPopover (app) as Popover<ListView, string?>;
999+
Assert.NotNull (popover);
1000+
Assert.True (popover.Visible);
1001+
1002+
int initialHeight = popover.ContentView!.Frame.Height;
1003+
Assert.Equal (9, initialHeight);
1004+
1005+
// Act
1006+
app.Driver.SetScreenSize (30, 5);
1007+
app.LayoutAndDraw ();
1008+
1009+
// Assert
1010+
int resizedHeight = popover.ContentView.Frame.Height;
1011+
Assert.Equal (4, resizedHeight);
1012+
Assert.NotEqual (initialHeight, resizedHeight);
1013+
1014+
app.End (token!);
1015+
}
1016+
9031017
// Helper to find the DropDownList popover (excludes the context menu popover)
9041018
private static IPopoverView? FindDropDownPopover (IApplication app) => app.Popovers?.Popovers.OfType<Popover<ListView, string?>> ().FirstOrDefault ();
9051019
}

0 commit comments

Comments
 (0)