Skip to content

Fixes #3951. Adds View dependency to DimFunc and PosFunc #4210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 40 commits into
base: v2_develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
73278bb
Fixes #4208. MainLoopSyncContext doesn't work with the v2 drivers
BDisp Jul 24, 2025
f9202c5
Merge branch 'v2_develop' into v2_3951_dimfunc-with-view-feature
BDisp Jul 25, 2025
b6d0aef
Fixes #3951. Add DimFuncWithView with a View dependency
BDisp Jul 25, 2025
50015ac
Revert to iteration which will handle the necessary processes
BDisp Jul 25, 2025
dadc75e
Revert "Revert to iteration which will handle the necessary processes"
BDisp Jul 25, 2025
4283f01
Layout and draw before position cursor
BDisp Jul 25, 2025
adcb3d0
Resolving merge conflicts
BDisp Jul 25, 2025
8f51903
Add optional View parameter and property to the DimFunc and PosFunc
BDisp Jul 25, 2025
3398222
Trying fix unit test error
BDisp Jul 25, 2025
384cab8
Revert layout changes
BDisp Jul 27, 2025
4032247
Merge branch 'v2_develop' into v2_3951_dimfunc-with-view-feature
BDisp Jul 27, 2025
08dfea6
Fixes #4216. Legacy drivers aren't refreshing the screen correctly on…
BDisp Jul 28, 2025
b111c88
Merge branch 'v2_4216_trail-drag-views-fix' into v2_3951_dimfunc-with…
BDisp Jul 28, 2025
03120b9
Add assertion proving NeedsLayout is always false before call OnSubVi…
BDisp Jul 28, 2025
8552842
Merge branch 'v2_4216_trail-drag-views-fix' into v2_3951_dimfunc-with…
BDisp Jul 28, 2025
58fd81e
Fix unit test error
BDisp Jul 28, 2025
456bad4
Merge branch 'v2_develop' into v2_4216_trail-drag-views-fix
BDisp Jul 28, 2025
ef063b9
Merge branch 'v2_develop' into v2_3951_dimfunc-with-view-feature
BDisp Jul 28, 2025
d7306e7
Increasing time to abort
BDisp Jul 28, 2025
64e0bb5
Revert "Increasing time to abort"
BDisp Jul 28, 2025
f25bcd8
Trying fix integration tests
BDisp Jul 28, 2025
c6774b2
Still trying fix integrations unit tests
BDisp Jul 28, 2025
6d6f62a
Merge branch 'v2_4216_trail-drag-views-fix' into v2_3951_dimfunc-with…
BDisp Jul 28, 2025
62bd31c
Revert comment
BDisp Jul 28, 2025
9329258
Layout is performed during the iteration
BDisp Jul 28, 2025
566b515
Using Dim.Func with status bar view
BDisp Jul 28, 2025
ae75832
Still trying fix integrations tests by locking _subviews
BDisp Jul 28, 2025
fc35486
Still trying fix integrations tests by locking _subviews
BDisp Jul 28, 2025
a892bff
Add internal SnapshotSubviews method
BDisp Jul 28, 2025
302df48
Resolving merge conflicts
BDisp Jul 28, 2025
c67f93a
Remove lock from SnapshotSubviews method
BDisp Jul 28, 2025
83c00f8
Using SnapshotSubviews method in the DrawSubViews method
BDisp Jul 28, 2025
08123da
Remove lock from SnapshotSubviews method
BDisp Jul 28, 2025
3dcb182
Using SnapshotSubviews method in the DrawSubViews method
BDisp Jul 28, 2025
b7dfca6
Using SnapshotSubviews
BDisp Jul 29, 2025
ca52522
Prevent new app if the previous wasn't yet finished
BDisp Jul 29, 2025
732bff4
Replace SnapshotSubviews method with ViewCollectionHelpers class
BDisp Jul 29, 2025
146a290
Lock entire GuiTestContext constructor
BDisp Jul 29, 2025
1d40f80
Using Snapshot in the ordered field
BDisp Jul 29, 2025
05b8628
Resolving merge conflicts
BDisp Jul 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public override void Main ()
{
X = 0,
Y = 1,
Width = Dim.Fill (Dim.Func (() => _categoryList!.Frame.Width)),
Height = Dim.Fill (),
// SchemeName = "Base"

Expand Down Expand Up @@ -172,6 +171,8 @@ public override void Main ()
};
top.Add (menu);

_charMap.Width = Dim.Fill (Dim.FuncWithView (v => v!.Frame.Width, _categoryList));

