From c2bda7a280b66144c8367dfd02432d1cc8c1754b Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Fri, 5 Jan 2024 08:00:56 -0700 Subject: [PATCH] Updated nuget refs --- ReactiveExample/ReactiveExample.csproj | 4 +- .../View/Layout/SizeChangedEventArgs.cs | 43 +- Terminal.Gui/View/Layout/ViewLayout.cs | 864 ++++++++++-------- UICatalog/UICatalog.csproj | 2 +- UnitTests/UnitTests.csproj | 2 +- 5 files changed, 487 insertions(+), 428 deletions(-) diff --git a/ReactiveExample/ReactiveExample.csproj b/ReactiveExample/ReactiveExample.csproj index b3c0c5558..921465ed4 100644 --- a/ReactiveExample/ReactiveExample.csproj +++ b/ReactiveExample/ReactiveExample.csproj @@ -11,8 +11,8 @@ 2.0 - - + + diff --git a/Terminal.Gui/View/Layout/SizeChangedEventArgs.cs b/Terminal.Gui/View/Layout/SizeChangedEventArgs.cs index adde33a15..2e0ae4502 100644 --- a/Terminal.Gui/View/Layout/SizeChangedEventArgs.cs +++ b/Terminal.Gui/View/Layout/SizeChangedEventArgs.cs @@ -1,31 +1,24 @@ using System; -namespace Terminal.Gui { +namespace Terminal.Gui; + +/// +/// Args for events about Size (e.g. Resized) +/// +public class SizeChangedEventArgs : EventArgs { + /// + /// Creates a new instance of the class. + /// + /// + public SizeChangedEventArgs (Size size) => Size = size; /// - /// Args for events about Size (e.g. Resized) + /// Gets the size the event describes. This should reflect the new/current size after the event. /// - public class SizeChangedEventArgs : EventArgs { + public Size Size { get; } - /// - /// Creates a new instance of the class. - /// - /// - public SizeChangedEventArgs (Size size) - { - Size = size; - } - - /// - /// Gets the size the event describes. This should - /// reflect the new/current size after the event - /// resolved. - /// - public Size Size { get; } - - /// - /// Set to to cause the resize to be cancelled, if appropriate. - /// - public bool Cancel { get; set; } - } -} + /// + /// Set to to cause the resize to be cancelled, if appropriate. + /// + public bool Cancel { get; set; } +} \ No newline at end of file diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs index a0afa861b..d02d83cb2 100644 --- a/Terminal.Gui/View/Layout/ViewLayout.cs +++ b/Terminal.Gui/View/Layout/ViewLayout.cs @@ -7,45 +7,59 @@ using System.Linq; namespace Terminal.Gui; /// -/// Determines the LayoutStyle for a , if Absolute, during , the -/// value from the will be used, if the value is Computed, then -/// will be updated from the X, Y objects and the Width and Height objects. +/// Determines the LayoutStyle for a , if Absolute, during , the +/// value from the will be used, if the value is Computed, then +/// will be updated from the X, Y objects and the Width and Height objects. /// public enum LayoutStyle { /// - /// The position and size of the view are based . + /// The position and size of the view are based . /// Absolute, /// - /// The position and size of the view will be computed based on - /// , , , and . will + /// The position and size of the view will be computed based on + /// , , , and . + /// will /// provide the absolute computed values. /// Computed } public partial class View { + bool _autoSize; + // The frame for the object. Relative to the SuperView's Bounds. Rect _frame; + LayoutStyle _layoutStyle; + + Dim _width, _height; + + Pos _x, _y; + /// - /// Gets or sets location and size of the view. The frame is relative to the 's . + /// Gets or sets location and size of the view. The frame is relative to the 's + /// . /// - /// The rectangle describing the location and size of the view, in coordinates relative to the . + /// + /// The rectangle describing the location and size of the view, in coordinates relative to the + /// . + /// /// - /// - /// Change the Frame when using the layout style to move or resize views. - /// - /// - /// Altering the Frame will change to . - /// Additionally, , , , and will be set - /// to the values of the Frame (using and ). - /// - /// - /// Altering the Frame will eventually (when the view is next drawn) cause the - /// and methods to be called. - /// + /// + /// Change the Frame when using the layout style to move or resize views. + /// + /// + /// Altering the Frame will change to . + /// Additionally, , , , and will be set + /// to the values of the Frame (using and ). + /// + /// + /// Altering the Frame will eventually (when the view is next drawn) cause the + /// + /// and methods to be called. + /// /// public virtual Rect Frame { get => _frame; @@ -65,41 +79,46 @@ public partial class View { } /// - /// The frame (specified as a ) that separates a View from other SubViews of the same SuperView. - /// The margin offsets the from the . + /// The frame (specified as a ) that separates a View from other SubViews of the same SuperView. + /// The margin offsets the from the . /// /// - /// - /// The frames (, , and ) are not part of the View's content - /// and are not clipped by the View's Clip Area. - /// - /// - /// Changing the size of a frame (, , or ) - /// will change the size of the and trigger to update the layout of the - /// and its . - /// + /// + /// The frames (, , and ) are not part of the + /// View's content + /// and are not clipped by the View's Clip Area. + /// + /// + /// Changing the size of a frame (, , or ) + /// will change the size of the and trigger to update the layout + /// of the + /// and its . + /// /// public Frame Margin { get; private set; } /// - /// The frame (specified as a ) inside of the view that offsets the from the . - /// The Border provides the space for a visual border (drawn using line-drawing glyphs) and the Title. - /// The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and - /// title will take up the first row and the second row will be filled with spaces. + /// The frame (specified as a ) inside of the view that offsets the from the + /// . + /// The Border provides the space for a visual border (drawn using line-drawing glyphs) and the Title. + /// The Border expands inward; in other words if `Border.Thickness.Top == 2` the border and + /// title will take up the first row and the second row will be filled with spaces. /// /// - /// - /// provides a simple helper for turning a simple border frame on or off. - /// - /// - /// The frames (, , and ) are not part of the View's content - /// and are not clipped by the View's Clip Area. - /// - /// - /// Changing the size of a frame (, , or ) - /// will change the size of the and trigger to update the layout of the - /// and its . - /// + /// + /// provides a simple helper for turning a simple border frame on or off. + /// + /// + /// The frames (, , and ) are not part of the + /// View's content + /// and are not clipped by the View's Clip Area. + /// + /// + /// Changing the size of a frame (, , or ) + /// will change the size of the and trigger to update the layout + /// of the + /// and its . + /// /// public Frame Border { get; private set; } @@ -107,18 +126,20 @@ public partial class View { /// Gets or sets whether the view has a one row/col thick border. /// /// - /// - /// This is a helper for manipulating the view's . Setting this property to any value other than - /// is equivalent to setting 's - /// to `1` and to the value. - /// - /// - /// Setting this property to is equivalent to setting 's - /// to `0` and to . - /// - /// - /// For more advanced customization of the view's border, manipulate see directly. - /// + /// + /// This is a helper for manipulating the view's . Setting this property to any value other + /// than + /// is equivalent to setting 's + /// to `1` and to the value. + /// + /// + /// Setting this property to is equivalent to setting 's + /// + /// to `0` and to . + /// + /// + /// For more advanced customization of the view's border, manipulate see directly. + /// /// public LineStyle BorderStyle { get => Border?.BorderStyle ?? LineStyle.None; @@ -138,113 +159,55 @@ public partial class View { } /// - /// The frame (specified as a ) inside of the view that offsets the from the . + /// The frame (specified as a ) inside of the view that offsets the from the + /// . /// /// - /// - /// The frames (, , and ) are not part of the View's content - /// and are not clipped by the View's Clip Area. - /// - /// - /// Changing the size of a frame (, , or ) - /// will change the size of the and trigger to update the layout of the - /// and its . - /// + /// + /// The frames (, , and ) are not part of the + /// View's content + /// and are not clipped by the View's Clip Area. + /// + /// + /// Changing the size of a frame (, , or ) + /// will change the size of the and trigger to update the layout + /// of the + /// and its . + /// /// public Frame Padding { get; private set; } /// - /// Helper to get the total thickness of the , , and . - /// - /// A thickness that describes the sum of the Frames' thicknesses. - public Thickness GetFramesThickness () - { - int left = Margin.Thickness.Left + Border.Thickness.Left + Padding.Thickness.Left; - int top = Margin.Thickness.Top + Border.Thickness.Top + Padding.Thickness.Top; - int right = Margin.Thickness.Right + Border.Thickness.Right + Padding.Thickness.Right; - int bottom = Margin.Thickness.Bottom + Border.Thickness.Bottom + Padding.Thickness.Bottom; - return new Thickness (left, top, right, bottom); - } - - /// - /// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of - /// , and . - /// - public Point GetBoundsOffset () => new (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0); - - /// - /// Creates the view's objects. This internal method is overridden by Frame to do nothing - /// to prevent recursion during View construction. - /// - internal virtual void CreateFrames () - { - void ThicknessChangedHandler (object sender, EventArgs e) - { - if (IsInitialized) { - LayoutFrames (); - } - SetNeedsLayout (); - SetNeedsDisplay (); - } - - if (Margin != null) { - Margin.ThicknessChanged -= ThicknessChangedHandler; - Margin.Dispose (); - } - Margin = new Frame () { Id = "Margin", Thickness = new Thickness (0) }; - Margin.ThicknessChanged += ThicknessChangedHandler; - Margin.Parent = this; - - if (Border != null) { - Border.ThicknessChanged -= ThicknessChangedHandler; - Border.Dispose (); - } - Border = new Frame () { Id = "Border", Thickness = new Thickness (0) }; - Border.ThicknessChanged += ThicknessChangedHandler; - Border.Parent = this; - - // TODO: Create View.AddAdornment - - if (Padding != null) { - Padding.ThicknessChanged -= ThicknessChangedHandler; - Padding.Dispose (); - } - Padding = new Frame () { Id = "Padding", Thickness = new Thickness (0) }; - Padding.ThicknessChanged += ThicknessChangedHandler; - Padding.Parent = this; - } - - LayoutStyle _layoutStyle; - - /// - /// Controls how the View's is computed during . If the style is set to - /// , LayoutSubviews does not change the . - /// If the style is the is updated using - /// the , , , and properties. + /// Controls how the View's is computed during . If the style is set to + /// , LayoutSubviews does not change the . + /// If the style is the is updated using + /// the , , , and properties. /// /// - /// - /// Setting this property to will cause to determine the - /// size and position of the view. and will be set to using . - /// - /// - /// Setting this property to will cause the view to use the method to - /// size and position of the view. If either of the and properties are `null` they will be set to using - /// the current value of . - /// If either of the and properties are `null` they will be set to using . - /// + /// + /// Setting this property to will cause to determine the + /// size and position of the view. and will be set to + /// using . + /// + /// + /// Setting this property to will cause the view to use the + /// method to + /// size and position of the view. If either of the and properties are `null` + /// they will be set to using + /// the current value of . + /// If either of the and properties are `null` they will be set to + /// using . + /// /// /// The layout style. public LayoutStyle LayoutStyle { - get { - return _layoutStyle; - //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; - //} else { - // return LayoutStyle.Computed; - //} - } + get => _layoutStyle; + //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; + //} else { + // return LayoutStyle.Computed; + //} set { _layoutStyle = value; //switch (_layoutStyle) { @@ -267,26 +230,31 @@ public partial class View { } /// - /// The bounds represent the View-relative rectangle used for this view; the area inside of the view where subviews and content are presented. + /// The bounds represent the View-relative rectangle used for this view; the area inside of the view where subviews and + /// content are presented. /// /// The rectangle describing the location and size of the area where the views' subviews and content are drawn. /// - /// - /// If is the value of Bounds is indeterminate until the - /// view has been initialized ( is true) and has been called. - /// - /// - /// Updates to the Bounds updates , and has the same side effects as updating the . - /// - /// - /// Altering the Bounds will eventually (when the view is next drawn) cause the - /// and methods to be called. - /// - /// - /// Because coordinates are relative to the upper-left corner of the , - /// the coordinates of the upper-left corner of the rectangle returned by this property are (0,0). - /// Use this property to obtain the size of the area of the view for tasks such as drawing the view's contents. - /// + /// + /// If is the value of Bounds is indeterminate until + /// the + /// view has been initialized ( is true) and has been + /// called. + /// + /// + /// Updates to the Bounds updates , and has the same side effects as updating the + /// . + /// + /// + /// Altering the Bounds will eventually (when the view is next drawn) cause the + /// + /// and methods to be called. + /// + /// + /// Because coordinates are relative to the upper-left corner of the , + /// the coordinates of the upper-left corner of the rectangle returned by this property are (0,0). + /// Use this property to obtain the size of the area of the view for tasks such as drawing the view's contents. + /// /// public virtual Rect Bounds { get { @@ -310,41 +278,33 @@ public partial class View { } } - Rect FrameGetInsideBounds () - { - if (Margin == null || Border == null || Padding == null) { - return new Rect (default, Frame.Size); - } - int width = Math.Max (0, Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal); - int height = Math.Max (0, Frame.Size.Height - Margin.Thickness.Vertical - Border.Thickness.Vertical - Padding.Thickness.Vertical); - return new Rect (Point.Empty, new Size (width, height)); - } - - Pos _x, _y; - /// - /// Gets or sets the X position for the view (the column). + /// Gets or sets the X position for the view (the column). /// - /// The object representing the X position. + /// The object representing the X position. /// - /// - /// If is the value is indeterminate until the - /// view has been initialized ( is true) and has been called. - /// - /// - /// Changing this property will eventually (when the view is next drawn) cause the and - /// methods to be called. - /// - /// - /// If is changing this property will cause the to be updated. If - /// the new value is not of type the will change to . - /// - /// - /// is the same as Pos.Absolute(0). - /// + /// + /// If is the value is indeterminate until the + /// view has been initialized ( is true) and has been + /// called. + /// + /// + /// Changing this property will eventually (when the view is next drawn) cause the + /// and + /// methods to be called. + /// + /// + /// If is changing this property will cause the + /// to be updated. If + /// the new value is not of type the will change to + /// . + /// + /// + /// is the same as Pos.Absolute(0). + /// /// public Pos X { - get => VerifyIsInitialized (_x, nameof(X)); + get => VerifyIsInitialized (_x, nameof (X)); set { // BUGBUG: null is the sames a Pos.Absolute(0). Should we be explicit and set it? @@ -359,28 +319,32 @@ public partial class View { } /// - /// Gets or sets the Y position for the view (the row). + /// Gets or sets the Y position for the view (the row). /// - /// The object representing the Y position. + /// The object representing the Y position. /// - /// - /// If is the value is indeterminate until the - /// view has been initialized ( is true) and has been called. - /// - /// - /// Changing this property will eventually (when the view is next drawn) cause the and - /// methods to be called. - /// - /// - /// If is changing this property will cause the to be updated. If - /// the new value is not of type the will change to . - /// - /// - /// is the same as Pos.Absolute(0). - /// + /// + /// If is the value is indeterminate until the + /// view has been initialized ( is true) and has been + /// called. + /// + /// + /// Changing this property will eventually (when the view is next drawn) cause the + /// and + /// methods to be called. + /// + /// + /// If is changing this property will cause the + /// to be updated. If + /// the new value is not of type the will change to + /// . + /// + /// + /// is the same as Pos.Absolute(0). + /// /// public Pos Y { - get => VerifyIsInitialized (_y, nameof(Y)); + get => VerifyIsInitialized (_y, nameof (Y)); set { // BUGBUG: null is the sames a Pos.Absolute(0). Should we be explicit and set it? @@ -394,25 +358,27 @@ public partial class View { } } - Dim _width, _height; - /// - /// Gets or sets the width of the view. + /// Gets or sets the width of the view. /// - /// The object representing the width of the view (the number of columns). + /// The object representing the width of the view (the number of columns). /// - /// - /// If is the value is indeterminate until the - /// view has been initialized ( is true) and has been called. - /// - /// - /// Changing this property will eventually (when the view is next drawn) cause the - /// and methods to be called. - /// - /// - /// If is changing this property will cause the to be updated. If - /// the new value is not of type the will change to . - /// + /// + /// If is the value is indeterminate until the + /// view has been initialized ( is true) and has been + /// called. + /// + /// + /// Changing this property will eventually (when the view is next drawn) cause the + /// + /// and methods to be called. + /// + /// + /// If is changing this property will cause the + /// to be updated. If + /// the new value is not of type the will change to + /// . + /// /// public Dim Width { get => VerifyIsInitialized (_width, nameof (Width)); @@ -428,7 +394,7 @@ public partial class View { _width = value; if (ValidatePosDim) { - bool isValidNewAutSize = AutoSize && IsValidAutoSizeWidth (_width); + var isValidNewAutSize = AutoSize && IsValidAutoSizeWidth (_width); if (IsAdded && AutoSize && !isValidNewAutSize) { throw new InvalidOperationException ("Must set AutoSize to false before set the Width."); @@ -439,22 +405,26 @@ public partial class View { } /// - /// Gets or sets the height of the view. + /// Gets or sets the height of the view. /// - /// The object representing the height of the view (the number of rows). + /// The object representing the height of the view (the number of rows). /// - /// - /// If is the value is indeterminate until the - /// view has been initialized ( is true) and has been called. - /// - /// - /// Changing this property will eventually (when the view is next drawn) cause the - /// and methods to be called. - /// - /// - /// If is changing this property will cause the to be updated. If - /// the new value is not of type the will change to . - /// + /// + /// If is the value is indeterminate until the + /// view has been initialized ( is true) and has been + /// called. + /// + /// + /// Changing this property will eventually (when the view is next drawn) cause the + /// + /// and methods to be called. + /// + /// + /// If is changing this property will cause the + /// to be updated. If + /// the new value is not of type the will change to + /// . + /// /// public Dim Height { get => VerifyIsInitialized (_height, nameof (Height)); @@ -470,7 +440,7 @@ public partial class View { _height = value; if (ValidatePosDim) { - bool isValidNewAutSize = AutoSize && IsValidAutoSizeHeight (_height); + var isValidNewAutSize = AutoSize && IsValidAutoSizeHeight (_height); if (IsAdded && AutoSize && !isValidNewAutSize) { throw new InvalidOperationException ("Must set AutoSize to false before setting the Height."); @@ -480,6 +450,127 @@ public partial class View { } } + /// + /// Gets or sets whether validation of and occurs. + /// + /// + /// Setting this to will enable validation of , , + /// , and + /// during set operations and in .If invalid settings are discovered exceptions will be thrown + /// indicating the error. + /// This will impose a performance penalty and thus should only be used for debugging. + /// + public bool ValidatePosDim { get; set; } + + internal bool LayoutNeeded { get; private set; } = true; + + /// + /// Gets or sets a flag that determines whether the View will be automatically resized to fit the + /// within + /// + /// The default is . Set to to turn on AutoSize. If + /// then + /// and will be used if can fit; + /// if won't fit the view will be resized as needed. + /// + /// + /// In addition, if is the new values of and + /// must be of the same types of the existing one to avoid breaking the settings. + /// + /// + public virtual bool AutoSize { + get => _autoSize; + set { + var v = ResizeView (value); + TextFormatter.AutoSize = v; + if (_autoSize != v) { + _autoSize = v; + TextFormatter.NeedsFormat = true; + UpdateTextFormatterText (); + OnResizeNeeded (); + } + } + } + + /// + /// Event called only once when the is being initialized for the first time. + /// Allows configurations and assignments to be performed before the being shown. + /// This derived from to allow notify all the views that are being + /// initialized. + /// + public event EventHandler Initialized; + + /// + /// Helper to get the total thickness of the , , and . + /// + /// A thickness that describes the sum of the Frames' thicknesses. + public Thickness GetFramesThickness () + { + var left = Margin.Thickness.Left + Border.Thickness.Left + Padding.Thickness.Left; + var top = Margin.Thickness.Top + Border.Thickness.Top + Padding.Thickness.Top; + var right = Margin.Thickness.Right + Border.Thickness.Right + Padding.Thickness.Right; + var bottom = Margin.Thickness.Bottom + Border.Thickness.Bottom + Padding.Thickness.Bottom; + return new Thickness (left, top, right, bottom); + } + + /// + /// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of + /// , and . + /// + public Point GetBoundsOffset () => new (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0); + + /// + /// Creates the view's objects. This internal method is overridden by Frame to do nothing + /// to prevent recursion during View construction. + /// + internal virtual void CreateFrames () + { + void ThicknessChangedHandler (object sender, EventArgs e) + { + if (IsInitialized) { + LayoutFrames (); + } + SetNeedsLayout (); + SetNeedsDisplay (); + } + + if (Margin != null) { + Margin.ThicknessChanged -= ThicknessChangedHandler; + Margin.Dispose (); + } + Margin = new Frame { Id = "Margin", Thickness = new Thickness (0) }; + Margin.ThicknessChanged += ThicknessChangedHandler; + Margin.Parent = this; + + if (Border != null) { + Border.ThicknessChanged -= ThicknessChangedHandler; + Border.Dispose (); + } + Border = new Frame { Id = "Border", Thickness = new Thickness (0) }; + Border.ThicknessChanged += ThicknessChangedHandler; + Border.Parent = this; + + // TODO: Create View.AddAdornment + + if (Padding != null) { + Padding.ThicknessChanged -= ThicknessChangedHandler; + Padding.Dispose (); + } + Padding = new Frame { Id = "Padding", Thickness = new Thickness (0) }; + Padding.ThicknessChanged += ThicknessChangedHandler; + Padding.Parent = this; + } + + Rect FrameGetInsideBounds () + { + if (Margin == null || Border == null || Padding == null) { + return new Rect (default, Frame.Size); + } + var width = Math.Max (0, Frame.Size.Width - Margin.Thickness.Horizontal - Border.Thickness.Horizontal - Padding.Thickness.Horizontal); + var height = Math.Max (0, Frame.Size.Height - Margin.Thickness.Vertical - Border.Thickness.Vertical - Padding.Thickness.Vertical); + return new Rect (Point.Empty, new Size (width, height)); + } + // Diagnostics to highlight when X or Y is read before the view has been initialized Pos VerifyIsInitialized (Pos pos, string member) { @@ -503,17 +594,8 @@ public partial class View { } /// - /// Gets or sets whether validation of and occurs. - /// - /// - /// Setting this to will enable validation of , , , and - /// during set operations and in .If invalid settings are discovered exceptions will be thrown indicating the error. - /// This will impose a performance penalty and thus should only be used for debugging. - /// - public bool ValidatePosDim { get; set; } - - /// - /// Throws an if any of the SubViews are using Dim objects that depend on this Views dimensions. + /// Throws an if any of the SubViews are using Dim objects that depend on this + /// Views dimensions. /// /// void CheckDimAuto () @@ -532,7 +614,7 @@ public partial class View { break; case Pos pos and Pos.PosCombine: // Recursively check for not Absolute or not View - ThrowInvalid (view, (pos as Pos.PosCombine)._left, name); + ThrowInvalid (view, (pos as Pos.PosCombine)._left, name); ThrowInvalid (view, (pos as Pos.PosCombine)._right, name); break; @@ -541,13 +623,14 @@ public partial class View { break; case Dim dim and Dim.DimCombine: // Recursively check for not Absolute or not View - ThrowInvalid (view, (dim as Dim.DimCombine)._left, name); + ThrowInvalid (view, (dim as Dim.DimCombine)._left, name); ThrowInvalid (view, (dim as Dim.DimCombine)._right, name); break; } if (bad != null) { - throw new InvalidOperationException (@$"{view.GetType ().Name}.{name} = {bad.GetType ().Name} which depends on the SuperView's dimensions and the SuperView uses Dim.Auto."); + throw new InvalidOperationException ( + @$"{view.GetType ().Name}.{name} = {bad.GetType ().Name} which depends on the SuperView's dimensions and the SuperView uses Dim.Auto."); } } @@ -555,18 +638,19 @@ public partial class View { foreach (var view in Subviews) { if (Width is Dim.DimAuto { _min: null }) { ThrowInvalid (view, view.Width, nameof (view.Width)); - ThrowInvalid (view, view.X, nameof (view.X)); + ThrowInvalid (view, view.X, nameof (view.X)); } if (Height is Dim.DimAuto { _min: null }) { ThrowInvalid (view, view.Height, nameof (view.Height)); - ThrowInvalid (view, view.Y, nameof (view.Y)); + ThrowInvalid (view, view.Y, nameof (view.Y)); } } } /// - /// Throws an if is or . - /// Used when is turned on to verify correct behavior. + /// Throws an if is or + /// . + /// Used when is turned on to verify correct behavior. /// /// /// Does not verify if this view is Toplevel (WHY??!?). @@ -586,28 +670,28 @@ public partial class View { } /// - /// Called whenever the view needs to be resized. Sets and - /// triggers a call. + /// Called whenever the view needs to be resized. Sets and + /// triggers a call. /// /// /// Can be overridden if the view resize behavior is different than the default. /// protected virtual void OnResizeNeeded () { - int actX = _x is Pos.PosAbsolute ? _x.Anchor (0) : _frame.X; - int actY = _y is Pos.PosAbsolute ? _y.Anchor (0) : _frame.Y; + var actX = _x is Pos.PosAbsolute ? _x.Anchor (0) : _frame.X; + var actY = _y is Pos.PosAbsolute ? _y.Anchor (0) : _frame.Y; if (AutoSize) { //if (TextAlignment == TextAlignment.Justified) { // throw new InvalidOperationException ("TextAlignment.Justified cannot be used with AutoSize"); //} var s = GetAutoSize (); - int w = _width is Dim.DimAbsolute && _width.Anchor (0) > s.Width ? _width.Anchor (0) : s.Width; - int h = _height is Dim.DimAbsolute && _height.Anchor (0) > s.Height ? _height.Anchor (0) : s.Height; + var w = _width is Dim.DimAbsolute && _width.Anchor (0) > s.Width ? _width.Anchor (0) : s.Width; + var h = _height is Dim.DimAbsolute && _height.Anchor (0) > s.Height ? _height.Anchor (0) : s.Height; _frame = new Rect (new Point (actX, actY), new Size (w, h)); // Set frame, not Frame! } else { - int w = _width is Dim.DimAbsolute ? _width.Anchor (0) : _frame.Width; - int h = _height is Dim.DimAbsolute ? _height.Anchor (0) : _frame.Height; + var w = _width is Dim.DimAbsolute ? _width.Anchor (0) : _frame.Width; + var h = _height is Dim.DimAbsolute ? _height.Anchor (0) : _frame.Height; // BUGBUG: v2 - ? - If layoutstyle is absolute, this overwrites the current frame h/w with 0. Hmmm... // This is needed for DimAbsolute values by setting the frame before LayoutSubViews. _frame = new Rect (new Point (actX, actY), new Size (w, h)); // Set frame, not Frame! @@ -621,9 +705,7 @@ public partial class View { SetNeedsDisplay (); } - if (IsInitialized - && SuperView != null - && LayoutStyle == LayoutStyle.Computed && (SuperView?.Height is Dim.DimAuto || SuperView?.Width is Dim.DimAuto)) { + if (IsInitialized && SuperView != null && LayoutStyle == LayoutStyle.Computed && (SuperView?.Height is Dim.DimAuto || SuperView?.Width is Dim.DimAuto)) { // DimAuto is in play, force a layout. // BUGBUG: This can cause LayoutSubviews to be called recursively resulting in a deadlock. // SetNeedsLayout should be sufficient, but it's not. @@ -631,8 +713,6 @@ public partial class View { } } - internal bool LayoutNeeded { get; private set; } = true; - internal void SetNeedsLayout () { if (LayoutNeeded) { @@ -653,9 +733,9 @@ public partial class View { /// /// Converts a screen-relative coordinate to a Frame-relative coordinate. Frame-relative means - /// relative to the View's 's . + /// relative to the View's 's . /// - /// The coordinate relative to the 's . + /// The coordinate relative to the 's . /// Screen-relative column. /// Screen-relative row. public Point ScreenToFrame (int x, int y) @@ -670,9 +750,9 @@ public partial class View { } /// - /// Converts a screen-relative coordinate to a bounds-relative coordinate. + /// Converts a screen-relative coordinate to a bounds-relative coordinate. /// - /// The coordinate relative to this view's . + /// The coordinate relative to this view's . /// Screen-relative column. /// Screen-relative row. public Point ScreenToBounds (int x, int y) @@ -683,15 +763,18 @@ public partial class View { } /// - /// Converts a -relative coordinate to a screen-relative coordinate. The output is optionally clamped to the screen dimensions. + /// Converts a -relative coordinate to a screen-relative coordinate. The output is optionally clamped + /// to the screen dimensions. /// - /// -relative column. - /// -relative row. + /// -relative column. + /// -relative row. /// Absolute column; screen-relative. /// Absolute row; screen-relative. - /// If , and will be clamped to the - /// screen dimensions (will never be negative and will always be less than and - /// , respectively. + /// + /// If , and will be clamped to the + /// screen dimensions (will never be negative and will always be less than and + /// , respectively. + /// public virtual void BoundsToScreen (int x, int y, out int rx, out int ry, bool clamped = true) { var boundsOffset = GetBoundsOffset (); @@ -714,16 +797,16 @@ public partial class View { } /// - /// Converts a -relative region to a screen-relative region. + /// Converts a -relative region to a screen-relative region. /// public Rect BoundsToScreen (Rect region) { - BoundsToScreen (region.X, region.Y, out int x, out int y, false); + BoundsToScreen (region.X, region.Y, out var x, out var y, false); return new Rect (x, y, region.Width, region.Height); } /// - /// Gets the with a screen-relative location. + /// Gets the with a screen-relative location. /// /// The location and size of the view in screen-relative coordinates. public virtual Rect FrameToScreen () @@ -741,10 +824,15 @@ public partial class View { // TODO: Come up with a better name for this method. "SetRelativeLayout" lacks clarity and confuses. AdjustSizeAndPosition? /// - /// Applies the view's position (, ) and dimension (, and ) to - /// , given a rectangle describing the SuperView's Bounds (nominally the same as this.SuperView.Bounds). + /// Applies the view's position (, ) and dimension (, and + /// ) to + /// , given a rectangle describing the SuperView's Bounds (nominally the same as + /// this.SuperView.Bounds). /// - /// The rectangle describing the SuperView's Bounds (nominally the same as this.SuperView.Bounds). + /// + /// The rectangle describing the SuperView's Bounds (nominally the same as + /// this.SuperView.Bounds). + /// internal void SetRelativeLayout (Rect superviewBounds) { int newX, newW, newY, newH; @@ -778,8 +866,8 @@ public partial class View { break; case Dim.DimCombine combine: - int leftNewDim = GetNewDimension (combine._left, location, dimension, autosize); - int rightNewDim = GetNewDimension (combine._right, location, dimension, autosize); + var leftNewDim = GetNewDimension (combine._left, location, dimension, autosize); + var rightNewDim = GetNewDimension (combine._right, location, dimension, autosize); if (combine._add) { newDimension = leftNewDim + rightNewDim; } else { @@ -797,11 +885,11 @@ public partial class View { var thickness = GetFramesThickness (); //newDimension = GetNewDimension (auto._min, location, dimension, autosize); if (width) { - int furthestRight = Subviews.Count == 0 ? 0 : Subviews.Where (v => v.X is not Pos.PosAnchorEnd).Max (v => v.Frame.X + v.Frame.Width); + var furthestRight = Subviews.Count == 0 ? 0 : Subviews.Where (v => v.X is not Pos.PosAnchorEnd).Max (v => v.Frame.X + v.Frame.Width); //Debug.Assert(superviewBounds.Width == (SuperView?.Bounds.Width ?? 0)); newDimension = int.Max (furthestRight + thickness.Left + thickness.Right, auto._min?.Anchor (superviewBounds.Width) ?? 0); } else { - int furthestBottom = Subviews.Count == 0 ? 0 : Subviews.Max (v => v.Frame.Y + v.Frame.Height); + var furthestBottom = Subviews.Count == 0 ? 0 : Subviews.Max (v => v.Frame.Y + v.Frame.Height); //Debug.Assert (superviewBounds.Height == (SuperView?.Bounds.Height ?? 0)); newDimension = int.Max (furthestBottom + thickness.Top + thickness.Bottom, auto._min?.Anchor (superviewBounds.Height) ?? 0); } @@ -818,7 +906,7 @@ public partial class View { } int newDimension, newLocation; - int superviewDimension = width ? superviewBounds.Width : superviewBounds.Height; + var superviewDimension = width ? superviewBounds.Width : superviewBounds.Height; // Determine new location switch (pos) { @@ -832,7 +920,7 @@ public partial class View { case Pos.PosCombine combine: int left, right; - (left, newDimension) = GetNewLocationAndDimension (width, superviewBounds, combine._left, dim, autosizeDimension); + (left, newDimension) = GetNewLocationAndDimension (width, superviewBounds, combine._left, dim, autosizeDimension); (right, newDimension) = GetNewLocationAndDimension (width, superviewBounds, combine._right, dim, autosizeDimension); if (combine._add) { newLocation = left + right; @@ -876,35 +964,32 @@ public partial class View { } /// - /// Fired after the View's method has completed. + /// Fired after the View's method has completed. /// /// - /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise changed. + /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise + /// changed. /// public event EventHandler LayoutStarted; /// - /// Raises the event. Called from before any subviews have been laid out. + /// Raises the event. Called from before any subviews have been + /// laid out. /// internal virtual void OnLayoutStarted (LayoutEventArgs args) => LayoutStarted?.Invoke (this, args); /// - /// Fired after the View's method has completed. + /// Fired after the View's method has completed. /// /// - /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise changed. + /// Subscribe to this event to perform tasks when the has been resized or the layout has otherwise + /// changed. /// public event EventHandler LayoutComplete; /// - /// Event called only once when the is being initialized for the first time. - /// Allows configurations and assignments to be performed before the being shown. - /// This derived from to allow notify all the views that are being initialized. - /// - public event EventHandler Initialized; - - /// - /// Raises the event. Called from before all sub-views have been laid out. + /// Raises the event. Called from before all sub-views have + /// been laid out. /// internal virtual void OnLayoutComplete (LayoutEventArgs args) => LayoutComplete?.Invoke (this, args); @@ -921,7 +1006,7 @@ public partial class View { } return; case Pos.PosCombine pc: - CollectPos (pc._left, from, ref nNodes, ref nEdges); + CollectPos (pc._left, from, ref nNodes, ref nEdges); CollectPos (pc._right, from, ref nNodes, ref nEdges); break; } @@ -940,7 +1025,7 @@ public partial class View { } return; case Dim.DimCombine dc: - CollectDim (dc._left, from, ref nNodes, ref nEdges); + CollectDim (dc._left, from, ref nNodes, ref nEdges); CollectDim (dc._right, from, ref nNodes, ref nEdges); break; } @@ -956,7 +1041,7 @@ public partial class View { } CollectPos (v.X, v, ref nNodes, ref nEdges); CollectPos (v.Y, v, ref nNodes, ref nEdges); - CollectDim (v.Width, v, ref nNodes, ref nEdges); + CollectDim (v.Width, v, ref nNodes, ref nEdges); CollectDim (v.Height, v, ref nNodes, ref nEdges); } } @@ -1019,9 +1104,8 @@ public partial class View { } else if (from != superView?.GetTopSuperView (to, from) && !ReferenceEquals (from, to)) { if (ReferenceEquals (from.SuperView, to)) { throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{to}\" references a SubView (\"{from}\")."); - } else { - throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{from}\" linked with \"{to}\" was not found. Did you forget to add it to {superView}?"); } + throw new InvalidOperationException ($"ComputedLayout for \"{superView}\": \"{from}\" linked with \"{to}\" was not found. Did you forget to add it to {superView}?"); } } // return L (a topologically sorted order) @@ -1029,7 +1113,7 @@ public partial class View { } // TopologicalSort /// - /// Overriden by to do nothing, as the does not have frames. + /// Overriden by to do nothing, as the does not have frames. /// internal virtual void LayoutFrames () { @@ -1075,13 +1159,13 @@ public partial class View { /// response to the container view or terminal resizing. /// /// - /// - /// The position and dimensions of the view are indeterminate until the view has been initialized. Therefore, - /// the behavior of this method is indeterminate if is . - /// - /// - /// Raises the event) before it returns. - /// + /// + /// The position and dimensions of the view are indeterminate until the view has been initialized. Therefore, + /// the behavior of this method is indeterminate if is . + /// + /// + /// Raises the event) before it returns. + /// /// public virtual void LayoutSubviews () { @@ -1098,7 +1182,7 @@ public partial class View { LayoutFrames (); var oldBounds = Bounds; - OnLayoutStarted (new LayoutEventArgs () { OldBounds = oldBounds }); + OnLayoutStarted (new LayoutEventArgs { OldBounds = oldBounds }); TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey (); @@ -1133,7 +1217,7 @@ public partial class View { LayoutNeeded = false; - OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds }); + OnLayoutComplete (new LayoutEventArgs { OldBounds = oldBounds }); } void LayoutSubview (View v, Rect contentArea) @@ -1146,42 +1230,13 @@ public partial class View { v.LayoutNeeded = false; } - bool _autoSize; - - /// - /// Gets or sets a flag that determines whether the View will be automatically resized to fit the - /// within - /// - /// The default is . Set to to turn on AutoSize. If then - /// and will be used if can fit; - /// if won't fit the view will be resized as needed. - /// - /// - /// In addition, if is the new values of and - /// must be of the same types of the existing one to avoid breaking the settings. - /// - /// - public virtual bool AutoSize { - get => _autoSize; - set { - bool v = ResizeView (value); - TextFormatter.AutoSize = v; - if (_autoSize != v) { - _autoSize = v; - TextFormatter.NeedsFormat = true; - UpdateTextFormatterText (); - OnResizeNeeded (); - } - } - } - bool ResizeView (bool autoSize) { if (!autoSize) { return false; } - bool boundsChanged = true; + var boundsChanged = true; var newFrameSize = GetAutoSize (); if (IsInitialized && newFrameSize != Frame.Size) { if (ValidatePosDim) { @@ -1202,9 +1257,9 @@ public partial class View { /// whether the Bounds was changed or not bool ResizeBoundsToFit (Size size) { - bool boundsChanged = false; - bool canSizeW = TrySetWidth (size.Width - GetHotKeySpecifierLength (), out int rW); - bool canSizeH = TrySetHeight (size.Height - GetHotKeySpecifierLength (false), out int rH); + var boundsChanged = false; + var canSizeW = TrySetWidth (size.Width - GetHotKeySpecifierLength (), out var rW); + var canSizeH = TrySetHeight (size.Height - GetHotKeySpecifierLength (false), out var rH); if (canSizeW) { boundsChanged = true; _width = rW; @@ -1221,21 +1276,22 @@ public partial class View { } /// - /// Gets the Frame dimensions required to fit within using the text specified by the - /// property and accounting for any characters. + /// Gets the Frame dimensions required to fit within using the text + /// specified by the + /// property and accounting for any characters. /// - /// The of the view required to fit the text. + /// The of the view required to fit the text. public Size GetAutoSize () { - int x = 0; - int y = 0; + var x = 0; + var y = 0; if (IsInitialized) { x = Bounds.X; y = Bounds.Y; } var rect = TextFormatter.CalcRect (x, y, TextFormatter.Text, TextFormatter.Direction); - int newWidth = rect.Size.Width - GetHotKeySpecifierLength () + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal; - int newHeight = rect.Size.Height - GetHotKeySpecifierLength (false) + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical; + var newWidth = rect.Size.Width - GetHotKeySpecifierLength () + Margin.Thickness.Horizontal + Border.Thickness.Horizontal + Padding.Thickness.Horizontal; + var newHeight = rect.Size.Height - GetHotKeySpecifierLength (false) + Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical; return new Size (newWidth, newHeight); } @@ -1244,36 +1300,40 @@ public partial class View { var rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection); autoSize = new Size (rect.Size.Width - GetHotKeySpecifierLength (), rect.Size.Height - GetHotKeySpecifierLength (false)); - return !(ValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)) - || _frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength () - || _frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false)); + return !(ValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)) || + _frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength () || + _frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false)); } bool IsValidAutoSizeWidth (Dim width) { var rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection); - int dimValue = width.Anchor (0); - return !(ValidatePosDim && !(width is Dim.DimAbsolute) || dimValue != rect.Size.Width - - GetHotKeySpecifierLength ()); + var dimValue = width.Anchor (0); + return !(ValidatePosDim && !(width is Dim.DimAbsolute) || dimValue != rect.Size.Width - GetHotKeySpecifierLength ()); } bool IsValidAutoSizeHeight (Dim height) { var rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection); - int dimValue = height.Anchor (0); - return !(ValidatePosDim && !(height is Dim.DimAbsolute) || dimValue != rect.Size.Height - - GetHotKeySpecifierLength (false)); + var dimValue = height.Anchor (0); + return !(ValidatePosDim && !(height is Dim.DimAbsolute) || dimValue != rect.Size.Height - GetHotKeySpecifierLength (false)); } /// - /// Determines if the View's can be set to a new value. + /// Determines if the View's can be set to a new value. /// /// - /// Contains the width that would result if were set to "/> - /// if the View's can be changed to the specified value. False otherwise. + /// + /// Contains the width that would result if were set to + /// "/> + /// + /// + /// if the View's can be changed to the specified value. False + /// otherwise. + /// internal bool TrySetWidth (int desiredWidth, out int resultWidth) { - int w = desiredWidth; + var w = desiredWidth; bool canSetWidth; switch (Width) { case Dim.DimCombine _: @@ -1285,7 +1345,7 @@ public partial class View { break; case Dim.DimFactor factor: // Tries to get the SuperView Width otherwise the view Width. - int sw = SuperView != null ? SuperView.Frame.Width : w; + var sw = SuperView != null ? SuperView.Frame.Width : w; if (factor.IsFromRemaining ()) { sw -= Frame.X; } @@ -1302,14 +1362,20 @@ public partial class View { } /// - /// Determines if the View's can be set to a new value. + /// Determines if the View's can be set to a new value. /// /// - /// Contains the width that would result if were set to "/> - /// if the View's can be changed to the specified value. False otherwise. + /// + /// Contains the width that would result if were set to + /// "/> + /// + /// + /// if the View's can be changed to the specified value. False + /// otherwise. + /// internal bool TrySetHeight (int desiredHeight, out int resultHeight) { - int h = desiredHeight; + var h = desiredHeight; bool canSetHeight; switch (Height) { case Dim.DimCombine _: @@ -1321,7 +1387,7 @@ public partial class View { break; case Dim.DimFactor factor: // Tries to get the SuperView height otherwise the view height. - int sh = SuperView != null ? SuperView.Frame.Height : h; + var sh = SuperView != null ? SuperView.Frame.Height : h; if (factor.IsFromRemaining ()) { sh -= Frame.Y; } @@ -1338,7 +1404,7 @@ public partial class View { } /// - /// Finds which view that belong to the superview at the provided location. + /// Finds which view that belong to the superview at the provided location. /// /// The superview where to look for. /// The column location in the superview. @@ -1346,8 +1412,8 @@ public partial class View { /// The found view screen relative column location. /// The found view screen relative row location. /// - /// The view that was found at the and coordinates. - /// if no view was found. + /// The view that was found at the and coordinates. + /// if no view was found. /// public static View FindDeepestView (View start, int x, int y, out int resx, out int resy) { @@ -1358,12 +1424,12 @@ public partial class View { var startFrame = start.Frame; if (start.InternalSubviews != null) { - int count = start.InternalSubviews.Count; + var count = start.InternalSubviews.Count; if (count > 0) { var boundsOffset = start.GetBoundsOffset (); - int rx = x - (startFrame.X + boundsOffset.X); - int ry = y - (startFrame.Y + boundsOffset.Y); - for (int i = count - 1; i >= 0; i--) { + var rx = x - (startFrame.X + boundsOffset.X); + var ry = y - (startFrame.Y + boundsOffset.Y); + for (var i = count - 1; i >= 0; i--) { var v = start.InternalSubviews [i]; if (v.Visible && v.Frame.Contains (rx, ry)) { var deep = FindDeepestView (v, rx, ry, out resx, out resy); diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj index a717e41bc..e767c55aa 100644 --- a/UICatalog/UICatalog.csproj +++ b/UICatalog/UICatalog.csproj @@ -29,7 +29,7 @@ - + diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index 48f79fce3..6df369db8 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -25,7 +25,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive