Skip to content
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

Layout subviews does not apply Width changes to Bounds #2672

Closed
tznind opened this issue May 25, 2023 · 8 comments
Closed

Layout subviews does not apply Width changes to Bounds #2672

tznind opened this issue May 25, 2023 · 8 comments
Labels
v2 For discussions, issues, etc... relavant for v2

Comments

@tznind
Copy link
Collaborator

tznind commented May 25, 2023

Describe the bug
Changes to Width are only reflected in Bounds after calling LayoutSubviews on super which seems fine. But subsequent changes to Width are not applied to Bounds even after calling LayoutSubviews again.

If there is a workaround or this is expected behaviour let me know and I can apply to the tests in TerminalGuiDesigner. This is a common use case in the designer (e.g. drag resizing a view) so there are several tests that fail because of it. I notice that Frame is updated but don't want to re-write all my tests to just check Frame instead without understanding if that is correct.

To Reproduce

[Fact, AutoInitShutdown]
public void TestResize ()
{
	var w = new Window ();
	var v = new View { Width = 8, Height = 8 };

	w.Add (v);

	Assert.Equal (0, v.Bounds.Width);

	w.LayoutSubviews ();

	Assert.Equal (8, v.Bounds.Width);

	v.Width = 10;

	w.LayoutSubviews ();

	// Fails here 
	Assert.Equal (10, v.Bounds.Width);
}

Expected behavior
Calling LayoutSubviews should always update the Bounds to respect the Width/Height

@tznind tznind added the v2 For discussions, issues, etc... relavant for v2 label May 25, 2023
@tig
Copy link
Collaborator

tig commented May 25, 2023

There are a whole set of issues around this in the current v2_develop codebase. These are caused by the fact that my work to rearchitect View for v2 is not complete. I introduced a few bugs like this and have been vaguely aware of it. Your test case is excellent and will help us figure this out! Thanks.

There's probably a way to fix this quickly to help you move forward. I'll start looking at it asap. Feel free to suggest a fix if you see something obvious. But note that our core unit tests for View don't capture all the subtle things that can break if the layout code is modified.

Related: #2465, #2491.

@BDisp
Copy link
Collaborator

BDisp commented May 25, 2023

This isn't a real bug, but it's because @tig decided in the v2 the layout views only truly works after BeginInit and EndInit has executed. This unit test will not fail:

		[Fact, AutoInitShutdown]
		public void TestResize ()
		{
			var w = new Window ();
			var v = new View { Width = 8, Height = 8 };

			w.Add (v);

			Assert.False (w.IsInitialized);
			Assert.False (v.IsInitialized);
			Assert.Equal (0, w.Bounds.Width);
			Assert.Equal (0, v.Bounds.Width);

			w.BeginInit ();
			w.EndInit ();
			Assert.True (w.IsInitialized);
			Assert.True (v.IsInitialized);
			Assert.Equal (0, w.Bounds.Width);
			Assert.Equal (8, v.Bounds.Width);

			w.LayoutSubviews ();

			Assert.Equal (0, w.Bounds.Width);
			Assert.Equal (8, v.Bounds.Width);

			v.Width = 10;

			w.LayoutSubviews ();

			// Wont fail here
			Assert.Equal (0, w.Bounds.Width);
			Assert.Equal (10, v.Bounds.Width);
		}

@tig
Copy link
Collaborator

tig commented May 25, 2023

To be clear, i didn't decide anything.

I just realized that previously any code that relied on Bounds being valid before IsInitialized was true was a bug and added code to make this more clear.

Does this test emit the "WARNING: " debug statement?

@BDisp
Copy link
Collaborator

BDisp commented May 25, 2023

To be clear, i didn't decide anything.

@tig when I said you have decided, it's wasn't any censure. Sorry if you interpret that.

I just realized that previously any code that relied on Bounds being valid before IsInitialized was true was a bug and added code to make this more clear.

In my opinion if a Pos/Dim are initialized with absolute values it may be considered before IsInitialized. With others types I agree forcing to be set after IsInitialized when the SuperView bounds are knowing.

Does this test emit the "WARNING: " debug statement?

Yes, it's emitting all the time :-)

@tznind
Copy link
Collaborator Author

tznind commented May 25, 2023

Thanks for digging into this. I will look at adding BeginInit/EndInit into my test or into the resize operation in the designer.

I guess the things that were wierd for me was that the first call to LayoutSubviews did change the Bounds but the second didn't. Also I noticed that the Frame did change when the Bounds did not which was also unexpected.

@BDisp
Copy link
Collaborator

BDisp commented May 25, 2023

Here is the reason why Frame did change but not Bounds, if (LayoutStyle == LayoutStyle.Computed && !IsInitialized):

		public virtual Rect Bounds {
			get {
#if DEBUG
				if (LayoutStyle == LayoutStyle.Computed && !IsInitialized) {
					Debug.WriteLine ($"WARNING: Bounds is being accessed before the View has been initialized. This is likely a bug. View: {this}");
				}
#endif // DEBUG
				var frameRelativeBounds = Padding?.Thickness.GetInside (Padding.Frame) ?? new Rect (default, Frame.Size);
				return new Rect (default, frameRelativeBounds.Size);
			}
			set {
				// BUGBUG: Margin etc.. can be null (if typeof(Frame))
				Frame = new Rect (Frame.Location,
					new Size (
						value.Size.Width + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal,
						value.Size.Height + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical
						)
					);
			}
		}

So, if you need calculated Bounds you need to run BeginInit/EndInit on the SuperView.

@tig
Copy link
Collaborator

tig commented May 26, 2023

In my opinion if a Pos/Dim are initialized with absolute values it may be considered before IsInitialized. With others types I agree forcing to be set after IsInitialized when the SuperView bounds are knowing.

I believe you and I are aligned on this.

I had created this issue, IIRC, specifically so we can fix this: #2465

@tig
Copy link
Collaborator

tig commented Jan 19, 2024

@tig tig closed this as completed Jan 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v2 For discussions, issues, etc... relavant for v2
Projects
None yet
Development

No branches or pull requests

3 participants