_charMap.SelectedCodePoint = 0;
_charMap.SetFocus ();

Expand Down
7 changes: 3 additions & 4 deletions Terminal.Gui/App/Application.Run.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public static RunState Begin (Toplevel toplevel)
if (!toplevel.IsInitialized)
{
toplevel.BeginInit ();
toplevel.EndInit (); // Calls Layout
toplevel.EndInit (); // Calls SetNeedsLayout
}

// Call ConfigurationManager Apply here to ensure all subscribers to ConfigurationManager.Applied
Expand All @@ -205,16 +205,15 @@ public static RunState Begin (Toplevel toplevel)

toplevel.OnLoaded ();

LayoutAndDraw (true);

if (PositionCursor ())
{
Driver?.UpdateCursor ();
}

NotifyNewRunState?.Invoke (toplevel, new (rs));

// Force an Idle event so that an Iteration (and Refresh) happen.
Invoke (() => { });

return rs;
}

Expand Down
10 changes: 10 additions & 0 deletions Terminal.Gui/ViewBase/Layout/Dim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@ public abstract record Dim : IEqualityOperators<Dim, Dim, bool>
/// <returns>The <see cref="Dim"/> returned from the function.</returns>
public static Dim Func (Func<int> function) { return new DimFunc (function); }

/// <summary>
/// Creates a function <see cref="Dim"/> object that computes the dimension based on the passed view and by executing
/// the provided function.
/// The function will be called every time the dimension is needed.
/// </summary>
/// <param name="function">The function to be executed.</param>
/// <param name="view">The view where the data will be retrieved.</param>
/// <returns>The <see cref="Dim"/> returned from the function based on the passed view.</returns>
public static Dim FuncWithView (Func<View, int> function, View? view) { return new DimFuncWithView (function, view); }

/// <summary>Creates a <see cref="Dim"/> object that tracks the Height of the specified <see cref="View"/>.</summary>
/// <returns>The height <see cref="Dim"/> of the other <see cref="View"/>.</returns>
/// <param name="view">The view that will be tracked.</param>
Expand Down
35 changes: 35 additions & 0 deletions Terminal.Gui/ViewBase/Layout/DimFuncWithView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#nullable enable
namespace Terminal.Gui.ViewBase;

/// <summary>
/// Represents a function <see cref="Dim"/> object that computes the dimension based on the passed view and by
/// executing the provided function.
/// </summary>
/// <remarks>
/// This is a low-level API that is typically used internally by the layout system. Use the various static
/// methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
/// </remarks>
/// <param name="Fn">The function that computes the dimension. If this function throws <see cref="LayoutException"/>... </param>
/// <param name="View">The <see cref="Dim"/> returned from the function based on the passed view.</param>
public record DimFuncWithView (Func<View, int> Fn, View? View) : Dim
{
/// <summary>
/// Gets the function that computes the dimension.
/// </summary>
public Func<View, int> Fn { get; } = Fn;

/// <summary>
/// Gets the passed view that the dimension is based on.
/// </summary>
public View View { get; } = View ?? throw new ArgumentNullException (nameof (View), @"View cannot be null");

/// <inheritdoc/>
public override string ToString () { return $"DimFuncWithView({Fn (View)})"; }

internal override int GetAnchor (int size)
{
View?.Layout ();

return Fn (View!);
}
}
7 changes: 0 additions & 7 deletions Terminal.Gui/ViewBase/View.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,6 @@ public virtual void EndInit ()
}
}

// Force a layout each time a View is initialized
// See: https://github.com/gui-cs/Terminal.Gui/issues/3951
// See: https://github.com/gui-cs/Terminal.Gui/issues/4204
Layout (); // the EventLog in AllViewsTester fails to layout correctly if this is not here (convoluted Dim.Fill(Func)).

// Complex layout scenarios (e.g. DimAuto and PosAlign) may require multiple layouts to be performed.
// Thus, we call SetNeedsLayout() to ensure that the layout is performed at least once.
SetNeedsLayout ();

