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

Simplify/Enforce LayoutStyle.Absolute when X, Y, Width, and/or Height are null or Absolute() #2465

Closed
tig opened this issue Mar 29, 2023 · 2 comments
Labels
v2 For discussions, issues, etc... relavant for v2

Comments

@tig
Copy link
Collaborator

tig commented Mar 29, 2023

I keep finding latent bugs and/or extra code in v1 relative to this topic.

The current API docs for ComputedLayout read:

image

IOW, these members are to be ignored if Absolute is set. However, in reality, nobody keeps this clear in their heads and there's tons of code where Views with Absolute get these members set using absolute values (e.g. view.X = 3).

Plus, Dim and Pos make this easy with their constructors that take int.

I propose the following for v2 to simplify and clarify all of this: View.LayoutStyle is no longer implemented as a field (the View.layoutStyle private member), but a calculated property.

v1:

		public LayoutStyle LayoutStyle {
			get {
				return layoutStyle;
			}
			set {
				layoutStyle = value;
				SetNeedsLayout ();
			}
		}

v2:

		/// <summary>
		/// Gets or sets what <see cref="Terminal.Gui.LayoutStyle"/> the view is using. 
		/// </summary>
		/// <remarks>
		/// <para>
		/// Setting this property to <see cref="Terminal.Gui.LayoutStyle.Absolute"/> will cause <see cref="Frame"/> to determine the size and position of the view. <see cref="X"/> and <see cref="Y"/> will be 
		/// set to <see cref="Dim.DimAbsolute"/> using <see cref="Frame"/>.
		/// </para>
		/// <para>
		/// Setting this property to <see cref="Terminal.Gui.LayoutStyle.Computed"/> will cause the view to use the <see cref="LayoutSubviews"/> method to 
		/// size and position of the view. If either of the <see cref="X"/> and <see cref="Y"/> properties are `null` they will be set to <see cref="Pos.PosAbsolute"/> using
		/// the current value of <see cref="Frame"/>. 
		/// If either of the <see cref="Width"/> and <see cref="Height"/> properties are `null` they will be set to <see cref="Dim.DimAbsolute"/> using <see cref="Frame"/>.
		/// </para>
		/// </remarks>
		/// <value>The layout style.</value>
		public LayoutStyle LayoutStyle {
			get {
				if ((X == null || X is Pos.PosAbsolute) &&  (Y == null || Y is Pos.PosAbsolute) && 
					(Width == null || Width is Dim.DimAbsolute) && (Height == null || Height is Dim.DimAbsolute)) {
					return LayoutStyle.Absolute;
				}
				return LayoutStyle.Computed;
			}
			set {
				switch (value) {
				case LayoutStyle.Absolute:
					X = Frame.X;
					Y = Frame.Y;
					Width = Frame.Width;
					Height = Frame.Height;
					break;
					
				case LayoutStyle.Computed:
					if (X == null) X = Frame.X;
					if (Y == null) Y = Frame.Y;
					if (Width == null) Width = Frame.Width;
					if (Height == null) Height = Frame.Height;
					break;
				}

				SetNeedsLayout ();
			}
		}

The implications of this are fairly straightforward, but there are sure to be some subtle gotchas in existing code and architecture.

  • I think once this is done, there's no need for X, Y, Width, or Height to ever be null. They are either of type Pos/Dim.Absolute or another. Their setters should throw InvalidArgumentException if value is null.

Thoughts? Comments?

@tig tig added the v2 For discussions, issues, etc... relavant for v2 label Mar 29, 2023
tig added a commit to tig/Terminal.Gui that referenced this issue Mar 30, 2023
tig added a commit to tig/Terminal.Gui that referenced this issue Mar 30, 2023
@BDisp
Copy link
Collaborator

BDisp commented Apr 5, 2023

			v = new View (frame.X, frame.Y, "v");
			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
			// BUGBUG: v2 - I think the default size should be 0,0
			Assert.Equal (new Rect(frame.X, frame.Y, 1, 1), v.Frame);

BUGBUG: v2 - I think the default size should be 0,0

The reason for this is the call to this (TextFormatter.CalcRect (x, y, text), text) { }

		[Fact]
		public void AbsoluteLayout_Change_Height_or_Width_NotAbsolute ()
		{
			var v = new View (Rect.Empty);
			v.Height = Dim.Fill ();
			v.Width = Dim.Fill ();
			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);  // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
		}

		[Fact]
		public void AbsoluteLayout_Change_X_or_Y_NotAbsolute ()
		{
			var v = new View (Rect.Empty);
			v.X = Pos.Center ();
			v.Y = Pos.Center ();
			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
		}

		[Fact]
		public void AbsoluteLayout_Change_X_or_Y_Null ()

BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle

LayoutStyle.Absolute is immediately set if a Rect is provided, no matter is empty or not. The reason for the set of a Pos/Dim not changing the LayoutStyle is to avoid throwing an exception if the ForceValidatePosDim is true, which you can be tweaked by set to LayoutStyle.Absolute to change the value and set again to LayoutStyle.Computed.

			// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
			v.X = null;
			v.Y = null;
			v.Height = null;
			v.Width = null;
			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??

If ForceValidatePosDim behavior doesn't matter you can advance to set automatically the LayoutStyle by setting the Pos/Dim.

		[Fact]
		public void AbsoluteLayout_Layout ()
		{
			var superRect = new Rect (0, 0, 100, 100);
			var super = new View (superRect, "super");
			Assert.True (super.LayoutStyle == LayoutStyle.Absolute);
			var v1 = new View () {
				X = 0,
				Y = 0,
				Width = 10,
				Height = 10
			};
			// BUGBUG: v2 - This should be LayoutStyle.Absolute
			Assert.True (v1.LayoutStyle == LayoutStyle.Computed);

BUGBUG: v2 - This should be LayoutStyle.Absolute

Based on your suggestion, yes, but based on the constructor, no.

@BDisp
Copy link
Collaborator

BDisp commented May 26, 2023

@tig I think you are in the right direction. Please go ahead. Thanks.

tig added a commit that referenced this issue Jan 4, 2024
… and/or Height are null or Absolute() (#2467)

* Merged v2_develop; updated API docs

* Code cleanup

* Fixed code that was using Dim/Pos before IsInit

* Fixed ComboBox using Bounds before IsInitalized and grabbing focus when it shouldn't

* Fixed ComboBox tests. Fixed FileDialog

* Fixed all !IsInitalized warnings

* Fixed AllviewsTester

* Fixed CharMap scenario

* Fixed ColorPicker (hack)

* Fixed CoputedLayout and Csv Editor

* Imrpoved warning

* Fixed more warnings

* Fixed GetTextFormatterSizeNeededForTextAndHotKey

* Fixed AllViewsTester

* AllViewsTester code cleanup

* AllViewsTester code cleanup

* AllViewsTester fixed for realz

* Decided Fill was better than Percent for default
@tig tig closed this as completed Jan 14, 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
No open projects
Status: ✅ Done
Development

No branches or pull requests

2 participants