Initialized?.Invoke (this, EventArgs.Empty);
Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/View/Adornment/ShadowStyleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ public void ShadowStyle_Button1Pressed_Causes_Movement (ShadowStyle style, int e
superView.Add (view);
superView.BeginInit ();
superView.EndInit ();
superView.Layout ();

Thickness origThickness = view.Margin!.Thickness;
view.NewMouseEvent (new () { Flags = MouseFlags.Button1Pressed, Position = new (0, 0) });
Expand Down
5 changes: 2 additions & 3 deletions Tests/UnitTests/View/Draw/ClearViewportTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ public void Clear_ClearsEntireViewport ()
superView.Add (view);
superView.BeginInit ();
superView.EndInit ();
superView.LayoutSubViews ();

superView.Layout ();
superView.Draw ();

DriverAssert.AssertDriverContentsWithFrameAre (
Expand Down Expand Up @@ -163,7 +162,7 @@ public void Clear_WithClearVisibleContentOnly_ClearsVisibleContentOnly ()
superView.Add (view);
superView.BeginInit ();
superView.EndInit ();
superView.LayoutSubViews ();
superView.Layout ();

superView.Draw ();

Expand Down
4 changes: 3 additions & 1 deletion Tests/UnitTests/View/Draw/ClipTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void FillRect_Fills_HonorsClip (int x, int y, int width, int height)
superView.Add (view);
superView.BeginInit ();
superView.EndInit ();
superView.LayoutSubViews ();
superView.Layout ();

superView.Draw ();

Expand Down Expand Up @@ -258,6 +258,7 @@ public void SetClip_ClipVisibleContentOnly_VisibleContentIsClipped ()
view.Border!.Thickness = new (1);
view.BeginInit ();
view.EndInit ();
view.Layout ();
Assert.Equal (view.Frame, View.GetClip ()!.GetBounds ());

// Act
Expand Down Expand Up @@ -291,6 +292,7 @@ public void SetClip_Default_ClipsToViewport ()
view.Border!.Thickness = new (1);
view.BeginInit ();
view.EndInit ();
view.Layout ();
Assert.Equal (view.Frame, View.GetClip ()!.GetBounds ());
view.Viewport = view.Viewport with { X = 1, Y = 1 };

Expand Down
3 changes: 3 additions & 0 deletions Tests/UnitTests/View/Layout/GetViewsUnderLocationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ public void Returns_Correct_If_Start_Has_Adornment_WithSubView (int testX, int t
Application.Top.Padding.Add (subview);
Application.Top.BeginInit ();
Application.Top.EndInit ();
Application.Top.LayoutSubViews ();

View? found = View.GetViewsUnderLocation (new (testX, testY), ViewportSettingsFlags.TransparentMouse).LastOrDefault ();

Expand Down Expand Up @@ -489,6 +490,7 @@ public void Returns_Correct_If_SubView_Has_Adornment_WithSubView (int testX, int
Application.Top.Add (subview);
Application.Top.BeginInit ();
Application.Top.EndInit ();
Application.Top.LayoutSubViews ();

View? found = View.GetViewsUnderLocation (new (testX, testY), ViewportSettingsFlags.TransparentMouse).LastOrDefault ();

Expand Down Expand Up @@ -540,6 +542,7 @@ public void Returns_Correct_If_SubView_Is_Scrolled_And_Has_Adornment_WithSubView
Application.Top.Add (subview);
Application.Top.BeginInit ();
Application.Top.EndInit ();
Application.Top.LayoutSubViews ();

View? found = View.GetViewsUnderLocation (new (testX, testY), ViewportSettingsFlags.TransparentMouse).LastOrDefault ();

Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/View/Mouse/MouseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ public void WantContinuousButtonPressed_True_And_WantMousePositionReports_True_B

// When mouse is held down
me.Flags = pressed;
view.Layout ();
view.NewMouseEvent (me);
Assert.Equal (0, clickedCount);
me.Handled = false;
Expand Down
2 changes: 2 additions & 0 deletions Tests/UnitTests/View/TextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,7 @@ public void Narrow_Wide_Runes ()
top.Add (frame);
top.BeginInit ();
top.EndInit ();
top.Layout ();

Assert.Equal (new (0, 0, 20, 1), horizontalView.Frame);
Assert.Equal (new (0, 3, 1, 20), verticalView.Frame);
Expand Down Expand Up @@ -1127,6 +1128,7 @@ public void SetText_RendersCorrectly ()
view = new Label { Text = text };
view.BeginInit ();
view.EndInit ();
view.Layout ();
view.Draw ();

DriverAssert.AssertDriverContentsWithFrameAre (text, output);
Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/View/ViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ public void New_Initializes ()

r.BeginInit ();
r.EndInit ();
r.Layout ();
Assert.False (r.CanFocus);
Assert.False (r.HasFocus);
Assert.Equal (new (0, 0, 1, 13), r.Viewport);
Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/Views/ButtonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ public void Constructors_Defaults ()
Assert.True (btn.CanFocus);

Application.Driver?.ClearContents ();
btn.Layout ();
btn.Draw ();

expected = @$"
Expand Down
2 changes: 1 addition & 1 deletion Tests/UnitTests/Views/ColorPicker16Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void Constructors ()

colorPicker.BeginInit ();
colorPicker.EndInit ();
colorPicker.LayoutSubViews ();
colorPicker.Layout ();
Assert.Equal (new (0, 0, 32, 4), colorPicker.Frame);
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/UnitTests/Views/ColorPickerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ public void ColorPicker_SwitchingColorModels_ResetsBars ()
// Switch to HSV
cp.Style.ColorModel = ColorModel.HSV;
cp.ApplyStyleChanges ();

cp.Layout ();
cp.Draw ();

ColorBar h = GetColorBar (cp, ColorPickerPart.Bar1);
Expand Down
2 changes: 1 addition & 1 deletion Tests/UnitTests/Views/LabelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ public void Label_Height_Zero_Stays_Zero ()
win.Add (label);
win.BeginInit ();
win.EndInit ();
win.LayoutSubViews ();
win.Layout ();
win.Draw ();

Assert.Equal (5, text.Length);
Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/Views/Menuv1/MenuBarv1Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,7 @@ public void MenuBar_Position_And_Size_With_HotKeys_Is_The_Same_As_Without_HotKey
Assert.True (menu.NewKeyDownEvent (menu.Key));
Assert.True (menu.IsMenuOpen);
View.SetClipToScreen ();
top.Layout ();
top.Draw ();
DriverAssert.AssertDriverContentsAre (expectedMenu.ExpectedSubMenuOpen (0), output);

Expand Down
8 changes: 4 additions & 4 deletions Tests/UnitTests/Views/ProgressBarTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public void Default_Constructor ()
var pb = new ProgressBar ();
pb.BeginInit ();
pb.EndInit ();

pb.Layout ();
Assert.False (pb.CanFocus);
Assert.Equal (0, pb.Fraction);

Expand All @@ -32,7 +32,7 @@ public void Fraction_Redraw ()

pb.BeginInit ();
pb.EndInit ();
pb.LayoutSubViews ();
pb.Layout ();

for (var i = 0; i <= pb.Frame.Width; i++)
{
Expand Down Expand Up @@ -174,7 +174,7 @@ public void Pulse_Redraw_BidirectionalMarquee_False ()

pb.BeginInit ();
pb.EndInit ();
pb.LayoutSubViews ();
pb.Layout ();

for (var i = 0; i < 38; i++)
{
Expand Down Expand Up @@ -879,7 +879,7 @@ public void Pulse_Redraw_BidirectionalMarquee_True_Default ()

pb.BeginInit ();
pb.EndInit ();
pb.LayoutSubViews ();
pb.Layout ();

for (var i = 0; i < 38; i++)
{
Expand Down
3 changes: 3 additions & 0 deletions Tests/UnitTests/Views/SliderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ private void DimAuto_Both_Respects_SuperView_ContentSize ()
view.Add (slider);
view.BeginInit ();
view.EndInit ();
view.Layout ();

Size expectedSize = slider.Frame.Size;

Expand Down Expand Up @@ -547,6 +548,7 @@ private void DimAuto_Width_Respects_SuperView_ContentSize ()
view.Add (slider);
view.BeginInit ();
view.EndInit ();
view.Layout ();

Size expectedSize = slider.Frame.Size;

Expand Down Expand Up @@ -580,6 +582,7 @@ private void DimAuto_Height_Respects_SuperView_ContentSize ()
view.Add (slider);
view.BeginInit ();
view.EndInit ();
view.Layout ();

Size expectedSize = slider.Frame.Size;

Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/Views/TextFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1673,6 +1673,7 @@ public void Draw_Esc_Rune ()
var tf = new TextField { Width = 5, Text = "\u001b" };
tf.BeginInit ();
tf.EndInit ();
tf.Layout ();
tf.Draw ();

DriverAssert.AssertDriverContentsWithFrameAre ("\u241b", output);
Expand Down
8 changes: 8 additions & 0 deletions Tests/UnitTests/Views/TileViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,10 @@ public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRebuildForTileCount
Assert.Equal (1, myReusableView.DisposalCount);
}
);

Assert.NotNull (Application.Top);
Application.Top.Dispose ();
Application.Shutdown ();
}

[Theory]
Expand Down Expand Up @@ -848,6 +852,10 @@ public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile (int idx)
Assert.True (myReusableView.DisposalCount >= 1);
}
);

Assert.NotNull (Application.Top);
Application.Top.Dispose ();
Application.Shutdown ();
}

[Fact]
Expand Down
Loading
Loading