Pārlūkot izejas kodu

Merge branch 'v2_develop' of tig:gui-cs/Terminal.Gui into v2_develop

Tig 1 gadu atpakaļ
vecāks
revīzija
65caf28e8a
100 mainītis faili ar 2503 papildinājumiem un 3074 dzēšanām
  1. 2 1
      .github/workflows/publish.yml
  2. 23 0
      Analyzers/Directory.Build.props
  3. 0 1
      Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Terminal.Gui.Analyzers.Internal.Debugging.csproj
  4. 1 4
      Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj
  5. 1 0
      Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/AssemblyExtendedEnumTypeAttribute.cs
  6. 0 22
      Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/CombinationGroupingAttribute.cs
  7. 0 110
      Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/GenerateEnumMemberCombinationsAttribute.cs
  8. 0 33
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/CompilerFeatureRequiredAttribute.cs
  9. 0 18
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IsExternalInit.cs
  10. 0 208
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/NullableAttributes.cs
  11. 0 12
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/RequiredMemberAttribute.cs
  12. 0 12
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/SetsRequiredMembersAttribute.cs
  13. 0 14
      Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/SkipLocalsInitAttribute.cs
  14. 13 11
      Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs
  15. 2 2
      Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/CodeWriter.cs
  16. 12 26
      Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsGenerationInfo.cs
  17. 4 4
      Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGenerator.cs
  18. 0 130
      Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumMemberCombinationsGenerator.cs
  19. 15 50
      Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj
  20. 0 0
      Directory.Build.props
  21. 5 0
      Directory.Build.targets
  22. 1 1
      ReactiveExample/LoginView.cs
  23. 1 1
      ReactiveExample/ReactiveExample.csproj
  24. 0 0
      Scripts/Terminal.Gui.PowerShell.Analyzers.psd1
  25. 10 19
      Scripts/Terminal.Gui.PowerShell.Analyzers.psm1
  26. 22 14
      Scripts/Terminal.Gui.PowerShell.Core.psm1
  27. 135 38
      Terminal.Gui/Application.cs
  28. 13 3
      Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
  29. 4 7
      Terminal.Gui/ConsoleDrivers/NetDriver.cs
  30. 29 24
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  31. 0 1
      Terminal.Gui/Directory.Build.props
  32. 333 0
      Terminal.Gui/Drawing/Justification.cs
  33. 13 14
      Terminal.Gui/Drawing/Thickness.cs
  34. 10 13
      Terminal.Gui/Input/Mouse.cs
  35. 12 4
      Terminal.Gui/Terminal.Gui.csproj
  36. 3 3
      Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs
  37. 295 152
      Terminal.Gui/Text/TextFormatter.cs
  38. 9 7
      Terminal.Gui/View/Adornment/Adornment.cs
  39. 5 5
      Terminal.Gui/View/Adornment/Border.cs
  40. 323 47
      Terminal.Gui/View/Layout/PosDim.cs
  41. 2 2
      Terminal.Gui/View/Layout/SizeChangedEventArgs.cs
  42. 193 354
      Terminal.Gui/View/Layout/ViewLayout.cs
  43. 17 11
      Terminal.Gui/View/View.cs
  44. 8 1
      Terminal.Gui/View/ViewAdornments.cs
  45. 70 31
      Terminal.Gui/View/ViewContent.cs
  46. 3 0
      Terminal.Gui/View/ViewDiagnostics.cs
  47. 7 17
      Terminal.Gui/View/ViewDrawing.cs
  48. 1 1
      Terminal.Gui/View/ViewKeyboard.cs
  49. 2 2
      Terminal.Gui/View/ViewMouse.cs
  50. 65 70
      Terminal.Gui/View/ViewSubViews.cs
  51. 52 241
      Terminal.Gui/View/ViewText.cs
  52. 4 14
      Terminal.Gui/Views/Button.cs
  53. 3 15
      Terminal.Gui/Views/CheckBox.cs
  54. 1 8
      Terminal.Gui/Views/ColorPicker.cs
  55. 7 6
      Terminal.Gui/Views/ComboBox.cs
  56. 1 2
      Terminal.Gui/Views/DateField.cs
  57. 0 2
      Terminal.Gui/Views/DatePicker.cs
  58. 2 4
      Terminal.Gui/Views/Dialog.cs
  59. 3 3
      Terminal.Gui/Views/FileDialog.cs
  60. 0 11
      Terminal.Gui/Views/FrameView.cs
  61. 0 9
      Terminal.Gui/Views/GraphView/GraphView.cs
  62. 15 37
      Terminal.Gui/Views/HexView.cs
  63. 3 9
      Terminal.Gui/Views/Label.cs
  64. 13 16
      Terminal.Gui/Views/ListView.cs
  65. 28 35
      Terminal.Gui/Views/Menu/Menu.cs
  66. 41 24
      Terminal.Gui/Views/Menu/MenuBar.cs
  67. 2 3
      Terminal.Gui/Views/MessageBox.cs
  68. 0 8
      Terminal.Gui/Views/ProgressBar.cs
  69. 13 13
      Terminal.Gui/Views/RadioGroup.cs
  70. 2 9
      Terminal.Gui/Views/ScrollBarView.cs
  71. 30 38
      Terminal.Gui/Views/ScrollView.cs
  72. 103 206
      Terminal.Gui/Views/Slider.cs
  73. 1 9
      Terminal.Gui/Views/StatusBar.cs
  74. 0 7
      Terminal.Gui/Views/TabView.cs
  75. 1 1
      Terminal.Gui/Views/TableView/CheckBoxTableSourceWrapper.cs
  76. 41 11
      Terminal.Gui/Views/TableView/TableView.cs
  77. 1 1
      Terminal.Gui/Views/TableView/TreeTableSource.cs
  78. 10 101
      Terminal.Gui/Views/TextField.cs
  79. 4 28
      Terminal.Gui/Views/TextValidateField.cs
  80. 181 198
      Terminal.Gui/Views/TextView.cs
  81. 11 17
      Terminal.Gui/Views/TileView.cs
  82. 1 1
      Terminal.Gui/Views/TimeField.cs
  83. 14 15
      Terminal.Gui/Views/Toplevel.cs
  84. 24 67
      Terminal.Gui/Views/TreeView/TreeView.cs
  85. 6 6
      Terminal.Gui/Views/Wizard/Wizard.cs
  86. 25 52
      Terminal.sln
  87. 1 0
      Terminal.sln.DotSettings
  88. 2 6
      UICatalog/Scenarios/ASCIICustomButton.cs
  89. 26 27
      UICatalog/Scenarios/Adornments.cs
  90. 43 38
      UICatalog/Scenarios/AllViewsTester.cs
  91. 0 114
      UICatalog/Scenarios/AutoSizeAndDirectionText.cs
  92. 0 2
      UICatalog/Scenarios/BasicColors.cs
  93. 17 30
      UICatalog/Scenarios/Buttons.cs
  94. 20 40
      UICatalog/Scenarios/CharacterMap.cs
  95. 0 2
      UICatalog/Scenarios/CollectionNavigatorTester.cs
  96. 1 2
      UICatalog/Scenarios/ComboBoxIteration.cs
  97. 0 12
      UICatalog/Scenarios/ComputedLayout.cs
  98. 20 6
      UICatalog/Scenarios/ContentScrolling.cs
  99. 2 2
      UICatalog/Scenarios/ContextMenus.cs
  100. 64 66
      UICatalog/Scenarios/Dialogs.cs

+ 2 - 1
.github/workflows/publish.yml

@@ -43,7 +43,8 @@ jobs:
     - name: Build Release
       run: |
         dotnet-gitversion /updateprojectfiles
-        dotnet build --no-restore -c Release
+        dotnet build ./Analyzers/Terminal.Gui.Analyzers.Internal --no-incremental --nologo --force --configuration Release
+        dotnet build --no-incremental --nologo --force --configuration Release
 
     - name: Pack
       run: dotnet pack -c Release --include-symbols -p:Version='${{ steps.gitversion.outputs.SemVer }}' 

+ 23 - 0
Analyzers/Directory.Build.props

@@ -0,0 +1,23 @@
+<Project>
+  <PropertyGroup>
+    <Nullable>enable</Nullable>
+    <AnalysisLevel>latest-recommended</AnalysisLevel>
+    <WarningLevel>7</WarningLevel>
+    <CharacterSet>UTF-8</CharacterSet>
+    <Deterministic>true</Deterministic>
+    <UTF8OutPut>true</UTF8OutPut>
+    <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
+    <NoLogo>True</NoLogo>
+    <DefineTrace>True</DefineTrace>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
+    <PackageReference Include="JetBrains.ExternalAnnotations" Version="10.2.147" />
+  </ItemGroup>
+  <ItemGroup>
+      <Using Include="System.Buffers" />
+      <Using Include="System.Collections.Specialized" />
+      <Using Include="System.Numerics" />
+      <Using Include="System.Runtime.CompilerServices" />
+  </ItemGroup>
+</Project>

+ 0 - 1
Analyzers/Terminal.Gui.Analyzers.Internal.Debugging/Terminal.Gui.Analyzers.Internal.Debugging.csproj

@@ -4,7 +4,6 @@
     <OutputType>Exe</OutputType>
     <TargetFramework>net8.0</TargetFramework>
     <ImplicitUsings>enable</ImplicitUsings>
-    <Nullable>enable</Nullable>
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.CodeAnalysis" Version="4.9.2" PrivateAssets="all" />

+ 1 - 4
Analyzers/Terminal.Gui.Analyzers.Internal.Tests/Terminal.Gui.Analyzers.Internal.Tests.csproj

@@ -4,15 +4,12 @@
     <TargetFramework>net8.0</TargetFramework>
     <ImplicitUsings>enable</ImplicitUsings>
     <LangVersion>12</LangVersion>
-    <Nullable>enable</Nullable>
     <IsPackable>false</IsPackable>
     <IsTestProject>true</IsTestProject>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-    <DefineTrace>True</DefineTrace>
     <DebugType>portable</DebugType>
     <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
     <ImplicitUsings>enable</ImplicitUsings>
-    <NoLogo>True</NoLogo>
     <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
   </PropertyGroup>
 
@@ -25,7 +22,7 @@
     <PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.9.2" PrivateAssets="all" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
     <PackageReference Include="NUnit" Version="4.1.0" />
-    <PackageReference Include="NUnit.Analyzers" Version="4.1.0">
+    <PackageReference Include="NUnit.Analyzers" Version="4.2.0">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>

+ 1 - 0
Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/AssemblyExtendedEnumTypeAttribute.cs

@@ -1,4 +1,5 @@
 // ReSharper disable ClassNeverInstantiated.Global
+// ReSharper disable once RedundantNullableDirective
 #nullable enable
 
 namespace Terminal.Gui.Analyzers.Internal.Attributes;

+ 0 - 22
Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/CombinationGroupingAttribute.cs

@@ -1,22 +0,0 @@
-using System;
-using JetBrains.Annotations;
-
-namespace Terminal.Gui.Analyzers.Internal.Attributes;
-
-/// <summary>
-///     Designates an enum member for inclusion in generation of bitwise combinations with other members decorated with
-///     this attribute which have the same <see cref="GroupTag"/> value.<br/>
-/// </summary>
-/// <remarks>
-///     This attribute is only considered for members of enum types which have the
-///     <see cref="GenerateEnumExtensionMethodsAttribute"/>.
-/// </remarks>
-[AttributeUsage (AttributeTargets.Field)]
-[UsedImplicitly]
-internal sealed class CombinationGroupingAttribute : Attribute
-{
-    /// <summary>
-    ///     Name of a group this member participates in, for FastHasFlags.
-    /// </summary>
-    public string GroupTag { get; set; }
-}

+ 0 - 110
Analyzers/Terminal.Gui.Analyzers.Internal/Attributes/GenerateEnumMemberCombinationsAttribute.cs

@@ -1,110 +0,0 @@
-// ReSharper disable RedundantUsingDirective
-
-using System;
-using JetBrains.Annotations;
-using Terminal.Gui.Analyzers.Internal.Compatibility;
-
-namespace Terminal.Gui.Analyzers.Internal.Attributes;
-
-/// <summary>
-///     Designates an enum member for inclusion in generation of bitwise combinations with other members decorated with
-///     this attribute which have the same <see cref="GroupTag"/> value.<br/>
-/// </summary>
-/// <remarks>
-///     <para>
-///         This attribute is only considered for enum types with the <see cref="GenerateEnumExtensionMethodsAttribute"/>.
-///     </para>
-/// </remarks>
-[AttributeUsage (AttributeTargets.Enum)]
-[UsedImplicitly]
-public sealed class GenerateEnumMemberCombinationsAttribute : System.Attribute
-{
-    private const byte MaximumPopCountLimit = 14;
-    private uint _mask;
-    private uint _maskPopCount;
-    private byte _popCountLimit = 8;
-    /// <inheritdoc cref="CombinationGroupingAttribute.GroupTag" />
-    public string GroupTag { get; set; }
-
-    /// <summary>
-    /// The mask for the group defined in <see cref="GroupTag"/>
-    /// </summary>
-    public uint Mask
-    {
-        get => _mask;
-        set
-        {
-#if NET8_0_OR_GREATER
-            _maskPopCount = uint.PopCount (value);
-#else
-            _maskPopCount = value.GetPopCount ();
-#endif
-            PopCountLimitExceeded = _maskPopCount > PopCountLimit;
-            MaximumPopCountLimitExceeded = _maskPopCount > MaximumPopCountLimit;
-
-            if (PopCountLimitExceeded || MaximumPopCountLimitExceeded)
-            {
-                return;
-            }
-
-            _mask = value;
-        }
-    }
-
-    /// <summary>
-    ///     The maximum number of bits allowed to be set to 1 in <see cref="Mask"/>.
-    /// </summary>
-    /// <remarks>
-    ///     <para>
-    ///         Default: 8 (256 possible combinations)
-    ///     </para>
-    ///     <para>
-    ///         Increasing this value is not recommended!<br/>
-    ///         Decreasing this value is pointless unless you want to limit maximum possible generated combinations even
-    ///         further.
-    ///     </para>
-    ///     <para>
-    ///         If the result of <see cref="NumericExtensions.GetPopCount(uint)"/>(<see cref="Mask"/>) exceeds 2 ^
-    ///         <see cref="PopCountLimit"/>, no
-    ///         combinations will be generated for the members which otherwise would have been included by <see cref="Mask"/>.
-    ///         Values exceeding the actual population count of <see cref="Mask"/> have no effect.
-    ///     </para>
-    ///     <para>
-    ///         This option is set to a sane default of 8, but also has a hard-coded limit of 14 (16384 combinations), as a
-    ///         protection against generation of extremely large files.
-    ///     </para>
-    ///     <para>
-    ///         CAUTION: The maximum number of possible combinations possible is equal to 1 &lt;&lt;
-    ///         <see cref="NumericExtensions.GetPopCount(uint)"/>(<see cref="Mask"/>).
-    ///         See <see cref="MaximumPopCountLimit"/> for hard-coded limit,
-    ///     </para>
-    /// </remarks>
-    public byte PopCountLimit
-    {
-        get => _popCountLimit;
-        set
-        {
-#if NET8_0_OR_GREATER
-            _maskPopCount = uint.PopCount (_mask);
-#else
-            _maskPopCount = _mask.GetPopCount ();
-#endif
-
-            PopCountLimitExceeded = _maskPopCount > value;
-            MaximumPopCountLimitExceeded = _maskPopCount > MaximumPopCountLimit;
-
-            if (PopCountLimitExceeded || MaximumPopCountLimitExceeded)
-            {
-                return;
-            }
-
-            _mask = value;
-            _popCountLimit = value;
-        }
-    }
-
-    [UsedImplicitly]
-    internal bool MaximumPopCountLimitExceeded { get; private set; }
-    [UsedImplicitly]
-    internal bool PopCountLimitExceeded { get; private set; }
-}

+ 0 - 33
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/CompilerFeatureRequiredAttribute.cs

@@ -1,33 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-// ReSharper disable once CheckNamespace
-namespace System.Runtime.CompilerServices;
-
-/// <summary>
-///     Indicates that compiler support for a particular feature is required for the location where this attribute is
-///     applied.
-/// </summary>
-[AttributeUsage (AttributeTargets.All, AllowMultiple = true, Inherited = false)]
-internal sealed class CompilerFeatureRequiredAttribute(string featureName) : Attribute
-{
-    /// <summary>
-    ///     The <see cref="FeatureName"/> used for the ref structs C# feature.
-    /// </summary>
-    public const string RefStructs = nameof (RefStructs);
-
-    /// <summary>
-    ///     The <see cref="FeatureName"/> used for the required members C# feature.
-    /// </summary>
-    public const string RequiredMembers = nameof (RequiredMembers);
-
-    /// <summary>
-    ///     The name of the compiler feature.
-    /// </summary>
-    public string FeatureName { get; } = featureName;
-    /// <summary>
-    ///     If true, the compiler can choose to allow access to the location where this attribute is applied if it does not
-    ///     understand <see cref="FeatureName"/>.
-    /// </summary>
-    public bool IsOptional { get; init; }
-}

+ 0 - 18
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/IsExternalInit.cs

@@ -1,18 +0,0 @@
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-
-// ReSharper disable CheckNamespace
-namespace System.Runtime.CompilerServices;
-
-/// <summary>
-///     Reserved to be used by the compiler for tracking metadata.
-///     This class should not be used by developers in source code.
-/// </summary>
-/// <remarks>
-///     Copied from .net source code, for support of init property accessors in netstandard2.0.
-/// </remarks>
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-[EditorBrowsable (EditorBrowsableState.Never)]
-public static class IsExternalInit;

+ 0 - 208
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/NullableAttributes.cs

@@ -1,208 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-//
-// This file is further modified from the original, for this project,
-// to comply with project style.
-// No changes are made which affect compatibility with the same types from
-// APIs later than netstandard2.0, nor will this file be included in compilations
-// targeted at later APIs.
-//
-// Originally rom https://github.com/dotnet/runtime/blob/ef72b95937703e485fdbbb75f3251fedfd1a0ef9/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
-
-// ReSharper disable CheckNamespace
-
-// ReSharper disable UnusedAutoPropertyAccessor.Global
-// ReSharper disable UnusedType.Global
-
-namespace System.Diagnostics.CodeAnalysis;
-
-/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class AllowNullAttribute : Attribute;
-
-/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class DisallowNullAttribute : Attribute;
-
-/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class MaybeNullAttribute : Attribute;
-
-/// <summary>
-///     Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input
-///     argument was not null when the call returns.
-/// </summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class NotNullAttribute : Attribute;
-
-/// <summary>
-///     Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding
-///     type disallows it.
-/// </summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Parameter)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class MaybeNullWhenAttribute : Attribute
-{
-    /// <summary>Initializes the attribute with the specified return value condition.</summary>
-    /// <param name="returnValue">
-    ///     The return value condition. If the method returns this value, the associated parameter may be null.
-    /// </param>
-#pragma warning disable IDE0290 // Use primary constructor
-    public MaybeNullWhenAttribute (bool returnValue) { ReturnValue = returnValue; }
-#pragma warning restore IDE0290 // Use primary constructor
-
-    /// <summary>Gets the return value condition.</summary>
-    public bool ReturnValue { get; }
-}
-
-/// <summary>
-///     Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the
-///     corresponding type allows it.
-/// </summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Parameter)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class NotNullWhenAttribute : Attribute
-{
-    /// <summary>Initializes the attribute with the specified return value condition.</summary>
-    /// <param name="returnValue">
-    ///     The return value condition. If the method returns this value, the associated parameter will not be null.
-    /// </param>
-#pragma warning disable IDE0290 // Use primary constructor
-    public NotNullWhenAttribute (bool returnValue) { ReturnValue = returnValue; }
-#pragma warning restore IDE0290 // Use primary constructor
-
-    /// <summary>Gets the return value condition.</summary>
-    public bool ReturnValue { get; }
-}
-
-/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class NotNullIfNotNullAttribute : Attribute
-{
-    /// <summary>Initializes the attribute with the associated parameter name.</summary>
-    /// <param name="parameterName">
-    ///     The associated parameter name.  The output will be non-null if the argument to the parameter specified is non-null.
-    /// </param>
-#pragma warning disable IDE0290 // Use primary constructor
-    public NotNullIfNotNullAttribute (string parameterName) { ParameterName = parameterName; }
-#pragma warning restore IDE0290 // Use primary constructor
-
-    /// <summary>Gets the associated parameter name.</summary>
-    public string ParameterName { get; }
-}
-
-/// <summary>Applied to a method that will never return under any circumstance.</summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Method, Inherited = false)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class DoesNotReturnAttribute : Attribute;
-
-/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Parameter)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class DoesNotReturnIfAttribute : Attribute
-{
-    /// <summary>Initializes the attribute with the specified parameter value.</summary>
-    /// <param name="parameterValue">
-    ///     The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument
-    ///     to
-    ///     the associated parameter matches this value.
-    /// </param>
-#pragma warning disable IDE0290 // Use primary constructor
-    public DoesNotReturnIfAttribute (bool parameterValue) { ParameterValue = parameterValue; }
-#pragma warning restore IDE0290 // Use primary constructor
-
-    /// <summary>Gets the condition parameter value.</summary>
-    public bool ParameterValue { get; }
-}
-
-/// <summary>
-///     Specifies that the method or property will ensure that the listed field and property members have not-null
-///     values.
-/// </summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class MemberNotNullAttribute : Attribute
-{
-    /// <summary>Initializes the attribute with a field or property member.</summary>
-    /// <param name="member">
-    ///     The field or property member that is promised to be not-null.
-    /// </param>
-    public MemberNotNullAttribute (string member) { Members = [member]; }
-
-    /// <summary>Initializes the attribute with the list of field and property members.</summary>
-    /// <param name="members">
-    ///     The list of field and property members that are promised to be not-null.
-    /// </param>
-    public MemberNotNullAttribute (params string [] members) { Members = members; }
-
-    /// <summary>Gets field or property member names.</summary>
-    public string [] Members { get; }
-}
-
-/// <summary>
-///     Specifies that the method or property will ensure that the listed field and property members have not-null values
-///     when returning with the specified return value condition.
-/// </summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
-[ExcludeFromCodeCoverage]
-[DebuggerNonUserCode]
-internal sealed class MemberNotNullWhenAttribute : Attribute
-{
-    /// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
-    /// <param name="returnValue">
-    ///     The return value condition. If the method returns this value, the associated parameter will not be null.
-    /// </param>
-    /// <param name="member">
-    ///     The field or property member that is promised to be not-null.
-    /// </param>
-    public MemberNotNullWhenAttribute (bool returnValue, string member)
-    {
-        ReturnValue = returnValue;
-        Members = [member];
-    }
-
-    /// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
-    /// <param name="returnValue">
-    ///     The return value condition. If the method returns this value, the associated parameter will not be null.
-    /// </param>
-    /// <param name="members">
-    ///     The list of field and property members that are promised to be not-null.
-    /// </param>
-    public MemberNotNullWhenAttribute (bool returnValue, params string [] members)
-    {
-        ReturnValue = returnValue;
-        Members = members;
-    }
-
-    /// <summary>Gets field or property member names.</summary>
-    public string [] Members { get; }
-
-    /// <summary>Gets the return value condition.</summary>
-    public bool ReturnValue { get; }
-}

+ 0 - 12
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/RequiredMemberAttribute.cs

@@ -1,12 +0,0 @@
-// ReSharper disable CheckNamespace
-// ReSharper disable ConditionalAnnotation
-
-using JetBrains.Annotations;
-
-namespace System.Runtime.CompilerServices;
-
-/// <summary>Polyfill to enable netstandard2.0 assembly to use the required keyword.</summary>
-/// <remarks>Excluded from output assembly via file specified in ApiCompatExcludeAttributesFile element in the project file.</remarks>
-[AttributeUsage (AttributeTargets.Property)]
-[UsedImplicitly]
-public sealed class RequiredMemberAttribute : Attribute;

+ 0 - 12
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/SetsRequiredMembersAttribute.cs

@@ -1,12 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-// ReSharper disable once CheckNamespace
-namespace System.Diagnostics.CodeAnalysis;
-
-/// <summary>
-///     Specifies that this constructor sets all required members for the current type, and callers
-///     do not need to set any required members themselves.
-/// </summary>
-[AttributeUsage (AttributeTargets.Constructor)]
-public sealed class SetsRequiredMembersAttribute : Attribute;

+ 0 - 14
Analyzers/Terminal.Gui.Analyzers.Internal/Compatibility/SkipLocalsInitAttribute.cs

@@ -1,14 +0,0 @@
-namespace System.Runtime.CompilerServices;
-
-[AttributeUsage (
-                    AttributeTargets.Class
-                    | AttributeTargets.Constructor
-                    | AttributeTargets.Event
-                    | AttributeTargets.Interface
-                    | AttributeTargets.Method
-                    | AttributeTargets.Module
-                    | AttributeTargets.Property
-                    | AttributeTargets.Struct,
-                    Inherited = false)]
-
-internal sealed class SkipLocalsInitAttribute : Attribute;

+ 13 - 11
Analyzers/Terminal.Gui.Analyzers.Internal/Constants/Strings.cs

@@ -46,7 +46,7 @@ internal static class Strings
             /// <inheritdoc cref="ExcludeFromCodeCoverageAttribute"/>
             internal const string ExcludeFromCodeCoverage = $"{Namespaces.System_Diagnostics_CodeAnalysis}.{nameof (ExcludeFromCodeCoverageAttribute)}";
 
-            internal const string Flags = $"{Namespaces.SystemNS}.{nameof (FlagsAttribute)}";
+            internal const string Flags = $"{Namespaces.SystemNs}.{nameof (FlagsAttribute)}";
 
             internal const string GeneratedCode = $"{Namespaces.System_CodeDom_Compiler}.{nameof (GeneratedCodeAttribute)}";
 
@@ -83,22 +83,24 @@ internal static class Strings
         /// <summary>Names of dotnet namespaces.</summary>
         internal static class Namespaces
         {
-            internal const string SystemNS = nameof (System);
-            internal const string System_CodeDom = $"{SystemNS}.{nameof (System.CodeDom)}";
+            internal const string SystemNs = nameof (System);
+            // ReSharper disable InconsistentNaming
+            internal const string System_CodeDom = $"{SystemNs}.{nameof (System.CodeDom)}";
             internal const string System_CodeDom_Compiler = $"{System_CodeDom}.{nameof (System.CodeDom.Compiler)}";
-            internal const string System_ComponentModel = $"{SystemNS}.{nameof (System.ComponentModel)}";
-            internal const string System_Diagnostics = $"{SystemNS}.{nameof (System.Diagnostics)}";
+            internal const string System_ComponentModel = $"{SystemNs}.{nameof (System.ComponentModel)}";
+            internal const string System_Diagnostics = $"{SystemNs}.{nameof (System.Diagnostics)}";
             internal const string System_Diagnostics_CodeAnalysis = $"{System_Diagnostics}.{nameof (System.Diagnostics.CodeAnalysis)}";
-            internal const string System_Numerics = $"{SystemNS}.{nameof (System.Numerics)}";
-            internal const string System_Runtime = $"{SystemNS}.{nameof (System.Runtime)}";
+            internal const string System_Numerics = $"{SystemNs}.{nameof (System.Numerics)}";
+            internal const string System_Runtime = $"{SystemNs}.{nameof (System.Runtime)}";
             internal const string System_Runtime_CompilerServices = $"{System_Runtime}.{nameof (System.Runtime.CompilerServices)}";
+            // ReSharper restore InconsistentNaming
         }
 
         internal static class Types
         {
-            internal const string Attribute = $"{Namespaces.SystemNS}.{nameof (System.Attribute)}";
-            internal const string AttributeTargets = $"{Namespaces.SystemNS}.{nameof (System.AttributeTargets)}";
-            internal const string AttributeUsageAttribute = $"{Namespaces.SystemNS}.{nameof (System.AttributeUsageAttribute)}";
+            internal const string Attribute = $"{Namespaces.SystemNs}.{nameof (System.Attribute)}";
+            internal const string AttributeTargets = $"{Namespaces.SystemNs}.{nameof (System.AttributeTargets)}";
+            internal const string AttributeUsageAttribute = $"{Namespaces.SystemNs}.{nameof (System.AttributeUsageAttribute)}";
 
             internal const string MethodImplOptions =
                 $"{Namespaces.System_Runtime_CompilerServices}.{nameof (System.Runtime.CompilerServices.MethodImplOptions)}";
@@ -131,7 +133,7 @@ internal static class Strings
 
         /// <summary>Using directives for common namespaces in generated code.</summary>
         internal const string DotnetNamespaceUsingDirectives = $"""
-                                                                using {DotnetNames.Namespaces.SystemNS};
+                                                                using {DotnetNames.Namespaces.SystemNs};
                                                                 using {DotnetNames.Namespaces.System_CodeDom};
                                                                 using {DotnetNames.Namespaces.System_CodeDom_Compiler};
                                                                 using {DotnetNames.Namespaces.System_ComponentModel};

+ 2 - 2
Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/CodeWriter.cs

@@ -147,14 +147,14 @@ internal sealed class CodeWriter (in EnumExtensionMethodsGenerationInfo metadata
         switch (Metadata.EnumBackingTypeCode)
         {
             case TypeCode.Int32:
-                foreach (int definedValue in Metadata.IntMembers)
+                foreach (int definedValue in Metadata._intMembers)
                 {
                     w.WriteLine ($"{definedValue:D} => true,");
                 }
 
                 break;
             case TypeCode.UInt32:
-                foreach (uint definedValue in Metadata.UIntMembers)
+                foreach (uint definedValue in Metadata._uIntMembers)
                 {
                     w.WriteLine ($"{definedValue:D} => true,");
                 }

+ 12 - 26
Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsGenerationInfo.cs

@@ -24,15 +24,13 @@ namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
 internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetadata<EnumExtensionMethodsGenerationInfo>,
                                                             IEqualityOperators<EnumExtensionMethodsGenerationInfo, EnumExtensionMethodsGenerationInfo, bool>
 {
-    private const int ExplicitFastHasFlagsMask = 0b1000;
-    private const int ExplicitFastIsDefinedMask = 0b1_0000;
-    private const int ExplicitIncludeInterfaceMask = 0b10_0000;
-    private const int ExplicitNameMask = 0b10;
-    private const int ExplicitNamespaceMask = 0b1;
-    private const int ExplicitPartialMask = 0b100;
+    private const int ExplicitFastHasFlagsMask  = 0b_0100;
+    private const int ExplicitFastIsDefinedMask = 0b_1000;
+    private const int ExplicitNameMask          = 0b_0010;
+    private const int ExplicitNamespaceMask     = 0b_0001;
     private const string GeneratorAttributeFullyQualifiedName = $"{GeneratorAttributeNamespace}.{GeneratorAttributeName}";
     private const string GeneratorAttributeName = nameof (GenerateEnumExtensionMethodsAttribute);
-    private const string GeneratorAttributeNamespace = Constants.Strings.AnalyzersAttributesNamespace;
+    private const string GeneratorAttributeNamespace = Strings.AnalyzersAttributesNamespace;
 
     /// <summary>
     ///     Type containing the information necessary to generate code according to the declared attribute values,
@@ -90,7 +88,7 @@ internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetada
     }
 
     [AccessedThroughProperty (nameof (EnumBackingTypeCode))]
-    private TypeCode _enumBackingTypeCode;
+    private readonly TypeCode _enumBackingTypeCode;
 
     [AccessedThroughProperty (nameof (GeneratedTypeName))]
     private string? _generatedTypeName;
@@ -159,7 +157,7 @@ internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetada
     public bool IsStatic => true;
 
     /// <inheritdoc/>
-    public bool IncludeInterface { get; private set; }
+    public bool IncludeInterface => false;
 
     public string GeneratedTypeFullName => $"{GeneratedTypeNamespace}.{GeneratedTypeName}";
 
@@ -189,7 +187,7 @@ internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetada
     public TypeCode EnumBackingTypeCode
     {
         get => _enumBackingTypeCode;
-        set
+        init
         {
             if (value is not TypeCode.Int32 and not TypeCode.UInt32)
             {
@@ -208,8 +206,8 @@ internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetada
     /// <summary>Whether a switch-based IsDefined replacement will be generated (Default: true)</summary>
     public bool GenerateFastIsDefined { [UsedImplicitly]get; set; } = true;
 
-    internal ImmutableHashSet<int>? IntMembers;
-    internal ImmutableHashSet<uint>? UIntMembers;
+    internal ImmutableHashSet<int>? _intMembers;
+    internal ImmutableHashSet<uint>? _uIntMembers;
 
     /// <summary>
     ///     Fully-qualified name of the extension class
@@ -309,11 +307,11 @@ internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetada
     {
         ImmutableArray<ISymbol> enumMembers = enumSymbol.GetMembers ();
         IEnumerable<IFieldSymbol> fieldSymbols = enumMembers.OfType<IFieldSymbol> ();
-        IntMembers = fieldSymbols.Select (static m => m.HasConstantValue ? (int)m.ConstantValue : 0).ToImmutableHashSet ();
+        _intMembers = fieldSymbols.Select (static m => m.HasConstantValue ? (int)m.ConstantValue : 0).ToImmutableHashSet ();
     }
     private void PopulateUIntMembersHashSet (INamedTypeSymbol enumSymbol)
     {
-        UIntMembers = enumSymbol.GetMembers ().OfType<IFieldSymbol> ().Select (static m => (uint)m.ConstantValue).ToImmutableHashSet ();
+        _uIntMembers = enumSymbol.GetMembers ().OfType<IFieldSymbol> ().Select (static m => (uint)m.ConstantValue).ToImmutableHashSet ();
     }
 
     private bool HasExplicitFastHasFlags
@@ -328,18 +326,6 @@ internal sealed record EnumExtensionMethodsGenerationInfo : IGeneratedTypeMetada
         set => _discoveredProperties [ExplicitFastIsDefinedMask] = value;
     }
 
-    private bool HasExplicitIncludeInterface
-    {
-        [UsedImplicitly]get => _discoveredProperties [ExplicitIncludeInterfaceMask];
-        set => _discoveredProperties [ExplicitIncludeInterfaceMask] = value;
-    }
-
-    private bool HasExplicitPartial
-    {
-        [UsedImplicitly]get => _discoveredProperties [ExplicitPartialMask];
-        set => _discoveredProperties [ExplicitPartialMask] = value;
-    }
-
     private bool HasExplicitTypeName
     {
         get => _discoveredProperties [ExplicitNameMask];

+ 4 - 4
Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumExtensionMethodsIncrementalGenerator.cs

@@ -22,7 +22,7 @@ public sealed class EnumExtensionMethodsIncrementalGenerator : IIncrementalGener
     private const string GeneratorAttributeName = nameof (GenerateEnumExtensionMethodsAttribute);
 
     /// <summary>Fully-qualified symbol name format without the "global::" prefix.</summary>
-    private static readonly SymbolDisplayFormat FullyQualifiedSymbolDisplayFormatWithoutGlobal =
+    private static readonly SymbolDisplayFormat _fullyQualifiedSymbolDisplayFormatWithoutGlobal =
         SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle (SymbolDisplayGlobalNamespaceStyle.Omitted);
 
     /// <inheritdoc/>
@@ -160,7 +160,7 @@ public sealed class EnumExtensionMethodsIncrementalGenerator : IIncrementalGener
 
         string enumName = namedSymbol.Name;
 
-        string enumNamespace = enumNamespaceSymbol.ToDisplayString (FullyQualifiedSymbolDisplayFormatWithoutGlobal);
+        string enumNamespace = enumNamespaceSymbol.ToDisplayString (_fullyQualifiedSymbolDisplayFormatWithoutGlobal);
 
         TypeCode enumTypeCode = namedSymbol.EnumUnderlyingType.Name switch
                                 {
@@ -260,8 +260,8 @@ public sealed class EnumExtensionMethodsIncrementalGenerator : IIncrementalGener
                                            ///     Used to enable source generation of a common set of extension methods for enum types.
                                            /// </summary>
                                            {{Strings.Templates.AttributesForGeneratedTypes}}
-                                           [System.AttributeUsageAttribute (System.AttributeTargets.Enum)]
-                                           public sealed class {{GeneratorAttributeName}} : Attribute
+                                           [{{Strings.DotnetNames.Types.AttributeUsageAttribute}} ({{Strings.DotnetNames.Types.AttributeTargets}}.Enum)]
+                                           public sealed class {{GeneratorAttributeName}} : {{Strings.DotnetNames.Types.Attribute}}
                                            {
                                                /// <summary>
                                                ///     The name of the generated static class.

+ 0 - 130
Analyzers/Terminal.Gui.Analyzers.Internal/Generators/EnumExtensions/EnumMemberCombinationsGenerator.cs

@@ -1,130 +0,0 @@
-using System.Text;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Text;
-using Terminal.Gui.Analyzers.Internal.Attributes;
-using Terminal.Gui.Analyzers.Internal.Constants;
-
-namespace Terminal.Gui.Analyzers.Internal.Generators.EnumExtensions;
-
-/// <summary>
-/// Implementation of <see cref="IIncrementalGenerator"/> for types decorated with <see cref="GenerateEnumMemberCombinationsAttribute"/>.
-/// </summary>
-[Generator]
-internal sealed class EnumMemberCombinationsGenerator : IIncrementalGenerator
-{
-    private const string AttributeCodeText = $$"""
-                                               {{Strings.Templates.StandardHeader}}
-                                               
-                                               namespace {{Strings.AnalyzersAttributesNamespace}};
-                                               
-                                               /// <summary>
-                                               ///     Designates an enum member for inclusion in generation of bitwise combinations with other members decorated with
-                                               ///     this attribute which have the same <see cref="{{nameof (GenerateEnumMemberCombinationsAttribute.GroupTag)}}"/> value.<br/>
-                                               /// </summary>
-                                               /// <remarks>
-                                               ///     <para>
-                                               ///         This attribute is only considered for enum types with the <see cref="{{nameof (GenerateEnumMemberCombinationsAttribute)}}"/>.
-                                               ///     </para>
-                                               ///     <para>
-                                               ///         Masks with more than 8 bits set will
-                                               ///     </para>
-                                               /// </remarks>
-                                               [AttributeUsageAttribute(AttributeTargets.Enum)]
-                                               internal sealed class {{nameof (GenerateEnumMemberCombinationsAttribute)}} : System.Attribute
-                                               {
-                                                   public const byte MaximumPopCountLimit = 14;
-                                                   private uint _mask;
-                                                   private uint _maskPopCount;
-                                                   private byte _popCountLimit = 8;
-                                                   public required string GroupTag { get; set; }
-                                               
-                                                   public required uint Mask
-                                                   {
-                                                       get => _mask;
-                                                       set
-                                                       {
-                                                           _maskPopCount = uint.PopCount(value);
-                                               
-                                                           PopCountLimitExceeded = _maskPopCount > PopCountLimit;
-                                                           MaximumPopCountLimitExceeded = _maskPopCount > MaximumPopCountLimit;
-                                               
-                                                           if (PopCountLimitExceeded || MaximumPopCountLimitExceeded)
-                                                           {
-                                                               return;
-                                                           }
-                                               
-                                                           _mask = value;
-                                                       }
-                                                   }
-                                               
-                                                   /// <summary>
-                                                   ///     The maximum number of bits allowed to be set to 1 in <see cref="{{nameof (GenerateEnumMemberCombinationsAttribute.Mask)}}"/>.
-                                                   /// </summary>
-                                                   /// <remarks>
-                                                   ///     <para>
-                                                   ///         Default: 8 (256 possible combinations)
-                                                   ///     </para>
-                                                   ///     <para>
-                                                   ///         Increasing this value is not recommended!<br/>
-                                                   ///         Decreasing this value is pointless unless you want to limit maximum possible generated combinations even
-                                                   ///         further.
-                                                   ///     </para>
-                                                   ///     <para>
-                                                   ///         If the result of <see cref="uint.PopCount"/>(<see cref="{{nameof (GenerateEnumMemberCombinationsAttribute.Mask)}}"/>) exceeds 2 ^ <see cref="PopCountLimit"/>, no
-                                                   ///         combinations will be generated for the members which otherwise would have been included by <see cref="{{nameof (GenerateEnumMemberCombinationsAttribute.Mask)}}"/>.
-                                                   ///         Values exceeding the actual population count of <see cref="{{nameof (GenerateEnumMemberCombinationsAttribute.Mask)}}"/> have no effect.
-                                                   ///     </para>
-                                                   ///     <para>
-                                                   ///         This option is set to a sane default of 8, but also has a hard-coded limit of 14 (16384 combinations), as a
-                                                   ///         protection against generation of extremely large files.
-                                                   ///     </para>
-                                                   ///     <para>
-                                                   ///         CAUTION: The maximum number of possible combinations possible is equal to 1 &lt;&lt;
-                                                   ///         <see cref="uint.PopCount"/>(<see cref="{{nameof (GenerateEnumMemberCombinationsAttribute.Mask)}}"/>).
-                                                   ///         See <see cref="MaximumPopCountLimit"/> for hard-coded limit,
-                                                   ///     </para>
-                                                   /// </remarks>
-                                                   public byte PopCountLimit
-                                                   {
-                                                       get => _popCountLimit;
-                                                       set
-                                                       {
-                                                           _maskPopCount = uint.PopCount(_mask);
-                                               
-                                                           PopCountLimitExceeded = _maskPopCount > value;
-                                                           MaximumPopCountLimitExceeded = _maskPopCount > MaximumPopCountLimit;
-                                               
-                                                           if (PopCountLimitExceeded || MaximumPopCountLimitExceeded)
-                                                           {
-                                                               return;
-                                                           }
-                                               
-                                                           _mask = value;
-                                                           _popCountLimit = value;
-                                                       }
-                                                   }
-                                               
-                                                   internal bool MaximumPopCountLimitExceeded { get; private set; }
-                                                   internal bool PopCountLimitExceeded { get; private set; }
-                                               }
-
-                                               """;
-
-    private const string AttributeFullyQualifiedName = $"{Strings.AnalyzersAttributesNamespace}.{AttributeName}";
-    private const string AttributeName = "GenerateEnumMemberCombinationsAttribute";
-
-    /// <inheritdoc/>
-    public void Initialize (IncrementalGeneratorInitializationContext context)
-    {
-        context.RegisterPostInitializationOutput (GenerateAttributeCode);
-
-        return;
-
-        static void GenerateAttributeCode (IncrementalGeneratorPostInitializationContext initContext)
-        {
-#pragma warning disable IDE0061 // Use expression body for local function
-            initContext.AddSource ($"{AttributeFullyQualifiedName}.g.cs", SourceText.From (AttributeCodeText, Encoding.UTF8));
-#pragma warning restore IDE0061 // Use expression body for local function
-        }
-    }
-}

+ 15 - 50
Analyzers/Terminal.Gui.Analyzers.Internal/Terminal.Gui.Analyzers.Internal.csproj

@@ -1,9 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
         <!-- 
-        Do not remove netstandard2.0 from the TargetFrameworks.
+        Do not remove netstandard2.0 from the TargetFramework.
         Visual Studio requires that Analyzers/Generators target netstandard2.0 to work properly.
-        Additional TFMs are for support of additional APIs and language features.
+        Also do not change this to TargetFrameworks without fully understanding the behavior change that implies.
         -->
         <TargetFramework>netstandard2.0</TargetFramework>
     </PropertyGroup>
@@ -11,21 +11,14 @@
     <PropertyGroup>
         <OutputType>Library</OutputType>
         <LangVersion>12</LangVersion>
-        <Nullable>enable</Nullable>
         <RootNamespace>Terminal.Gui.Analyzers.Internal</RootNamespace>
         <ImplicitUsings>disable</ImplicitUsings>
         <InvariantGlobalization>true</InvariantGlobalization>
         <EnableNETAnalyzers>true</EnableNETAnalyzers>
         <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
-        <AnalysisLevel>latest-recommended</AnalysisLevel>
-        <WarningLevel>7</WarningLevel>
-        <CharacterSet>UTF-8</CharacterSet>
         <CodeAnalysisIgnoreGeneratedCode>true</CodeAnalysisIgnoreGeneratedCode>
-        <Deterministic>true</Deterministic>
         <ProduceReferenceAssembly>true</ProduceReferenceAssembly>
-        <UTF8OutPut>true</UTF8OutPut>
         <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
-        <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
         <GenerateDocumentationFile>True</GenerateDocumentationFile>
         <IsRoslynComponent>true</IsRoslynComponent>
         <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
@@ -39,33 +32,13 @@
         <Compile Remove="Compatibility/*.cs" />
     </ItemGroup>
 
-    <Choose>
-        <When Condition="'$(TargetFramework)' == 'netstandard2.0'">
-            <PropertyGroup>
-                <!-- Disabling some useless warnings caused by the netstandard2.0 target -->
-                <NoWarn>$(NoWarn);nullable;CA1067</NoWarn>
-            </PropertyGroup>
-            <ItemGroup>                                                                         
-                <Compile Include="Compatibility/CompilerFeatureRequiredAttribute.cs" />         
-                <Compile Include="Compatibility/IsExternalInit.cs" />                           
-                <Compile Include="Compatibility/IEqualityOperators.cs" />
-                <Compile Include="Compatibility/NullableAttributes.cs" />                         
-                <Compile Include="Compatibility/RequiredMemberAttribute.cs" />                  
-                <Compile Include="Compatibility/SetsRequiredMembersAttribute.cs" />             
-            </ItemGroup>                                                                        
-            <ItemGroup>
-                <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" PrivateAssets="all" />
-                <PackageReference Include="System.Runtime.Extensions" Version="4.3.1" PrivateAssets="all" />
-                <PackageReference Include="System.Runtime.Numerics" Version="4.3.0" PrivateAssets="all" />
-            </ItemGroup>
-        </When>
-        <When Condition="'$(TargetFramework)' == 'net8.0'">
-        </When>
-    </Choose>
-    
-    <ItemGroup>
+    <PropertyGroup>
+        <!-- Disabling some useless warnings caused by the netstandard2.0 target -->
+        <NoWarn>$(NoWarn);nullable;CA1067</NoWarn>
+    </PropertyGroup>
+    <ItemGroup>                           
+        <Compile Include="Compatibility/IEqualityOperators.cs" />             
         <Compile Include="Compatibility/NumericExtensions.cs" />
-        <Compile Include="Compatibility/SkipLocalsInitAttribute.cs" />
     </ItemGroup>
 
     <ItemGroup>
@@ -74,25 +47,17 @@
     </ItemGroup>
 
     <ItemGroup>
+        <PackageReference Include="Meziantou.Polyfill" Version="1.0.38" PrivateAssets="all" />
         <PackageReference Include="Microsoft.CodeAnalysis" Version="4.9.2" PrivateAssets="all" />
         <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
         <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.9.2" PrivateAssets="all" />
         <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" PrivateAssets="all" />
         <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" PrivateAssets="all" />
-        <PackageReference Include="Roslynator.Analyzers" Version="4.12.1" PrivateAssets="all">
-            <!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
-        </PackageReference>
-        <PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.12.1" PrivateAssets="all">
-            <!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
-        </PackageReference>
-        <PackageReference Include="Roslynator.CSharp" Version="4.12.1" PrivateAssets="all" />
+        <PackageReference Include="Roslynator.Analyzers" Version="4.12.2" PrivateAssets="all" />
+        <PackageReference Include="Roslynator.CodeAnalysis.Analyzers" Version="4.12.2" PrivateAssets="all" />
+        <PackageReference Include="Roslynator.CSharp" Version="4.12.2" PrivateAssets="all" />
+        <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" PrivateAssets="all" />
+        <PackageReference Include="System.Runtime.Extensions" Version="4.3.1" PrivateAssets="all" />
+        <PackageReference Include="System.Runtime.Numerics" Version="4.3.0" PrivateAssets="all" />
     </ItemGroup>
-
-    <ItemGroup>
-        <Using Include="System.Buffers" />
-        <Using Include="System.Collections.Specialized" />
-        <Using Include="System.Numerics" />
-        <Using Include="System.Runtime.CompilerServices" />
-    </ItemGroup>
-
 </Project>

+ 0 - 0
Directory.build.props → Directory.Build.props


+ 5 - 0
Directory.Build.targets

@@ -0,0 +1,5 @@
+<Project>
+  <PropertyGroup>
+    <DefineConstants>$(DefineConstants);DIMAUTO</DefineConstants>
+  </PropertyGroup>
+</Project>

+ 1 - 1
ReactiveExample/LoginView.cs

@@ -79,7 +79,7 @@ public class LoginView : Window, IViewFor<LoginViewModel>
 
         var loginProgressLabel = new Label
         {
-            AutoSize = false,  X = Pos.Left (previous), Y = Pos.Top (previous) + 1, Width = 40, Height = 1, Text = idle
+            X = Pos.Left (previous), Y = Pos.Top (previous) + 1, Width = 40, Height = 1, Text = idle
         };
 
         ViewModel

+ 1 - 1
ReactiveExample/ReactiveExample.csproj

@@ -12,7 +12,7 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
-    <PackageReference Include="ReactiveUI" Version="19.6.1" />
+    <PackageReference Include="ReactiveUI" Version="20.0.1" />
     <PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="1.3.1" PrivateAssets="all" />
   </ItemGroup>
   <ItemGroup>

+ 0 - 0
Scripts/Terminal.Gui.Powershell.Analyzers.psd1 → Scripts/Terminal.Gui.PowerShell.Analyzers.psd1


+ 10 - 19
Scripts/Terminal.Gui.PowerShell.Analyzers.psm1

@@ -55,43 +55,34 @@ Function Build-Analyzers {
     return
   }
   
-  New-Variable -Name solutionRoot -Visibility Public -Value (Resolve-Path ..)
-  Push-Location $solutionRoot
-  New-Variable -Name solutionFile -Visibility Public -Value (Resolve-Path ./Terminal.sln)
-  $mainProjectRoot = Resolve-Path ./Terminal.Gui
-  $mainProjectFile = Join-Path $mainProjectRoot Terminal.Gui.csproj
-  $analyzersRoot = Resolve-Path ./Analyzers
-  $internalAnalyzersProjectRoot = Join-Path $analyzersRoot Terminal.Gui.Analyzers.Internal
-  $internalAnalyzersProjectFile = Join-Path $internalAnalyzersProjectRoot Terminal.Gui.Analyzers.Internal.csproj
+  Push-Location $InternalAnalyzersProjectDirectory
   
   if(!$NoClean) {
     if(!$Quiet) {
       Write-Host Deleting bin and obj folders for Terminal.Gui
     }
-    if(Test-Path $mainProjectRoot/bin) {
-      Remove-Item -Recurse -Force $mainProjectRoot/bin
-      Remove-Item -Recurse -Force $mainProjectRoot/obj
-    }
+    Remove-Item -Recurse -Force $TerminalGuiProjectDirectory/bin -ErrorAction SilentlyContinue
+    Remove-Item -Recurse -Force $TerminalGuiProjectDirectory/obj -ErrorAction SilentlyContinue
 
     if(!$Quiet) {
       Write-Host Deleting bin and obj folders for Terminal.Gui.InternalAnalyzers
     }
-    if(Test-Path $internalAnalyzersProjectRoot/bin) {
-      Remove-Item -Recurse -Force $internalAnalyzersProjectRoot/bin
-      Remove-Item -Recurse -Force $internalAnalyzersProjectRoot/obj
-    }
+    Remove-Item -Recurse -Force $InternalAnalyzersProjectDirectory/bin -ErrorAction SilentlyContinue
+    Remove-Item -Recurse -Force $InternalAnalyzersProjectDirectory/obj -ErrorAction SilentlyContinue
   }
   
   if(!$Quiet) {
     Write-Host Building analyzers in Debug configuration
   }
-  dotnet build $internalAnalyzersProjectFile --no-incremental --nologo --force --configuration Debug
+  dotnet build $InternalAnalyzersProjectFilePath --no-incremental --nologo --force --configuration Debug
 
   if(!$Quiet) {
     Write-Host Building analyzers in Release configuration
   }
-  dotnet build $internalAnalyzersProjectFile --no-incremental --nologo --force --configuration Release
+  dotnet build $InternalAnalyzersProjectFilePath --no-incremental --nologo --force --configuration Release
 
+  Pop-Location
+  
   if(!$AutoLaunch) {
     Write-Host -ForegroundColor Green Finished. Restart Visual Studio for changes to take effect.
   } else {
@@ -102,4 +93,4 @@ Function Build-Analyzers {
   }
 
   return
-}
+}

+ 22 - 14
Scripts/Terminal.Gui.PowerShell.Core.psm1

@@ -14,17 +14,18 @@ Function Open-Solution {
   [CmdletBinding()]
   param(
     [Parameter(Mandatory=$false, HelpMessage="The path to the solution file to open.")]
-    [Uri]$SolutionFilePath = (Resolve-Path "../Terminal.sln")
+    [ValidatePattern(".*Terminal\.sln" )]
+    [string]$Path = $SolutionFilePath
   )
   
   if(!$IsWindows) {
     [string]$warningMessage = "The Open-Solution cmdlet is only supported on Windows.`n`
-    Attempt to open file $SolutionFilePath with the system default handler?"
+    Attempt to open file $Path with the system default handler?"
     
     Write-Warning $warningMessage -WarningAction Inquire
   }
   
-  Invoke-Item $SolutionFilePath
+  Invoke-Item $Path
   return
 }
 
@@ -62,11 +63,15 @@ Function Set-PowerShellEnvironment {
   [CmdletBinding()]
   param()
 
-  # Set a custom prompt to indicate we're in our modified environment.
-  # Save the normal one first, though.
-  # And save it as ReadOnly and without the -Force parameter, so this will be skipped if run more than once in the same session without a reset.
-  New-Variable -Name NormalPrompt -Option ReadOnly -Scope Global -Value (Get-Item Function:prompt).ScriptBlock -ErrorAction SilentlyContinue
-  Set-Item Function:prompt { "TGPS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "; }
+  # Set up some common globals
+  New-Variable -Name ScriptsDirectory -Value $PSScriptRoot -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name RepositoryRootDirectory -Value (Join-Path -Resolve $ScriptsDirectory "..") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name SolutionFilePath -Value (Join-Path -Resolve $RepositoryRootDirectory "Terminal.sln") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name TerminalGuiProjectDirectory -Value (Join-Path -Resolve $RepositoryRootDirectory "Terminal.Gui") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name TerminalGuiProjectFilePath -Value (Join-Path -Resolve $TerminalGuiProjectDirectory "Terminal.Gui.csproj") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name AnalyzersDirectory -Value (Join-Path -Resolve $RepositoryRootDirectory "Analyzers") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name InternalAnalyzersProjectDirectory -Value (Join-Path -Resolve $AnalyzersDirectory "Terminal.Gui.Analyzers.Internal") -Option ReadOnly -Scope Global -Visibility Public
+  New-Variable -Name InternalAnalyzersProjectFilePath -Value (Join-Path -Resolve $InternalAnalyzersProjectDirectory "Terminal.Gui.Analyzers.Internal.csproj") -Option ReadOnly -Scope Global -Visibility Public
 
   # Save existing PSModulePath for optional reset later.
   # If it is already saved, do not overwrite, but continue anyway.
@@ -121,17 +126,20 @@ Function Reset-PowerShellEnvironment {
     [Environment]::Exit(0)
   }
 
-  if(Get-Variable -Name NormalPrompt -Scope Global -ErrorAction SilentlyContinue){
-    Set-Item Function:prompt $NormalPrompt
-    Remove-Variable -Name NormalPrompt -Scope Global -Force -ErrorAction SilentlyContinue
-  }
-
   if(Get-Variable -Name OriginalPSModulePath -Scope Global -ErrorAction SilentlyContinue){
     $Env:PSModulePath = $OriginalPSModulePath
     Remove-Variable -Name OriginalPSModulePath -Scope Global -Force -ErrorAction SilentlyContinue
   }
 
   Remove-Variable -Name PathVarSeparator -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name RepositoryRootDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name SolutionFilePath -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name TerminalGuiProjectDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name TerminalGuiProjectFilePath -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name ScriptsDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name AnalyzersDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name InternalAnalyzersProjectDirectory -Scope Global -Force -ErrorAction SilentlyContinue
+  Remove-Variable -Name InternalAnalyzersProjectFilePath -Scope Global -Force -ErrorAction SilentlyContinue
 }
 
 # This ensures the environment is reset when unloading the module.
@@ -140,4 +148,4 @@ $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
   Reset-PowerShellEnvironment
 }
 
-Set-PowerShellEnvironment
+Set-PowerShellEnvironment

+ 135 - 38
Terminal.Gui/Application.cs

@@ -542,8 +542,11 @@ public static partial class Application
             toplevel.OnLoaded ();
             toplevel.SetNeedsDisplay ();
             toplevel.Draw ();
-            toplevel.PositionCursor ();
-            Driver.Refresh ();
+            Driver.UpdateScreen ();
+            if (PositionCursor (toplevel))
+            {
+                Driver.UpdateCursor ();
+            }
         }
 
         NotifyNewRunState?.Invoke (toplevel, new (rs));
@@ -551,6 +554,90 @@ public static partial class Application
         return rs;
     }
 
+    /// <summary>
+    /// Calls <see cref="View.PositionCursor"/> on the most focused view in the view starting with <paramref name="view"/>.
+    /// </summary>
+    /// <remarks>
+    /// Does nothing if <paramref name="view"/> is <see langword="null"/> or if the most focused view is not visible or enabled.
+    /// <para>
+    /// If the most focused view is not visible within it's superview, the cursor will be hidden.
+    /// </para>
+    /// </remarks>
+    /// <returns><see langword="true"/> if a view positioned the cursor and the position is visible.</returns>
+    internal static bool PositionCursor (View view)
+    {
+        // Find the most focused view and position the cursor there.
+        View mostFocused = view?.MostFocused;
+
+        if (mostFocused is null)
+        {
+            if (view is { HasFocus: true })
+            {
+                mostFocused = view;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        // If the view is not visible or enabled, don't position the cursor
+        if (!mostFocused.Visible || !mostFocused.Enabled)
+        {
+            Driver.GetCursorVisibility (out CursorVisibility current);
+            if (current != CursorVisibility.Invisible)
+            {
+                Driver.SetCursorVisibility (CursorVisibility.Invisible);
+            }
+
+            return false;
+        }
+
+        // If the view is not visible within it's superview, don't position the cursor
+        Rectangle mostFocusedViewport = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = Point.Empty });
+        Rectangle superViewViewport = mostFocused.SuperView?.ViewportToScreen (mostFocused.SuperView.Viewport with { Location = Point.Empty }) ?? Driver.Screen;
+        if (!superViewViewport.IntersectsWith (mostFocusedViewport))
+        {
+            return false;
+        }
+
+        Point? cursor = mostFocused.PositionCursor ();
+
+        Driver.GetCursorVisibility (out CursorVisibility currentCursorVisibility);
+
+        if (cursor is { })
+        {
+            // Convert cursor to screen coords
+            cursor = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = cursor.Value }).Location;
+
+            // If the cursor is not in a visible location in the SuperView, hide it
+            if (!superViewViewport.Contains (cursor.Value))
+            {
+                if (currentCursorVisibility != CursorVisibility.Invisible)
+                {
+                    Driver.SetCursorVisibility (CursorVisibility.Invisible);
+                }
+
+                return false;
+            }
+
+            // Show it
+            if (currentCursorVisibility == CursorVisibility.Invisible)
+            {
+                Driver.SetCursorVisibility (mostFocused.CursorVisibility);
+            }
+
+            return true;
+        }
+
+        if (currentCursorVisibility != CursorVisibility.Invisible)
+        {
+            Driver.SetCursorVisibility (CursorVisibility.Invisible);
+        }
+
+        return false;
+    }
+
     /// <summary>
     ///     Runs the application by creating a <see cref="Toplevel"/> object and calling
     ///     <see cref="Run(Toplevel, Func{Exception, bool}, ConsoleDriver)"/>.
@@ -764,7 +851,6 @@ public static partial class Application
             last = v;
         }
 
-        last?.PositionCursor ();
         Driver.Refresh ();
     }
 
@@ -877,11 +963,21 @@ public static partial class Application
         if (state.Toplevel.NeedsDisplay || state.Toplevel.SubViewNeedsDisplay || state.Toplevel.LayoutNeeded || OverlappedChildNeedsDisplay ())
         {
             state.Toplevel.Draw ();
-            state.Toplevel.PositionCursor ();
-            Driver.Refresh ();
+            Driver.UpdateScreen ();
+            //Driver.UpdateCursor ();
         }
-        else
+
+        if (PositionCursor (state.Toplevel))
+        {
+            Driver.UpdateCursor ();
+        }
+
+        //        else
         {
+            //if (PositionCursor (state.Toplevel))
+            //{
+            //    Driver.Refresh ();
+            //}
             //Driver.UpdateCursor ();
         }
 
@@ -1132,10 +1228,10 @@ public static partial class Application
     /// <value>The current.</value>
     public static Toplevel Current { get; private set; }
 
-    private static void EnsureModalOrVisibleAlwaysOnTop (Toplevel Toplevel)
+    private static void EnsureModalOrVisibleAlwaysOnTop (Toplevel topLevel)
     {
-        if (!Toplevel.Running
-            || (Toplevel == Current && Toplevel.Visible)
+        if (!topLevel.Running
+            || (topLevel == Current && topLevel.Visible)
             || OverlappedTop == null
             || _topLevels.Peek ().Modal)
         {
@@ -1152,24 +1248,24 @@ public static partial class Application
             }
         }
 
-        if (!Toplevel.Visible && Toplevel == Current)
+        if (!topLevel.Visible && topLevel == Current)
         {
             OverlappedMoveNext ();
         }
     }
 
 #nullable enable
-    private static Toplevel? FindDeepestTop (Toplevel start, int x, int y)
+    private static Toplevel? FindDeepestTop (Toplevel start, in Point location)
     {
-        if (!start.Frame.Contains (x, y))
+        if (!start.Frame.Contains (location))
         {
             return null;
         }
 
         if (_topLevels is { Count: > 0 })
         {
-            int rx = x - start.Frame.X;
-            int ry = y - start.Frame.Y;
+            int rx = location.X - start.Frame.X;
+            int ry = location.Y - start.Frame.Y;
 
             foreach (Toplevel t in _topLevels)
             {
@@ -1304,17 +1400,22 @@ public static partial class Application
     {
         SizeChanging?.Invoke (null, args);
 
-        if (args.Cancel)
+        if (args.Cancel || args.Size is null)
         {
             return false;
         }
 
         foreach (Toplevel t in _topLevels)
         {
-            t.SetRelativeLayout (args.Size);
+            t.SetRelativeLayout (args.Size.Value);
             t.LayoutSubviews ();
             t.PositionToplevels ();
             t.OnSizeChanging (new (args.Size));
+
+            if (PositionCursor (t))
+            {
+                Driver.UpdateCursor ();
+            }
         }
 
         Refresh ();
@@ -1457,7 +1558,7 @@ public static partial class Application
             return;
         }
 
-        var view = View.FindDeepestView (Current, mouseEvent.X, mouseEvent.Y);
+        var view = View.FindDeepestView (Current, mouseEvent.Position);
 
         if (view is { })
         {
@@ -1475,18 +1576,17 @@ public static partial class Application
         {
             // If the mouse is grabbed, send the event to the view that grabbed it.
             // The coordinates are relative to the Bounds of the view that grabbed the mouse.
-            Point frameLoc = MouseGrabView.ScreenToViewport (mouseEvent.X, mouseEvent.Y);
+            Point frameLoc = MouseGrabView.ScreenToViewport (mouseEvent.Position);
 
             var viewRelativeMouseEvent = new MouseEvent
             {
-                X = frameLoc.X,
-                Y = frameLoc.Y,
+                Position = frameLoc,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = new (mouseEvent.X, mouseEvent.Y),
+                ScreenPosition = mouseEvent.Position,
                 View = MouseGrabView
             };
 
-            if ((MouseGrabView.Viewport with { Location = Point.Empty }).Contains (viewRelativeMouseEvent.X, viewRelativeMouseEvent.Y) is false)
+            if ((MouseGrabView.Viewport with { Location = Point.Empty }).Contains (viewRelativeMouseEvent.Position) is false)
             {
                 // The mouse has moved outside the bounds of the view that grabbed the mouse
                 _mouseEnteredView?.NewMouseLeaveEvent (mouseEvent);
@@ -1519,10 +1619,10 @@ public static partial class Application
             {
                 // This occurs when there are multiple overlapped "tops"
                 // E.g. "Mdi" - in the Background Worker Scenario
-                View? top = FindDeepestTop (Top, mouseEvent.X, mouseEvent.Y);
-                view = View.FindDeepestView (top, mouseEvent.X, mouseEvent.Y);
+                View? top = FindDeepestTop (Top, mouseEvent.Position);
+                view = View.FindDeepestView (top, mouseEvent.Position);
 
-                if (view is { } && view != OverlappedTop && top != Current)
+                if (view is { } && view != OverlappedTop && top != Current && top is { })
                 {
                     MoveCurrent ((Toplevel)top);
                 }
@@ -1538,27 +1638,25 @@ public static partial class Application
 
         if (view is Adornment adornment)
         {
-            Point frameLoc = adornment.ScreenToFrame (mouseEvent.X, mouseEvent.Y);
+            Point frameLoc = adornment.ScreenToFrame (mouseEvent.Position);
 
             me = new ()
             {
-                X = frameLoc.X,
-                Y = frameLoc.Y,
+                Position = frameLoc,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = new (mouseEvent.X, mouseEvent.Y),
+                ScreenPosition = mouseEvent.Position,
                 View = view
             };
         }
-        else if (view.ViewportToScreen (Rectangle.Empty with { Size = view.Viewport.Size }).Contains (mouseEvent.X, mouseEvent.Y))
+        else if (view.ViewportToScreen (Rectangle.Empty with { Size = view.Viewport.Size }).Contains (mouseEvent.Position))
         {
-            Point viewportLocation = view.ScreenToViewport (mouseEvent.X, mouseEvent.Y);
+            Point viewportLocation = view.ScreenToViewport (mouseEvent.Position);
 
             me = new ()
             {
-                X = viewportLocation.X,
-                Y = viewportLocation.Y,
+                Position = viewportLocation,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = new (mouseEvent.X, mouseEvent.Y),
+                ScreenPosition = mouseEvent.Position,
                 View = view
             };
         }
@@ -1610,14 +1708,13 @@ public static partial class Application
                 break;
             }
 
-            Point boundsPoint = view.ScreenToViewport (mouseEvent.X, mouseEvent.Y);
+            Point boundsPoint = view.ScreenToViewport (mouseEvent.Position);
 
             me = new ()
             {
-                X = boundsPoint.X,
-                Y = boundsPoint.Y,
+                Position = boundsPoint,
                 Flags = mouseEvent.Flags,
-                ScreenPosition = new (mouseEvent.X, mouseEvent.Y),
+                ScreenPosition = mouseEvent.Position,
                 View = view
             };
         }

+ 13 - 3
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -214,9 +214,13 @@ internal class CursesDriver : ConsoleDriver
         if (!RunningUnitTests && Col >= 0 && Col < Cols && Row >= 0 && Row < Rows)
         {
             Curses.move (Row, Col);
+            Curses.raw ();
+            Curses.noecho ();
+            Curses.refresh ();
         }
     }
 
+
     public override void UpdateScreen ()
     {
         for (var row = 0; row < Rows; row++)
@@ -606,6 +610,12 @@ internal class CursesDriver : ConsoleDriver
                 k = KeyCode.Enter;
             }
 
+            // Strip the KeyCode.Space flag off if it's set
+            if (k != KeyCode.Space && k.HasFlag (KeyCode.Space))
+            {
+                k &= ~KeyCode.Space;
+            }
+
             OnKeyDown (new Key (k));
             OnKeyUp (new Key (k));
         }
@@ -809,8 +819,8 @@ internal class CursesDriver : ConsoleDriver
 
         _lastMouseFlags = mouseFlag;
 
-        var me = new MouseEvent { Flags = mouseFlag, X = pos.X, Y = pos.Y };
-        Debug.WriteLine ($"CursesDriver: ({me.X},{me.Y}) - {me.Flags}");
+        var me = new MouseEvent { Flags = mouseFlag, Position = pos };
+        //Debug.WriteLine ($"CursesDriver: ({me.Position}) - {me.Flags}");
 
         OnMouseEvent (me);
     }
@@ -823,7 +833,7 @@ internal class CursesDriver : ConsoleDriver
     /// <returns></returns>
     private static Attribute MakeColor (short foreground, short background)
     {
-        var v = (short)(foreground | (background << 4));
+        var v = (short)((ushort)foreground | (background << 4));
 
         // TODO: for TrueColor - Use InitExtendedPair
         Curses.InitColorPair (v, foreground, background);

+ 4 - 7
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -1137,7 +1137,7 @@ internal class NetDriver : ConsoleDriver
                 break;
             case EventType.Mouse:
                 MouseEvent me = ToDriverMouse (inputEvent.MouseEvent);
-                Debug.WriteLine ($"NetDriver: ({me.X},{me.Y}) - {me.Flags}");
+                //Debug.WriteLine ($"NetDriver: ({me.X},{me.Y}) - {me.Flags}");
                 OnMouseEvent (me);
 
                 break;
@@ -1523,7 +1523,7 @@ internal class NetDriver : ConsoleDriver
             mouseFlag |= MouseFlags.ButtonAlt;
         }
 
-        return new MouseEvent { X = me.Position.X, Y = me.Position.Y, Flags = mouseFlag };
+        return new MouseEvent { Position = me.Position, Flags = mouseFlag };
     }
 
     #endregion Mouse Handling
@@ -1591,10 +1591,7 @@ internal class NetDriver : ConsoleDriver
                 return KeyCode.Tab;
             }
 
-            if (keyInfo.Key == ConsoleKey.Tab)
-            {
-                return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.Key));
-            }
+            return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.Key));
         }
 
         // Handle control keys (e.g. CursorUp)
@@ -1648,7 +1645,7 @@ internal class NetDriver : ConsoleDriver
         }
 
 
-        return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.Key));
+        return MapToKeyCodeModifiers (keyInfo.Modifiers, (KeyCode)((uint)keyInfo.KeyChar));
     }
 
     #endregion Keyboard Handling

+ 29 - 24
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -20,6 +20,7 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using System.Text;
 using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping;
+using static Terminal.Gui.SpinnerStyle;
 
 namespace Terminal.Gui;
 
@@ -156,10 +157,7 @@ internal class WindowsConsole
             }
         }
 
-        if (!_initialCursorVisibility.HasValue && GetCursorVisibility (out CursorVisibility visibility))
-        {
-            _initialCursorVisibility = visibility;
-        }
+        SetInitialCursorVisibility ();
 
         if (!SetConsoleActiveScreenBuffer (_screenBuffer))
         {
@@ -216,11 +214,11 @@ internal class WindowsConsole
         }
         else if (info.dwSize > 50)
         {
-            visibility = CursorVisibility.Box;
+            visibility = CursorVisibility.Default;
         }
         else
         {
-            visibility = CursorVisibility.Underline;
+            visibility = CursorVisibility.Default;
         }
 
         return true;
@@ -815,6 +813,11 @@ internal class WindowsConsole
     [StructLayout (LayoutKind.Sequential)]
     public struct ConsoleCursorInfo
     {
+        /// <summary>
+        /// The percentage of the character cell that is filled by the cursor.This value is between 1 and 100.
+        /// The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal
+        /// line at the bottom of the cell.
+        /// </summary>
         public uint dwSize;
         public bool bVisible;
     }
@@ -1436,6 +1439,8 @@ internal class WindowsDriver : ConsoleDriver
 #if HACK_CHECK_WINCHANGED
         _mainLoopDriver.WinChanged = ChangeWin;
 #endif
+
+        WinConsole?.SetInitialCursorVisibility ();
         return new MainLoop (_mainLoopDriver);
     }
 
@@ -1478,7 +1483,7 @@ internal class WindowsDriver : ConsoleDriver
             case WindowsConsole.EventType.Mouse:
                 MouseEvent me = ToDriverMouse (inputEvent.MouseEvent);
 
-               if (me is null || me.Flags == MouseFlags.None)
+                if (me is null || me.Flags == MouseFlags.None)
                 {
                     break;
                 }
@@ -1489,8 +1494,7 @@ internal class WindowsDriver : ConsoleDriver
                 {
                     OnMouseEvent (new ()
                     {
-                        X = me.X,
-                        Y = me.Y,
+                        Position = me.Position,
                         Flags = ProcessButtonClick (inputEvent.MouseEvent)
                     });
                 }
@@ -1517,23 +1521,28 @@ internal class WindowsDriver : ConsoleDriver
 #if HACK_CHECK_WINCHANGED
     private void ChangeWin (object s, SizeChangedEventArgs e)
     {
-        int w = e.Size.Width;
+        if (e.Size is null)
+        {
+            return;
+        }
 
-        if (w == Cols - 3 && e.Size.Height < Rows)
+        int w = e.Size.Value.Width;
+
+        if (w == Cols - 3 && e.Size.Value.Height < Rows)
         {
             w += 3;
         }
 
         Left = 0;
         Top = 0;
-        Cols = e.Size.Width;
-        Rows = e.Size.Height;
+        Cols = e.Size.Value.Width;
+        Rows = e.Size.Value.Height;
 
         if (!RunningUnitTests)
         {
             Size newSize = WinConsole.SetConsoleWindow (
                                                         (short)Math.Max (w, 16),
-                                                        (short)Math.Max (e.Size.Height, 0));
+                                                        (short)Math.Max (e.Size.Value.Height, 0));
 
             Cols = newSize.Width;
             Rows = newSize.Height;
@@ -1804,8 +1813,7 @@ internal class WindowsDriver : ConsoleDriver
         {
             var me = new MouseEvent
             {
-                X = _pointMove.X,
-                Y = _pointMove.Y,
+                Position = _pointMove,
                 Flags = mouseFlag
             };
 
@@ -2119,8 +2127,7 @@ internal class WindowsDriver : ConsoleDriver
 
         return new MouseEvent
         {
-            X = mouseEvent.MousePosition.X,
-            Y = mouseEvent.MousePosition.Y,
+            Position = new (mouseEvent.MousePosition.X, mouseEvent.MousePosition.Y),
             Flags = mouseFlag
         };
     }
@@ -2334,11 +2341,9 @@ internal class WindowsMainLoop : IMainLoopDriver
 
 internal class WindowsClipboard : ClipboardBase
 {
-    private const uint _cfUnicodeText = 13;
-
-    public WindowsClipboard () { IsSupported = IsClipboardFormatAvailable (_cfUnicodeText); }
+    private const uint CF_UNICODE_TEXT = 13;
 
-    public override bool IsSupported { get; }
+    public override bool IsSupported { get; } = IsClipboardFormatAvailable (CF_UNICODE_TEXT);
 
     protected override string GetClipboardDataImpl ()
     {
@@ -2349,7 +2354,7 @@ internal class WindowsClipboard : ClipboardBase
                 return string.Empty;
             }
 
-            nint handle = GetClipboardData (_cfUnicodeText);
+            nint handle = GetClipboardData (CF_UNICODE_TEXT);
 
             if (handle == nint.Zero)
             {
@@ -2421,7 +2426,7 @@ internal class WindowsClipboard : ClipboardBase
                 GlobalUnlock (target);
             }
 
-            if (SetClipboardData (_cfUnicodeText, hGlobal) == default (nint))
+            if (SetClipboardData (CF_UNICODE_TEXT, hGlobal) == default (nint))
             {
                 ThrowWin32 ();
             }

+ 0 - 1
Terminal.Gui/Directory.Build.props

@@ -7,5 +7,4 @@
     -->
     <Authors>Miguel de Icaza, Charlie Kindel (@tig), @BDisp</Authors>
   </PropertyGroup>
-
 </Project>

+ 333 - 0
Terminal.Gui/Drawing/Justification.cs

@@ -0,0 +1,333 @@
+namespace Terminal.Gui;
+
+/// <summary>
+///     Controls how the <see cref="Justifier"/> justifies items within a container. 
+/// </summary>
+public enum Justification
+{
+    /// <summary>
+    ///     The items will be aligned to the left.
+    ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
+    ///     each item.
+    /// </summary>
+    /// <example>
+    ///     <c>
+    ///         111 2222 33333
+    ///     </c>
+    /// </example>
+    Left,
+
+    /// <summary>
+    ///     The items will be aligned to the right.
+    ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
+    ///     each item.
+    /// </summary>
+    /// <example>
+    ///     <c>
+    ///         111 2222 33333
+    ///     </c>
+    /// </example>
+    Right,
+
+    /// <summary>
+    ///     The group will be centered in the container.
+    ///     If centering is not possible, the group will be left-justified.
+    ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
+    ///     each item.
+    /// </summary>
+    /// <example>
+    ///     <c>
+    ///         111 2222 33333
+    ///     </c>
+    /// </example>
+    Centered,
+
+    /// <summary>
+    ///     The items will be justified. Space will be added between the items such that the first item
+    ///     is at the start and the right side of the last item against the end.
+    ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
+    ///     each item.
+    /// </summary>
+    /// <example>
+    ///     <c>
+    ///         111    2222     33333
+    ///     </c>
+    /// </example>
+    Justified,
+
+    /// <summary>
+    ///     The first item will be aligned to the left and the remaining will aligned to the right.
+    ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
+    ///     each item.
+    /// </summary>
+    /// <example>
+    ///     <c>
+    ///         111        2222 33333
+    ///     </c>
+    /// </example>
+    FirstLeftRestRight,
+
+    /// <summary>
+    ///     The last item will be aligned to the right and the remaining will aligned to the left.
+    ///     Set <see cref="Justifier.PutSpaceBetweenItems"/> to <see langword="true"/> to ensure at least one space between
+    ///     each item.
+    /// </summary>
+    /// <example>
+    ///     <c>
+    ///         111 2222        33333
+    ///     </c>
+    /// </example>
+    LastRightRestLeft
+}
+
+/// <summary>
+///     Justifies items within a container based on the specified <see cref="Justification"/>.
+/// </summary>
+public class Justifier
+{
+    /// <summary>
+    /// Gets or sets how the <see cref="Justifier"/> justifies items within a container.
+    /// </summary>
+    public Justification Justification { get; set; }
+
+    /// <summary>
+    /// The size of the container.
+    /// </summary>
+    public int ContainerSize { get; set; }
+
+    /// <summary>
+    ///     Gets or sets whether <see cref="Justify(int[])"/> puts a space is placed between items. Default is <see langword="false"/>. If <see langword="true"/>, a space will be
+    ///     placed between each item, which is useful for justifying text.
+    /// </summary>
+    public bool PutSpaceBetweenItems { get; set; }
+
+    /// <summary>
+    ///     Takes a list of items and returns their positions when justified within a container <see name="ContainerSize"/> wide based on the specified
+    ///     <see cref="Justification"/>.
+    /// </summary>
+    /// <param name="sizes">The sizes of the items to justify.</param>
+    /// <returns>The locations of the items, from left to right.</returns>
+    public int [] Justify (int [] sizes)
+    {
+        return Justify (Justification, PutSpaceBetweenItems, ContainerSize, sizes);
+    }
+
+    /// <summary>
+    ///     Takes a list of items and returns their positions when justified within a container <paramref name="containerSize"/> wide based on the specified
+    ///     <see cref="Justification"/>.
+    /// </summary>
+    /// <param name="sizes">The sizes of the items to justify.</param>
+    /// <param name="justification">The justification style.</param>
+    /// <param name="putSpaceBetweenItems"></param>
+    /// <param name="containerSize">The size of the container.</param>
+    /// <returns>The locations of the items, from left to right.</returns>
+    public static int [] Justify (Justification justification, bool putSpaceBetweenItems, int containerSize, int [] sizes)
+    {
+        if (sizes.Length == 0)
+        {
+            return new int [] { };
+        }
+
+        int maxSpaceBetweenItems = putSpaceBetweenItems ? 1 : 0;
+
+        var positions = new int [sizes.Length]; // positions of the items. the return value.
+        int totalItemsSize = sizes.Sum ();
+        int totalGaps = sizes.Length - 1; // total gaps between items
+        int totalItemsAndSpaces = totalItemsSize + totalGaps * maxSpaceBetweenItems; // total size of items and spaces if we had enough room
+
+        int spaces = totalGaps * maxSpaceBetweenItems; // We'll decrement this below to place one space between each item until we run out
+        if (totalItemsSize >= containerSize)
+        {
+            spaces = 0;
+        }
+        else if (totalItemsAndSpaces > containerSize)
+        {
+            spaces = containerSize - totalItemsSize;
+        }
+
+        switch (justification)
+        {
+            case Justification.Left:
+                var currentPosition = 0;
+
+                for (var i = 0; i < sizes.Length; i++)
+                {
+                    if (sizes [i] < 0)
+                    {
+                        throw new ArgumentException ("The size of an item cannot be negative.");
+                    }
+
+                    if (i == 0)
+                    {
+                        positions [0] = 0; // first item position
+
+                        continue;
+                    }
+
+                    int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
+
+                    // subsequent items are placed one space after the previous item
+                    positions [i] = positions [i - 1] + sizes [i - 1] + spaceBefore;
+                }
+
+                break;
+            case Justification.Right:
+                currentPosition = Math.Max (0, containerSize - totalItemsSize - spaces);
+
+                for (var i = 0; i < sizes.Length; i++)
+                {
+                    if (sizes [i] < 0)
+                    {
+                        throw new ArgumentException ("The size of an item cannot be negative.");
+                    }
+
+                    int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
+
+                    positions [i] = currentPosition;
+                    currentPosition += sizes [i] + spaceBefore;
+                }
+
+                break;
+
+            case Justification.Centered:
+                if (sizes.Length > 1)
+                {
+                    // remaining space to be distributed before first and after the items
+                    int remainingSpace = Math.Max (0, containerSize - totalItemsSize - spaces);
+
+                    for (var i = 0; i < sizes.Length; i++)
+                    {
+                        if (sizes [i] < 0)
+                        {
+                            throw new ArgumentException ("The size of an item cannot be negative.");
+                        }
+
+                        if (i == 0)
+                        {
+                            positions [i] = remainingSpace / 2; // first item position
+
+                            continue;
+                        }
+
+                        int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
+
+                        // subsequent items are placed one space after the previous item
+                        positions [i] = positions [i - 1] + sizes [i - 1] + spaceBefore;
+                    }
+                }
+                else if (sizes.Length == 1)
+                {
+                    if (sizes [0] < 0)
+                    {
+                        throw new ArgumentException ("The size of an item cannot be negative.");
+                    }
+
+                    positions [0] = (containerSize - sizes [0]) / 2; // single item is centered
+                }
+
+                break;
+
+            case Justification.Justified:
+                int spaceBetween = sizes.Length > 1 ? (containerSize - totalItemsSize) / (sizes.Length - 1) : 0;
+                int remainder = sizes.Length > 1 ? (containerSize - totalItemsSize) % (sizes.Length - 1) : 0;
+                currentPosition = 0;
+
+                for (var i = 0; i < sizes.Length; i++)
+                {
+                    if (sizes [i] < 0)
+                    {
+                        throw new ArgumentException ("The size of an item cannot be negative.");
+                    }
+
+                    positions [i] = currentPosition;
+                    int extraSpace = i < remainder ? 1 : 0;
+                    currentPosition += sizes [i] + spaceBetween + extraSpace;
+                }
+
+                break;
+
+            // 111 2222        33333
+            case Justification.LastRightRestLeft:
+                if (sizes.Length > 1)
+                {
+                    currentPosition = 0;
+
+                    for (var i = 0; i < sizes.Length; i++)
+                    {
+                        if (sizes [i] < 0)
+                        {
+                            throw new ArgumentException ("The size of an item cannot be negative.");
+                        }
+
+                        if (i < sizes.Length - 1)
+                        {
+                            int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
+
+                            positions [i] = currentPosition;
+                            currentPosition += sizes [i] + spaceBefore;
+                        }
+                    }
+
+                    positions [sizes.Length - 1] = containerSize - sizes [sizes.Length - 1];
+                }
+                else if (sizes.Length == 1)
+                {
+                    if (sizes [0] < 0)
+                    {
+                        throw new ArgumentException ("The size of an item cannot be negative.");
+                    }
+
+                    positions [0] = containerSize - sizes [0]; // single item is flush right
+                }
+
+                break;
+
+            // 111        2222 33333
+            case Justification.FirstLeftRestRight:
+                if (sizes.Length > 1)
+                {
+                    currentPosition = 0;
+                    positions [0] = currentPosition; // first item is flush left
+
+                    for (int i = sizes.Length - 1; i >= 0; i--)
+                    {
+                        if (sizes [i] < 0)
+                        {
+                            throw new ArgumentException ("The size of an item cannot be negative.");
+                        }
+
+                        if (i == sizes.Length - 1)
+                        {
+                            // start at right
+                            currentPosition = containerSize - sizes [i];
+                            positions [i] = currentPosition;
+                        }
+
+                        if (i < sizes.Length - 1 && i > 0)
+                        {
+                            int spaceBefore = spaces-- > 0 ? maxSpaceBetweenItems : 0;
+
+                            positions [i] = currentPosition - sizes [i] - spaceBefore;
+                            currentPosition = positions [i];
+                        }
+                    }
+                }
+                else if (sizes.Length == 1)
+                {
+                    if (sizes [0] < 0)
+                    {
+                        throw new ArgumentException ("The size of an item cannot be negative.");
+                    }
+
+                    positions [0] = 0; // single item is flush left
+                }
+
+                break;
+
+            default:
+                throw new ArgumentOutOfRangeException (nameof (justification), justification, null);
+        }
+
+        return positions;
+    }
+}

+ 13 - 14
Terminal.Gui/Drawing/Thickness.cs

@@ -9,7 +9,8 @@ namespace Terminal.Gui;
 /// </summary>
 /// <remarks>
 ///     <para>
-///         Use the helper API (<see cref="GetInside(Rectangle)"/> to get the rectangle describing the insides of the frame,
+///         Use the helper API (<see cref="GetInside(Rectangle)"/> to get the rectangle describing the insides of the
+///         frame,
 ///         with the thickness widths subtracted.
 ///     </para>
 ///     <para>Use the helper API (<see cref="Draw(Rectangle, string)"/> to draw the frame with the specified thickness.</para>
@@ -86,32 +87,29 @@ public class Thickness : IEquatable<Thickness>
     public bool Equals (Thickness other) { return other is { } && Left == other.Left && Right == other.Right && Top == other.Top && Bottom == other.Bottom; }
 
     /// <summary>
-    ///     Gets whether the specified coordinates lie within the thickness (inside the bounding rectangle but outside of
+    ///     Gets whether the specified coordinates lie within the thickness (inside the bounding rectangle but outside
     ///     the rectangle described by <see cref="GetInside(Rectangle)"/>.
     /// </summary>
     /// <param name="outside">Describes the location and size of the rectangle that contains the thickness.</param>
-    /// <param name="x">The x coord to check.</param>
-    /// <param name="y">The y coord to check.</param>
+    /// <param name="location">The coordinate to check.</param>
     /// <returns><see langword="true"/> if the specified coordinate is within the thickness; <see langword="false"/> otherwise.</returns>
-    public bool Contains (Rectangle outside, int x, int y)
+    public bool Contains (in Rectangle outside, in Point location)
     {
         Rectangle inside = GetInside (outside);
 
-        return outside.Contains (x, y) && !inside.Contains (x, y);
+        return outside.Contains (location) && !inside.Contains (location);
     }
 
     /// <summary>
-    /// Adds the thickness widths of another <see cref="Thickness"/> to the current <see cref="Thickness"/>, returning a new <see cref="Thickness"/>.
+    ///     Adds the thickness widths of another <see cref="Thickness"/> to the current <see cref="Thickness"/>, returning a
+    ///     new <see cref="Thickness"/>.
     /// </summary>
     /// <param name="other"></param>
     /// <returns></returns>
-    public Thickness Add (Thickness other)
-    {
-        return new Thickness (Left + other.Left, Top + other.Top, Right + other.Right, Bottom + other.Bottom);
-    }
+    public Thickness Add (Thickness other) { return new (Left + other.Left, Top + other.Top, Right + other.Right, Bottom + other.Bottom); }
 
     /// <summary>
-    /// Adds the thickness widths of another <see cref="Thickness"/> to another <see cref="Thickness"/>.
+    ///     Adds the thickness widths of another <see cref="Thickness"/> to another <see cref="Thickness"/>.
     /// </summary>
     /// <param name="a"></param>
     /// <param name="b"></param>
@@ -194,7 +192,7 @@ public class Thickness : IEquatable<Thickness>
                                         );
         }
 
-        if (View.Diagnostics.HasFlag(ViewDiagnosticFlags.Ruler))
+        if (View.Diagnostics.HasFlag (ViewDiagnosticFlags.Ruler))
         {
             // PERF: This can almost certainly be simplified down to a single point offset and fewer calls to Draw
             // Top
@@ -233,7 +231,8 @@ public class Thickness : IEquatable<Thickness>
             {
                 Text = label is null ? string.Empty : $"{label} {this}",
                 Alignment = TextAlignment.Centered,
-                VerticalAlignment = VerticalTextAlignment.Bottom
+                VerticalAlignment = VerticalTextAlignment.Bottom,
+                AutoSize = true
             };
             tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute, rect);
         }

+ 10 - 13
Terminal.Gui/Input/Mouse.cs

@@ -116,24 +116,15 @@ public class MouseEvent
     /// <summary>The View at the location for the mouse event.</summary>
     public View View { get; set; }
 
-    /// <summary>The X position of the mouse in <see cref="Gui.View.Viewport"/>-relative coordinates.</summary>
-    public int X { get; set; }
-
-    /// <summary>The Y position of the mouse in <see cref="Gui.View.Viewport"/>-relative coordinates.</summary>
-    public int Y { get; set; }
-
-    /// <summary>
-    ///     Indicates if the current mouse event has been processed. Set this value to <see langword="true"/> to indicate the mouse
-    ///     event was handled.
-    /// </summary>
-    public bool Handled { get; set; }
+    /// <summary>The position of the mouse in <see cref="Gui.View.Viewport"/>-relative coordinates.</summary>
+    public Point Position { get; set; }
 
     /// <summary>
     ///     The screen-relative mouse position.
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         The <see cref="X"/> and <see cref="Y"/> properties are always <see cref="Gui.View.Viewport"/>-relative. When the mouse is grabbed by a view,
+    ///         <see cref="Position"/> is <see cref="Gui.View.Viewport"/>-relative. When the mouse is grabbed by a view,
     ///         <see cref="ScreenPosition"/> provides the mouse position screen-relative coordinates, enabling the grabbed view to know how much the
     ///         mouse has moved.
     ///     </para>
@@ -143,7 +134,13 @@ public class MouseEvent
     /// </remarks>
     public Point ScreenPosition { get; set; }
 
+    /// <summary>
+    ///     Indicates if the current mouse event has been processed. Set this value to <see langword="true"/> to indicate the mouse
+    ///     event was handled.
+    /// </summary>
+    public bool Handled { get; set; }
+
     /// <summary>Returns a <see cref="T:System.String"/> that represents the current <see cref="MouseEvent"/>.</summary>
     /// <returns>A <see cref="T:System.String"/> that represents the current <see cref="MouseEvent"/>.</returns>
-    public override string ToString () { return $"({X},{Y}):{Flags}"; }
+    public override string ToString () { return $"({Position}):{Flags}"; }
 }

+ 12 - 4
Terminal.Gui/Terminal.Gui.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <!-- =================================================================== -->
   <!-- Version numbers -->
   <!-- Automatically updated by gitversion (run `dotnet-gitversion /updateprojectfiles`)  -->
@@ -18,7 +18,7 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <DefineTrace>True</DefineTrace>
     <DebugType>portable</DebugType>
-    <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL</DefineConstants>
+    <DefineConstants>$(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL;CODE_ANALYSIS</DefineConstants>
     <ImplicitUsings>enable</ImplicitUsings>
     <NoLogo>True</NoLogo>
     <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
@@ -45,19 +45,27 @@
   <!-- =================================================================== -->
   <ItemGroup>
     <PackageReference Include="ColorHelper" Version="1.8.1" />
-    <PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
+    <PackageReference Include="JetBrains.Annotations" Version="2023.3.0" PrivateAssets="All" />
+    <PackageReference Include="Microsoft.CodeAnalysis" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.9.2" PrivateAssets="all" />
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
     <!-- Enable Nuget Source Link for github -->
     <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
     <PackageReference Include="System.IO.Abstractions" Version="21.0.2" />
     <PackageReference Include="System.Text.Json" Version="8.0.3" />
     <PackageReference Include="Wcwidth" Version="2.0.0" />
+    <ProjectReference Include="..\Analyzers\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj">
+      <PrivateAssets>all</PrivateAssets>
+      <OutputItemType>Analyzer</OutputItemType>
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+    </ProjectReference>
   </ItemGroup>
   <!-- =================================================================== -->
   <!-- Global Usings and Type Aliases -->
   <!-- =================================================================== -->
   <ItemGroup>
     <Using Include="JetBrains.Annotations" />
-    <Using Include="System.Diagnostics.Contracts.PureAttribute" Alias="PureAttribute" />
+    <Using Include="JetBrains.Annotations.PureAttribute" Alias="PureAttribute" />
     <Using Include="System.Drawing" />
     <Using Include="System.Text" />
   </ItemGroup>

+ 3 - 3
Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs

@@ -143,7 +143,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
 
         if (me.Flags == MouseFlags.Button1Clicked)
         {
-            SelectedIdx = me.Y - ScrollOffset;
+            SelectedIdx = me.Position.Y - ScrollOffset;
 
             return Select ();
         }
@@ -465,9 +465,9 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
     /// <param name="me"></param>
     protected void RenderSelectedIdxByMouse (MouseEvent me)
     {
-        if (SelectedIdx != me.Y - ScrollOffset)
+        if (SelectedIdx != me.Position.Y - ScrollOffset)
         {
-            SelectedIdx = me.Y - ScrollOffset;
+            SelectedIdx = me.Position.Y - ScrollOffset;
 
             if (LastPopupPos is { })
             {

+ 295 - 152
Terminal.Gui/Text/TextFormatter.cs

@@ -30,7 +30,7 @@ public class TextFormatter
 
     /// <summary>Gets or sets whether the <see cref="Size"/> should be automatically changed to fit the <see cref="Text"/>.</summary>
     /// <remarks>
-    ///     <para>Used by <see cref="View.AutoSize"/> to resize the view's <see cref="View.Viewport"/> to fit <see cref="Size"/>.</para>
+    ///     <para>Used when <see cref="View"/> is using <see cref="Dim.Auto"/> to resize the view's <see cref="View.Viewport"/> to fit <see cref="Size"/>.</para>
     ///     <para>
     ///         AutoSize is ignored if <see cref="TextAlignment.Justified"/> and
     ///         <see cref="VerticalTextAlignment.Justified"/> are used.
@@ -43,13 +43,54 @@ public class TextFormatter
         {
             _autoSize = EnableNeedsFormat (value);
 
-            if (_autoSize && Alignment != TextAlignment.Justified && VerticalAlignment != VerticalTextAlignment.Justified)
+            if (_autoSize)
             {
-                Size = CalcRect (0, 0, _text, Direction, TabWidth).Size;
+                Size = GetAutoSize ();
             }
         }
     }
 
+    private Size GetAutoSize ()
+    {
+        Size size = CalcRect (0, 0, Text, Direction, TabWidth).Size;
+        return size with
+        {
+            Width = size.Width - GetHotKeySpecifierLength (),
+            Height = size.Height - GetHotKeySpecifierLength (false)
+        };
+
+    }
+    /// <summary>
+    ///     Gets the width or height of the <see cref="TextFormatter.HotKeySpecifier"/> characters
+    ///     in the <see cref="Text"/> property.
+    /// </summary>
+    /// <remarks>
+    ///     Only the first HotKey specifier found in <see cref="Text"/> is supported.
+    /// </remarks>
+    /// <param name="isWidth">
+    ///     If <see langword="true"/> (the default) the width required for the HotKey specifier is returned. Otherwise the
+    ///     height
+    ///     is returned.
+    /// </param>
+    /// <returns>
+    ///     The number of characters required for the <see cref="TextFormatter.HotKeySpecifier"/>. If the text
+    ///     direction specified
+    ///     by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is returned.
+    /// </returns>
+    public int GetHotKeySpecifierLength (bool isWidth = true)
+    {
+        if (isWidth)
+        {
+            return TextFormatter.IsHorizontalDirection (Direction) && Text?.Contains ((char)HotKeySpecifier.Value) == true
+                       ? Math.Max (HotKeySpecifier.GetColumns (), 0)
+                       : 0;
+        }
+
+        return TextFormatter.IsVerticalDirection (Direction) && Text?.Contains ((char)HotKeySpecifier.Value) == true
+                   ? Math.Max (HotKeySpecifier.GetColumns (), 0)
+                   : 0;
+    }
+
     /// <summary>
     ///     Gets the cursor position of the <see cref="HotKey"/>. If the <see cref="HotKey"/> is defined, the cursor will
     ///     be positioned over it.
@@ -65,13 +106,14 @@ public class TextFormatter
         {
             _textDirection = EnableNeedsFormat (value);
 
-            if (AutoSize && Alignment != TextAlignment.Justified && VerticalAlignment != VerticalTextAlignment.Justified)
+            if (AutoSize)
             {
-                Size = CalcRect (0, 0, Text, Direction, TabWidth).Size;
+                Size = GetAutoSize ();
             }
         }
     }
 
+
     /// <summary>
     ///     Determines if the viewport width will be used or only the text width will be used,
     ///     If <see langword="true"/> all the viewport area will be filled with whitespaces and the same background color
@@ -148,9 +190,9 @@ public class TextFormatter
         get => _size;
         set
         {
-            if (AutoSize && Alignment != TextAlignment.Justified && VerticalAlignment != VerticalTextAlignment.Justified)
+            if (AutoSize)
             {
-                _size = EnableNeedsFormat (CalcRect (0, 0, Text, Direction, TabWidth).Size);
+                _size = EnableNeedsFormat (GetAutoSize());
             }
             else
             {
@@ -172,12 +214,11 @@ public class TextFormatter
         get => _text;
         set
         {
-            bool textWasNull = _text is null && value != null;
             _text = EnableNeedsFormat (value);
 
-            if ((AutoSize && Alignment != TextAlignment.Justified && VerticalAlignment != VerticalTextAlignment.Justified) || (textWasNull && Size.IsEmpty))
+            if (AutoSize)
             {
-                Size = CalcRect (0, 0, _text, Direction, TabWidth).Size;
+                Size = GetAutoSize (); ;
             }
         }
     }
@@ -228,17 +269,6 @@ public class TextFormatter
 
         List<string> linesFormatted = GetLines ();
 
-        switch (Direction)
-        {
-            case TextDirection.TopBottom_RightLeft:
-            case TextDirection.LeftRight_BottomTop:
-            case TextDirection.RightLeft_BottomTop:
-            case TextDirection.BottomTop_RightLeft:
-                linesFormatted.Reverse ();
-
-                break;
-        }
-
         bool isVertical = IsVerticalDirection (Direction);
         Rectangle maxScreen = screen;
 
@@ -286,25 +316,16 @@ public class TextFormatter
 
             Rune [] runes = linesFormatted [line].ToRunes ();
 
-            runes = Direction switch
-            {
-                TextDirection.RightLeft_BottomTop => runes.Reverse ().ToArray (),
-                TextDirection.RightLeft_TopBottom => runes.Reverse ().ToArray (),
-                TextDirection.BottomTop_LeftRight => runes.Reverse ().ToArray (),
-                TextDirection.BottomTop_RightLeft => runes.Reverse ().ToArray (),
-                _ => runes
-            };
-
             // When text is justified, we lost left or right, so we use the direction to align. 
 
             int x, y;
 
             // Horizontal Alignment
-            if (Alignment == TextAlignment.Right || (Alignment == TextAlignment.Justified && !IsLeftToRight (Direction)))
+            if (Alignment is TextAlignment.Right)
             {
                 if (isVertical)
                 {
-                    int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, tabWidth: TabWidth);
+                    int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, line, linesFormatted.Count - line, TabWidth);
                     x = screen.Right - runesWidth;
                     CursorPosition = screen.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0);
                 }
@@ -315,12 +336,12 @@ public class TextFormatter
                     CursorPosition = screen.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0);
                 }
             }
-            else if (Alignment is TextAlignment.Left or TextAlignment.Justified)
+            else if (Alignment is TextAlignment.Left)
             {
                 if (isVertical)
                 {
                     int runesWidth = line > 0
-                                         ? GetColumnsRequiredForVerticalText (linesFormatted, tabWidth: TabWidth)
+                                         ? GetColumnsRequiredForVerticalText (linesFormatted, 0, line, TabWidth)
                                          : 0;
                     x = screen.Left + runesWidth;
                 }
@@ -331,12 +352,36 @@ public class TextFormatter
 
                 CursorPosition = _hotKeyPos > -1 ? _hotKeyPos : 0;
             }
-            else if (Alignment == TextAlignment.Centered)
+            else if (Alignment is TextAlignment.Justified)
             {
                 if (isVertical)
                 {
-                    int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, tabWidth: TabWidth);
-                    x = screen.Left + line + (screen.Width - runesWidth) / 2;
+                    int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, linesFormatted.Count, TabWidth);
+                    int prevLineWidth = line > 0 ? GetColumnsRequiredForVerticalText (linesFormatted, line - 1, 1, TabWidth) : 0;
+                    int firstLineWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, 1, TabWidth);
+                    int lastLineWidth = GetColumnsRequiredForVerticalText (linesFormatted, linesFormatted.Count - 1, 1, TabWidth);
+                    var interval = (int)Math.Round ((double)(screen.Width + firstLineWidth + lastLineWidth) / linesFormatted.Count);
+
+                    x = line == 0
+                            ? screen.Left
+                            : line < linesFormatted.Count - 1
+                                ? screen.Width - runesWidth <= lastLineWidth ? screen.Left + prevLineWidth : screen.Left + line * interval
+                                : screen.Right - lastLineWidth;
+                }
+                else
+                {
+                    x = screen.Left;
+                }
+
+                CursorPosition = _hotKeyPos > -1 ? _hotKeyPos : 0;
+            }
+            else if (Alignment is TextAlignment.Centered)
+            {
+                if (isVertical)
+                {
+                    int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, linesFormatted.Count, TabWidth);
+                    int linesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, line, TabWidth);
+                    x = screen.Left + linesWidth + (screen.Width - runesWidth) / 2;
 
                     CursorPosition = (screen.Width - runesWidth) / 2 + (_hotKeyPos > -1 ? _hotKeyPos : 0);
                 }
@@ -354,7 +399,7 @@ public class TextFormatter
             }
 
             // Vertical Alignment
-            if (VerticalAlignment == VerticalTextAlignment.Bottom || (VerticalAlignment == VerticalTextAlignment.Justified && !IsTopToBottom (Direction)))
+            if (VerticalAlignment is VerticalTextAlignment.Bottom)
             {
                 if (isVertical)
                 {
@@ -365,7 +410,7 @@ public class TextFormatter
                     y = screen.Bottom - linesFormatted.Count + line;
                 }
             }
-            else if (VerticalAlignment is VerticalTextAlignment.Top or VerticalTextAlignment.Justified)
+            else if (VerticalAlignment is VerticalTextAlignment.Top)
             {
                 if (isVertical)
                 {
@@ -376,7 +421,21 @@ public class TextFormatter
                     y = screen.Top + line;
                 }
             }
-            else if (VerticalAlignment == VerticalTextAlignment.Middle)
+            else if (VerticalAlignment is VerticalTextAlignment.Justified)
+            {
+                if (isVertical)
+                {
+                    y = screen.Top;
+                }
+                else
+                {
+                    var interval = (int)Math.Round ((double)(screen.Height + 2) / linesFormatted.Count);
+
+                    y = line == 0 ? screen.Top :
+                        line < linesFormatted.Count - 1 ? screen.Height - interval <= 1 ? screen.Top + 1 : screen.Top + line * interval : screen.Bottom - 1;
+                }
+            }
+            else if (VerticalAlignment is VerticalTextAlignment.Middle)
             {
                 if (isVertical)
                 {
@@ -410,7 +469,10 @@ public class TextFormatter
 
                 if (lastZeroWidthPos is null)
                 {
-                    if (idx < 0 || x + current + colOffset < 0)
+                    if (idx < 0
+                        || (isVertical
+                                ? VerticalAlignment != VerticalTextAlignment.Bottom && current < 0
+                                : Alignment != TextAlignment.Right && x + current + colOffset < 0))
                     {
                         current++;
 
@@ -422,8 +484,8 @@ public class TextFormatter
                         break;
                     }
 
-                    if ((!isVertical && current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset)
-                        || (isVertical && idx > maxScreen.Top + maxScreen.Height - screen.Y))
+                    if ((!isVertical && (current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset || (idx < runes.Length && runes [idx].GetColumns () > screen.Width)))
+                        || (isVertical && ((current > start + size + zeroLengthCount && idx > maxScreen.Top + maxScreen.Height - screen.Y) || (idx < runes.Length && runes [idx].GetColumns () > screen.Width))))
                     {
                         break;
                     }
@@ -600,7 +662,7 @@ public class TextFormatter
     /// <remarks>
     ///     <para>
     ///         If the text needs to be formatted (if <see cref="NeedsFormat"/> is <see langword="true"/>)
-    ///         <see cref="Format(string, int, bool, bool, bool, int, TextDirection, bool)"/> will be called and upon return
+    ///         <see cref="Format()"/> will be called and upon return
     ///         <see cref="NeedsFormat"/> will be <see langword="false"/>.
     ///     </para>
     ///     <para>
@@ -642,7 +704,8 @@ public class TextFormatter
                                  PreserveTrailingSpaces,
                                  TabWidth,
                                  Direction,
-                                 MultiLine
+                                 MultiLine,
+                                 this
                                 );
 
                 if (!AutoSize)
@@ -665,7 +728,8 @@ public class TextFormatter
                                  PreserveTrailingSpaces,
                                  TabWidth,
                                  Direction,
-                                 MultiLine
+                                 MultiLine,
+                                 this
                                 );
 
                 if (!AutoSize && _lines.Count > Size.Height)
@@ -932,6 +996,7 @@ public class TextFormatter
     /// </param>
     /// <param name="tabWidth">The number of columns used for a tab.</param>
     /// <param name="textDirection">The text direction.</param>
+    /// <param name="textFormatter"><see cref="TextFormatter"/> instance to access any of his objects.</param>
     /// <returns>A list of word wrapped lines.</returns>
     /// <remarks>
     ///     <para>This method does not do any justification.</para>
@@ -947,7 +1012,8 @@ public class TextFormatter
         int width,
         bool preserveTrailingSpaces = false,
         int tabWidth = 0,
-        TextDirection textDirection = TextDirection.LeftRight_TopBottom
+        TextDirection textDirection = TextDirection.LeftRight_TopBottom,
+        TextFormatter textFormatter = null
     )
     {
         if (width < 0)
@@ -955,7 +1021,6 @@ public class TextFormatter
             throw new ArgumentOutOfRangeException ($"{nameof (width)} cannot be negative.");
         }
 
-        int start = 0, end;
         List<string> lines = new ();
 
         if (string.IsNullOrEmpty (text))
@@ -965,6 +1030,13 @@ public class TextFormatter
 
         List<Rune> runes = StripCRLF (text).ToRuneList ();
 
+        int start = Math.Max (
+                              !runes.Contains ((Rune)' ') && textFormatter is { VerticalAlignment: VerticalTextAlignment.Bottom } && IsVerticalDirection (textDirection)
+                                  ? runes.Count - width
+                                  : 0,
+                              0);
+        int end;
+
         if (preserveTrailingSpaces)
         {
             while ((end = start) < runes.Count)
@@ -997,7 +1069,8 @@ public class TextFormatter
                               + GetLengthThatFits (
                                                    runes.GetRange (start, runes.Count - start),
                                                    width,
-                                                   tabWidth
+                                                   tabWidth,
+                                                   textDirection
                                                   ))
                        < runes.Count)
                 {
@@ -1012,13 +1085,15 @@ public class TextFormatter
                               + GetLengthThatFits (
                                                    runes.GetRange (end, runes.Count - end),
                                                    width,
-                                                   tabWidth
+                                                   tabWidth,
+                                                   textDirection
                                                   );
                     }
 
                     var str = StringExtensions.ToString (runes.GetRange (start, end - start));
+                    int zeroLength = text.EnumerateRunes ().Sum (r => r.GetColumns () == 0 ? 1 : 0);
 
-                    if (end > start && GetRuneWidth (str, tabWidth) <= width)
+                    if (end > start && GetRuneWidth (str, tabWidth, textDirection) <= width + zeroLength)
                     {
                         lines.Add (str);
                         start = end;
@@ -1177,16 +1252,18 @@ public class TextFormatter
     /// <param name="talign">Alignment.</param>
     /// <param name="textDirection">The text direction.</param>
     /// <param name="tabWidth">The number of columns used for a tab.</param>
+    /// <param name="textFormatter"><see cref="TextFormatter"/> instance to access any of his objects.</param>
     /// <returns>Justified and clipped text.</returns>
     public static string ClipAndJustify (
         string text,
         int width,
         TextAlignment talign,
         TextDirection textDirection = TextDirection.LeftRight_TopBottom,
-        int tabWidth = 0
+        int tabWidth = 0,
+        TextFormatter textFormatter = null
     )
     {
-        return ClipAndJustify (text, width, talign == TextAlignment.Justified, textDirection, tabWidth);
+        return ClipAndJustify (text, width, talign == TextAlignment.Justified, textDirection, tabWidth, textFormatter);
     }
 
     /// <summary>Justifies text within a specified width.</summary>
@@ -1198,13 +1275,15 @@ public class TextFormatter
     /// <param name="justify">Justify.</param>
     /// <param name="textDirection">The text direction.</param>
     /// <param name="tabWidth">The number of columns used for a tab.</param>
+    /// <param name="textFormatter"><see cref="TextFormatter"/> instance to access any of his objects.</param>
     /// <returns>Justified and clipped text.</returns>
     public static string ClipAndJustify (
         string text,
         int width,
         bool justify,
         TextDirection textDirection = TextDirection.LeftRight_TopBottom,
-        int tabWidth = 0
+        int tabWidth = 0,
+        TextFormatter textFormatter = null
     )
     {
         if (width < 0)
@@ -1219,20 +1298,39 @@ public class TextFormatter
 
         text = ReplaceTABWithSpaces (text, tabWidth);
         List<Rune> runes = text.ToRuneList ();
+        int zeroLength = runes.Sum (r => r.GetColumns () == 0 ? 1 : 0);
 
-        if (runes.Count > width)
+        if (runes.Count - zeroLength > width)
         {
             if (IsHorizontalDirection (textDirection))
             {
-                return StringExtensions.ToString (
-                                                  runes.GetRange (
-                                                                  0,
-                                                                  GetLengthThatFits (text, width, tabWidth)
-                                                                 )
-                                                 );
+                if (textFormatter is { Alignment: TextAlignment.Right })
+                {
+                    return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection);
+                }
+
+                if (textFormatter is { Alignment: TextAlignment.Centered })
+                {
+                    return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+                }
+
+                return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection);
             }
 
-            int zeroLength = runes.Sum (r => r.GetColumns () == 0 ? 1 : 0);
+            if (IsVerticalDirection (textDirection))
+            {
+                if (textFormatter is { VerticalAlignment: VerticalTextAlignment.Bottom })
+                {
+                    return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection);
+                }
+
+                if (textFormatter is { VerticalAlignment: VerticalTextAlignment.Middle })
+                {
+                    return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+                }
+
+                return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection);
+            }
 
             return StringExtensions.ToString (runes.GetRange (0, width + zeroLength));
         }
@@ -1242,19 +1340,57 @@ public class TextFormatter
             return Justify (text, width, ' ', textDirection, tabWidth);
         }
 
-        if (IsHorizontalDirection (textDirection) && GetRuneWidth (text, tabWidth) > width)
+        if (IsHorizontalDirection (textDirection))
         {
-            return StringExtensions.ToString (
-                                              runes.GetRange (
-                                                              0,
-                                                              GetLengthThatFits (text, width, tabWidth)
-                                                             )
-                                             );
+            if (textFormatter is { Alignment: TextAlignment.Right })
+            {
+                if (GetRuneWidth (text, tabWidth, textDirection) > width)
+                {
+                    return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection);
+                }
+            }
+            else if (textFormatter is { Alignment: TextAlignment.Centered })
+            {
+                return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+            }
+            else if (GetRuneWidth (text, tabWidth, textDirection) > width)
+            {
+                return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection);
+            }
+        }
+
+        if (IsVerticalDirection (textDirection))
+        {
+            if (textFormatter is { VerticalAlignment: VerticalTextAlignment.Bottom })
+            {
+                if (runes.Count - zeroLength > width)
+                {
+                    return GetRangeThatFits (runes, runes.Count - width, text, width, tabWidth, textDirection);
+                }
+            }
+            else if (textFormatter is { VerticalAlignment: VerticalTextAlignment.Middle })
+            {
+                return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+            }
+            else if (runes.Count - zeroLength > width)
+            {
+                return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection);
+            }
         }
 
         return text;
     }
 
+    private static string GetRangeThatFits (List<Rune> runes, int index, string text, int width, int tabWidth, TextDirection textDirection)
+    {
+        return StringExtensions.ToString (
+                                          runes.GetRange (
+                                                          Math.Max (index, 0),
+                                                          GetLengthThatFits (text, width, tabWidth, textDirection)
+                                                         )
+                                         );
+    }
+
     /// <summary>
     ///     Justifies the text to fill the width provided. Space will be added between words to make the text just fit
     ///     <c>width</c>. Spaces will not be added to the start or end.
@@ -1289,7 +1425,7 @@ public class TextFormatter
 
         if (IsHorizontalDirection (textDirection))
         {
-            textCount = words.Sum (arg => GetRuneWidth (arg, tabWidth));
+            textCount = words.Sum (arg => GetRuneWidth (arg, tabWidth, textDirection));
         }
         else
         {
@@ -1352,6 +1488,7 @@ public class TextFormatter
     /// <param name="tabWidth">The number of columns used for a tab.</param>
     /// <param name="textDirection">The text direction.</param>
     /// <param name="multiLine">If <see langword="true"/> new lines are allowed.</param>
+    /// <param name="textFormatter"><see cref="TextFormatter"/> instance to access any of his objects.</param>
     /// <returns>A list of word wrapped lines.</returns>
     /// <remarks>
     ///     <para>An empty <paramref name="text"/> string will result in one empty line.</para>
@@ -1366,7 +1503,8 @@ public class TextFormatter
         bool preserveTrailingSpaces = false,
         int tabWidth = 0,
         TextDirection textDirection = TextDirection.LeftRight_TopBottom,
-        bool multiLine = false
+        bool multiLine = false,
+        TextFormatter textFormatter = null
     )
     {
         return Format (
@@ -1377,7 +1515,8 @@ public class TextFormatter
                        preserveTrailingSpaces,
                        tabWidth,
                        textDirection,
-                       multiLine
+                       multiLine,
+                       textFormatter
                       );
     }
 
@@ -1397,6 +1536,7 @@ public class TextFormatter
     /// <param name="tabWidth">The number of columns used for a tab.</param>
     /// <param name="textDirection">The text direction.</param>
     /// <param name="multiLine">If <see langword="true"/> new lines are allowed.</param>
+    /// <param name="textFormatter"><see cref="TextFormatter"/> instance to access any of his objects.</param>
     /// <returns>A list of word wrapped lines.</returns>
     /// <remarks>
     ///     <para>An empty <paramref name="text"/> string will result in one empty line.</para>
@@ -1411,7 +1551,8 @@ public class TextFormatter
         bool preserveTrailingSpaces = false,
         int tabWidth = 0,
         TextDirection textDirection = TextDirection.LeftRight_TopBottom,
-        bool multiLine = false
+        bool multiLine = false,
+        TextFormatter textFormatter = null
     )
     {
         if (width < 0)
@@ -1457,16 +1598,17 @@ public class TextFormatter
 
                 foreach (string line in lines)
                 {
-                    lineResult.Add (ClipAndJustify (line, width, justify, textDirection, tabWidth));
+
+                    lineResult.Add (ClipAndJustify (PerformCorrectFormatDirection (textDirection, line), width, justify, textDirection, tabWidth, textFormatter));
                 }
 
-                return lineResult;
+                return PerformCorrectFormatDirection (textDirection, lineResult);
             }
 
             text = ReplaceCRLFWithSpace (text);
-            lineResult.Add (ClipAndJustify (text, width, justify, textDirection, tabWidth));
+            lineResult.Add (ClipAndJustify (PerformCorrectFormatDirection (textDirection, text), width, justify, textDirection, tabWidth, textFormatter));
 
-            return lineResult;
+            return PerformCorrectFormatDirection (textDirection, lineResult);
         }
 
         List<Rune> runes = StripCRLF (text, true).ToRuneList ();
@@ -1481,11 +1623,12 @@ public class TextFormatter
             {
                 List<string> wrappedLines =
                     WordWrapText (
-                                  StringExtensions.ToString (runes.GetRange (lp, i - lp)),
+                                  StringExtensions.ToString (PerformCorrectFormatDirection (textDirection, runes.GetRange (lp, i - lp))),
                                   width,
                                   preserveTrailingSpaces,
                                   tabWidth,
-                                  textDirection
+                                  textDirection,
+                                  textFormatter
                                  );
 
                 foreach (string line in wrappedLines)
@@ -1503,87 +1646,66 @@ public class TextFormatter
         }
 
         foreach (string line in WordWrapText (
-                                              StringExtensions.ToString (runes.GetRange (lp, runeCount - lp)),
+                                              StringExtensions.ToString (PerformCorrectFormatDirection (textDirection, runes.GetRange (lp, runeCount - lp))),
                                               width,
                                               preserveTrailingSpaces,
                                               tabWidth,
-                                              textDirection
+                                              textDirection,
+                                              textFormatter
                                              ))
         {
             lineResult.Add (ClipAndJustify (line, width, justify, textDirection, tabWidth));
         }
 
-        return lineResult;
+        return PerformCorrectFormatDirection (textDirection, lineResult);
     }
 
-    /// <summary>Returns the number of lines needed to render the specified text given the width.</summary>
-    /// <remarks>Calls <see cref="Format()"/>.</remarks>
-    /// <returns>Number of lines.</returns>
-    /// <param name="text">Text, may contain newlines.</param>
-    /// <param name="width">The minimum width for the text.</param>
-    public static int GetLineCount (string text, int width)
+    private static string PerformCorrectFormatDirection (TextDirection textDirection, string line)
     {
-        List<string> result = Format (text, width, false, true);
-
-        return result.Count;
+        return textDirection switch
+               {
+                   TextDirection.RightLeft_BottomTop
+                       or TextDirection.RightLeft_TopBottom
+                       or TextDirection.BottomTop_LeftRight
+                       or TextDirection.BottomTop_RightLeft => StringExtensions.ToString (line.EnumerateRunes ().Reverse ()),
+                   _ => line
+               };
     }
 
-    /// <summary>
-    ///     Returns the maximum number of columns needed to render the text (single line or multiple lines, word wrapped)
-    ///     given a number of columns to constrain the text to.
-    /// </summary>
-    /// <remarks>
-    ///     Calls <see cref="Format()"/>. This API will return incorrect results if the text includes glyphs who's width
-    ///     is dependent on surrounding glyphs (e.g. Arabic).
-    /// </remarks>
-    /// <returns>Width of the longest line after formatting the text constrained by <paramref name="maxColumns"/>.</returns>
-    /// <param name="text">Text, may contain newlines.</param>
-    /// <param name="maxColumns">The number of columns to constrain the text to for formatting.</param>
-    /// <param name="tabWidth">The number of columns used for a tab.</param>
-    public static int GetWidestLineLength (string text, int maxColumns, int tabWidth = 0)
+    private static List<Rune> PerformCorrectFormatDirection (TextDirection textDirection, List<Rune> runes)
     {
-        List<string> result = Format (text, maxColumns, false, true);
-        var max = 0;
-
-        result.ForEach (
-                        s =>
-                        {
-                            var m = 0;
-                            s.ToRuneList ().ForEach (r => m += GetRuneWidth (r, tabWidth));
-
-                            if (m > max)
-                            {
-                                max = m;
-                            }
-                        }
-                       );
+        return PerformCorrectFormatDirection (textDirection, StringExtensions.ToString (runes)).ToRuneList ();
+    }
 
-        return max;
+    private static List<string> PerformCorrectFormatDirection (TextDirection textDirection, List<string> lines)
+    {
+        return textDirection switch
+               {
+                   TextDirection.TopBottom_RightLeft
+                       or TextDirection.LeftRight_BottomTop
+                       or TextDirection.RightLeft_BottomTop
+                       or TextDirection.BottomTop_RightLeft => lines.ToArray ().Reverse ().ToList (),
+                   _ => lines
+               };
     }
 
-    /// <summary>
-    ///     Returns the number of columns in the widest line in the text, without word wrap, accounting for wide-glyphs
-    ///     (uses <see cref="StringExtensions.GetColumns"/>). <paramref name="text"/> if it contains newlines.
-    /// </summary>
-    /// <remarks>
-    ///     This API will return incorrect results if the text includes glyphs who's width is dependent on surrounding
-    ///     glyphs (e.g. Arabic).
-    /// </remarks>
+    /// <summary>Returns the number of lines needed to render the specified text given the width.</summary>
+    /// <remarks>Calls <see cref="Format()"/>.</remarks>
+    /// <returns>Number of lines.</returns>
     /// <param name="text">Text, may contain newlines.</param>
-    /// <param name="tabWidth">The number of columns used for a tab.</param>
-    /// <returns>The length of the longest line.</returns>
-    public static int GetWidestLineLength (string text, int tabWidth = 0)
+    /// <param name="width">The minimum width for the text.</param>
+    public static int GetLineCount (string text, int width)
     {
-        List<string> result = SplitNewLine (text);
+        List<string> result = Format (text, width, false, true);
 
-        return result.Max (x => GetRuneWidth (x, tabWidth));
+        return result.Count;
     }
 
     /// <summary>
     ///     Returns the number of columns required to render <paramref name="lines"/> oriented vertically.
     /// </summary>
     /// <remarks>
-    ///     This API will return incorrect results if the text includes glyphs who's width is dependent on surrounding
+    ///     This API will return incorrect results if the text includes glyphs whose width is dependent on surrounding
     ///     glyphs (e.g. Arabic).
     /// </remarks>
     /// <param name="lines">The lines.</param>
@@ -1605,16 +1727,32 @@ public class TextFormatter
              i++)
         {
             string runes = lines [i];
-
             if (runes.Length > 0)
             {
                 max += runes.EnumerateRunes ().Max (r => GetRuneWidth (r, tabWidth));
             }
         }
-
         return max;
     }
 
+    /// <summary>
+    ///     Returns the number of columns in the widest line in the text, without word wrap, accounting for wide-glyphs
+    ///     (uses <see cref="StringExtensions.GetColumns"/>). <paramref name="text"/> if it contains newlines.
+    /// </summary>
+    /// <remarks>
+    ///     This API will return incorrect results if the text includes glyphs who's width is dependent on surrounding
+    ///     glyphs (e.g. Arabic).
+    /// </remarks>
+    /// <param name="text">Text, may contain newlines.</param>
+    /// <param name="tabWidth">The number of columns used for a tab.</param>
+    /// <returns>The length of the longest line.</returns>
+    public static int GetWidestLineLength (string text, int tabWidth = 0)
+    {
+        List<string> result = SplitNewLine (text);
+
+        return result.Max (x => GetRuneWidth (x, tabWidth));
+    }
+
     /// <summary>
     ///     Gets the maximum number of columns from the text based on the <paramref name="startIndex"/> and the
     ///     <paramref name="length"/>.
@@ -1643,27 +1781,32 @@ public class TextFormatter
         return max;
     }
 
-    /// <summary>Gets the number of the Runes in the text that will fit in <paramref name="columns"/>.</summary>
+    /// <summary>Gets the number of the Runes in the text that will fit in <paramref name="width"/>.</summary>
     /// <remarks>
     ///     This API will return incorrect results if the text includes glyphs who's width is dependent on surrounding
     ///     glyphs (e.g. Arabic).
     /// </remarks>
     /// <param name="text">The text.</param>
-    /// <param name="columns">The width.</param>
-    /// <param name="tabWidth">The number of columns used for a tab.</param>
+    /// <param name="width">The width.</param>
+    /// <param name="tabWidth">The width used for a tab.</param>
+    /// <param name="textDirection">The text direction.</param>
     /// <returns>The index of the text that fit the width.</returns>
-    public static int GetLengthThatFits (string text, int columns, int tabWidth = 0) { return GetLengthThatFits (text?.ToRuneList (), columns, tabWidth); }
+    public static int GetLengthThatFits (string text, int width, int tabWidth = 0, TextDirection textDirection = TextDirection.LeftRight_TopBottom)
+    {
+        return GetLengthThatFits (text?.ToRuneList (), width, tabWidth, textDirection);
+    }
 
-    /// <summary>Gets the number of the Runes in a list of Runes that will fit in <paramref name="columns"/>.</summary>
+    /// <summary>Gets the number of the Runes in a list of Runes that will fit in <paramref name="width"/>.</summary>
     /// <remarks>
     ///     This API will return incorrect results if the text includes glyphs who's width is dependent on surrounding
     ///     glyphs (e.g. Arabic).
     /// </remarks>
     /// <param name="runes">The list of runes.</param>
-    /// <param name="columns">The width.</param>
-    /// <param name="tabWidth">The number of columns used for a tab.</param>
-    /// <returns>The index of the last Rune in <paramref name="runes"/> that fit in <paramref name="columns"/>.</returns>
-    public static int GetLengthThatFits (List<Rune> runes, int columns, int tabWidth = 0)
+    /// <param name="width">The width.</param>
+    /// <param name="tabWidth">The width used for a tab.</param>
+    /// <param name="textDirection">The text direction.</param>
+    /// <returns>The index of the last Rune in <paramref name="runes"/> that fit in <paramref name="width"/>.</returns>
+    public static int GetLengthThatFits (List<Rune> runes, int width, int tabWidth = 0, TextDirection textDirection = TextDirection.LeftRight_TopBottom)
     {
         if (runes is null || runes.Count == 0)
         {
@@ -1675,9 +1818,9 @@ public class TextFormatter
 
         for (; runeIdx < runes.Count; runeIdx++)
         {
-            int runeWidth = GetRuneWidth (runes [runeIdx], tabWidth);
+            int runeWidth = GetRuneWidth (runes [runeIdx], tabWidth, textDirection);
 
-            if (runesLength + runeWidth > columns)
+            if (runesLength + runeWidth > width)
             {
                 break;
             }
@@ -1688,12 +1831,12 @@ public class TextFormatter
         return runeIdx;
     }
 
-    private static int GetRuneWidth (string str, int tabWidth) { return GetRuneWidth (str.EnumerateRunes ().ToList (), tabWidth); }
-    private static int GetRuneWidth (List<Rune> runes, int tabWidth) { return runes.Sum (r => GetRuneWidth (r, tabWidth)); }
+    private static int GetRuneWidth (string str, int tabWidth, TextDirection textDirection = TextDirection.LeftRight_TopBottom) { return GetRuneWidth (str.EnumerateRunes ().ToList (), tabWidth, textDirection); }
+    private static int GetRuneWidth (List<Rune> runes, int tabWidth, TextDirection textDirection = TextDirection.LeftRight_TopBottom) { return runes.Sum (r => GetRuneWidth (r, tabWidth, textDirection)); }
 
-    private static int GetRuneWidth (Rune rune, int tabWidth)
+    private static int GetRuneWidth (Rune rune, int tabWidth, TextDirection textDirection = TextDirection.LeftRight_TopBottom)
     {
-        int runeWidth = rune.GetColumns ();
+        int runeWidth = IsHorizontalDirection (textDirection) ? rune.GetColumns () : 1;
 
         if (rune.Value == '\t')
         {
@@ -2039,4 +2182,4 @@ public class TextFormatter
     }
 
     #endregion // Static Members
-}
+}

+ 9 - 7
Terminal.Gui/View/Adornment/Adornment.cs

@@ -135,7 +135,10 @@ public class Adornment : View
     }
 
     /// <inheritdoc/>
-    public override Point ScreenToFrame (int x, int y) { return Parent.ScreenToFrame (x - Frame.X, y - Frame.Y); }
+    public override Point ScreenToFrame (in Point location)
+    {
+        return Parent.ScreenToFrame (new (location.X - Frame.X, location.Y - Frame.Y));
+    }
 
     /// <summary>Does nothing for Adornment</summary>
     /// <returns></returns>
@@ -206,12 +209,11 @@ public class Adornment : View
     /// Indicates whether the specified Parent's SuperView-relative coordinates are within the Adornment's Thickness.
     /// </summary>
     /// <remarks>
-    ///     The <paramref name="x"/> and <paramref name="x"/> are relative to the PARENT's SuperView.
+    ///     The <paramref name="location"/> is relative to the PARENT's SuperView.
     /// </remarks>
-    /// <param name="x"></param>
-    /// <param name="y"></param>
+    /// <param name="location"></param>
     /// <returns><see langword="true"/> if the specified Parent's SuperView-relative coordinates are within the Adornment's Thickness. </returns>
-    public override bool Contains (int x, int y)
+    public override bool Contains (in Point location)
     {
         if (Parent is null)
         {
@@ -221,7 +223,7 @@ public class Adornment : View
         Rectangle frame = Frame;
         frame.Offset (Parent.Frame.Location);
 
-        return Thickness.Contains (frame, x, y);
+        return Thickness.Contains (frame, location);
     }
 
     /// <inheritdoc/>
@@ -244,7 +246,7 @@ public class Adornment : View
     protected internal override bool OnMouseLeave (MouseEvent mouseEvent)
     {
         // Invert Normal
-        if (Diagnostics.HasFlag (ViewDiagnosticFlags.MouseEnter) && ColorScheme != null)
+        if (Diagnostics.FastHasFlags (ViewDiagnosticFlags.MouseEnter) && ColorScheme != null)
         {
             var cs = new ColorScheme (ColorScheme)
             {

+ 5 - 5
Terminal.Gui/View/Adornment/Border.cs

@@ -273,11 +273,11 @@ public class Border : Adornment
 
             // Only start grabbing if the user clicks in the Thickness area
             // Adornment.Contains takes Parent SuperView=relative coords.
-            if (Contains (mouseEvent.X + Parent.Frame.X + Frame.X, mouseEvent.Y + Parent.Frame.Y + Frame.Y))
+            if (Contains (new (mouseEvent.Position.X + Parent.Frame.X + Frame.X, mouseEvent.Position.Y + Parent.Frame.Y + Frame.Y)))
             {
                 // Set the start grab point to the Frame coords
-                _startGrabPoint = new (mouseEvent.X + Frame.X, mouseEvent.Y + Frame.Y);
-                _dragPosition = new (mouseEvent.X, mouseEvent.Y);
+                _startGrabPoint = new (mouseEvent.Position.X + Frame.X, mouseEvent.Position.Y + Frame.Y);
+                _dragPosition = mouseEvent.Position;
                 Application.GrabMouse (this);
                 SetHighlight (HighlightStyle);
             }
@@ -299,9 +299,9 @@ public class Border : Adornment
                     Parent.SuperView.SetNeedsDisplay ();
                 }
 
-                _dragPosition = new Point (mouseEvent.X, mouseEvent.Y);
+                _dragPosition = mouseEvent.Position;
 
-                Point parentLoc = Parent.SuperView?.ScreenToViewport (mouseEvent.ScreenPosition.X, mouseEvent.ScreenPosition.Y) ?? mouseEvent.ScreenPosition;
+                Point parentLoc = Parent.SuperView?.ScreenToViewport (new (mouseEvent.ScreenPosition.X, mouseEvent.ScreenPosition.Y)) ?? mouseEvent.ScreenPosition;
 
                 GetLocationEnsuringFullVisibility (
                                      Parent,

+ 323 - 47
Terminal.Gui/View/Layout/PosDim.cs

@@ -1,4 +1,4 @@
-using static Terminal.Gui.Dialog;
+using System.Diagnostics;
 
 namespace Terminal.Gui;
 
@@ -339,14 +339,27 @@ public class Pos
     ///     height for y-coordinate calculation.
     /// </param>
     /// <param name="dim">The dimension of the View. It could be the current width or height.</param>
-    /// <param name="autosize">Obsolete; to be deprecated.</param>
-    /// <param name="autoSize">Obsolete; to be deprecated.</param>
+    /// <param name="us">The View that holds this Pos object.</param>
+    /// <param name="dimension">Width or Height</param>
     /// <returns>
     ///     The calculated position of the View. The way this position is calculated depends on the specific subclass of Pos
     ///     that
     ///     is used.
     /// </returns>
-    internal virtual int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize) { return Anchor (superviewDimension); }
+    internal virtual int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension)
+    {
+        return Anchor (superviewDimension);
+    }
+
+
+    /// <summary>
+    /// Diagnostics API to determine if this Pos object references other views.
+    /// </summary>
+    /// <returns></returns>
+    internal virtual bool ReferencesOtherViews ()
+    {
+        return false;
+    }
 
     internal class PosAbsolute (int n) : Pos
     {
@@ -382,7 +395,7 @@ public class Pos
             return width - _offset;
         }
 
-        internal override int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize)
+        internal override int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension)
         {
             int newLocation = Anchor (superviewDimension);
 
@@ -400,9 +413,9 @@ public class Pos
         public override string ToString () { return "Center"; }
         internal override int Anchor (int width) { return width / 2; }
 
-        internal override int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize)
+        internal override int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension)
         {
-            int newDimension = Math.Max (dim.Calculate (0, superviewDimension, autosize, autoSize), 0);
+            int newDimension = Math.Max (dim.Calculate (0, superviewDimension, us, dimension), 0);
 
             return Anchor (superviewDimension - newDimension);
         }
@@ -428,11 +441,11 @@ public class Pos
             return la - ra;
         }
 
-        internal override int Calculate (int superviewDimension, Dim dim, int autosize, bool autoSize)
+        internal override int Calculate (int superviewDimension, Dim dim, View us, Dim.Dimension dimension)
         {
-            int newDimension = dim.Calculate (0, superviewDimension, autosize, autoSize);
-            int left = _left.Calculate (superviewDimension, dim, autosize, autoSize);
-            int right = _right.Calculate (superviewDimension, dim, autosize, autoSize);
+            int newDimension = dim.Calculate (0, superviewDimension, us, dimension);
+            int left = _left.Calculate (superviewDimension, dim, us, dimension);
+            int right = _right.Calculate (superviewDimension, dim, us, dimension);
 
             if (_add)
             {
@@ -441,6 +454,25 @@ public class Pos
 
             return left - right;
         }
+
+        /// <summary>
+        /// Diagnostics API to determine if this Pos object references other views.
+        /// </summary>
+        /// <returns></returns>
+        internal override bool ReferencesOtherViews ()
+        {
+            if (_left.ReferencesOtherViews ())
+            {
+                return true;
+            }
+
+            if (_right.ReferencesOtherViews ())
+            {
+                return true;
+            }
+
+            return false;
+        }
     }
 
     internal class PosFactor (float factor) : Pos
@@ -525,6 +557,15 @@ public class Pos
                 _ => 0
             };
         }
+
+        /// <summary>
+        /// Diagnostics API to determine if this Pos object references other views.
+        /// </summary>
+        /// <returns></returns>
+        internal override bool ReferencesOtherViews ()
+        {
+            return true;
+        }
     }
 }
 
@@ -548,6 +589,15 @@ public class Pos
 ///             </listheader>
 ///             <item>
 ///                 <term>
+///                     <see cref="Dim.Auto"/>
+///                 </term>
+///                 <description>
+///                     Creates a <see cref="Dim"/> object that automatically sizes the view to fit
+///                     the view's Text, SubViews, or ContentArea.
+///                 </description>
+///             </item>
+///             <item>
+///                 <term>
 ///                     <see cref="Dim.Function(Func{int})"/>
 ///                 </term>
 ///                 <description>
@@ -597,6 +647,104 @@ public class Pos
 /// </remarks>
 public class Dim
 {
+    /// <summary>
+    ///     Specifies how <see cref="DimAuto"/> will compute the dimension.
+    /// </summary>
+    [Flags]
+    public enum DimAutoStyle
+    {
+        /// <summary>
+        ///     The dimension will be computed using both the view's <see cref="View.Text"/> and
+        ///     <see cref="View.Subviews"/> (whichever is larger).
+        /// </summary>
+        Auto = Content | Text,
+
+        /// <summary>
+        ///     The dimensions will be computed based on the View's non-Text content.
+        /// <para>
+        ///     If <see cref="View.ContentSize"/> is explicitly set (is not <see langword="null"/>) then <see cref="View.ContentSize"/>
+        ///     will be used to determine the dimension.
+        /// </para>
+        /// <para>
+        ///     Otherwise, the Subview in <see cref="View.Subviews"/> with the largest corresponding position plus dimension
+        ///     will determine the dimension.
+        /// </para>
+        /// <para>
+        ///     The corresponding dimension of the view's <see cref="View.Text"/> will be ignored.
+        /// </para>
+        /// </summary>
+        Content = 1,
+
+        /// <summary>
+        /// <para>
+        ///     The corresponding dimension of the view's <see cref="View.Text"/>, formatted using the
+        ///     <see cref="View.TextFormatter"/> settings,
+        ///     will be used to determine the dimension.
+        /// </para>
+        /// <para>
+        ///     The corresponding dimensions of the <see cref="View.Subviews"/> will be ignored.
+        /// </para>
+        /// </summary>
+        Text = 2
+    }
+
+
+    /// <summary>
+    /// 
+    /// </summary>
+    public enum Dimension
+    {
+        /// <summary>
+        /// No dimension specified.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// The height dimension.
+        /// </summary>
+        Height = 1,
+
+        /// <summary>
+        /// The width dimension.
+        /// </summary>
+        Width = 2
+    }
+
+
+    /// <summary>
+    ///     Creates a <see cref="Dim"/> object that automatically sizes the view to fit all the view's SubViews and/or Text.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         See <see cref="DimAutoStyle"/>.
+    ///     </para>
+    /// </remarks>
+    /// <example>
+    ///     This initializes a <see cref="View"/> with two SubViews. The view will be automatically sized to fit the two
+    ///     SubViews.
+    /// <code>
+    /// var button = new Button () { Text = "Click Me!", X = 1, Y = 1, Width = 10, Height = 1 };
+    /// var textField = new TextField { Text = "Type here", X = 1, Y = 2, Width = 20, Height = 1 };
+    /// var view = new Window () { Title = "MyWindow", X = 0, Y = 0, Width = Dim.Auto (), Height = Dim.Auto () };
+    /// view.Add (button, textField);
+    /// </code>
+    /// </example>
+    /// <returns>The <see cref="Dim"/> object.</returns>
+    /// <param name="style">
+    ///     Specifies how <see cref="DimAuto"/> will compute the dimension. The default is <see cref="DimAutoStyle.Auto"/>.
+    /// </param>
+    /// <param name="min">Specifies the minimum dimension that view will be automatically sized to.</param>
+    /// <param name="max">Specifies the maximum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.</param>
+    public static Dim Auto (DimAutoStyle style = DimAutoStyle.Auto, Dim min = null, Dim max = null)
+    {
+        if (max != null)
+        {
+            throw new NotImplementedException (@"max is not implemented");
+        }
+
+        return new DimAuto (style, min, max);
+    }
+
     /// <summary>Determines whether the specified object is equal to the current object.</summary>
     /// <param name="other">The object to compare with the current object. </param>
     /// <returns>
@@ -727,24 +875,31 @@ public class Dim
 
     /// <summary>
     ///     Calculates and returns the dimension of a <see cref="View"/> object. It takes into account the location of the
-    ///     <see cref="View"/>, its current size, and whether it should automatically adjust its size based on its content.
+    ///     <see cref="View"/>, it's SuperView's ContentSize, and whether it should automatically adjust its size based on its content.
     /// </summary>
     /// <param name="location">
     ///     The starting point from where the size calculation begins. It could be the left edge for width calculation or the
     ///     top edge for height calculation.
     /// </param>
-    /// <param name="dimension">The current size of the View. It could be the current width or height.</param>
-    /// <param name="autosize">Obsolete; To be deprecated.</param>
-    /// <param name="autoSize">Obsolete; To be deprecated.</param>
+    /// <param name="superviewContentSize">The size of the SuperView's content. It could be width or height.</param>
+    /// <param name="us">The View that holds this Pos object.</param>
+    /// <param name="dimension">Width or Height</param>
     /// <returns>
     ///     The calculated size of the View. The way this size is calculated depends on the specific subclass of Dim that
     ///     is used.
     /// </returns>
-    internal virtual int Calculate (int location, int dimension, int autosize, bool autoSize)
+    internal virtual int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
     {
-        int newDimension = Math.Max (Anchor (dimension - location), 0);
+        return Math.Max (Anchor (superviewContentSize - location), 0);
+    }
 
-        return autoSize && autosize > newDimension ? autosize : newDimension;
+    /// <summary>
+    /// Diagnostics API to determine if this Dim object references other views.
+    /// </summary>
+    /// <returns></returns>
+    internal virtual bool ReferencesOtherViews ()
+    {
+        return false;
     }
 
     internal class DimAbsolute (int n) : Dim
@@ -755,15 +910,129 @@ public class Dim
         public override string ToString () { return $"Absolute({_n})"; }
         internal override int Anchor (int width) { return _n; }
 
-        internal override int Calculate (int location, int dimension, int autosize, bool autoSize)
+        internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
         {
             // DimAbsolute.Anchor (int width) ignores width and returns n
-            int newDimension = Math.Max (Anchor (0), 0);
-
-            return autoSize && autosize > newDimension ? autosize : newDimension;
+            return Math.Max (Anchor (0), 0);
         }
     }
 
+    /// <summary>
+    ///     A <see cref="Dim"/> object that automatically sizes the view to fit all the view's SubViews and/or Text.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         See <see cref="Dim.DimAutoStyle"/>.
+    ///     </para>
+    /// </remarks>
+    /// <param name="style">
+    ///     Specifies how <see cref="Dim.DimAuto"/> will compute the dimension. The default is <see cref="Dim.DimAutoStyle.Auto"/>.
+    /// </param>
+    /// <param name="min">Specifies the minimum dimension that view will be automatically sized to.</param>
+    /// <param name="max">Specifies the maximum dimension that view will be automatically sized to. NOT CURRENTLY SUPPORTED.</param>
+    public class DimAuto (DimAutoStyle style, Dim min, Dim max) : Dim
+    {
+        internal readonly Dim _max = max;
+        internal readonly Dim _min = min;
+        internal readonly DimAutoStyle _style = style;
+        internal int _size;
+
+        /// <inheritdoc />
+        public override bool Equals (object other) { return other is DimAuto auto && auto._min == _min && auto._max == _max && auto._style == _style; }
+        /// <inheritdoc />
+        public override int GetHashCode () { return HashCode.Combine (base.GetHashCode (), _min, _max, _style); }
+        /// <inheritdoc />
+        public override string ToString () { return $"Auto({_style},{_min},{_max})"; }
+
+        internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
+        {
+            if (us == null)
+            {
+                return _max?.Anchor (0) ?? 0;
+            }
+
+            var textSize = 0;
+            var subviewsSize = 0;
+
+            int autoMin = _min?.Anchor (superviewContentSize) ?? 0;
+
+            if (superviewContentSize < autoMin)
+            {
+                Debug.WriteLine ($"WARNING: DimAuto specifies a min size ({autoMin}), but the SuperView's bounds are smaller ({superviewContentSize}).");
+
+                return superviewContentSize;
+            }
+
+            if (_style.HasFlag (Dim.DimAutoStyle.Text))
+            {
+                textSize = int.Max (autoMin, dimension == Dimension.Width ? us.TextFormatter.Size.Width : us.TextFormatter.Size.Height);
+            }
+
+            if (_style.HasFlag (DimAutoStyle.Content))
+            {
+                if (us._contentSize is { })
+                {
+                    subviewsSize = dimension == Dimension.Width ? us.ContentSize!.Value.Width : us.ContentSize!.Value.Height;
+                }
+                else
+                {
+                    // TODO: AnchorEnd needs work
+                    // TODO: If _min > 0 we can SetRelativeLayout for the subviews?
+                    subviewsSize = 0;
+                    if (us.Subviews.Count > 0)
+                    {
+                        for (int i = 0; i < us.Subviews.Count; i++)
+                        {
+                            var v = us.Subviews [i];
+                            bool isNotPosAnchorEnd = dimension == Dim.Dimension.Width ? v.X is not Pos.PosAnchorEnd : v.Y is not Pos.PosAnchorEnd;
+
+                            //if (!isNotPosAnchorEnd)
+                            //{
+                            //    v.SetRelativeLayout(dimension == Dim.Dimension.Width ? (new Size (autoMin, 0)) : new Size (0, autoMin));
+                            //}
+
+                            if (isNotPosAnchorEnd)
+                            {
+                                int size = dimension == Dim.Dimension.Width ? v.Frame.X + v.Frame.Width : v.Frame.Y + v.Frame.Height;
+                                if (size > subviewsSize)
+                                {
+                                    subviewsSize = size;
+                                }
+                            }
+                        }
+                    }
+
+                }
+            }
+
+            int max = int.Max (textSize, subviewsSize);
+
+            Thickness thickness = us.GetAdornmentsThickness ();
+
+            if (dimension == Dimension.Width)
+            {
+                max += thickness.Horizontal;
+            }
+            else
+            {
+                max += thickness.Vertical;
+            }
+
+            max = int.Max (max, autoMin);
+            return int.Min (max, _max?.Anchor (superviewContentSize) ?? superviewContentSize);
+        }
+
+        /// <summary>
+        /// Diagnostics API to determine if this Dim object references other views.
+        /// </summary>
+        /// <returns></returns>
+        internal override bool ReferencesOtherViews ()
+        {
+            // BUGBUG: This is not correct. _contentSize may be null.
+            return _style.HasFlag (Dim.DimAutoStyle.Content);
+        }
+
+    }
     internal class DimCombine (bool add, Dim left, Dim right) : Dim
     {
         internal bool _add = add;
@@ -784,10 +1053,10 @@ public class Dim
             return la - ra;
         }
 
-        internal override int Calculate (int location, int dimension, int autosize, bool autoSize)
+        internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
         {
-            int leftNewDim = _left.Calculate (location, dimension, autosize, autoSize);
-            int rightNewDim = _right.Calculate (location, dimension, autosize, autoSize);
+            int leftNewDim = _left.Calculate (location, superviewContentSize, us, dimension);
+            int rightNewDim = _right.Calculate (location, superviewContentSize, us, dimension);
 
             int newDimension;
 
@@ -800,7 +1069,27 @@ public class Dim
                 newDimension = Math.Max (0, leftNewDim - rightNewDim);
             }
 
-            return autoSize && autosize > newDimension ? autosize : newDimension;
+            return newDimension;
+        }
+
+
+        /// <summary>
+        /// Diagnostics API to determine if this Dim object references other views.
+        /// </summary>
+        /// <returns></returns>
+        internal override bool ReferencesOtherViews ()
+        {
+            if (_left.ReferencesOtherViews ())
+            {
+                return true;
+            }
+
+            if (_right.ReferencesOtherViews ())
+            {
+                return true;
+            }
+
+            return false;
         }
     }
 
@@ -815,11 +1104,9 @@ public class Dim
         public override string ToString () { return $"Factor({_factor},{_remaining})"; }
         internal override int Anchor (int width) { return (int)(width * _factor); }
 
-        internal override int Calculate (int location, int dimension, int autosize, bool autoSize)
+        internal override int Calculate (int location, int superviewContentSize, View us, Dimension dimension)
         {
-            int newDimension = _remaining ? Math.Max (Anchor (dimension - location), 0) : Anchor (dimension);
-
-            return autoSize && autosize > newDimension ? autosize : newDimension;
+            return _remaining ? Math.Max (Anchor (superviewContentSize - location), 0) : Anchor (superviewContentSize);
         }
     }
 
@@ -842,22 +1129,6 @@ public class Dim
         internal override int Anchor (int width) { return _function (); }
     }
 
-    /// <summary>
-    /// 
-    /// </summary>
-    public enum Dimension
-    {
-        /// <summary>
-        /// The height dimension.
-        /// </summary>
-        Height = 0,
-
-        /// <summary>
-        /// The width dimension.
-        /// </summary>
-        Width = 1
-    }
-
     internal class DimView : Dim
     {
         private readonly Dimension _side;
@@ -898,5 +1169,10 @@ public class Dim
                 _ => 0
             };
         }
+
+        internal override bool ReferencesOtherViews ()
+        {
+            return true;
+        }
     }
-}
+}

+ 2 - 2
Terminal.Gui/View/Layout/SizeChangedEventArgs.cs

@@ -5,11 +5,11 @@ public class SizeChangedEventArgs : EventArgs
 {
     /// <summary>Creates a new instance of the <see cref="SizeChangedEventArgs"/> class.</summary>
     /// <param name="size"></param>
-    public SizeChangedEventArgs (Size size) { Size = size; }
+    public SizeChangedEventArgs (Size? size) { Size = size; }
 
     /// <summary>Set to <see langword="true"/> to cause the resize to be cancelled, if appropriate.</summary>
     public bool Cancel { get; set; }
 
     /// <summary>Gets the size the event describes.  This should reflect the new/current size after the event resolved.</summary>
-    public Size Size { get; }
+    public Size? Size { get; }
 }

+ 193 - 354
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -1,4 +1,5 @@
 using System.Diagnostics;
+using Microsoft.CodeAnalysis;
 
 namespace Terminal.Gui;
 
@@ -26,9 +27,12 @@ public enum LayoutStyle
 
     /// <summary>
     ///     Indicates one or more of the <see cref="View.X"/>, <see cref="View.Y"/>, <see cref="View.Width"/>, or
-    ///     <see cref="View.Height"/> objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.
-    ///     The position and size of the view will be computed based on these objects at layout time. <see cref="View.Frame"/>
-    ///     will provide the absolute computed values.
+    ///     <see cref="View.Height"/>
+    ///     objects are relative to the <see cref="View.SuperView"/> and are computed at layout time.  The position and size of
+    ///     the
+    ///     view
+    ///     will be computed based on these objects at layout time. <see cref="View.Frame"/> will provide the absolute computed
+    ///     values.
     /// </summary>
     Computed
 }
@@ -85,7 +89,7 @@ public partial class View
         }
     }
 
-    private void SetFrame (Rectangle frame)
+    private void SetFrame (in Rectangle frame)
     {
         var oldViewport = Rectangle.Empty;
 
@@ -98,6 +102,11 @@ public partial class View
         _frame = frame;
 
         OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
+
+        if (!TextFormatter.AutoSize)
+        {
+            TextFormatter.Size = ContentSize.GetValueOrDefault ();
+        }
     }
 
     /// <summary>Gets the <see cref="Frame"/> with a screen-relative location.</summary>
@@ -137,25 +146,22 @@ public partial class View
     ///     View's <see cref="SuperView"/>'s <see cref="Viewport"/>.
     /// </summary>
     /// <returns>The coordinate relative to the <see cref="SuperView"/>'s <see cref="Viewport"/>.</returns>
-    /// <param name="x">Screen-relative column.</param>
-    /// <param name="y">Screen-relative row.</param>
-    public virtual Point ScreenToFrame (int x, int y)
+    /// <param name="location">Screen-relative coordinate.</param>
+    public virtual Point ScreenToFrame (in Point location)
     {
         if (SuperView is null)
         {
-            return new (x - Frame.X, y - Frame.Y);
+            return new (location.X - Frame.X, location.Y - Frame.Y);
         }
 
         Point superViewViewportOffset = SuperView.GetViewportOffsetFromFrame ();
-        superViewViewportOffset.X -= SuperView.Viewport.X;
-        superViewViewportOffset.Y -= SuperView.Viewport.Y;
+        superViewViewportOffset.Offset(-SuperView.Viewport.X, -SuperView.Viewport.Y);
 
-        x -= superViewViewportOffset.X;
-        y -= superViewViewportOffset.Y;
+        Point frame = location;
+        frame.Offset(-superViewViewportOffset.X, -superViewViewportOffset.Y);
 
-        Point frame = SuperView.ScreenToFrame (x, y);
-        frame.X -= Frame.X;
-        frame.Y -= Frame.Y;
+        frame = SuperView.ScreenToFrame (frame);
+        frame.Offset (-Frame.X, -Frame.Y);
 
         return frame;
     }
@@ -170,7 +176,7 @@ public partial class View
     ///     </para>
     ///     <para>
     ///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
-    ///         initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Size)"/> has been
+    ///         initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout"/> has been
     ///         called.
     ///     </para>
     ///     <para>
@@ -209,7 +215,7 @@ public partial class View
     ///     </para>
     ///     <para>
     ///         If set to a relative value (e.g. <see cref="Pos.Center"/>) the value is indeterminate until the view has been
-    ///         initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Size)"/> has been
+    ///         initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout"/> has been
     ///         called.
     ///     </para>
     ///     <para>
@@ -248,7 +254,7 @@ public partial class View
     ///     </para>
     ///     <para>
     ///         If set to a relative value (e.g. <see cref="Dim.Fill(int)"/>) the value is indeterminate until the view has
-    ///         been initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Size)"/> has been
+    ///         been initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout"/> has been
     ///         called.
     ///     </para>
     ///     <para>
@@ -271,26 +277,14 @@ public partial class View
                 return;
             }
 
-            _height = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Height)} cannot be null");
-
-            if (AutoSize)
+            if (_height is Dim.DimAuto)
             {
-                Debug.WriteLine (@$"Must set AutoSize to false before setting {nameof (Height)}.");
-                AutoSize = false;
+                // Reset ContentSize to Viewport
+                _contentSize = null;
             }
 
-            //if (ValidatePosDim) {
-            bool isValidNewAutoSize = AutoSize && IsValidAutoSizeHeight (_height);
-
-            if (IsAdded && AutoSize && !isValidNewAutoSize)
-            {
-                Debug.WriteLine (
-                                 @$"Must set AutoSize to false before setting the {nameof (Height)}."
-                                );
-                AutoSize = false;
-            }
+            _height = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Height)} cannot be null");
 
-            //}
             OnResizeNeeded ();
         }
     }
@@ -306,7 +300,7 @@ public partial class View
     ///     </para>
     ///     <para>
     ///         If set to a relative value (e.g. <see cref="Dim.Fill(int)"/>) the value is indeterminate until the view has
-    ///         been initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout(Size)"/> has been
+    ///         been initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout"/> has been
     ///         called.
     ///     </para>
     ///     <para>
@@ -329,21 +323,13 @@ public partial class View
                 return;
             }
 
-            _width = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Width)} cannot be null");
-
-            if (AutoSize)
+            if (_width is Dim.DimAuto)
             {
-                Debug.WriteLine ($@"Must set AutoSize to false before setting {nameof (Width)}.");
-                AutoSize = false;
+                // Reset ContentSize to Viewport
+                _contentSize = null;
             }
 
-            bool isValidNewAutoSize = AutoSize && IsValidAutoSizeWidth (_width);
-
-            if (IsAdded && AutoSize && !isValidNewAutoSize)
-            {
-                Debug.WriteLine ($@"Must set AutoSize to false before setting {nameof (Width)}.");
-                AutoSize = false;
-            }
+            _width = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Width)} cannot be null");
 
             OnResizeNeeded ();
         }
@@ -351,219 +337,19 @@ public partial class View
 
     #endregion Frame
 
-    #region AutoSize
-
-    private bool _autoSize;
-
-    /// <summary>
-    ///     Gets or sets a flag that determines whether the View will be automatically resized to fit the <see cref="Text"/>
-    ///     within <see cref="Viewport"/>.
-    ///     <para>
-    ///         The default is <see langword="false"/>. Set to <see langword="true"/> to turn on AutoSize. If
-    ///         <see langword="true"/> then <see cref="Width"/> and <see cref="Height"/> will be used if <see cref="Text"/> can
-    ///         fit; if <see cref="Text"/> won't fit the view will be resized as needed.
-    ///     </para>
-    ///     <para>
-    ///         If <see cref="AutoSize"/> is set to <see langword="true"/> then <see cref="Width"/> and <see cref="Height"/>
-    ///         will be changed to <see cref="Dim.DimAbsolute"/> if they are not already.
-    ///     </para>
-    ///     <para>
-    ///         If <see cref="AutoSize"/> is set to <see langword="false"/> then <see cref="Width"/> and <see cref="Height"/>
-    ///         will left unchanged.
-    ///     </para>
-    /// </summary>
-    public virtual bool AutoSize
-    {
-        get => _autoSize;
-        set
-        {
-            if (Width != Dim.Sized (0) && Height != Dim.Sized (0))
-            {
-                Debug.WriteLine (
-                                 $@"WARNING: {GetType ().Name} - Setting {nameof (AutoSize)} invalidates {nameof (Width)} and {nameof (Height)}."
-                                );
-            }
-
-            bool v = ResizeView (value);
-            TextFormatter.AutoSize = v;
-
-            if (_autoSize != v)
-            {
-                _autoSize = v;
-                TextFormatter.NeedsFormat = true;
-                UpdateTextFormatterText ();
-                OnResizeNeeded ();
-            }
-        }
-    }
-
-    /// <summary>If <paramref name="autoSize"/> is true, resizes the view.</summary>
-    /// <param name="autoSize"></param>
-    /// <returns></returns>
-    private bool ResizeView (bool autoSize)
-    {
-        if (!autoSize)
-        {
-            return false;
-        }
-
-        var boundsChanged = true;
-        Size newFrameSize = GetAutoSize ();
-
-        if (IsInitialized && newFrameSize != Frame.Size)
-        {
-            if (ValidatePosDim)
-            {
-                // BUGBUG: This ain't right, obviously.  We need to figure out how to handle this.
-                boundsChanged = ResizeViewportToFit (newFrameSize);
-            }
-            else
-            {
-                Height = newFrameSize.Height;
-                Width = newFrameSize.Width;
-            }
-        }
-
-        return boundsChanged;
-    }
-
-    /// <summary>Determines if the View's <see cref="Height"/> can be set to a new value.</summary>
-    /// <remarks>TrySetHeight can only be called when AutoSize is true (or being set to true).</remarks>
-    /// <param name="desiredHeight"></param>
-    /// <param name="resultHeight">
-    ///     Contains the width that would result if <see cref="Height"/> were set to
-    ///     <paramref name="desiredHeight"/>"/>
-    /// </param>
-    /// <returns>
-    ///     <see langword="true"/> if the View's <see cref="Height"/> can be changed to the specified value. False
-    ///     otherwise.
-    /// </returns>
-    internal bool TrySetHeight (int desiredHeight, out int resultHeight)
-    {
-        int h = desiredHeight;
-        bool canSetHeight;
-
-        switch (Height)
-        {
-            case Dim.DimCombine _:
-            case Dim.DimView _:
-            case Dim.DimFill _:
-                // It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored.
-                h = Height.Anchor (h);
-                canSetHeight = !ValidatePosDim;
-
-                break;
-            case Dim.DimFactor factor:
-                // Tries to get the SuperView height otherwise the view height.
-                int sh = SuperView is { } ? SuperView.Frame.Height : h;
-
-                if (factor.IsFromRemaining ())
-                {
-                    sh -= Frame.Y;
-                }
-
-                h = Height.Anchor (sh);
-                canSetHeight = !ValidatePosDim;
-
-                break;
-            default:
-                canSetHeight = true;
-
-                break;
-        }
-
-        resultHeight = h;
-
-        return canSetHeight;
-    }
-
-    /// <summary>Determines if the View's <see cref="Width"/> can be set to a new value.</summary>
-    /// <remarks>TrySetWidth can only be called when AutoSize is true (or being set to true).</remarks>
-    /// <param name="desiredWidth"></param>
-    /// <param name="resultWidth">
-    ///     Contains the width that would result if <see cref="Width"/> were set to
-    ///     <paramref name="desiredWidth"/>"/>
-    /// </param>
-    /// <returns>
-    ///     <see langword="true"/> if the View's <see cref="Width"/> can be changed to the specified value. False
-    ///     otherwise.
-    /// </returns>
-    internal bool TrySetWidth (int desiredWidth, out int resultWidth)
-    {
-        int w = desiredWidth;
-        bool canSetWidth;
-
-        switch (Width)
-        {
-            case Dim.DimCombine _:
-            case Dim.DimView _:
-            case Dim.DimFill _:
-                // It's a Dim.DimCombine and so can't be assigned. Let it have it's Width anchored.
-                w = Width.Anchor (w);
-                canSetWidth = !ValidatePosDim;
-
-                break;
-            case Dim.DimFactor factor:
-                // Tries to get the SuperView Width otherwise the view Width.
-                int sw = SuperView is { } ? SuperView.Frame.Width : w;
-
-                if (factor.IsFromRemaining ())
-                {
-                    sw -= Frame.X;
-                }
-
-                w = Width.Anchor (sw);
-                canSetWidth = !ValidatePosDim;
-
-                break;
-            default:
-                canSetWidth = true;
-
-                break;
-        }
-
-        resultWidth = w;
-
-        return canSetWidth;
-    }
-
-    /// <summary>Resizes the View to fit the specified size. Factors in the HotKey.</summary>
-    /// <remarks>ResizeBoundsToFit can only be called when AutoSize is true (or being set to true).</remarks>
-    /// <param name="size"></param>
-    /// <returns>whether the Viewport was changed or not</returns>
-    private bool ResizeViewportToFit (Size size)
-    {
-        //if (AutoSize == false) {
-        //	throw new InvalidOperationException ("ResizeViewportToFit can only be called when AutoSize is true");
-        //}
-
-        var changed = false;
-        bool canSizeW = TrySetWidth (size.Width - GetHotKeySpecifierLength (), out int rW);
-        bool canSizeH = TrySetHeight (size.Height - GetHotKeySpecifierLength (false), out int rH);
-
-        if (canSizeW)
-        {
-            changed = true;
-            _width = rW;
-        }
-
-        if (canSizeH)
-        {
-            changed = true;
-            _height = rH;
-        }
+    #region Layout Engine
 
-        if (changed)
-        {
-            Viewport = new (Viewport.X, Viewport.Y, canSizeW ? rW : Viewport.Width, canSizeH ? rH : Viewport.Height);
-        }
 
-        return changed;
-    }
+    // @tig Notes on layout flow. Ignore for now.
+    // BeginLayout
+    //   If !LayoutNeeded return
+    //   If !SizeNeeded return
+    //   Call OnLayoutStarted
+    //      Views and subviews can update things
+    //   
 
-    #endregion AutoSize
 
-    #region Layout Engine
+    // EndLayout
 
     /// <summary>
     ///     Controls how the View's <see cref="Frame"/> is computed during <see cref="LayoutSubviews"/>. If the style is
@@ -607,10 +393,9 @@ public partial class View
     /// <summary>
     ///     Indicates whether the specified SuperView-relative coordinates are within the View's <see cref="Frame"/>.
     /// </summary>
-    /// <param name="x">SuperView-relative X coordinate.</param>
-    /// <param name="y">SuperView-relative Y coordinate.</param>
+    /// <param name="location">SuperView-relative coordinate</param>
     /// <returns><see langword="true"/> if the specified SuperView-relative coordinates are within the View.</returns>
-    public virtual bool Contains (int x, int y) { return Frame.Contains (x, y); }
+    public virtual bool Contains (in Point location) { return Frame.Contains (location); }
 
 #nullable enable
     /// <summary>Finds the first Subview of <paramref name="start"/> that is visible at the provided location.</summary>
@@ -620,29 +405,29 @@ public partial class View
     ///     </para>
     /// </remarks>
     /// <param name="start">The view to scope the search by.</param>
-    /// <param name="x"><paramref name="start"/>.SuperView-relative X coordinate.</param>
-    /// <param name="y"><paramref name="start"/>.SuperView-relative Y coordinate.</param>
+    /// <param name="location"><paramref name="start"/>.SuperView-relative coordinate.</param>
     /// <returns>
-    ///     The view that was found at the <paramref name="x"/> and <paramref name="y"/> coordinates.
+    ///     The view that was found at the <paramref name="location"/> coordinate.
     ///     <see langword="null"/> if no view was found.
     /// </returns>
 
     // CONCURRENCY: This method is not thread-safe. Undefined behavior and likely program crashes are exposed by unsynchronized access to InternalSubviews.
-    internal static View? FindDeepestView (View? start, int x, int y)
+    internal static View? FindDeepestView (View? start, in Point location)
     {
-        while (start is { Visible: true } && start.Contains (x, y))
+        Point currentLocation = location;
+        while (start is { Visible: true } && start.Contains (currentLocation))
         {
             Adornment? found = null;
 
-            if (start.Margin.Contains (x, y))
+            if (start.Margin.Contains (currentLocation))
             {
                 found = start.Margin;
             }
-            else if (start.Border.Contains (x, y))
+            else if (start.Border.Contains (currentLocation))
             {
                 found = start.Border;
             }
-            else if (start.Padding.Contains (x, y))
+            else if (start.Padding.Contains (currentLocation))
             {
                 found = start.Padding;
             }
@@ -655,19 +440,19 @@ public partial class View
                 viewportOffset = found.Parent.Frame.Location;
             }
 
-            int startOffsetX = x - (start.Frame.X + viewportOffset.X);
-            int startOffsetY = y - (start.Frame.Y + viewportOffset.Y);
+            int startOffsetX = currentLocation.X - (start.Frame.X + viewportOffset.X);
+            int startOffsetY = currentLocation.Y - (start.Frame.Y + viewportOffset.Y);
 
             View? subview = null;
 
             for (int i = start.InternalSubviews.Count - 1; i >= 0; i--)
             {
                 if (start.InternalSubviews [i].Visible
-                    && start.InternalSubviews [i].Contains (startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y))
+                    && start.InternalSubviews [i].Contains (new (startOffsetX + start.Viewport.X, startOffsetY + start.Viewport.Y)))
                 {
                     subview = start.InternalSubviews [i];
-                    x = startOffsetX + start.Viewport.X;
-                    y = startOffsetY + start.Viewport.Y;
+                    currentLocation.X = startOffsetX + start.Viewport.X;
+                    currentLocation.Y = startOffsetY + start.Viewport.Y;
 
                     // start is the deepest subview under the mouse; stop searching the subviews
                     break;
@@ -733,12 +518,12 @@ public partial class View
             superView = viewToMove.SuperView;
         }
 
-        if (superView.Margin is { } && superView == viewToMove.SuperView)
+        if (superView?.Margin is { } && superView == viewToMove.SuperView)
         {
             maxDimension -= superView.GetAdornmentsThickness ().Left + superView.GetAdornmentsThickness ().Right;
         }
 
-        if (viewToMove.Frame.Width <= maxDimension)
+        if (viewToMove!.Frame.Width <= maxDimension)
         {
             nx = Math.Max (targetX, 0);
             nx = nx + viewToMove.Frame.Width > maxDimension ? Math.Max (maxDimension - viewToMove.Frame.Width, 0) : nx;
@@ -759,7 +544,7 @@ public partial class View
 
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         {
-            menuVisible = Application.Top.MenuBar?.Visible == true;
+            menuVisible = Application.Top?.MenuBar?.Visible == true;
         }
         else
         {
@@ -770,9 +555,9 @@ public partial class View
                 t = t.SuperView;
             }
 
-            if (t is Toplevel toplevel)
+            if (t is Toplevel topLevel)
             {
-                menuVisible = toplevel.MenuBar?.Visible == true;
+                menuVisible = topLevel.MenuBar?.Visible == true;
             }
         }
 
@@ -789,8 +574,8 @@ public partial class View
 
         if (viewToMove?.SuperView is null || viewToMove == Application.Top || viewToMove?.SuperView == Application.Top)
         {
-            statusVisible = Application.Top.StatusBar?.Visible == true;
-            statusBar = Application.Top.StatusBar;
+            statusVisible = Application.Top?.StatusBar?.Visible == true;
+            statusBar = Application.Top?.StatusBar;
         }
         else
         {
@@ -817,14 +602,14 @@ public partial class View
             maxDimension = statusVisible ? viewToMove.SuperView.Viewport.Height - 1 : viewToMove.SuperView.Viewport.Height;
         }
 
-        if (superView.Margin is { } && superView == viewToMove.SuperView)
+        if (superView?.Margin is { } && superView == viewToMove?.SuperView)
         {
             maxDimension -= superView.GetAdornmentsThickness ().Top + superView.GetAdornmentsThickness ().Bottom;
         }
 
         ny = Math.Min (ny, maxDimension);
 
-        if (viewToMove.Frame.Height <= maxDimension)
+        if (viewToMove?.Frame.Height <= maxDimension)
         {
             ny = ny + viewToMove.Frame.Height > maxDimension
                      ? Math.Max (maxDimension - viewToMove.Frame.Height, menuVisible ? 1 : 0)
@@ -856,8 +641,8 @@ public partial class View
     public event EventHandler<LayoutEventArgs> LayoutStarted;
 
     /// <summary>
-    ///     Invoked when a view starts executing or when the dimensions of the view have changed, for example in response
-    ///     to the container view or terminal resizing.
+    ///     Invoked when a view starts executing or when the dimensions of the view have changed, for example in response to
+    ///     the container view or terminal resizing.
     /// </summary>
     /// <remarks>
     ///     <para>
@@ -870,9 +655,7 @@ public partial class View
     {
         if (!IsInitialized)
         {
-            Debug.WriteLine (
-                             $"WARNING: LayoutSubviews called before view has been initialized. This is likely a bug in {this}"
-                            );
+            Debug.WriteLine ($"WARNING: LayoutSubviews called before view has been initialized. This is likely a bug in {this}");
         }
 
         if (!LayoutNeeded)
@@ -880,9 +663,12 @@ public partial class View
             return;
         }
 
-        LayoutAdornments ();
+        CheckDimAuto ();
 
-        OnLayoutStarted (new (ContentSize));
+        var contentSize = ContentSize.GetValueOrDefault ();
+        OnLayoutStarted (new (contentSize));
+
+        LayoutAdornments ();
 
         SetTextFormatterSize ();
 
@@ -894,26 +680,27 @@ public partial class View
 
         foreach (View v in ordered)
         {
-            LayoutSubview (v, ContentSize);
+            LayoutSubview (v, contentSize);
         }
 
-        // If the 'to' is rooted to 'from' and the layoutstyle is Computed it's a special-case.
-        // Use LayoutSubview with the Frame of the 'from' 
+        // If the 'to' is rooted to 'from' it's a special-case.
+        // Use LayoutSubview with the Frame of the 'from'.
         if (SuperView is { } && GetTopSuperView () is { } && LayoutNeeded && edges.Count > 0)
         {
             foreach ((View from, View to) in edges)
             {
-                LayoutSubview (to, from.ContentSize);
+                LayoutSubview (to, from.ContentSize.GetValueOrDefault ());
             }
         }
 
         LayoutNeeded = false;
 
-        OnLayoutComplete (new (ContentSize));
+        OnLayoutComplete (new (contentSize));
     }
 
     private void LayoutSubview (View v, Size contentSize)
     {
+        // BUGBUG: Calling SetRelativeLayout before LayoutSubviews is problematic. Need to resolve.
         v.SetRelativeLayout (contentSize);
         v.LayoutSubviews ();
         v.LayoutNeeded = false;
@@ -928,6 +715,9 @@ public partial class View
     /// </summary>
     internal virtual void OnLayoutComplete (LayoutEventArgs args) { LayoutComplete?.Invoke (this, args); }
 
+    // BUGBUG: We need an API/event that is called from SetRelativeLayout instead of/in addition to 
+    // BUGBUG: OnLayoutStarted which is called from LayoutSubviews.
+
     /// <summary>
     ///     Raises the <see cref="LayoutStarted"/> event. Called from  <see cref="LayoutSubviews"/> before any subviews
     ///     have been laid out.
@@ -941,33 +731,31 @@ public partial class View
     /// <remarks>
     ///     <para>
     ///         Determines the relative bounds of the <see cref="View"/> and its <see cref="Frame"/>s, and then calls
-    ///         <see cref="SetRelativeLayout(Size)"/> to update the view.
+    ///         <see cref="SetRelativeLayout"/> to update the view.
     ///     </para>
     /// </remarks>
     internal void OnResizeNeeded ()
     {
         // TODO: Identify a real-world use-case where this API should be virtual. 
         // TODO: Until then leave it `internal` and non-virtual
+
         // First try SuperView.Viewport, then Application.Top, then Driver.Viewport.
         // Finally, if none of those are valid, use int.MaxValue (for Unit tests).
-        Size contentSize = SuperView is { IsInitialized: true } ? SuperView.ContentSize :
+        Size? contentSize = SuperView is { IsInitialized: true } ? SuperView.ContentSize :
                            Application.Top is { } && Application.Top != this && Application.Top.IsInitialized ? Application.Top.ContentSize :
                            Application.Driver?.Screen.Size ?? new (int.MaxValue, int.MaxValue);
-        SetRelativeLayout (contentSize);
 
-        // TODO: Determine what, if any of the below is actually needed here.
+        SetTextFormatterSize ();
+
+        SetRelativeLayout (contentSize.GetValueOrDefault ());
+
         if (IsInitialized)
         {
-            if (AutoSize)
-            {
-                SetFrameToFitText ();
-                SetTextFormatterSize ();
-            }
-
             LayoutAdornments ();
-            SetNeedsDisplay ();
-            SetNeedsLayout ();
         }
+
+        SetNeedsDisplay ();
+        SetNeedsLayout ();
     }
 
     internal bool LayoutNeeded { get; private set; } = true;
@@ -1010,24 +798,23 @@ public partial class View
     /// <param name="superviewContentSize">
     ///     The size of the SuperView's content (nominally the same as <c>this.SuperView.ContentSize</c>).
     /// </param>
-    internal void SetRelativeLayout (Size superviewContentSize)
+    internal void SetRelativeLayout (Size? superviewContentSize)
     {
         Debug.Assert (_x is { });
         Debug.Assert (_y is { });
         Debug.Assert (_width is { });
         Debug.Assert (_height is { });
 
-        var autoSize = Size.Empty;
-
-        if (AutoSize)
+        if (superviewContentSize is null)
         {
-            autoSize = GetAutoSize ();
+            return;
         }
 
-        int newX = _x.Calculate (superviewContentSize.Width, _width, autoSize.Width, AutoSize);
-        int newW = _width.Calculate (newX, superviewContentSize.Width, autoSize.Width, AutoSize);
-        int newY = _y.Calculate (superviewContentSize.Height, _height, autoSize.Height, AutoSize);
-        int newH = _height.Calculate (newY, superviewContentSize.Height, autoSize.Height, AutoSize);
+        CheckDimAuto ();
+        int newX = _x.Calculate (superviewContentSize.Value.Width, _width, this, Dim.Dimension.Width);
+        int newW = _width.Calculate (newX, superviewContentSize.Value.Width, this, Dim.Dimension.Width);
+        int newY = _y.Calculate (superviewContentSize.Value.Height, _height, this, Dim.Dimension.Height);
+        int newH = _height.Calculate (newY, superviewContentSize.Value.Height, this, Dim.Dimension.Height);
 
         Rectangle newFrame = new (newX, newY, newW, newH);
 
@@ -1057,31 +844,9 @@ public partial class View
                 _height = Frame.Height;
             }
 
-            SetNeedsLayout ();
-            SetNeedsDisplay ();
-        }
-
-        if (AutoSize)
-        {
-            if (autoSize.Width == 0 || autoSize.Height == 0)
-            {
-                // Set the frame. Do NOT use `Frame` as it overwrites X, Y, Width, and Height, making
-                // the view LayoutStyle.Absolute.
-                SetFrame (_frame with { Size = autoSize });
-
-                if (autoSize.Width == 0)
-                {
-                    _width = 0;
-                }
-
-                if (autoSize.Height == 0)
-                {
-                    _height = 0;
-                }
-            }
-            else if (!SetFrameToFitText ())
+            if (!string.IsNullOrEmpty (Title))
             {
-                SetTextFormatterSize ();
+                SetTitleTextFormatterSize ();
             }
 
             SetNeedsLayout ();
@@ -1234,12 +999,14 @@ public partial class View
                 if (ReferenceEquals (from.SuperView, to))
                 {
                     throw new InvalidOperationException (
-                                                         $"ComputedLayout for \"{superView}\": \"{to}\" references a SubView (\"{from}\")."
+                                                         $"ComputedLayout for \"{superView}\": \"{to}\" "
+                                                         + $"references a SubView (\"{from}\")."
                                                         );
                 }
 
                 throw new InvalidOperationException (
-                                                     $"ComputedLayout for \"{superView}\": \"{from}\" linked with \"{to}\" was not found. Did you forget to add it to {superView}?"
+                                                     $"ComputedLayout for \"{superView}\": \"{from}\" "
+                                                     + $"linked with \"{to}\" was not found. Did you forget to add it to {superView}?"
                                                     );
             }
         }
@@ -1248,34 +1015,35 @@ public partial class View
         return result;
     } // TopologicalSort
 
-    #region Diagnostics
-
-    // Diagnostics to highlight when Width or Height is read before the view has been initialized
-    private Dim VerifyIsInitialized (Dim dim, string member)
+    // Diagnostics to highlight when X or Y is read before the view has been initialized
+    private Pos VerifyIsInitialized (Pos pos, string member)
     {
 #if DEBUG
-        if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
+        if ((pos.ReferencesOtherViews () || pos.ReferencesOtherViews ()) && !IsInitialized)
         {
             Debug.WriteLine (
-                             $"WARNING: \"{this}\" has not been initialized; {member} is indeterminate: {dim}. This is potentially a bug."
+                             $"WARNING: The {pos} of {this} is dependent on other views and {member} "
+                             + $"is being accessed before the View has been initialized. This is likely a bug."
                             );
         }
-#endif // DEBUG		
-        return dim;
+#endif // DEBUG
+        return pos;
     }
 
-    // Diagnostics to highlight when X or Y is read before the view has been initialized
-    private Pos VerifyIsInitialized (Pos pos, string member)
+    // Diagnostics to highlight when Width or Height is read before the view has been initialized
+    private Dim VerifyIsInitialized (Dim dim, string member)
     {
 #if DEBUG
-        if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
+        if ((dim.ReferencesOtherViews () || dim.ReferencesOtherViews ()) && !IsInitialized)
         {
             Debug.WriteLine (
-                             $"WARNING: \"{this}\" has not been initialized; {member} is indeterminate {pos}. This is potentially a bug."
+                             $"WARNING: The {member} of {this} is dependent on other views and is "
+                             + $"is being accessed before the View has been initialized. This is likely a bug. "
+                             + $"{member} is {dim}"
                             );
         }
 #endif // DEBUG
-        return pos;
+        return dim;
     }
 
     /// <summary>Gets or sets whether validation of <see cref="Pos"/> and <see cref="Dim"/> occurs.</summary>
@@ -1287,5 +1055,76 @@ public partial class View
     /// </remarks>
     public bool ValidatePosDim { get; set; }
 
-    #endregion
+
+    // TODO: Move this logic into the Pos/Dim classes
+    /// <summary>
+    ///     Throws an <see cref="InvalidOperationException"/> if any SubViews are using Dim objects that depend on this
+    ///     Views dimensions.
+    /// </summary>
+    /// <exception cref="InvalidOperationException"></exception>
+    private void CheckDimAuto ()
+    {
+        if (!ValidatePosDim || !IsInitialized || (Width is not Dim.DimAuto && Height is not Dim.DimAuto))
+        {
+            return;
+        }
+
+        // Verify none of the subviews are using Dim objects that depend on the SuperView's dimensions.
+        foreach (View view in Subviews)
+        {
+            if (Width is Dim.DimAuto { _min: null })
+            {
+                ThrowInvalid (view, view.Width, nameof (view.Width));
+                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));
+            }
+        }
+
+        return;
+
+        void ThrowInvalid (View view, object checkPosDim, string name)
+        {
+            object bad = null;
+
+            switch (checkPosDim)
+            {
+                case Pos pos and not Pos.PosAbsolute and not Pos.PosView and not Pos.PosCombine:
+                    bad = pos;
+
+                    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)._right, name);
+
+                    break;
+
+                case Dim dim and not Dim.DimAbsolute and not Dim.DimView and not Dim.DimCombine:
+                    bad = dim;
+
+                    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)._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."
+                                                     );
+            }
+        }
+    }
 }

+ 17 - 11
Terminal.Gui/View/View.cs

@@ -32,10 +32,11 @@ namespace Terminal.Gui;
 ///         <see cref="Enabled"/>, <see cref="Visible"/>, and <see cref="CanFocus"/> will receive focus.
 ///     </para>
 ///     <para>
-///         Views that are focusable should implement the <see cref="PositionCursor"/> to make sure that the cursor is
-///         placed in a location that makes sense. Unix terminals do not have a way of hiding the cursor, so it can be
+///         Views that are focusable should override <see cref="PositionCursor"/> to make sure that the cursor is
+///         placed in a location that makes sense. Some terminals do not have a way of hiding the cursor, so it can be
 ///         distracting to have the cursor left at the last focused view. So views should make sure that they place the
-///         cursor in a visually sensible place.
+///         cursor in a visually sensible place. The default implementation of <see cref="PositionCursor"/> will place the
+///         cursor at either the hotkey (if defined) or <c>0,0</c>.
 ///     </para>
 ///     <para>
 ///         The View defines the base functionality for user interface elements in Terminal.Gui. Views can contain one or
@@ -139,6 +140,8 @@ public partial class View : Responder, ISupportInitializeNotification
     /// </remarks>
     public View ()
     {
+        CreateAdornments ();
+
         HotKeySpecifier = (Rune)'_';
         TitleTextFormatter.HotKeyChanged += TitleTextFormatter_HotKeyChanged;
 
@@ -150,8 +153,6 @@ public partial class View : Responder, ISupportInitializeNotification
         TabStop = false;
 
         AddCommands ();
-
-        CreateAdornments ();
     }
 
     /// <summary>
@@ -456,12 +457,7 @@ public partial class View : Responder, ISupportInitializeNotification
                 _title = value;
                 TitleTextFormatter.Text = _title;
 
-                TitleTextFormatter.Size = new (
-                                               TextFormatter.GetWidestLineLength (TitleTextFormatter.Text)
-                                               - (TitleTextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
-                                                      ? Math.Max (HotKeySpecifier.GetColumns (), 0)
-                                                      : 0),
-                                               1);
+                SetTitleTextFormatterSize ();
                 SetHotKeyFromTitle ();
                 SetNeedsDisplay ();
 #if DEBUG
@@ -475,6 +471,16 @@ public partial class View : Responder, ISupportInitializeNotification
         }
     }
 
+    private void SetTitleTextFormatterSize ()
+    {
+        TitleTextFormatter.Size = new (
+                                       TextFormatter.GetWidestLineLength (TitleTextFormatter.Text)
+                                       - (TitleTextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
+                                              ? Math.Max (HotKeySpecifier.GetColumns (), 0)
+                                              : 0),
+                                       1);
+    }
+
     /// <summary>Called when the <see cref="View.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.</summary>
     /// <param name="oldTitle">The <see cref="View.Title"/> that is/has been replaced.</param>
     /// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>

+ 8 - 1
Terminal.Gui/View/ViewAdornments.cs

@@ -136,7 +136,14 @@ public partial class View
     ///     <para>Gets the thickness describing the sum of the Adornments' thicknesses.</para>
     /// </summary>
     /// <returns>A thickness that describes the sum of the Adornments' thicknesses.</returns>
-    public Thickness GetAdornmentsThickness () { return Margin.Thickness + Border.Thickness + Padding.Thickness; }
+    public Thickness GetAdornmentsThickness ()
+    {
+        if (Margin is null)
+        {
+            return Thickness.Empty;
+        }
+        return Margin.Thickness + Border.Thickness + Padding.Thickness;
+    }
 
     /// <summary>Lays out the Adornments of the View.</summary>
     /// <remarks>

+ 70 - 31
Terminal.Gui/View/ViewContent.cs

@@ -120,27 +120,31 @@ public partial class View
 {
     #region Content Area
 
-    private Size _contentSize;
+    internal Size? _contentSize;
 
     /// <summary>
-    ///     Gets or sets the size of the View's content. If not set, the value will be the same as the size of <see cref="Viewport"/>,
+    ///     Gets or sets the size of the View's content. If <see langword="null"/>, the value will be the same as the size of <see cref="Viewport"/>,
     ///     and <c>Viewport.Location</c> will always be <c>0, 0</c>.
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         If a positive size is provided, <see cref="Viewport"/> describes the portion of the content currently visible
+    ///         If a size is provided, <see cref="Viewport"/> describes the portion of the content currently visible
     ///         to the view. This enables virtual scrolling.
     ///     </para>
     ///     <para>
+    ///         If a size is provided, the behavior of <see cref="Dim.DimAutoStyle.Content"/> will be to use the ContentSize
+    ///         to determine the size of the view.
+    ///     </para>
+    ///     <para>
     ///         Negative sizes are not supported.
     ///     </para>
     /// </remarks>
-    public Size ContentSize
+    public Size? ContentSize
     {
-        get => _contentSize == Size.Empty ? Viewport.Size : _contentSize;
+        get => _contentSize ?? Viewport.Size;
         set
         {
-            if (value.Width < 0 || value.Height < 0)
+            if (value?.Width < 0 || value?.Height < 0)
             {
                 throw new ArgumentException (@"ContentSize cannot be negative.", nameof (value));
             }
@@ -166,8 +170,9 @@ public partial class View
 
         if (e.Cancel != true)
         {
-            SetNeedsLayout ();
-            SetNeedsDisplay ();
+            OnResizeNeeded ();
+            //SetNeedsLayout ();
+            //SetNeedsDisplay ();
         }
 
         return e.Cancel;
@@ -191,9 +196,7 @@ public partial class View
         contentRelativeToViewport.Offset (-Viewport.X, -Viewport.Y);
 
         // Translate to Screen-Relative (our SuperView's Viewport-relative coordinates)
-        Rectangle screen = ViewportToScreen (new (contentRelativeToViewport, Size.Empty));
-
-        return screen.Location;
+        return ViewportToScreen (contentRelativeToViewport);
     }
 
     /// <summary>Converts a Screen-relative coordinate to a Content-relative coordinate.</summary>
@@ -206,7 +209,7 @@ public partial class View
     public Point ScreenToContent (in Point location)
     {
         Point viewportOffset = GetViewportOffsetFromFrame ();
-        Point screen = ScreenToFrame (location.X, location.Y);
+        Point screen = ScreenToFrame (location);
         screen.Offset (Viewport.X - viewportOffset.X, Viewport.Y - viewportOffset.Y);
 
         return screen;
@@ -251,7 +254,8 @@ public partial class View
     /// <summary>
     ///     Gets or sets the rectangle describing the portion of the View's content that is visible to the user.
     ///     The viewport Location is relative to the top-left corner of the inner rectangle of <see cref="Padding"/>.
-    ///     If the viewport Size is the same as <see cref="ContentSize"/> the Location will be <c>0, 0</c>.
+    ///     If the viewport Size is the same as <see cref="ContentSize"/>, or <see cref="ContentSize"/> is
+    ///     <see langword="null"/> the Location will be <c>0, 0</c>.
     /// </summary>
     /// <value>
     ///     The rectangle describing the location and size of the viewport into the View's virtual content, described by
@@ -289,10 +293,10 @@ public partial class View
         get
         {
 #if DEBUG
-            if (LayoutStyle == LayoutStyle.Computed && !IsInitialized)
+            if ((_width.ReferencesOtherViews () || _height.ReferencesOtherViews ()) && !IsInitialized)
             {
                 Debug.WriteLine (
-                                 $"WARNING: Viewport is being accessed before the View has been initialized. This is likely a bug in {this}"
+                                 $"WARNING: The dimensions of {this} are dependent on other views and Viewport is being accessed before the View has been initialized. This is likely a bug."
                                 );
             }
 #endif // DEBUG
@@ -303,8 +307,26 @@ public partial class View
                 return new (_viewportLocation, Frame.Size);
             }
 
-            Thickness thickness = GetAdornmentsThickness ();
+            // BUGBUG: This is a hack. Viewport_get should not have side effects.
+            if (Frame.Size == Size.Empty)
+            {
+                // The Frame has not been set yet (e.g. the view has not been added to a SuperView yet).
+                // 
+                if ((Width is Dim.DimAuto widthAuto && widthAuto._style.HasFlag(Dim.DimAutoStyle.Text))
+                    || (Height is Dim.DimAuto heightAuto && heightAuto._style.HasFlag (Dim.DimAutoStyle.Text)))
+                {
+                    if (TextFormatter.NeedsFormat)
+                    {
+                        // This updates TextFormatter.Size to the text size
+                        TextFormatter.AutoSize = true;
+
+                        // Whenever DimAutoStyle.Text is set, ContentSize will match TextFormatter.Size.
+                        ContentSize = TextFormatter.Size == Size.Empty ? null : TextFormatter.Size;
+                    }
+                }
+            }
 
+            Thickness thickness = GetAdornmentsThickness ();
             return new (
                         _viewportLocation,
                         new (
@@ -337,7 +359,6 @@ public partial class View
             }
 
             OnViewportChanged (new (IsInitialized ? Viewport : Rectangle.Empty, oldViewport));
-
             return;
         }
 
@@ -353,9 +374,9 @@ public partial class View
         {
             if (!ViewportSettings.HasFlag (ViewportSettings.AllowXGreaterThanContentWidth))
             {
-                if (newViewport.X >= ContentSize.Width)
+                if (newViewport.X >= ContentSize.GetValueOrDefault ().Width)
                 {
-                    newViewport.X = ContentSize.Width - 1;
+                    newViewport.X = ContentSize.GetValueOrDefault ().Width - 1;
                 }
             }
 
@@ -370,9 +391,9 @@ public partial class View
 
             if (!ViewportSettings.HasFlag (ViewportSettings.AllowYGreaterThanContentHeight))
             {
-                if (newViewport.Y >= ContentSize.Height)
+                if (newViewport.Y >= ContentSize.GetValueOrDefault().Height)
                 {
-                    newViewport.Y = ContentSize.Height - 1;
+                    newViewport.Y = ContentSize.GetValueOrDefault ().Height - 1;
                 }
             }
 
@@ -397,7 +418,23 @@ public partial class View
     ///     Called when the <see cref="Viewport"/> changes. Invokes the <see cref="ViewportChanged"/> event.
     /// </summary>
     /// <param name="e"></param>
-    protected virtual void OnViewportChanged (DrawEventArgs e) { ViewportChanged?.Invoke (this, e); }
+    protected virtual void OnViewportChanged (DrawEventArgs e)
+    {
+        ViewportChanged?.Invoke (this, e);
+    }
+
+    /// <summary>
+    ///     Converts a <see cref="Viewport"/>-relative location and size to a screen-relative location and size.
+    /// </summary>
+    /// <remarks>
+    ///     Viewport-relative means relative to the top-left corner of the inner rectangle of the <see cref="Padding"/>.
+    /// </remarks>
+    /// <param name="viewport">Viewport-relative location and size.</param>
+    /// <returns>Screen-relative location and size.</returns>
+    public Rectangle ViewportToScreen (in Rectangle viewport)
+    {
+        return viewport with { Location = ViewportToScreen (viewport.Location) };
+    }
 
     /// <summary>
     ///     Converts a <see cref="Viewport"/>-relative location to a screen-relative location.
@@ -405,14 +442,16 @@ public partial class View
     /// <remarks>
     ///     Viewport-relative means relative to the top-left corner of the inner rectangle of the <see cref="Padding"/>.
     /// </remarks>
-    public Rectangle ViewportToScreen (in Rectangle location)
+    /// <param name="viewportLocation">Viewport-relative location.</param>
+    /// <returns>Screen-relative location.</returns>
+    public Point ViewportToScreen (in Point viewportLocation)
     {
         // Translate bounds to Frame (our SuperView's Viewport-relative coordinates)
         Rectangle screen = FrameToScreen ();
         Point viewportOffset = GetViewportOffsetFromFrame ();
-        screen.Offset (viewportOffset.X + location.X, viewportOffset.Y + location.Y);
+        screen.Offset (viewportOffset.X + viewportLocation.X, viewportOffset.Y + viewportLocation.Y);
 
-        return new (screen.Location, location.Size);
+        return screen.Location;
     }
 
     /// <summary>Converts a screen-relative coordinate to a Viewport-relative coordinate.</summary>
@@ -420,15 +459,15 @@ public partial class View
     /// <remarks>
     ///     Viewport-relative means relative to the top-left corner of the inner rectangle of the <see cref="Padding"/>.
     /// </remarks>
-    /// <param name="x">Column relative to the left side of the Viewport.</param>
-    /// <param name="y">Row relative to the top of the Viewport</param>
-    public Point ScreenToViewport (int x, int y)
+    /// <param name="location">Screen-Relative Coordinate.</param>
+    /// <returns>Viewport-relative location.</returns>
+    public Point ScreenToViewport (in Point location)
     {
         Point viewportOffset = GetViewportOffsetFromFrame ();
-        Point screen = ScreenToFrame (x, y);
-        screen.Offset (-viewportOffset.X, -viewportOffset.Y);
+        Point frame = ScreenToFrame (location);
+        frame.Offset (-viewportOffset.X, -viewportOffset.Y);
 
-        return screen;
+        return frame;
     }
 
     /// <summary>

+ 3 - 0
Terminal.Gui/View/ViewDiagnostics.cs

@@ -1,8 +1,11 @@
 
+using Terminal.Gui.Analyzers.Internal.Attributes;
+
 namespace Terminal.Gui;
 
 /// <summary>Enables diagnostic functions for <see cref="View"/>.</summary>
 [Flags]
+[GenerateEnumExtensionMethods(FastHasFlags = true)]
 public enum ViewDiagnosticFlags : uint
 {
     /// <summary>All diagnostics off</summary>

+ 7 - 17
Terminal.Gui/View/ViewDrawing.cs

@@ -106,11 +106,11 @@ public partial class View
 
         if (ViewportSettings.HasFlag (ViewportSettings.ClearContentOnly))
         {
-            Rectangle visibleContent = ViewportToScreen (new (new (-Viewport.X, -Viewport.Y), ContentSize));
+            Rectangle visibleContent = ViewportToScreen (new Rectangle (new (-Viewport.X, -Viewport.Y), ContentSize.GetValueOrDefault ()));
             toClear = Rectangle.Intersect (toClear, visibleContent);
         }
 
-        Attribute prev = Driver.SetAttribute (GetNormalColor());
+        Attribute prev = Driver.SetAttribute (GetNormalColor ());
         Driver.FillRect (toClear);
         Driver.SetAttribute (prev);
 
@@ -134,7 +134,7 @@ public partial class View
 
         Driver.Clip = Rectangle.Intersect (prevClip, ViewportToScreen (Viewport with { Location = new (0, 0) }));
 
-        Attribute prev = Driver.SetAttribute (new (color ?? GetNormalColor().Background));
+        Attribute prev = Driver.SetAttribute (new (color ?? GetNormalColor ().Background));
         Driver.FillRect (toClear);
         Driver.SetAttribute (prev);
 
@@ -172,7 +172,7 @@ public partial class View
         if (ViewportSettings.HasFlag (ViewportSettings.ClipContentOnly))
         {
             // Clamp the Clip to the just content area that is within the viewport
-            Rectangle visibleContent = ViewportToScreen (new (new (-Viewport.X, -Viewport.Y), ContentSize));
+            Rectangle visibleContent = ViewportToScreen (new Rectangle (new (-Viewport.X, -Viewport.Y), ContentSize.GetValueOrDefault ()));
             clip = Rectangle.Intersect (clip, visibleContent);
         }
 
@@ -396,7 +396,7 @@ public partial class View
             return false;
         }
 
-        Rectangle screen = ViewportToScreen (new (col, row, 0, 0));
+        var screen = ViewportToScreen (new Point (col, row));
         Driver?.Move (screen.X, screen.Y);
 
         return true;
@@ -475,7 +475,7 @@ public partial class View
 
             // This should NOT clear 
             // TODO: If the output is not in the Viewport, do nothing
-            var drawRect = new Rectangle (ContentToScreen (Point.Empty), ContentSize);
+            var drawRect = new Rectangle (ContentToScreen (Point.Empty), ContentSize.GetValueOrDefault ());
 
             TextFormatter?.Draw (
                                  drawRect,
@@ -577,10 +577,7 @@ public partial class View
     /// </remarks>
     public void SetNeedsDisplay ()
     {
-        if (IsInitialized)
-        {
-            SetNeedsDisplay (Viewport);
-        }
+        SetNeedsDisplay (Viewport);
     }
 
     /// <summary>Expands the area of this view needing to be redrawn to include <paramref name="region"/>.</summary>
@@ -597,13 +594,6 @@ public partial class View
     /// <param name="region">The content-relative region that needs to be redrawn.</param>
     public void SetNeedsDisplay (Rectangle region)
     {
-        if (!IsInitialized)
-        {
-            _needsDisplayRect = region;
-
-            return;
-        }
-
         if (_needsDisplayRect.IsEmpty)
         {
             _needsDisplayRect = region;

+ 1 - 1
Terminal.Gui/View/ViewKeyboard.cs

@@ -205,7 +205,7 @@ public partial class View
         }
         set
         {
-            TitleTextFormatter.HotKeySpecifier = value;
+            TitleTextFormatter.HotKeySpecifier = TextFormatter.HotKeySpecifier = value;
             SetHotKeyFromTitle ();
         }
     }

+ 2 - 2
Terminal.Gui/View/ViewMouse.cs

@@ -333,7 +333,7 @@ public partial class View
                 mouseEvent.Handled = true;
             }
 
-            if (Viewport.Contains (mouseEvent.X, mouseEvent.Y))
+            if (Viewport.Contains (mouseEvent.Position))
             {
                 if (SetHighlight (HighlightStyle.HasFlag (HighlightStyle.Pressed) ? HighlightStyle.Pressed : HighlightStyle.None) == true)
                 {
@@ -414,7 +414,7 @@ public partial class View
             }
 
             // If mouse is still in bounds, click
-            if (!WantContinuousButtonPressed && Viewport.Contains (mouseEvent.X, mouseEvent.Y))
+            if (!WantContinuousButtonPressed && Viewport.Contains (mouseEvent.Position))
             {
                 return OnMouseClick (new (mouseEvent));
             }

+ 65 - 70
Terminal.Gui/View/ViewSubViews.cs

@@ -31,14 +31,14 @@ public partial class View
 
     /// <summary>Adds a subview (child) to this view.</summary>
     /// <remarks>
-    /// <para>
-    ///     The Views that have been added to this view can be retrieved via the <see cref="Subviews"/> property. See also
-    ///     <seealso cref="Remove(View)"/> <seealso cref="RemoveAll"/>
-    /// </para>
-    /// <para>
-    ///     Subviews will be disposed when this View is disposed. In other-words, calling this method causes
-    ///     the lifecycle of the subviews to be transferred to this View.
-    /// </para>
+    ///     <para>
+    ///         The Views that have been added to this view can be retrieved via the <see cref="Subviews"/> property. See also
+    ///         <seealso cref="Remove(View)"/> <seealso cref="RemoveAll"/>
+    ///     </para>
+    ///     <para>
+    ///         Subviews will be disposed when this View is disposed. In other-words, calling this method causes
+    ///         the lifecycle of the subviews to be transferred to this View.
+    ///     </para>
     /// </remarks>
     public virtual void Add (View view)
     {
@@ -49,12 +49,12 @@ public partial class View
 
         if (_subviews is null)
         {
-            _subviews = new List<View> ();
+            _subviews = new ();
         }
 
         if (_tabIndexes is null)
         {
-            _tabIndexes = new List<View> ();
+            _tabIndexes = new ();
         }
 
         _subviews.Add (view);
@@ -83,7 +83,7 @@ public partial class View
             view.Enabled = false;
         }
 
-        OnAdded (new SuperViewChangedEventArgs (this, view));
+        OnAdded (new (this, view));
 
         if (IsInitialized && !view.IsInitialized)
         {
@@ -91,6 +91,7 @@ public partial class View
             view.EndInit ();
         }
 
+        CheckDimAuto ();
         SetNeedsLayout ();
         SetNeedsDisplay ();
     }
@@ -98,14 +99,14 @@ public partial class View
     /// <summary>Adds the specified views (children) to the view.</summary>
     /// <param name="views">Array of one or more views (can be optional parameter).</param>
     /// <remarks>
-    /// <para>
-    ///     The Views that have been added to this view can be retrieved via the <see cref="Subviews"/> property. See also
-    ///     <seealso cref="Remove(View)"/> and <seealso cref="RemoveAll"/>.
-    /// </para>
-    /// <para>
-    ///     Subviews will be disposed when this View is disposed. In other-words, calling this method causes
-    ///     the lifecycle of the subviews to be transferred to this View.
-    /// </para>
+    ///     <para>
+    ///         The Views that have been added to this view can be retrieved via the <see cref="Subviews"/> property. See also
+    ///         <seealso cref="Remove(View)"/> and <seealso cref="RemoveAll"/>.
+    ///     </para>
+    ///     <para>
+    ///         Subviews will be disposed when this View is disposed. In other-words, calling this method causes
+    ///         the lifecycle of the subviews to be transferred to this View.
+    ///     </para>
     /// </remarks>
     public void Add (params View [] views)
     {
@@ -198,10 +199,11 @@ public partial class View
 
     /// <summary>Removes a subview added via <see cref="Add(View)"/> or <see cref="Add(View[])"/> from this View.</summary>
     /// <remarks>
-    /// <para>
-    ///     Normally Subviews will be disposed when this View is disposed. Removing a Subview causes ownership of the Subview's
-    ///     lifecycle to be transferred to the caller; the caller muse call <see cref="Dispose"/>.
-    /// </para>
+    ///     <para>
+    ///         Normally Subviews will be disposed when this View is disposed. Removing a Subview causes ownership of the
+    ///         Subview's
+    ///         lifecycle to be transferred to the caller; the caller muse call <see cref="Dispose"/>.
+    ///     </para>
     /// </remarks>
     public virtual void Remove (View view)
     {
@@ -226,7 +228,7 @@ public partial class View
             }
         }
 
-        OnRemoved (new SuperViewChangedEventArgs (this, view));
+        OnRemoved (new (this, view));
 
         if (Focused == view)
         {
@@ -235,13 +237,15 @@ public partial class View
     }
 
     /// <summary>
-    /// Removes all subviews (children) added via <see cref="Add(View)"/> or <see cref="Add(View[])"/> from this View.
+    ///     Removes all subviews (children) added via <see cref="Add(View)"/> or <see cref="Add(View[])"/> from this View.
     /// </summary>
     /// <remarks>
-    /// <para>
-    ///     Normally Subviews will be disposed when this View is disposed. Removing a Subview causes ownership of the Subview's
-    ///     lifecycle to be transferred to the caller; the caller must call <see cref="Dispose"/> on any Views that were added.
-    /// </para>
+    ///     <para>
+    ///         Normally Subviews will be disposed when this View is disposed. Removing a Subview causes ownership of the
+    ///         Subview's
+    ///         lifecycle to be transferred to the caller; the caller must call <see cref="Dispose"/> on any Views that were
+    ///         added.
+    ///     </para>
     /// </remarks>
     public virtual void RemoveAll ()
     {
@@ -378,7 +382,6 @@ public partial class View
         }
     }
 
-
     /// <summary>Event fired when the <see cref="CanFocus"/> value is being changed.</summary>
     public event EventHandler CanFocusChanged;
 
@@ -481,7 +484,9 @@ public partial class View
         }
     }
 
-    /// <summary>Method invoked when a view gets focus.</summary>
+    /// <summary>
+    /// Called when a view gets focus.
+    /// </summary>
     /// <param name="view">The view that is losing focus.</param>
     /// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
     public virtual bool OnEnter (View view)
@@ -493,11 +498,10 @@ public partial class View
         {
             return true;
         }
-        
+
         return false;
     }
 
-
     /// <summary>Method invoked when a view loses focus.</summary>
     /// <param name="view">The view that is getting focus.</param>
     /// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
@@ -511,16 +515,16 @@ public partial class View
             return true;
         }
 
-        Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-
         return false;
     }
 
-    /// <summary>Returns the currently focused view inside this view, or null if nothing is focused.</summary>
+    // BUGBUG: This API is poorly defined and implemented. It does not specify what it means if THIS view is focused and has no subviews.
+    /// <summary>Returns the currently focused Subview inside this view, or null if nothing is focused.</summary>
     /// <value>The focused.</value>
     public View Focused { get; private set; }
 
-    /// <summary>Returns the most focused view in the chain of subviews (the leaf view that has the focus).</summary>
+    // BUGBUG: This API is poorly defined and implemented. It does not specify what it means if THIS view is focused and has no subviews.
+    /// <summary>Returns the most focused Subview in the chain of subviews (the leaf view that has the focus).</summary>
     /// <value>The most focused View.</value>
     public View MostFocused
     {
@@ -848,43 +852,34 @@ public partial class View
         return view.Focused is { } ? GetMostFocused (view.Focused) : view;
     }
 
-    /// <summary>Positions the cursor in the right position based on the currently focused view in the chain.</summary>
-    /// Views that are focusable should override
-    /// <see cref="PositionCursor"/>
-    /// to ensure
-    /// the cursor is placed in a location that makes sense. Unix terminals do not have
-    /// a way of hiding the cursor, so it can be distracting to have the cursor left at
-    /// the last focused view. Views should make sure that they place the cursor
-    /// in a visually sensible place.
-    public virtual void PositionCursor ()
-    {
-        if (!CanBeVisible (this) || !Enabled)
-        {
-            return;
-        }
-
-        // BUGBUG: v2 - This needs to support Subviews of Adornments too
+    /// <summary>
+    /// Gets or sets the cursor style to be used when the view is focused. The default is <see cref="CursorVisibility.Invisible"/>.
+    /// </summary>
+    public CursorVisibility CursorVisibility { get; set; } = CursorVisibility.Invisible;
 
-        if (Focused is null && SuperView is { })
-        {
-            SuperView.EnsureFocus ();
-        }
-        else if (Focused is { Visible: true, Enabled: true, Frame: { Width: > 0, Height: > 0 } })
-        {
-            Focused.PositionCursor ();
-        }
-        else if (Focused?.Visible == true && Focused?.Enabled == false)
-        {
-            Focused = null;
-        }
-        else if (CanFocus && HasFocus && Visible && Frame.Width > 0 && Frame.Height > 0)
+    /// <summary>
+    ///     Positions the cursor in the right position based on the currently focused view in the chain.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Views that are focusable should override <see cref="PositionCursor"/> to make sure that the cursor is
+    ///         placed in a location that makes sense. Some terminals do not have a way of hiding the cursor, so it can be
+    ///         distracting to have the cursor left at the last focused view. So views should make sure that they place the
+    ///         cursor in a visually sensible place. The default implementation of <see cref="PositionCursor"/> will place the
+    ///         cursor at either the hotkey (if defined) or <c>0,0</c>.
+    ///     </para>
+    /// </remarks>
+    /// <returns>Viewport-relative cursor position. Return <see langword="null"/> to ensure the cursor is not visible.</returns>
+    public virtual Point? PositionCursor ()
+    {
+        if (IsInitialized && CanFocus && HasFocus && ContentSize.HasValue)
         {
+            // By default, position the cursor at the hotkey (if any) or 0, 0.
             Move (TextFormatter.HotKeyPos == -1 ? 0 : TextFormatter.CursorPosition, 0);
         }
-        else
-        {
-            Move (_frame.X, _frame.Y);
-        }
+
+        // Returning null will hide the cursor.
+        return null;
     }
 
     #endregion Focus

+ 52 - 241
Terminal.Gui/View/ViewText.cs

@@ -1,13 +1,16 @@
-namespace Terminal.Gui;
+using static Terminal.Gui.SpinnerStyle;
+
+namespace Terminal.Gui;
 
 public partial class View
 {
     private string _text;
 
     /// <summary>
-    ///     Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved or not when
-    ///     <see cref="TextFormatter.WordWrap"/> is enabled. If <see langword="true"/> trailing spaces at the end of wrapped
-    ///     lines will be removed when <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
+    ///     Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
+    ///     or not when <see cref="TextFormatter.WordWrap"/> is enabled.
+    ///     If <see langword="true"/> trailing spaces at the end of wrapped lines will be removed when
+    ///     <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
     /// </summary>
     public virtual bool PreserveTrailingSpaces
     {
@@ -22,18 +25,23 @@ public partial class View
         }
     }
 
-    /// <summary>The text displayed by the <see cref="View"/>.</summary>
+    /// <summary>
+    ///     The text displayed by the <see cref="View"/>.
+    /// </summary>
     /// <remarks>
-    ///     <para>The text will be drawn before any subviews are drawn.</para>
     ///     <para>
-    ///         The text will be drawn starting at the view origin (0, 0) and will be formatted according to
-    ///         <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
+    ///         The text will be drawn before any subviews are drawn.
     ///     </para>
     ///     <para>
-    ///         The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="Viewport"/>'s height
+    ///         The text will be drawn starting at the view origin (0, 0) and will be formatted according
+    ///         to <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
+    ///     </para>
+    ///     <para>
+    ///         The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="ContentSize"/>'s height
     ///         is 1, the text will be clipped.
     ///     </para>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Viewport"/> will be adjusted to fit the text.</para>
+    ///     <para>If <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="Dim.DimAutoStyle.Text"/>,
+    ///     the <see cref="ContentSize"/> will be adjusted to fit the text.</para>
     ///     <para>When the text changes, the <see cref="TextChanged"/> is fired.</para>
     /// </remarks>
     public virtual string Text
@@ -41,13 +49,9 @@ public partial class View
         get => _text;
         set
         {
-            if (value == _text)
-            {
-                return;
-            }
-
             string old = _text;
             _text = value;
+
             UpdateTextFormatterText ();
             OnResizeNeeded ();
 #if DEBUG
@@ -80,7 +84,7 @@ public partial class View
     ///     redisplay the <see cref="View"/>.
     /// </summary>
     /// <remarks>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Viewport"/> will be adjusted to fit the text.</para>
+    ///     <para> <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="Dim.DimAutoStyle.Text"/>, the <see cref="ContentSize"/> will be adjusted to fit the text.</para>
     /// </remarks>
     /// <value>The text alignment.</value>
     public virtual TextAlignment TextAlignment
@@ -99,7 +103,7 @@ public partial class View
     ///     <see cref="View"/>.
     /// </summary>
     /// <remarks>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Viewport"/> will be adjusted to fit the text.</para>
+    ///     <para> <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="Dim.DimAutoStyle.Text"/>, the <see cref="ContentSize"/> will be adjusted to fit the text.</para>
     /// </remarks>
     /// <value>The text alignment.</value>
     public virtual TextDirection TextDirection
@@ -112,15 +116,18 @@ public partial class View
         }
     }
 
-    /// <summary>Gets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.</summary>
-    public TextFormatter TextFormatter { get; init; } = new ();
+    /// <summary>
+    ///     Gets or sets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.
+    /// </summary>
+    public TextFormatter TextFormatter { get; init; } = new () { };
 
     /// <summary>
     ///     Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will
-    ///     redisplay the <see cref="View"/>.
+    ///     redisplay
+    ///     the <see cref="View"/>.
     /// </summary>
     /// <remarks>
-    ///     <para>If <see cref="AutoSize"/> is <c>true</c>, the <see cref="Viewport"/> will be adjusted to fit the text.</para>
+    ///     <para> <see cref="View.Width"/> or <see cref="View.Height"/> are using <see cref="Dim.DimAutoStyle.Text"/>, the <see cref="ContentSize"/> will be adjusted to fit the text.</para>
     /// </remarks>
     /// <value>The text alignment.</value>
     public virtual VerticalTextAlignment VerticalTextAlignment
@@ -134,78 +141,9 @@ public partial class View
     }
 
     /// <summary>
-    ///     Gets the Frame dimensions required to fit <see cref="Text"/> within <see cref="Viewport"/> using the text
-    ///     <see cref="NavigationDirection"/> specified by the <see cref="TextFormatter"/> property and accounting for any
-    ///     <see cref="HotKeySpecifier"/> characters.
+    ///     Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
+    ///     different format than the default.
     /// </summary>
-    /// <returns>The <see cref="Size"/> the <see cref="Frame"/> needs to be set to fit the text.</returns>
-    public Size GetAutoSize ()
-    {
-        var x = 0;
-        var y = 0;
-
-        if (IsInitialized)
-        {
-            x = Viewport.X;
-            y = Viewport.Y;
-        }
-
-        Rectangle rect = TextFormatter.CalcRect (x, y, TextFormatter.Text, TextFormatter.Direction);
-
-        int newWidth = rect.Size.Width
-                       - GetHotKeySpecifierLength ()
-                       + (Margin == null
-                              ? 0
-                              : Margin.Thickness.Horizontal
-                                + Border.Thickness.Horizontal
-                                + Padding.Thickness.Horizontal);
-
-        int newHeight = rect.Size.Height
-                        - GetHotKeySpecifierLength (false)
-                        + (Margin == null
-                               ? 0
-                               : Margin.Thickness.Vertical + Border.Thickness.Vertical + Padding.Thickness.Vertical);
-
-        return new (newWidth, newHeight);
-    }
-
-    /// <summary>
-    ///     Gets the width or height of the <see cref="TextFormatter.HotKeySpecifier"/> characters in the
-    ///     <see cref="Text"/> property.
-    /// </summary>
-    /// <remarks>
-    ///     <para>
-    ///         This is for <see cref="Text"/>, not <see cref="Title"/>. For <see cref="Text"/> to show the hotkey,
-    ///         set <c>View.</c><see cref="TextFormatter.HotKeySpecifier"/> to the desired character.
-    ///     </para>
-    ///     <para>
-    ///         Only the first HotKey specifier found in <see cref="Text"/> is supported.
-    ///     </para>
-    /// </remarks>
-    /// <param name="isWidth">
-    ///     If <see langword="true"/> (the default) the width required for the HotKey specifier is returned.
-    ///     Otherwise the height is returned.
-    /// </param>
-    /// <returns>
-    ///     The number of characters required for the <see cref="TextFormatter.HotKeySpecifier"/>. If the text direction
-    ///     specified by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is
-    ///     returned.
-    /// </returns>
-    public int GetHotKeySpecifierLength (bool isWidth = true)
-    {
-        if (isWidth)
-        {
-            return TextFormatter.IsHorizontalDirection (TextDirection) && TextFormatter.Text?.Contains ((char)TextFormatter.HotKeySpecifier.Value) == true
-                       ? Math.Max (TextFormatter.HotKeySpecifier.GetColumns (), 0)
-                       : 0;
-        }
-
-        return TextFormatter.IsVerticalDirection (TextDirection) && TextFormatter.Text?.Contains ((char)TextFormatter.HotKeySpecifier.Value) == true
-                   ? Math.Max (TextFormatter.HotKeySpecifier.GetColumns (), 0)
-                   : 0;
-    }
-
-    /// <summary>Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has different format than the default.</summary>
     protected virtual void UpdateTextFormatterText ()
     {
         if (TextFormatter is { })
@@ -214,14 +152,15 @@ public partial class View
         }
     }
 
-    /// <summary>Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="TextFormatter.HotKeySpecifier"/>.</summary>
+    /// <summary>
+    ///     Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="TextFormatter.HotKeySpecifier"/>.
+    /// </summary>
     /// <returns></returns>
     internal Size GetSizeNeededForTextWithoutHotKey ()
     {
-        return new (
-                    TextFormatter.Size.Width - GetHotKeySpecifierLength (),
-                    TextFormatter.Size.Height - GetHotKeySpecifierLength (false)
-                   );
+        return new Size (
+                         TextFormatter.Size.Width - TextFormatter.GetHotKeySpecifierLength (),
+                         TextFormatter.Size.Height - TextFormatter.GetHotKeySpecifierLength (false));
     }
 
     /// <summary>
@@ -229,171 +168,43 @@ public partial class View
     ///     <see cref="TextFormatter.HotKeySpecifier"/>.
     /// </summary>
     /// <remarks>
-    ///     Use this API to set <see cref="TextFormatter.Size"/> when the view has changed such that the size required to
-    ///     fit the text has changed. changes.
+    ///     Use this API to set <see cref="TextFormatter.Size"/> when the view has changed such that the
+    ///     size required to fit the text has changed.
+    ///     changes.
     /// </remarks>
     /// <returns></returns>
     internal void SetTextFormatterSize ()
     {
-        if (!IsInitialized)
-        {
-            TextFormatter.Size = Size.Empty;
-
-            return;
-        }
+        UpdateTextFormatterText ();
 
-        if (string.IsNullOrEmpty (TextFormatter.Text))
+        // TODO: This is a hack. Figure out how to move this into DimDimAuto
+        // Use _width & _height instead of Width & Height to avoid debug spew
+        if ((_width is Dim.DimAuto widthAuto && widthAuto._style.HasFlag (Dim.DimAutoStyle.Text))
+            || (_height is Dim.DimAuto heightAuto && heightAuto._style.HasFlag (Dim.DimAutoStyle.Text)))
         {
-            TextFormatter.Size = ContentSize;
+            // This updates TextFormatter.Size to the text size
+            TextFormatter.AutoSize = true;
 
+            // Whenever DimAutoStyle.Text is set, ContentSize will match TextFormatter.Size.
+            ContentSize = TextFormatter.Size == Size.Empty ? null : TextFormatter.Size;
             return;
         }
 
-        TextFormatter.Size = new (
-                                  ContentSize.Width + GetHotKeySpecifierLength (),
-                                  ContentSize.Height + GetHotKeySpecifierLength (false)
-                                 );
-    }
-
-    private bool IsValidAutoSize (out Size autoSize)
-    {
-        Rectangle rect = TextFormatter.CalcRect (_frame.X, _frame.Y, TextFormatter.Text, TextDirection);
-
-        autoSize = new (
-                        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));
-    }
-
-    private bool IsValidAutoSizeHeight (Dim height)
-    {
-        Rectangle 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));
-    }
-
-    private bool IsValidAutoSizeWidth (Dim width)
-    {
-        Rectangle 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 ());
-    }
-
-    /// <summary>Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>.</summary>
-    /// <returns>
-    ///     <see langword="true"/> if the size was changed; <see langword="false"/> if <see cref="AutoSize"/> ==
-    ///     <see langword="true"/> or <see cref="Text"/> will not fit.
-    /// </returns>
-    /// <remarks>
-    ///     Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or if
-    ///     <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero. Does not take into
-    ///     account word wrapping.
-    /// </remarks>
-    private bool SetFrameToFitText ()
-    {
-        if (AutoSize == false)
-        {
-            throw new InvalidOperationException ("SetFrameToFitText can only be called when AutoSize is true");
-        }
-
-        // BUGBUG: This API is broken - should not assume Frame.Height == Viewport.Height
-        // <summary>
-        // Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
-        // </summary>
-        // <param name="sizeRequired">The minimum dimensions required.</param>
-        // <returns><see langword="true"/> if the dimensions fit within the View's <see cref="Viewport"/>, <see langword="false"/> otherwise.</returns>
-        // <remarks>
-        // Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
-        // if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
-        // Does not take into account word wrapping.
-        // </remarks>
-        bool GetMinimumSizeOfText (out Size sizeRequired)
-        {
-            if (!IsInitialized)
-            {
-                sizeRequired = Size.Empty;
-
-                return false;
-            }
-
-            sizeRequired = ContentSize;
-
-            if (AutoSize || string.IsNullOrEmpty (TextFormatter.Text))
-            {
-                return false;
-            }
-
-            switch (TextFormatter.IsVerticalDirection (TextDirection))
-            {
-                case true:
-                    int colWidth = TextFormatter.GetColumnsRequiredForVerticalText (new List<string> { TextFormatter.Text }, 0, 1);
-
-                    // TODO: v2 - This uses frame.Width; it should only use Viewport
-                    if (_frame.Width < colWidth
-                        && (Width is null || (ContentSize.Width >= 0 && Width is Dim.DimAbsolute && Width.Anchor (0) >= 0 && Width.Anchor (0) < colWidth)))
-                    {
-                        sizeRequired = new (colWidth, ContentSize.Height);
-
-                        return true;
-                    }
-
-                    break;
-                default:
-                    if (_frame.Height < 1 && (Height is null || (Height is Dim.DimAbsolute && Height.Anchor (0) == 0)))
-                    {
-                        sizeRequired = new (ContentSize.Width, 1);
-
-                        return true;
-                    }
-
-                    break;
-            }
-
-            return false;
-        }
-
-        if (GetMinimumSizeOfText (out Size size))
-        {
-            // TODO: This is a hack.
-            //_width  = size.Width;
-            //_height = size.Height;
-            SetFrame (new (_frame.Location, size));
-
-            //throw new InvalidOperationException ("This is a hack.");
-            return true;
-        }
-
-        return false;
+        TextFormatter.AutoSize = false;
+        TextFormatter.Size = new Size (ContentSize.GetValueOrDefault ().Width, ContentSize.GetValueOrDefault ().Height);
     }
 
-    // only called from EndInit
     private void UpdateTextDirection (TextDirection newDirection)
     {
-        bool directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction)
-                                != TextFormatter.IsHorizontalDirection (newDirection);
+        bool directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction) != TextFormatter.IsHorizontalDirection (newDirection);
         TextFormatter.Direction = newDirection;
 
-        bool isValidOldAutoSize = AutoSize && IsValidAutoSize (out Size _);
-
         UpdateTextFormatterText ();
 
-        if ((!ValidatePosDim && directionChanged && AutoSize)
-            || (ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize))
+        if (directionChanged)
         {
             OnResizeNeeded ();
         }
-        else if (AutoSize && directionChanged && IsAdded)
-        {
-            ResizeViewportToFit (Viewport.Size);
-        }
 
         SetTextFormatterSize ();
         SetNeedsDisplay ();

+ 4 - 14
Terminal.Gui/Views/Button.cs

@@ -45,11 +45,10 @@ public class Button : View
         _leftDefault = Glyphs.LeftDefaultIndicator;
         _rightDefault = Glyphs.RightDefaultIndicator;
 
-        // Ensures a height of 1 if AutoSize is set to false
         Height = 1;
+        Width = Dim.Auto (Dim.DimAutoStyle.Text);
 
         CanFocus = true;
-        AutoSize = true;
         HighlightStyle |= HighlightStyle.Pressed;
 #if HOVER
         HighlightStyle |= HighlightStyle.Hover;
@@ -139,15 +138,7 @@ public class Button : View
     public bool NoPadding { get; set; }
 
     /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
-    /// <inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (HotKey.IsValid && Text != "")
         {
@@ -156,13 +147,12 @@ public class Button : View
                 if (TextFormatter.Text [i] == Text [0])
                 {
                     Move (i, 0);
-
-                    return;
+                    return null; // Don't show the cursor
                 }
             }
         }
 
-        base.PositionCursor ();
+        return base.PositionCursor ();
     }
 
     /// <inheritdoc/>

+ 3 - 15
Terminal.Gui/Views/CheckBox.cs

@@ -20,11 +20,10 @@ public class CheckBox : View
         _charChecked = Glyphs.Checked;
         _charUnChecked = Glyphs.UnChecked;
 
-        // Ensures a height of 1 if AutoSize is set to false
         Height = 1;
+        Width = Dim.Auto (Dim.DimAutoStyle.Text);
 
         CanFocus = true;
-        AutoSize = true;
 
         // Things this view knows how to do
         AddCommand (Command.Accept, OnToggled);
@@ -95,14 +94,6 @@ public class CheckBox : View
         }
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>Called when the <see cref="Checked"/> property changes. Invokes the <see cref="Toggled"/> event.</summary>
     /// <remarks>
     /// </remarks>
@@ -151,9 +142,6 @@ public class CheckBox : View
         return true;
     }
 
-    /// <inheritdoc/>
-    public override void PositionCursor () { Move (0, 0); }
-
     /// <summary>Toggled event, raised when the <see cref="CheckBox"/> is toggled.</summary>
     /// <remarks>
     /// <para>
@@ -192,11 +180,11 @@ public class CheckBox : View
 
     private string GetFormatterText ()
     {
-        if (AutoSize || string.IsNullOrEmpty (Title) || Frame.Width <= 2)
+        if (Width is Dim.DimAuto || string.IsNullOrEmpty (Title) || ContentSize?.Width <= 2)
         {
             return Text;
         }
 
-        return Text [..Math.Min (Frame.Width - 2, Text.GetRuneCount ())];
+        return ContentSize is null ? Text : Text [..Math.Min (ContentSize.Value.Width - 2, Text.GetRuneCount ())];
     }
 }

+ 1 - 8
Terminal.Gui/Views/ColorPicker.cs

@@ -53,7 +53,7 @@ public class ColorPicker : View
     {
         if (CanFocus)
         {
-            Cursor = new Point (me.MouseEvent.X / _boxWidth, me.MouseEvent.Y / _boxHeight);
+            Cursor = new Point (me.MouseEvent.Position.X / _boxWidth, me.MouseEvent.Position.Y / _boxHeight);
             SetFocus ();
             me.Handled = true;
         }
@@ -188,13 +188,6 @@ public class ColorPicker : View
         }
     }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
 
     /// <summary>Add the commands.</summary>
     private void AddCommands ()

+ 7 - 6
Terminal.Gui/Views/ComboBox.cs

@@ -245,8 +245,8 @@ public class ComboBox : View
     /// <inheritdoc/>
     protected internal override bool OnMouseEvent  (MouseEvent me)
     {
-        if (me.X == Viewport.Right - 1
-            && me.Y == Viewport.Top
+        if (me.Position.X == Viewport.Right - 1
+            && me.Position.Y == Viewport.Top
             && me.Flags == MouseFlags.Button1Pressed
             && _autoHide)
         {
@@ -612,13 +612,14 @@ public class ComboBox : View
             Height = _minimumHeight;
         }
 
+        // BUGBUG: This uses Viewport. Should use ContentSize
         if ((!_autoHide && Viewport.Width > 0 && _search.Frame.Width != Viewport.Width)
             || (_autoHide && Viewport.Width > 0 && _search.Frame.Width != Viewport.Width - 1))
         {
             _search.Width = _listview.Width = _autoHide ? Viewport.Width - 1 : Viewport.Width;
             _listview.Height = CalculatetHeight ();
-            _search.SetRelativeLayout (ContentSize);
-            _listview.SetRelativeLayout (ContentSize);
+            _search.SetRelativeLayout (ContentSize.GetValueOrDefault());
+            _listview.SetRelativeLayout (ContentSize.GetValueOrDefault ());
         }
     }
 
@@ -827,7 +828,7 @@ public class ComboBox : View
             {
                 if (isMousePositionValid)
                 {
-                    _highlighted = Math.Min (TopItem + me.Y, Source.Count);
+                    _highlighted = Math.Min (TopItem + me.Position.Y, Source.Count);
                     SetNeedsDisplay ();
                 }
 
@@ -945,7 +946,7 @@ public class ComboBox : View
 
         private bool IsMousePositionValid (MouseEvent me)
         {
-            if (me.X >= 0 && me.X < Frame.Width && me.Y >= 0 && me.Y < Frame.Height)
+            if (me.Position.X >= 0 && me.Position.X < Frame.Width && me.Position.Y >= 0 && me.Position.Y < Frame.Height)
             {
                 return true;
             }

+ 1 - 2
Terminal.Gui/Views/DateField.cs

@@ -120,8 +120,7 @@ public class DateField : TextField
 
         if (result && SelectedLength == 0 && ev.Flags.HasFlag (MouseFlags.Button1Pressed))
         {
-            int point = ev.X;
-            AdjCursorPosition (point);
+            AdjCursorPosition (ev.Position.X);
         }
 
         return result;

+ 0 - 2
Terminal.Gui/Views/DatePicker.cs

@@ -214,7 +214,6 @@ public class DatePicker : View
 
         _previousMonthButton = new Button
         {
-            AutoSize = false,
             X = Pos.Center () - 2,
             Y = Pos.Bottom (_calendar) - 1,
             Height = 1,
@@ -234,7 +233,6 @@ public class DatePicker : View
 
         _nextMonthButton = new Button
         {
-            AutoSize = false,
             X = Pos.Right (_previousMonthButton) + 2,
             Y = Pos.Bottom (_calendar) - 1,
             Height = 1,

+ 2 - 4
Terminal.Gui/Views/Dialog.cs

@@ -61,9 +61,8 @@ public class Dialog : Window
         Y = Pos.Center ();
         ValidatePosDim = true;
 
-        Width = Dim.Percent (85); // Dim.Auto (min: Dim.Percent (10));
-        Height = Dim.Percent (85); //Dim.Auto (min: Dim.Percent (50));
-
+        Width = Dim.Percent (85); 
+        Height = Dim.Percent (85);
         ColorScheme = Colors.ColorSchemes ["Dialog"];
 
         Modal = true;
@@ -147,7 +146,6 @@ public class Dialog : Window
             return;
         }
 
-        //button.AutoSize = false; // BUGBUG: v2 - Hack to get around autosize not accounting for Margin?
         _buttons.Add (button);
         Add (button);
 

+ 3 - 3
Terminal.Gui/Views/FileDialog.cs

@@ -1071,7 +1071,7 @@ public class FileDialog : Dialog
 
     private void OnTableViewMouseClick (object sender, MouseEventEventArgs e)
     {
-        Point? clickedCell = _tableView.ScreenToCell (e.MouseEvent.X, e.MouseEvent.Y, out int? clickedCol);
+        Point? clickedCell = _tableView.ScreenToCell (e.MouseEvent.Position.X, e.MouseEvent.Position.Y, out int? clickedCol);
 
         if (clickedCol is { })
         {
@@ -1269,7 +1269,7 @@ public class FileDialog : Dialog
 
         var contextMenu = new ContextMenu
         {
-            Position = new Point (e.MouseEvent.X + 1, e.MouseEvent.Y + 1),
+            Position = new Point (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1),
             MenuItems = new MenuBarItem (
                                          [
                                              new MenuItem (Strings.fdCtxNew, string.Empty, New),
@@ -1290,7 +1290,7 @@ public class FileDialog : Dialog
 
         var contextMenu = new ContextMenu
         {
-            Position = new Point (e.MouseEvent.X + 1, e.MouseEvent.Y + 1),
+            Position = new Point (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1),
             MenuItems = new MenuBarItem (
                                          [
                                              new MenuItem (

+ 0 - 11
Terminal.Gui/Views/FrameView.cs

@@ -39,15 +39,4 @@ public class FrameView : View
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
     [JsonConverter (typeof (JsonStringEnumConverter))]
     public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
-
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        if (Subviews.Count == 0 || !Subviews.Any (subview => subview.CanFocus))
-        {
-            Application.Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
-        return base.OnEnter (view);
-    }
 }

+ 0 - 9
Terminal.Gui/Views/GraphView/GraphView.cs

@@ -277,15 +277,6 @@ public class GraphView : View
         }
     }
 
-    /// <inheritdoc/>
-    /// <remarks>Also ensures that cursor is invisible after entering the <see cref="GraphView"/>.</remarks>
-    public override bool OnEnter (View view)
-    {
-        Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>Scrolls the graph down 1 page.</summary>
     public void PageDown () { Scroll (0, -1 * CellSize.Y * Viewport.Height); }
 

+ 15 - 37
Terminal.Gui/Views/HexView.cs

@@ -31,7 +31,6 @@ public class HexView : View
     private const int displayWidth = 9;
 
     private int bpl;
-    private CursorVisibility desiredCursorVisibility = CursorVisibility.Default;
     private long displayStart, pos;
     private SortedDictionary<long, byte> edits = [];
     private bool firstNibble, leftSide;
@@ -50,6 +49,7 @@ public class HexView : View
         // BUG: This will always call the most-derived definition of CanFocus.
         // Either seal it or don't set it here.
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
         leftSide = true;
         firstNibble = true;
 
@@ -129,21 +129,6 @@ public class HexView : View
         }
     }
 
-    /// <summary>Get / Set the wished cursor when the field is focused</summary>
-    public CursorVisibility DesiredCursorVisibility
-    {
-        get => desiredCursorVisibility;
-        set
-        {
-            if (desiredCursorVisibility != value && HasFocus)
-            {
-                Application.Driver.SetCursorVisibility (value);
-            }
-
-            desiredCursorVisibility = value;
-        }
-    }
-
     /// <summary>
     ///     Sets or gets the offset into the <see cref="Stream"/> that will displayed at the top of the
     ///     <see cref="HexView"/>
@@ -293,7 +278,7 @@ public class HexView : View
             return true;
         }
 
-        if (me.X < displayWidth)
+        if (me.Position.X < displayWidth)
         {
             return true;
         }
@@ -302,14 +287,14 @@ public class HexView : View
         int blocksSize = nblocks * 14;
         int blocksRightOffset = displayWidth + blocksSize - 1;
 
-        if (me.X > blocksRightOffset + bytesPerLine - 1)
+        if (me.Position.X > blocksRightOffset + bytesPerLine - 1)
         {
             return true;
         }
 
-        leftSide = me.X >= blocksRightOffset;
-        long lineStart = me.Y * bytesPerLine + displayStart;
-        int x = me.X - displayWidth + 1;
+        leftSide = me.Position.X >= blocksRightOffset;
+        long lineStart = me.Position.Y * bytesPerLine + displayStart;
+        int x = me.Position.X - displayWidth + 1;
         int block = x / 14;
         x -= block * 2;
         int empty = x % 3;
@@ -324,7 +309,7 @@ public class HexView : View
 
         if (leftSide)
         {
-            position = Math.Min (lineStart + me.X - blocksRightOffset, source.Length);
+            position = Math.Min (lineStart + me.Position.X - blocksRightOffset, source.Length);
         }
         else
         {
@@ -462,14 +447,6 @@ public class HexView : View
     /// <param name="e">The key value pair.</param>
     public virtual void OnEdited (HexViewEditEventArgs e) { Edited?.Invoke (this, e); }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>
     ///     Method used to invoke the <see cref="PositionChanged"/> event passing the <see cref="HexViewEventArgs"/>
     ///     arguments.
@@ -547,7 +524,7 @@ public class HexView : View
     public event EventHandler<HexViewEventArgs> PositionChanged;
 
     ///<inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         var delta = (int)(position - displayStart);
         int line = delta / bytesPerLine;
@@ -555,14 +532,15 @@ public class HexView : View
         int block = item / bsize;
         int column = item % bsize * 3;
 
-        if (leftSide)
+        int x = displayWidth + block * 14 + column + (firstNibble ? 0 : 1);
+        int y = line;
+        if (!leftSide)
         {
-            Move (displayWidth + block * 14 + column + (firstNibble ? 0 : 1), line);
-        }
-        else
-        {
-            Move (displayWidth + bytesPerLine / bsize * 14 + item - 1, line);
+            x = displayWidth + bytesPerLine / bsize * 14 + item - 1;
         }
+
+        Move (x, y);
+        return new (x, y);
     }
 
     internal void SetDisplayStart (long value)

+ 3 - 9
Terminal.Gui/Views/Label.cs

@@ -15,8 +15,9 @@ public class Label : View
     /// <inheritdoc/>
     public Label ()
     {
-        Height = 1;
-        AutoSize = true;
+        Height = Dim.Auto (Dim.DimAutoStyle.Text);
+        Width = Dim.Auto (Dim.DimAutoStyle.Text);
+        TextFormatter.AutoSize = true;
 
         // Things this view knows how to do
         AddCommand (Command.HotKey, FocusNext);
@@ -63,11 +64,4 @@ public class Label : View
 
         return true;
     }
-
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-        return base.OnEnter (view);
-    }
 }

+ 13 - 16
Terminal.Gui/Views/ListView.cs

@@ -413,14 +413,14 @@ public class ListView : View
             return true;
         }
 
-        if (me.Y + Viewport.Y >= _source.Count
-            || me.Y + Viewport.Y < 0
-            || me.Y + Viewport.Y > Viewport.Y + Viewport.Height)
+        if (me.Position.Y + Viewport.Y >= _source.Count
+            || me.Position.Y + Viewport.Y < 0
+            || me.Position.Y + Viewport.Y > Viewport.Y + Viewport.Height)
         {
             return true;
         }
 
-        _selected = Viewport.Y + me.Y;
+        _selected = Viewport.Y + me.Position.Y;
 
         if (AllowsAll ())
         {
@@ -700,11 +700,6 @@ public class ListView : View
     /// <inheritdoc/>
     public override bool OnEnter (View view)
     {
-        if (IsInitialized)
-        {
-            Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
         if (_lastSelectedItem != _selected)
         {
             EnsureSelectedItemVisible ();
@@ -781,16 +776,18 @@ public class ListView : View
     public event EventHandler<ListViewItemEventArgs> OpenSelectedItem;
 
     /// <inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
-        if (_allowsMarking)
-        {
-            Move (0, _selected - Viewport.Y);
-        }
-        else
+        int x = 0;
+        int y = _selected - Viewport.Y;
+        if (!_allowsMarking)
         {
-            Move (Viewport.Width - 1, _selected - Viewport.Y);
+            x = Viewport.Width - 1;
         }
+
+        Move (x, y);
+
+        return null; // Don't show the cursor
     }
 
     /// <summary>This event is invoked when this <see cref="ListView"/> is being drawn before rendering.</summary>

+ 28 - 35
Terminal.Gui/Views/Menu/Menu.cs

@@ -726,13 +726,12 @@ internal sealed class Menu : View
 
         View view = a.View ?? this;
 
-        Point boundsPoint = view.ScreenToViewport (a.X, a.Y);
+        Point boundsPoint = view.ScreenToViewport (new (a.Position.X, a.Position.Y));
         var me = new MouseEvent
         {
-            X = boundsPoint.X,
-            Y = boundsPoint.Y,
+            Position = boundsPoint,
             Flags = a.Flags,
-            ScreenPosition = new (a.X, a.Y),
+            ScreenPosition = a.Position,
             View = view
         };
 
@@ -751,7 +750,7 @@ internal sealed class Menu : View
 
         if (index == _currentChild)
         {
-            return ColorScheme.Focus;
+            return GetFocusColor ();
         }
 
         return !item.IsEnabled () ? ColorScheme.Disabled : GetNormalColor ();
@@ -787,12 +786,12 @@ internal sealed class Menu : View
 
             Driver.SetAttribute (
                                  item is null ? GetNormalColor () :
-                                 i == _currentChild ? ColorScheme.Focus : GetNormalColor ()
+                                 i == _currentChild ? GetFocusColor() : GetNormalColor ()
                                 );
 
             if (item is null && BorderStyle != LineStyle.None)
             {
-                var s = ViewportToScreen (new (-1, i, 0, 0));
+                var s = ViewportToScreen (new Point (-1, i));
                 Driver.Move (s.X, s.Y);
                 Driver.AddRune (Glyphs.LeftTee);
             }
@@ -840,7 +839,7 @@ internal sealed class Menu : View
             {
                 if (BorderStyle != LineStyle.None && SuperView?.Frame.Right - Frame.X > Frame.Width)
                 {
-                    var s = ViewportToScreen (new (Frame.Width - 2, i, 0, 0));
+                    var s = ViewportToScreen (new Point (Frame.Width - 2, i));
                     Driver.Move (s.X, s.Y);
                     Driver.AddRune (Glyphs.RightTee);
                 }
@@ -877,7 +876,7 @@ internal sealed class Menu : View
                 textToDraw = item.Title;
             }
 
-            Rectangle screen = ViewportToScreen (new (new (0 , i), Size.Empty));
+            var screen = ViewportToScreen (new Point(0  , i));
             if (screen.X < Driver.Cols)
             {
                 Driver.Move (screen.X + 1, screen.Y);
@@ -890,13 +889,14 @@ internal sealed class Menu : View
                 {
                     var tf = new TextFormatter
                     {
+                        AutoSize = true,
                         Alignment = TextAlignment.Centered, HotKeySpecifier = MenuBar.HotKeySpecifier, Text = textToDraw
                     };
 
                     // The -3 is left/right border + one space (not sure what for)
                     tf.Draw (
-                             ViewportToScreen (new (1, i, Frame.Width - 3, 1)),
-                             i == _currentChild ? ColorScheme.Focus : GetNormalColor (),
+                             ViewportToScreen (new Rectangle(1, i, Frame.Width - 3, 1)),
+                             i == _currentChild ? GetFocusColor () : GetNormalColor (),
                              i == _currentChild ? ColorScheme.HotFocus : ColorScheme.HotNormal,
                              SuperView?.ViewportToScreen (SuperView.Viewport) ?? Rectangle.Empty
                             );
@@ -906,7 +906,7 @@ internal sealed class Menu : View
                     DrawHotString (
                                    textToDraw,
                                    i == _currentChild ? ColorScheme.HotFocus : ColorScheme.HotNormal,
-                                   i == _currentChild ? ColorScheme.Focus : GetNormalColor ()
+                                   i == _currentChild ? GetFocusColor () : GetNormalColor ()
                                   );
                 }
 
@@ -915,7 +915,7 @@ internal sealed class Menu : View
                             ? item.Help.GetColumns ()
                             : item.Help.GetColumns () + item.ShortcutTag.GetColumns () + 2;
                 int col = Frame.Width - l - 3;
-                screen = ViewportToScreen (new (new (col, i), Size.Empty));
+                screen = ViewportToScreen (new Point (col, i));
 
                 if (screen.X < Driver.Cols)
                 {
@@ -934,7 +934,7 @@ internal sealed class Menu : View
 
         Driver.Clip = savedClip;
 
-        PositionCursor ();
+       // PositionCursor ();
     }
 
     private void Current_DrawContentComplete (object sender, DrawEventArgs e)
@@ -945,23 +945,24 @@ internal sealed class Menu : View
         }
     }
 
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (_host?.IsMenuOpen != false)
         {
             if (_barItems.IsTopLevel)
             {
-                _host?.PositionCursor ();
+                return _host?.PositionCursor ();
             }
             else
             {
                 Move (2, 1 + _currentChild);
+
+                return null; // Don't show the cursor
+
             }
         }
-        else
-        {
-            _host?.PositionCursor ();
-        }
+
+        return _host?.PositionCursor ();
     }
 
     public void Run (Action action)
@@ -1189,17 +1190,17 @@ internal sealed class Menu : View
         {
             disabled = false;
 
-            if (me.Y < 0)
+            if (me.Position.Y < 0)
             {
                 return me.Handled = true;
             }
 
-            if (me.Y >= _barItems.Children.Length)
+            if (me.Position.Y >= _barItems.Children.Length)
             {
                 return me.Handled = true;
             }
 
-            MenuItem item = _barItems.Children [me.Y];
+            MenuItem item = _barItems.Children [me.Position.Y];
 
             if (item is null || !item.IsEnabled ())
             {
@@ -1211,7 +1212,7 @@ internal sealed class Menu : View
                 return me.Handled = true;
             }
 
-            _currentChild = me.Y;
+            _currentChild = me.Position.Y;
             RunSelected ();
 
             return me.Handled = true;
@@ -1229,12 +1230,12 @@ internal sealed class Menu : View
         {
             disabled = false;
 
-            if (me.Y < 0 || me.Y >= _barItems.Children.Length)
+            if (me.Position.Y < 0 || me.Position.Y >= _barItems.Children.Length)
             {
                 return me.Handled = true;
             }
 
-            MenuItem item = _barItems.Children [me.Y];
+            MenuItem item = _barItems.Children [me.Position.Y];
 
             if (item is null)
             {
@@ -1248,7 +1249,7 @@ internal sealed class Menu : View
 
             if (!disabled)
             {
-                _currentChild = me.Y;
+                _currentChild = me.Position.Y;
             }
 
             if (_host.UseSubMenusSingleFrame || !CheckSubMenu ())
@@ -1333,14 +1334,6 @@ internal sealed class Menu : View
         return pos;
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     protected override void Dispose (bool disposing)
     {
         if (Application.Current is { })

+ 41 - 24
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -509,7 +509,7 @@ public class MenuBar : View
                    + _rightPadding;
         }
 
-        PositionCursor ();
+        //PositionCursor ();
     }
 
     /// <summary>Virtual method that will invoke the <see cref="MenuAllClosed"/>.</summary>
@@ -605,7 +605,7 @@ public class MenuBar : View
     }
 
     /// <inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (_selected == -1 && HasFocus && Menus.Length > 0)
         {
@@ -621,7 +621,7 @@ public class MenuBar : View
                 pos++;
                 Move (pos + 1, 0);
 
-                return;
+                return null; // Don't show the cursor
             }
 
             pos += _leftPadding
@@ -631,6 +631,7 @@ public class MenuBar : View
                           : 0)
                    + _rightPadding;
         }
+        return null; // Don't show the cursor
     }
 
     // Activates the menu, handles either first focus, or activating an entry when it was already active
@@ -738,7 +739,7 @@ public class MenuBar : View
             case false:
                 if (_openMenu is { })
                 {
-                    Application.Current.Remove (_openMenu);
+                    Application.Current?.Remove (_openMenu);
                 }
 
                 SetNeedsDisplay ();
@@ -787,7 +788,7 @@ public class MenuBar : View
                 else
                 {
                     SetFocus ();
-                    PositionCursor ();
+                    //PositionCursor ();
                 }
 
                 IsMenuOpen = false;
@@ -822,7 +823,12 @@ public class MenuBar : View
 
         Rectangle superViewFrame = SuperView is null ? Driver.Screen : SuperView.Frame;
         View sv = SuperView is null ? Application.Current : SuperView;
-        Point viewportOffset = sv.GetViewportOffsetFromFrame ();
+        if (sv is null)
+        {
+            // Support Unit Tests
+            return Point.Empty;
+        }
+        Point viewportOffset = sv?.GetViewportOffsetFromFrame () ?? Point.Empty;
 
         return new (
                     superViewFrame.X - sv.Frame.X - viewportOffset.X,
@@ -964,7 +970,7 @@ public class MenuBar : View
 
                 if (_openMenu is { })
                 {
-                    Application.Current.Remove (_openMenu);
+                    Application.Current?.Remove (_openMenu);
                     _openMenu.Dispose ();
                     _openMenu = null;
                 }
@@ -1001,7 +1007,15 @@ public class MenuBar : View
                 openCurrentMenu = _openMenu;
                 openCurrentMenu._previousSubFocused = _openMenu;
 
-                Application.Current.Add (_openMenu);
+                if (Application.Current is { })
+                {
+                    Application.Current.Add (_openMenu);
+                }
+                else
+                {
+                    _openMenu.BeginInit();
+                    _openMenu.EndInit();
+                }
                 _openMenu.SetFocus ();
 
                 break;
@@ -1059,7 +1073,14 @@ public class MenuBar : View
 
                     openCurrentMenu._previousSubFocused = last._previousSubFocused;
                     _openSubMenu.Add (openCurrentMenu);
-                    Application.Current.Add (openCurrentMenu);
+                    Application.Current?.Add (openCurrentMenu);
+
+                    if (!openCurrentMenu.IsInitialized)
+                    {
+                        // Supports unit tests
+                        openCurrentMenu.BeginInit ();
+                        openCurrentMenu.EndInit ();
+                    }
                 }
 
                 _selectedSub = _openSubMenu.Count - 1;
@@ -1315,7 +1336,7 @@ public class MenuBar : View
 
         if (mi.IsTopLevel)
         {
-            Rectangle screen = ViewportToScreen (new (new (0, i), Size.Empty));
+            var screen = ViewportToScreen (new Point (0 , i));
             var menu = new Menu { Host = this, X = screen.X, Y = screen.Y, BarItems = mi };
             menu.Run (mi.Action);
             menu.Dispose ();
@@ -1630,13 +1651,6 @@ public class MenuBar : View
 
     #region Mouse Handling
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
 
     /// <inheritdoc/>
     public override bool OnLeave (View view)
@@ -1675,7 +1689,7 @@ public class MenuBar : View
                 locationOffset.Y += SuperView.Border.Thickness.Top;
             }
 
-            int cx = me.X - locationOffset.X;
+            int cx = me.Position.X - locationOffset.X;
 
             for (var i = 0; i < Menus.Length; i++)
             {
@@ -1685,7 +1699,7 @@ public class MenuBar : View
                     {
                         if (Menus [i].IsTopLevel)
                         {
-                            Rectangle screen = ViewportToScreen (new (new (0, i), Size.Empty));
+                            var screen = ViewportToScreen (new Point(0 , i));
                             var menu = new Menu { Host = this, X = screen.X, Y = screen.Y, BarItems = Menus [i] };
                             menu.Run (Menus [i].Action);
                             menu.Dispose ();
@@ -1789,21 +1803,24 @@ public class MenuBar : View
                     Application.GrabMouse (v);
                     MouseEvent nme;
 
-                    if (me.Y > -1)
+                    if (me.Position.Y > -1)
                     {
-                        Point frameLoc = v.ScreenToFrame (me.X, me.Y);
+                        Point frameLoc = v.ScreenToFrame (me.Position);
 
                         nme = new ()
                         {
-                            X = frameLoc.X,
-                            Y = frameLoc.Y,
+                            Position = frameLoc,
                             Flags = me.Flags,
                             View = v
                         };
                     }
                     else
                     {
-                        nme = new () { X = me.X + current.Frame.X, Y = 0, Flags = me.Flags, View = v };
+                        nme = new ()
+                        {
+                            Position = new (me.Position.X + current.Frame.X, me.Position.Y + current.Frame.Y),
+                            Flags = me.Flags, View = v
+                        };
                     }
 
                     v.NewMouseEvent (nme);

+ 2 - 3
Terminal.Gui/Views/MessageBox.cs

@@ -369,14 +369,13 @@ public static class MessageBox
 
         var messageLabel = new Label
         {
-            AutoSize = !wrapMessage,
             Text = message,
             TextAlignment = TextAlignment.Centered,
             X = Pos.Center (),
             Y = 0
         };
 
-        if (!messageLabel.AutoSize)
+        if (wrapMessage)
         {
             messageLabel.Width = Dim.Fill ();
             messageLabel.Height = Dim.Fill (1);
@@ -467,7 +466,7 @@ public static class MessageBox
                                      + adornmentsThickness.Vertical);
             }
 
-            d.SetRelativeLayout (d.SuperView?.ContentSize ?? Application.Top.ContentSize);
+            d.SetRelativeLayout (d.SuperView?.ContentSize.GetValueOrDefault () ?? Application.Top.ContentSize.GetValueOrDefault ());
             d.LayoutSubviews ();
         }
     }

+ 0 - 8
Terminal.Gui/Views/ProgressBar.cs

@@ -198,14 +198,6 @@ public class ProgressBar : View
         }
     }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>Notifies the <see cref="ProgressBar"/> that some progress has taken place.</summary>
     /// <remarks>
     ///     If the <see cref="ProgressBar"/> is percentage mode, it switches to activity mode. If is in activity mode, the

+ 13 - 13
Terminal.Gui/Views/RadioGroup.cs

@@ -88,8 +88,8 @@ public class RadioGroup : View
     {
         SetFocus ();
 
-        int boundsX = e.MouseEvent.X;
-        int boundsY = e.MouseEvent.Y;
+        int boundsX = e.MouseEvent.Position.X;
+        int boundsY = e.MouseEvent.Position.Y;
 
         int pos = _orientation == Orientation.Horizontal ? boundsX : boundsY;
 
@@ -276,14 +276,6 @@ public class RadioGroup : View
         }
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool? OnInvokingKeyBindings (Key keyEvent)
     {
@@ -351,19 +343,27 @@ public class RadioGroup : View
     public event EventHandler<OrientationEventArgs> OrientationChanged;
 
     /// <inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
+        int x = 0;
+        int y = 0;
         switch (Orientation)
         {
             case Orientation.Vertical:
-                Move (0, _cursor);
+                y = _cursor;
 
                 break;
             case Orientation.Horizontal:
-                Move (_horizontal [_cursor].pos, 0);
+                x = _horizontal [_cursor].pos;
 
                 break;
+
+            default:
+                return null;
         }
+
+        Move (x, y);
+        return null; // Don't show the cursor
     }
 
     /// <summary>Allow to invoke the <see cref="SelectedItemChanged"/> after their creation.</summary>

+ 2 - 9
Terminal.Gui/Views/ScrollBarView.cs

@@ -299,7 +299,7 @@ public class ScrollBarView : View
             Host.SetFocus ();
         }
 
-        int location = _vertical ? mouseEvent.Y : mouseEvent.X;
+        int location = _vertical ? mouseEvent.Position.Y : mouseEvent.Position.X;
         int barsize = _vertical ? Viewport.Height : Viewport.Width;
         int posTopLeftTee = _vertical ? _posTopTee + 1 : _posLeftTee + 1;
         int posBottomRightTee = _vertical ? _posBottomTee + 1 : _posRightTee + 1;
@@ -667,13 +667,6 @@ public class ScrollBarView : View
         }
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
 
     /// <summary>Only used for a hosted view that will update and redraw the scrollbars.</summary>
     public virtual void Refresh () { ShowHideScrollBars (); }
@@ -944,7 +937,7 @@ public class ScrollBarView : View
         // BUGBUG: v2 - If Host is also the ScrollBarView's superview, this is all bogus because it's not
         // supported that a view can reference it's superview's Dims. This code also assumes the host does 
         //  not have a margin/borderframe/padding.
-        if (!IsInitialized)
+        if (!IsInitialized || _otherScrollBarView is { IsInitialized: false })
         {
             return;
         }

+ 30 - 38
Terminal.Gui/Views/ScrollView.cs

@@ -88,10 +88,10 @@ public class ScrollView : View
         AddCommand (Command.PageDown, () => ScrollDown (Viewport.Height));
         AddCommand (Command.PageLeft, () => ScrollLeft (Viewport.Width));
         AddCommand (Command.PageRight, () => ScrollRight (Viewport.Width));
-        AddCommand (Command.TopHome, () => ScrollUp (ContentSize.Height));
-        AddCommand (Command.BottomEnd, () => ScrollDown (ContentSize.Height));
-        AddCommand (Command.LeftHome, () => ScrollLeft (ContentSize.Width));
-        AddCommand (Command.RightEnd, () => ScrollRight (ContentSize.Width));
+        AddCommand (Command.TopHome, () => ScrollUp (ContentSize.Value.Height));
+        AddCommand (Command.BottomEnd, () => ScrollDown (ContentSize.Value.Height));
+        AddCommand (Command.LeftHome, () => ScrollLeft (ContentSize.Value.Width));
+        AddCommand (Command.RightEnd, () => ScrollRight (ContentSize.Value.Width));
 
         // Default keybindings for this view
         KeyBindings.Add (Key.CursorUp, Command.ScrollUp);
@@ -127,7 +127,7 @@ public class ScrollView : View
                            }
 
                            SetContentOffset (_contentOffset);
-                           _contentView.Frame = new Rectangle (ContentOffset, ContentSize);
+                           _contentView.Frame = new Rectangle (ContentOffset, ContentSize.GetValueOrDefault ());
 
                            // PERF: How about calls to Point.Offset instead?
                            _vertical.ChangedPosition += delegate { ContentOffset = new Point (ContentOffset.X, _vertical.Position); };
@@ -138,9 +138,13 @@ public class ScrollView : View
 
     private void ScrollViewContentSizeChanged (object sender, SizeChangedEventArgs e)
     {
-        _contentView.Frame = new Rectangle (ContentOffset, e.Size with {Width = e.Size.Width-1, Height = e.Size.Height-1});
-        _vertical.Size = e.Size.Height;
-        _horizontal.Size = e.Size.Width;
+        if (e.Size is null)
+        {
+            return;
+        }
+        _contentView.Frame = new Rectangle (ContentOffset, e.Size.Value with { Width = e.Size.Value.Width - 1, Height = e.Size.Value.Height - 1 });
+        _vertical.Size = e.Size.Value.Height;
+        _horizontal.Size = e.Size.Value.Width;
     }
 
     private void Application_UnGrabbedMouse (object sender, ViewEventArgs e)
@@ -240,26 +244,26 @@ public class ScrollView : View
                 _horizontal.OtherScrollBarView.KeepContentAlwaysInViewport = value;
                 Point p = default;
 
-                if (value && -_contentOffset.X + Viewport.Width > ContentSize.Width)
+                if (value && -_contentOffset.X + Viewport.Width > ContentSize.GetValueOrDefault ().Width)
                 {
                     p = new Point (
-                                   ContentSize.Width - Viewport.Width + (_showVerticalScrollIndicator ? 1 : 0),
+                                   ContentSize.GetValueOrDefault ().Width - Viewport.Width + (_showVerticalScrollIndicator ? 1 : 0),
                                    -_contentOffset.Y
                                   );
                 }
 
-                if (value && -_contentOffset.Y + Viewport.Height > ContentSize.Height)
+                if (value && -_contentOffset.Y + Viewport.Height > ContentSize.GetValueOrDefault ().Height)
                 {
                     if (p == default (Point))
                     {
                         p = new Point (
                                        -_contentOffset.X,
-                                       ContentSize.Height - Viewport.Height + (_showHorizontalScrollIndicator ? 1 : 0)
+                                       ContentSize.GetValueOrDefault ().Height - Viewport.Height + (_showHorizontalScrollIndicator ? 1 : 0)
                                       );
                     }
                     else
                     {
-                        p.Y = ContentSize.Height - Viewport.Height + (_showHorizontalScrollIndicator ? 1 : 0);
+                        p.Y = ContentSize.GetValueOrDefault ().Height - Viewport.Height + (_showHorizontalScrollIndicator ? 1 : 0);
                     }
                 }
 
@@ -380,17 +384,6 @@ public class ScrollView : View
         DrawScrollBars ();
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        if (Subviews.Count == 0 || !Subviews.Any (subview => subview.CanFocus))
-        {
-            Application.Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool OnKeyDown (Key a)
     {
@@ -410,7 +403,7 @@ public class ScrollView : View
     }
 
     /// <inheritdoc/>
-    protected internal override bool OnMouseEvent  (MouseEvent me)
+    protected internal override bool OnMouseEvent (MouseEvent me)
     {
         if (!Enabled)
         {
@@ -434,11 +427,11 @@ public class ScrollView : View
         {
             ScrollLeft (1);
         }
-        else if (me.X == _vertical.Frame.X && ShowVerticalScrollIndicator)
+        else if (me.Position.X == _vertical.Frame.X && ShowVerticalScrollIndicator)
         {
             _vertical.NewMouseEvent (me);
         }
-        else if (me.Y == _horizontal.Frame.Y && ShowHorizontalScrollIndicator)
+        else if (me.Position.Y == _horizontal.Frame.Y && ShowHorizontalScrollIndicator)
         {
             _horizontal.NewMouseEvent (me);
         }
@@ -447,20 +440,19 @@ public class ScrollView : View
             Application.UngrabMouse ();
         }
 
-        return base.OnMouseEvent(me);
+        return base.OnMouseEvent (me);
     }
 
     /// <inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (InternalSubviews.Count == 0)
         {
             Move (0, 0);
+
+            return null; // Don't show the cursor
         }
-        else
-        {
-            base.PositionCursor ();
-        }
+        return base.PositionCursor ();
     }
 
     /// <summary>Removes the view from the scrollview.</summary>
@@ -615,7 +607,7 @@ public class ScrollView : View
     {
         // INTENT: Unclear intent. How about a call to Offset?
         _contentOffset = new Point (-Math.Abs (offset.X), -Math.Abs (offset.Y));
-        _contentView.Frame = new Rectangle (_contentOffset, ContentSize);
+        _contentView.Frame = new Rectangle (_contentOffset, ContentSize.GetValueOrDefault ());
         int p = Math.Max (0, -_contentOffset.Y);
 
         if (_vertical.Position != p)
@@ -646,7 +638,7 @@ public class ScrollView : View
         bool v = false, h = false;
         var p = false;
 
-        if (Viewport.Height == 0 || Viewport.Height > ContentSize.Height)
+        if (ContentSize is { } && (Viewport.Height == 0 || Viewport.Height > ContentSize.Value.Height))
         {
             if (ShowVerticalScrollIndicator)
             {
@@ -655,7 +647,7 @@ public class ScrollView : View
 
             v = false;
         }
-        else if (Viewport.Height > 0 && Viewport.Height == ContentSize.Height)
+        else if (ContentSize is { } && Viewport.Height > 0 && Viewport.Height == ContentSize.Value.Height)
         {
             p = true;
         }
@@ -669,7 +661,7 @@ public class ScrollView : View
             v = true;
         }
 
-        if (Viewport.Width == 0 || Viewport.Width > ContentSize.Width)
+        if (ContentSize is { } && (Viewport.Width == 0 || Viewport.Width > ContentSize.Value.Width))
         {
             if (ShowHorizontalScrollIndicator)
             {
@@ -678,7 +670,7 @@ public class ScrollView : View
 
             h = false;
         }
-        else if (Viewport.Width > 0 && Viewport.Width == ContentSize.Width && p)
+        else if (ContentSize is { } && Viewport.Width > 0 && Viewport.Width == ContentSize.Value.Width && p)
         {
             if (ShowHorizontalScrollIndicator)
             {

+ 103 - 206
Terminal.Gui/Views/Slider.cs

@@ -150,7 +150,6 @@ public class SliderStyle
 internal class SliderConfiguration
 {
     internal bool _allowEmpty;
-    internal bool _autoSize;
     internal int _endSpacing;
     internal int _innerSpacing;
     internal Orientation _legendsOrientation = Orientation.Horizontal;
@@ -243,7 +242,10 @@ public class Slider<T> : View
         Orientation orientation = Orientation.Horizontal
     )
     {
+        Width = Dim.Auto (Dim.DimAutoStyle.Content);
+        Height = Dim.Auto (Dim.DimAutoStyle.Content);
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
 
         _options = options ?? new List<SliderOption<T>> ();
 
@@ -254,22 +256,19 @@ public class Slider<T> : View
         SetDefaultStyle ();
         SetCommands ();
 
-        // When we lose focus of the View(Slider), if we are range selecting we stop it.
-        Leave += (s, e) =>
-                 {
-                     //if (_settingRange == true) {
-                     //	_settingRange = false;
-                     //}
-                     Driver.SetCursorVisibility (CursorVisibility.Invisible);
-                 };
-
         Enter += (s, e) => { };
 
-        LayoutComplete += (s, e) =>
+        // BUGBUG: This should not be needed - Need to ensure SetRelativeLayout gets called during EndInit
+        Initialized += (s, e) =>
+                         {
+                             SetContentSizeBestFit ();
+                         };
+
+        LayoutStarted += (s, e) =>
                           {
-                              CalcSpacingConfig ();
-                              SetBoundsBestFit ();
+                              SetContentSizeBestFit ();
                           };
+
     }
 
     #endregion
@@ -309,7 +308,7 @@ public class Slider<T> : View
         {
             _lastFocusedOption = FocusedOption;
             FocusedOption = newFocusedOption;
-            PositionCursor ();
+            //PositionCursor ();
         }
 
         return args.Cancel;
@@ -373,29 +372,6 @@ public class Slider<T> : View
         }
     }
 
-    /// <summary>
-    ///     If <see langword="true"/> the slider will be sized to fit the available space (the Viewport of the the
-    ///     SuperView).
-    /// </summary>
-    /// <remarks>
-    ///     For testing, if there is no SuperView, the slider will be sized based on what <see cref="InnerSpacing"/> is
-    ///     set to.
-    /// </remarks>
-    public override bool AutoSize
-    {
-        get => _config._autoSize;
-        set
-        {
-            _config._autoSize = value;
-
-            if (IsInitialized)
-            {
-                CalcSpacingConfig ();
-                SetBoundsBestFit ();
-            }
-        }
-    }
-
     /// <summary>Gets or sets the number of rows/columns between <see cref="Options"/></summary>
     public int InnerSpacing
     {
@@ -404,11 +380,7 @@ public class Slider<T> : View
         {
             _config._innerSpacing = value;
 
-            if (IsInitialized)
-            {
-                CalcSpacingConfig ();
-                SetBoundsBestFit ();
-            }
+            SetContentSizeBestFit ();
         }
     }
 
@@ -452,11 +424,7 @@ public class Slider<T> : View
             _config._sliderOrientation = newOrientation;
             SetKeyBindings ();
 
-            if (IsInitialized)
-            {
-                CalcSpacingConfig ();
-                SetBoundsBestFit ();
-            }
+            SetContentSizeBestFit ();
         }
 
         return args.Cancel;
@@ -470,11 +438,7 @@ public class Slider<T> : View
         {
             _config._legendsOrientation = value;
 
-            if (IsInitialized)
-            {
-                CalcSpacingConfig ();
-                SetBoundsBestFit ();
-            }
+            SetContentSizeBestFit ();
         }
     }
 
@@ -506,8 +470,7 @@ public class Slider<T> : View
                 return;
             }
 
-            CalcSpacingConfig ();
-            SetBoundsBestFit ();
+            SetContentSizeBestFit ();
         }
     }
 
@@ -536,7 +499,7 @@ public class Slider<T> : View
         set
         {
             _config._showLegends = value;
-            SetBoundsBestFit ();
+            SetContentSizeBestFit ();
         }
     }
 
@@ -644,168 +607,110 @@ public class Slider<T> : View
         // Last = '┤',
     }
 
-    /// <summary>
-    ///     Calculates the spacing configuration (start, inner, end) as well as turning on/off legend abbreviation if
-    ///     needed. Behaves differently based on <see cref="AutoSize"/> and <see cref="View.IsInitialized"/> .
-    /// </summary>
-    internal void CalcSpacingConfig ()
+    /// <summary>Adjust the dimensions of the Slider to the best value.</summary>
+    public void SetContentSizeBestFit ()
     {
-        var size = 0;
-
-        if (_options.Count == 0 || !IsInitialized)
+        if (!IsInitialized || /*!(Height is Dim.DimAuto && Width is Dim.DimAuto) || */_options.Count == 0)
         {
             return;
         }
 
-        _config._innerSpacing = 0;
-        _config._startSpacing = 0;
-        _config._endSpacing = 0;
+        CalcSpacingConfig ();
 
-        if (AutoSize)
-        {
-            // Max size is SuperView's Viewport. Min Size is size that will fit.
-            if (SuperView is { })
-            {
-                // Calculate the size of the slider based on the size of the SuperView's Viewport.
-                if (_config._sliderOrientation == Orientation.Horizontal)
-                {
-                    size = int.Min (SuperView.Viewport.Width, CalcBestLength ());
-                }
-                else
-                {
-                    size = int.Min (SuperView.Viewport.Height, CalcBestLength ());
-                }
-            }
-            else
-            {
-                // Use the config values
-                size = CalcMinLength ();
+        Thickness adornmentsThickness = GetAdornmentsThickness ();
 
-                return;
-            }
+        var svWidth = SuperView?.ContentSize?.Width ?? 0;
+        var svHeight = SuperView?.ContentSize?.Height ?? 0;
+
+        if (_config._sliderOrientation == Orientation.Horizontal)
+        {
+            ContentSize = new (int.Min (svWidth, CalcBestLength ()), int.Min (svHeight, CalcThickness ()));
         }
         else
         {
-            // Fit Slider to the Viewport
-            if (_config._sliderOrientation == Orientation.Horizontal)
-            {
-                size = Viewport.Width;
-            }
-            else
-            {
-                size = Viewport.Height;
-            }
+            ContentSize = new (int.Min (svWidth, CalcThickness ()), int.Min (svHeight, CalcBestLength ()));
         }
 
-        int max_legend; // Because the legends are centered, the longest one determines inner spacing
+        return;
 
-        if (_config._sliderOrientation == _config._legendsOrientation)
+        void CalcSpacingConfig ()
         {
-            max_legend = int.Max (_options.Max (s => s.Legend?.Length ?? 1), 1);
-        }
-        else
-        {
-            max_legend = 1;
-        }
+            _config._innerSpacing = 0;
+            _config._startSpacing = 0;
+            _config._endSpacing = 0;
 
-        int min_size_that_fits_legends = _options.Count == 1 ? max_legend : max_legend / (_options.Count - 1);
+            int size = 0;
+            if (ContentSize is { })
+            {
+                size = _config._sliderOrientation == Orientation.Horizontal ? ContentSize.Value.Width : ContentSize.Value.Height;
+            }
 
-        string first;
-        string last;
+            int max_legend; // Because the legends are centered, the longest one determines inner spacing
 
-        if (max_legend >= size)
-        {
             if (_config._sliderOrientation == _config._legendsOrientation)
             {
-                _config._showLegendsAbbr = true;
-
-                foreach (SliderOption<T> o in _options.Where (op => op.LegendAbbr == default (Rune)))
-                {
-                    o.LegendAbbr = (Rune)(o.Legend?.Length > 0 ? o.Legend [0] : ' ');
-                }
+                max_legend = int.Max (_options.Max (s => s.Legend?.Length ?? 1), 1);
+            }
+            else
+            {
+                max_legend = 1;
             }
 
-            first = "x";
-            last = "x";
-        }
-        else
-        {
-            _config._showLegendsAbbr = false;
-            first = _options.First ().Legend;
-            last = _options.Last ().Legend;
-        }
+            int min_size_that_fits_legends = _options.Count == 1 ? max_legend : max_legend / (_options.Count - 1);
 
-        // --o--
-        // Hello
-        // Left = He
-        // Right = lo
-        int first_left = (first.Length - 1) / 2; // Chars count of the first option to the left.
-        int last_right = last.Length / 2; // Chars count of the last option to the right.
+            string first;
+            string last;
 
-        if (_config._sliderOrientation != _config._legendsOrientation)
-        {
-            first_left = 0;
-            last_right = 0;
-        }
+            if (max_legend >= size)
+            {
+                if (_config._sliderOrientation == _config._legendsOrientation)
+                {
+                    _config._showLegendsAbbr = true;
 
-        // -1 because it's better to have an extra space at right than to clip
-        int width = size - first_left - last_right - 1;
+                    foreach (SliderOption<T> o in _options.Where (op => op.LegendAbbr == default (Rune)))
+                    {
+                        o.LegendAbbr = (Rune)(o.Legend?.Length > 0 ? o.Legend [0] : ' ');
+                    }
+                }
 
-        _config._startSpacing = first_left;
+                first = "x";
+                last = "x";
+            }
+            else
+            {
+                _config._showLegendsAbbr = false;
+                first = _options.First ().Legend;
+                last = _options.Last ().Legend;
+            }
 
-        if (_options.Count == 1)
-        {
-            _config._innerSpacing = max_legend;
-        }
-        else
-        {
-            _config._innerSpacing = Math.Max (0, (int)Math.Floor ((double)width / (_options.Count - 1)) - 1);
-        }
+            // --o--
+            // Hello
+            // Left = He
+            // Right = lo
+            int first_left = (first.Length - 1) / 2; // Chars count of the first option to the left.
+            int last_right = last.Length / 2; // Chars count of the last option to the right.
 
-        _config._endSpacing = last_right;
-    }
+            if (_config._sliderOrientation != _config._legendsOrientation)
+            {
+                first_left = 0;
+                last_right = 0;
+            }
 
-    /// <summary>Adjust the dimensions of the Slider to the best value if <see cref="AutoSize"/> is true.</summary>
-    public void SetBoundsBestFit ()
-    {
-        if (!IsInitialized || AutoSize == false)
-        {
-            return;
-        }
+            // -1 because it's better to have an extra space at right than to clip
+            int width = size - first_left - last_right - 1;
 
-        Thickness adornmentsThickness = GetAdornmentsThickness ();
+            _config._startSpacing = first_left;
 
-        if (_config._sliderOrientation == Orientation.Horizontal)
-        {
-            Viewport = new (
-                          Viewport.Location,
-                          new (
-                               int.Min (
-                                        SuperView.Viewport.Width - adornmentsThickness.Horizontal,
-                                        CalcBestLength ()
-                                       ),
-                               int.Min (
-                                        SuperView.Viewport.Height - adornmentsThickness.Vertical,
-                                        CalcThickness ()
-                                       )
-                              )
-                         );
-        }
-        else
-        {
-            Viewport = new (
-                          Viewport.Location,
-                          new (
-                               int.Min (
-                                        SuperView.Viewport.Width - adornmentsThickness.Horizontal,
-                                        CalcThickness ()
-                                       ),
-                               int.Min (
-                                        SuperView.Viewport.Height - adornmentsThickness.Vertical,
-                                        CalcBestLength ()
-                                       )
-                              )
-                         );
+            if (_options.Count == 1)
+            {
+                _config._innerSpacing = max_legend;
+            }
+            else
+            {
+                _config._innerSpacing = Math.Max (0, (int)Math.Floor ((double)width / (_options.Count - 1)) - 1);
+            }
+
+            _config._endSpacing = last_right;
         }
     }
 
@@ -973,26 +878,18 @@ public class Slider<T> : View
     #region Cursor and Drawing
 
     /// <inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
-        //base.PositionCursor ();
-
-        if (HasFocus)
-        {
-            Driver?.SetCursorVisibility (CursorVisibility.Default);
-        }
-        else
-        {
-            Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
         if (TryGetPositionByOption (FocusedOption, out (int x, int y) position))
         {
             if (IsInitialized && Viewport.Contains (position.x, position.y))
             {
                 Move (position.x, position.y);
+
+                return new (position.x, position.x);
             }
         }
+        return base.PositionCursor ();
     }
 
     /// <inheritdoc/>
@@ -1522,7 +1419,7 @@ public class Slider<T> : View
     private Point? _moveRenderPosition;
 
     /// <inheritdoc/>
-    protected internal override bool OnMouseEvent  (MouseEvent mouseEvent)
+    protected internal override bool OnMouseEvent (MouseEvent mouseEvent)
     {
         // Note(jmperricone): Maybe we click to focus the cursor, and on next click we set the option.
         //                    That will makes OptionFocused Event more relevant.
@@ -1568,7 +1465,7 @@ public class Slider<T> : View
         {
             if (mouseEvent.Flags.HasFlag (MouseFlags.ReportMousePosition))
             {
-                _dragPosition = new Point (mouseEvent.X, mouseEvent.Y);
+                _dragPosition = mouseEvent.Position;
                 _moveRenderPosition = ClampMovePosition ((Point)_dragPosition);
                 Application.GrabMouse (this);
             }
@@ -1583,7 +1480,7 @@ public class Slider<T> : View
             && mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed))
         {
             // Continue Drag
-            _dragPosition = new Point (mouseEvent.X, mouseEvent.Y);
+            _dragPosition = mouseEvent.Position;
             _moveRenderPosition = ClampMovePosition ((Point)_dragPosition);
 
             var success = false;
@@ -1592,11 +1489,11 @@ public class Slider<T> : View
             // how far has user dragged from original location?						
             if (Orientation == Orientation.Horizontal)
             {
-                success = TryGetOptionByPosition (mouseEvent.X, 0, Math.Max (0, _config._innerSpacing / 2), out option);
+                success = TryGetOptionByPosition (mouseEvent.Position.X, 0, Math.Max (0, _config._innerSpacing / 2), out option);
             }
             else
             {
-                success = TryGetOptionByPosition (0, mouseEvent.Y, Math.Max (0, _config._innerSpacing / 2), out option);
+                success = TryGetOptionByPosition (0, mouseEvent.Position.Y, Math.Max (0, _config._innerSpacing / 2), out option);
             }
 
             if (!_config._allowEmpty && success)
@@ -1626,11 +1523,11 @@ public class Slider<T> : View
 
             if (Orientation == Orientation.Horizontal)
             {
-                success = TryGetOptionByPosition (mouseEvent.X, 0, Math.Max (0, _config._innerSpacing / 2), out option);
+                success = TryGetOptionByPosition (mouseEvent.Position.X, 0, Math.Max (0, _config._innerSpacing / 2), out option);
             }
             else
             {
-                success = TryGetOptionByPosition (0, mouseEvent.Y, Math.Max (0, _config._innerSpacing / 2), out option);
+                success = TryGetOptionByPosition (0, mouseEvent.Position.Y, Math.Max (0, _config._innerSpacing / 2), out option);
             }
 
             if (success)

+ 1 - 9
Terminal.Gui/Views/StatusBar.cs

@@ -153,7 +153,7 @@ public class StatusBar : View
 
         for (var i = 0; i < Items.Length; i++)
         {
-            if (me.X >= pos && me.X < pos + GetItemTitleLength (Items [i].Title))
+            if (me.Position.X >= pos && me.Position.X < pos + GetItemTitleLength (Items [i].Title))
             {
                 StatusItem item = Items [i];
 
@@ -215,14 +215,6 @@ public class StatusBar : View
         }
     }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool? OnInvokingKeyBindings (Key keyEvent)
     {

+ 0 - 7
Terminal.Gui/Views/TabView.cs

@@ -1204,13 +1204,6 @@ public class TabView : View
             }
         }
 
-        public override bool OnEnter (View view)
-        {
-            Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-            return base.OnEnter (view);
-        }
-
         private int GetUnderlineYPosition ()
         {
             if (_host.Style.TabsOnBottom)

+ 1 - 1
Terminal.Gui/Views/TableView/CheckBoxTableSourceWrapper.cs

@@ -158,7 +158,7 @@ public abstract class CheckBoxTableSourceWrapperBase : ITableSource
             return;
         }
 
-        Point? hit = tableView.ScreenToCell (e.MouseEvent.X, e.MouseEvent.Y, out int? headerIfAny);
+        Point? hit = tableView.ScreenToCell (e.MouseEvent.Position.X, e.MouseEvent.Position.Y, out int? headerIfAny);
 
         if (headerIfAny.HasValue && headerIfAny.Value == 0)
         {

+ 41 - 11
Terminal.Gui/Views/TableView/TableView.cs

@@ -841,8 +841,8 @@ public class TableView : View
                 return true;
         }
 
-        int boundsX = me.X;
-        int boundsY = me.Y;
+        int boundsX = me.Position.X;
+        int boundsY = me.Position.Y;
 
         if (me.Flags.HasFlag (MouseFlags.Button1Clicked))
         {
@@ -978,8 +978,6 @@ public class TableView : View
     {
         if (TableIsNullOrInvisible ())
         {
-            PositionCursor ();
-
             return false;
         }
 
@@ -1017,13 +1015,11 @@ public class TableView : View
     ///     Positions the cursor in the area of the screen in which the start of the active cell is rendered.  Calls base
     ///     implementation if active cell is not visible due to scrolling or table is loaded etc
     /// </summary>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (TableIsNullOrInvisible ())
         {
-            base.PositionCursor ();
-
-            return;
+            return base.PositionCursor ();
         }
 
         Point? screenPoint = CellToScreen (SelectedColumn, SelectedRow);
@@ -1031,11 +1027,15 @@ public class TableView : View
         if (screenPoint is { })
         {
             Move (screenPoint.Value.X, screenPoint.Value.Y);
+
+            return null;//screenPoint;
         }
+
+        return null;
     }
 
     /// <summary>
-    ///     . Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
+    ///     Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
     ///     to the control client area).  Returns null if the point is in the header, no table is loaded or outside the control
     ///     bounds.
     /// </summary>
@@ -1044,6 +1044,15 @@ public class TableView : View
     /// <returns>Cell clicked or null.</returns>
     public Point? ScreenToCell (int clientX, int clientY) { return ScreenToCell (clientX, clientY, out _, out _); }
 
+    /// <summary>
+    ///     Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
+    ///     to the control client area).  Returns null if the point is in the header, no table is loaded or outside the control
+    ///     bounds.
+    /// </summary>
+    /// <param name="client">offset from the top left of the control.</param>
+    /// <returns>The position.</returns>
+    public Point? ScreenToCell (Point client) { return ScreenToCell (client, out _, out _); }
+
     /// <summary>
     ///     . Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
     ///     to the control client area).  Returns null if the point is in the header, no table is loaded or outside the control
@@ -1055,7 +1064,16 @@ public class TableView : View
     public Point? ScreenToCell (int clientX, int clientY, out int? headerIfAny) { return ScreenToCell (clientX, clientY, out headerIfAny, out _); }
 
     /// <summary>
-    ///     . Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
+    ///     Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
+    ///     to the control client area).  Returns null if the point is in the header, no table is loaded or outside the control
+    ///     bounds.
+    /// </summary>
+    /// <param name="client">offset from the top left of the control.</param>
+    /// <param name="headerIfAny">If the click is in a header this is the column clicked.</param>
+    public Point? ScreenToCell (Point client, out int? headerIfAny) { return ScreenToCell (client, out headerIfAny, out _); }
+
+    /// <summary>
+    ///     Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
     ///     to the control client area).  Returns null if the point is in the header, no table is loaded or outside the control
     ///     bounds.
     /// </summary>
@@ -1107,6 +1125,19 @@ public class TableView : View
         return null;
     }
 
+    /// <summary>
+    ///     Returns the column and row of <see cref="Table"/> that corresponds to a given point on the screen (relative
+    ///     to the control client area).  Returns null if the point is in the header, no table is loaded or outside the control
+    ///     bounds.
+    /// </summary>
+    /// <param name="client">offset from the top left of the control.</param>
+    /// <param name="headerIfAny">If the click is in a header this is the column clicked.</param>
+    /// <param name="offsetX">The horizontal offset of the click within the returned cell.</param>
+    public Point? ScreenToCell (Point client, out int? headerIfAny, out int? offsetX)
+    {
+        return ScreenToCell (client.X, client.Y, out headerIfAny, out offsetX);
+    }
+
     /// <summary>
     ///     When <see cref="MultiSelect"/> is on, creates selection over all cells in the table (replacing any old
     ///     selection regions)
@@ -1528,7 +1559,6 @@ public class TableView : View
             SelectedRow = match;
             EnsureValidSelection ();
             EnsureSelectedCellIsVisible ();
-            PositionCursor ();
             SetNeedsDisplay ();
 
             return true;

+ 1 - 1
Terminal.Gui/Views/TableView/TreeTableSource.cs

@@ -168,7 +168,7 @@ public class TreeTableSource<T> : IEnumerableTableSource<T>, IDisposable where T
 
     private void Table_MouseClick (object sender, MouseEventEventArgs e)
     {
-        Point? hit = _tableView.ScreenToCell (e.MouseEvent.X, e.MouseEvent.Y, out int? headerIfAny, out int? offsetX);
+        Point? hit = _tableView.ScreenToCell (e.MouseEvent.Position.X, e.MouseEvent.Position.Y, out int? headerIfAny, out int? offsetX);
 
         if (hit is null || headerIfAny is { } || !IsInTreeColumn (hit.Value.X, false) || offsetX is null)
         {

+ 10 - 101
Terminal.Gui/Views/TextField.cs

@@ -9,10 +9,8 @@ namespace Terminal.Gui;
 public class TextField : View
 {
     private readonly HistoryText _historyText;
-    private readonly CursorVisibility _savedCursorVisibility;
     private CultureInfo _currentCulture;
     private int _cursorPosition;
-    private CursorVisibility _desiredCursorVisibility;
     private bool _isButtonPressed;
     private bool _isButtonReleased;
     private bool _isDrawing;
@@ -21,7 +19,6 @@ public class TextField : View
     private string _selectedText;
     private int _start;
     private List<Rune> _text;
-    private CursorVisibility _visibility;
 
     /// <summary>
     ///     Initializes a new instance of the <see cref="TextField"/> class using <see cref="LayoutStyle.Computed"/>
@@ -30,7 +27,6 @@ public class TextField : View
     public TextField ()
     {
         _historyText = new HistoryText ();
-        _desiredCursorVisibility = CursorVisibility.Default;
         _isButtonReleased = true;
         _selectedStart = -1;
         _text = new List<Rune> ();
@@ -40,9 +36,9 @@ public class TextField : View
         Height = 1;
 
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
         Used = true;
         WantMousePositionReports = true;
-        _savedCursorVisibility = _desiredCursorVisibility;
 
         _historyText.ChangeText += HistoryText_ChangeText;
 
@@ -469,21 +465,6 @@ public class TextField : View
         }
     }
 
-    /// <summary>Get / Set the wished cursor when the field is focused</summary>
-    public CursorVisibility DesiredCursorVisibility
-    {
-        get => _desiredCursorVisibility;
-        set
-        {
-            if ((_desiredCursorVisibility != value || _visibility != value) && HasFocus)
-            {
-                Application.Driver.SetCursorVisibility (value);
-            }
-
-            _desiredCursorVisibility = _visibility = value;
-        }
-    }
-
     /// <summary>
     ///     Indicates whatever the text has history changes or not. <see langword="true"/> if the text has history changes
     ///     <see langword="false"/> otherwise.
@@ -776,11 +757,11 @@ public class TextField : View
     {
         foreach (char ch in toAdd)
         {
-            KeyCode key;
+            Key key;
 
             try
             {
-                key = (KeyCode)ch;
+                key = ch;
             }
             catch (Exception)
             {
@@ -789,7 +770,7 @@ public class TextField : View
                                             );
             }
 
-            InsertText (new Key { KeyCode = key }, useOldCursorPos);
+            InsertText (key, useOldCursorPos);
         }
     }
 
@@ -839,7 +820,7 @@ public class TextField : View
     }
 
     /// <inheritdoc/>
-    protected internal override bool OnMouseEvent  (MouseEvent ev)
+    protected internal override bool OnMouseEvent (MouseEvent ev)
     {
         if (!ev.Flags.HasFlag (MouseFlags.Button1Pressed)
             && !ev.Flags.HasFlag (MouseFlags.ReportMousePosition)
@@ -951,7 +932,7 @@ public class TextField : View
             ShowContextMenu ();
         }
 
-        SetNeedsDisplay ();
+        //SetNeedsDisplay ();
 
         return true;
 
@@ -1055,17 +1036,6 @@ public class TextField : View
         _isDrawing = false;
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        if (IsInitialized)
-        {
-            Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-        }
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool? OnInvokingKeyBindings (Key a)
     {
@@ -1172,13 +1142,8 @@ public class TextField : View
     }
 
     /// <summary>Sets the cursor position.</summary>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
-        if (!IsInitialized)
-        {
-            return;
-        }
-
         ProcessAutocomplete ();
 
         var col = 0;
@@ -1195,31 +1160,8 @@ public class TextField : View
         }
 
         int pos = _cursorPosition - ScrollOffset + Math.Min (Frame.X, 0);
-        int offB = OffSetBackground ();
-        Rectangle containerFrame = SuperView?.ViewportToScreen (SuperView.Viewport) ?? default (Rectangle);
-        Rectangle thisFrame = ViewportToScreen (Viewport);
-
-        if (pos > -1
-            && col >= pos
-            && pos < Frame.Width + offB
-            && containerFrame.IntersectsWith (thisFrame))
-        {
-            RestoreCursorVisibility ();
-            Move (col, 0);
-        }
-        else
-        {
-            HideCursorVisibility ();
-
-            if (pos < 0)
-            {
-                Move (pos, 0);
-            }
-            else
-            {
-                Move (pos - offB, 0);
-            }
-        }
+        Move (pos, 0);
+        return new Point (pos, 0);
     }
 
     /// <summary>Redoes the latest changes.</summary>
@@ -1231,21 +1173,6 @@ public class TextField : View
         }
 
         _historyText.Redo ();
-
-        //if (string.IsNullOrEmpty (Clipboard.Contents))
-        //	return true;
-        //var clip = TextModel.ToRunes (Clipboard.Contents);
-        //if (clip is null)
-        //	return true;
-
-        //if (point == text.Count) {
-        //	point = text.Count;
-        //	SetText(text.Concat(clip).ToList());
-        //} else {
-        //	point += clip.Count;
-        //	SetText(text.GetRange(0, oldCursorPos).Concat(clip).Concat(text.GetRange(oldCursorPos, text.Count - oldCursorPos)));
-        //}
-        //Adjust ();
     }
 
     /// <summary>Selects all text.</summary>
@@ -1465,14 +1392,6 @@ public class TextField : View
         return new Attribute (cs.Disabled.Foreground, cs.Focus.Background);
     }
 
-    private void HideCursorVisibility ()
-    {
-        if (_desiredCursorVisibility != CursorVisibility.Invisible)
-        {
-            DesiredCursorVisibility = CursorVisibility.Invisible;
-        }
-    }
-
     private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
     {
         if (obj is null)
@@ -1761,7 +1680,7 @@ public class TextField : View
 
     private int PositionCursor (MouseEvent ev)
     {
-        return PositionCursor (TextModel.GetColFromX (_text, ScrollOffset, ev.X), false);
+        return PositionCursor (TextModel.GetColFromX (_text, ScrollOffset, ev.Position.X), false);
     }
 
     private int PositionCursor (int x, bool getX = true)
@@ -1886,16 +1805,6 @@ public class TextField : View
         Driver.AddStr (render);
     }
 
-    private void RestoreCursorVisibility ()
-    {
-        Application.Driver.GetCursorVisibility (out _visibility);
-
-        if (_desiredCursorVisibility != _savedCursorVisibility || _visibility != _savedCursorVisibility)
-        {
-            DesiredCursorVisibility = _savedCursorVisibility;
-        }
-    }
-
     private void SetClipboard (IEnumerable<Rune> text)
     {
         if (!Secret)

+ 4 - 28
Terminal.Gui/Views/TextValidateField.cs

@@ -537,7 +537,7 @@ namespace Terminal.Gui
         {
             if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed))
             {
-                int c = _provider.Cursor (mouseEvent.X - GetMargins (Viewport.Width).left);
+                int c = _provider.Cursor (mouseEvent.Position.X - GetMargins (Viewport.Width).left);
 
                 if (_provider.Fixed == false && TextAlignment == TextAlignment.Right && Text.Length > 0)
                 {
@@ -598,22 +598,6 @@ namespace Terminal.Gui
             }
         }
 
-        /// <inheritdoc/>
-        public override bool OnEnter (View view)
-        {
-            Application.Driver.SetCursorVisibility (CursorVisibility.Default);
-
-            return base.OnEnter (view);
-        }
-
-        /// <inheritdoc/>
-        public override bool OnLeave (View view)
-        {
-            Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-            return base.OnLeave (view);
-        }
-
         /// <inheritdoc/>
         public override bool OnProcessKeyDown (Key a)
         {
@@ -640,7 +624,7 @@ namespace Terminal.Gui
         }
 
         /// <inheritdoc/>
-        public override void PositionCursor ()
+        public override Point? PositionCursor ()
         {
             (int left, _) = GetMargins (Viewport.Width);
 
@@ -652,22 +636,14 @@ namespace Terminal.Gui
             if (_provider?.Fixed == false && TextAlignment == TextAlignment.Right)
             {
                 curPos = _cursorPosition + left - 1;
-                Move (curPos, 0);
             }
             else
             {
                 curPos = _cursorPosition + left;
-                Move (curPos, 0);
             }
+            Move (curPos, 0);
 
-            if (curPos < 0 || curPos >= Viewport.Width)
-            {
-                Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-            }
-            else
-            {
-                Application.Driver.SetCursorVisibility (CursorVisibility.Default);
-            }
+            return new (curPos, 0);
         }
 
         /// <summary>Delete char at cursor position - 1, moving the cursor.</summary>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 181 - 198
Terminal.Gui/Views/TextView.cs


+ 11 - 17
Terminal.Gui/Views/TileView.cs

@@ -219,7 +219,7 @@ public class TileView : View
                 bool isRoot = _splitterLines.Contains (line);
 
                 Rectangle screen = line.ViewportToScreen (Rectangle.Empty);
-                Point origin = ScreenToFrame (screen.X, screen.Y);
+                Point origin = ScreenToFrame (screen.Location);
                 int length = line.Orientation == Orientation.Horizontal ? line.Frame.Width : line.Frame.Height;
 
                 if (!isRoot)
@@ -841,7 +841,7 @@ public class TileView : View
         public Point GetLocalCoordinateForTitle (TileView intoCoordinateSpace)
         {
             Rectangle screen = Tile.ContentView.ViewportToScreen (Rectangle.Empty);
-            return intoCoordinateSpace.ScreenToFrame (screen.X, screen.Y - 1);
+            return intoCoordinateSpace.ScreenToFrame (new (screen.X, screen.Y - 1));
         }
 
         internal string GetTrimmedTitle ()
@@ -912,7 +912,7 @@ public class TileView : View
 
                 if (mouseEvent.Flags == MouseFlags.Button1Pressed)
                 {
-                    dragPosition = new Point (mouseEvent.X, mouseEvent.Y);
+                    dragPosition = mouseEvent.Position;
                     dragOrignalPos = Orientation == Orientation.Horizontal ? Y : X;
                     Application.GrabMouse (this);
 
@@ -922,7 +922,7 @@ public class TileView : View
                     {
                         moveRuneRenderLocation = new Point (
                                                             0,
-                                                            Math.Max (1, Math.Min (Viewport.Height - 2, mouseEvent.Y))
+                                                            Math.Max (1, Math.Min (Viewport.Height - 2, mouseEvent.Position.Y))
                                                            );
                     }
                 }
@@ -938,15 +938,15 @@ public class TileView : View
                 // how far has user dragged from original location?						
                 if (Orientation == Orientation.Horizontal)
                 {
-                    int dy = mouseEvent.Y - dragPosition.Value.Y;
+                    int dy = mouseEvent.Position.Y - dragPosition.Value.Y;
                     Parent.SetSplitterPos (Idx, Offset (Y, dy));
-                    moveRuneRenderLocation = new Point (mouseEvent.X, 0);
+                    moveRuneRenderLocation = new Point (mouseEvent.Position.X, 0);
                 }
                 else
                 {
-                    int dx = mouseEvent.X - dragPosition.Value.X;
+                    int dx = mouseEvent.Position.X - dragPosition.Value.X;
                     Parent.SetSplitterPos (Idx, Offset (X, dx));
-                    moveRuneRenderLocation = new Point (0, Math.Max (1, Math.Min (Viewport.Height - 2, mouseEvent.Y)));
+                    moveRuneRenderLocation = new Point (0, Math.Max (1, Math.Min (Viewport.Height - 2, mouseEvent.Position.Y)));
                 }
 
                 Parent.SetNeedsDisplay ();
@@ -979,20 +979,14 @@ public class TileView : View
             DrawSplitterSymbol ();
         }
 
-        public override bool OnEnter (View view)
-        {
-            Driver.SetCursorVisibility (CursorVisibility.Default);
-            PositionCursor ();
-
-            return base.OnEnter (view);
-        }
-
-        public override void PositionCursor ()
+        public override Point? PositionCursor ()
         {
             base.PositionCursor ();
 
             Point location = moveRuneRenderLocation ?? new Point (Viewport.Width / 2, Viewport.Height / 2);
             Move (location.X, location.Y);
+
+            return null; // Hide cursor
         }
 
         /// <summary>

+ 1 - 1
Terminal.Gui/Views/TimeField.cs

@@ -169,7 +169,7 @@ public class TimeField : TextField
 
         if (result && SelectedLength == 0 && ev.Flags.HasFlag (MouseFlags.Button1Pressed))
         {
-            int point = ev.X;
+            int point = ev.Position.X;
             AdjCursorPosition (point);
         }
 

+ 14 - 15
Terminal.Gui/Views/Toplevel.cs

@@ -333,44 +333,37 @@ public partial class Toplevel : View
     }
 
     /// <inheritdoc/>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (!IsOverlappedContainer)
         {
-            base.PositionCursor ();
-
             if (Focused is null)
             {
                 EnsureFocus ();
-
-                if (Focused is null)
-                {
-                    Driver.SetCursorVisibility (CursorVisibility.Invisible);
-                }
             }
 
-            return;
+            return null;
         }
 
+        // This code path only happens when the Toplevel is an Overlapped container
+
         if (Focused is null)
         {
+            // TODO: this is an Overlapped hack
             foreach (Toplevel top in Application.OverlappedChildren)
             {
                 if (top != this && top.Visible)
                 {
                     top.SetFocus ();
 
-                    return;
+                    return null;
                 }
             }
         }
 
-        base.PositionCursor ();
+        var cursor2 = base.PositionCursor ();
 
-        if (Focused is null)
-        {
-            Driver.SetCursorVisibility (CursorVisibility.Invisible);
-        }
+        return null; 
     }
 
     /// <summary>
@@ -389,6 +382,12 @@ public partial class Toplevel : View
                                               out int ny,
                                               out StatusBar sb
                                              );
+
+        if (superView is null)
+        {
+            return;
+        }
+
         var layoutSubviews = false;
         var maxWidth = 0;
 

+ 24 - 67
Terminal.Gui/Views/TreeView/TreeView.cs

@@ -64,8 +64,6 @@ public class TreeView<T> : View, ITreeView where T : class
     /// <summary>Cached result of <see cref="BuildLineMap"/></summary>
     private IReadOnlyCollection<Branch<T>> cachedLineMap;
 
-    private CursorVisibility desiredCursorVisibility = CursorVisibility.Invisible;
-
     private KeyCode objectActivationKey = KeyCode.Enter;
     private int scrollOffsetHorizontal;
     private int scrollOffsetVertical;
@@ -325,27 +323,6 @@ public class TreeView<T> : View, ITreeView where T : class
     /// <summary>The current number of rows in the tree (ignoring the controls bounds).</summary>
     public int ContentHeight => BuildLineMap ().Count ();
 
-    /// <summary>
-    ///     Get / Set the wished cursor when the tree is focused. Only applies when <see cref="MultiSelect"/> is true.
-    ///     Defaults to <see cref="CursorVisibility.Invisible"/>.
-    /// </summary>
-    public CursorVisibility DesiredCursorVisibility
-    {
-        get => MultiSelect ? desiredCursorVisibility : CursorVisibility.Invisible;
-        set
-        {
-            if (desiredCursorVisibility != value)
-            {
-                desiredCursorVisibility = value;
-
-                if (HasFocus)
-                {
-                    Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-                }
-            }
-        }
-    }
-
     /// <summary>
     ///     Gets the <see cref="CollectionNavigator"/> that searches the <see cref="Objects"/> collection as the user
     ///     types.
@@ -468,7 +445,6 @@ public class TreeView<T> : View, ITreeView where T : class
             // TODO: Should this be cancelable?
             ObjectActivatedEventArgs<T> e = new (this, o);
             OnObjectActivated (e);
-            PositionCursor ();
             return true;
         }
         return false;
@@ -675,8 +651,6 @@ public class TreeView<T> : View, ITreeView where T : class
         // search for next branch that begins with that letter
         var characterAsStr = character.ToString ();
         AdjustSelectionToNext (b => AspectGetter (b.Model).StartsWith (characterAsStr, caseSensitivity));
-
-        PositionCursor ();
     }
 
     /// <summary>
@@ -1002,7 +976,7 @@ public class TreeView<T> : View, ITreeView where T : class
     public bool IsSelected (T model) { return Equals (SelectedObject, model) || (MultiSelect && multiSelectedRegions.Any (s => s.Contains (model))); }
 
     ///<inheritdoc/>
-    protected internal override bool OnMouseEvent  (MouseEvent me)
+    protected internal override bool OnMouseEvent (MouseEvent me)
     {
         // If it is not an event we care about
         if (!me.Flags.HasFlag (MouseFlags.Button1Clicked)
@@ -1054,14 +1028,14 @@ public class TreeView<T> : View, ITreeView where T : class
         if (me.Flags.HasFlag (MouseFlags.Button1Clicked))
         {
             // The line they clicked on a branch
-            Branch<T> clickedBranch = HitTest (me.Y);
+            Branch<T> clickedBranch = HitTest (me.Position.Y);
 
             if (clickedBranch is null)
             {
                 return false;
             }
 
-            bool isExpandToggleAttempt = clickedBranch.IsHitOnExpandableSymbol (Driver, me.X);
+            bool isExpandToggleAttempt = clickedBranch.IsHitOnExpandableSymbol (Driver, me.Position.X);
 
             // If we are already selected (double click)
             if (Equals (SelectedObject, clickedBranch.Model))
@@ -1104,7 +1078,7 @@ public class TreeView<T> : View, ITreeView where T : class
         if (ObjectActivationButton.HasValue && me.Flags.HasFlag (ObjectActivationButton.Value))
         {
             // The line they clicked on a branch
-            Branch<T> clickedBranch = HitTest (me.Y);
+            Branch<T> clickedBranch = HitTest (me.Position.Y);
 
             if (clickedBranch is null)
             {
@@ -1183,8 +1157,6 @@ public class TreeView<T> : View, ITreeView where T : class
     ///<inheritdoc/>
     public override bool OnEnter (View view)
     {
-        Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-
         if (SelectedObject is null && Objects.Any ())
         {
             SelectedObject = Objects.First ();
@@ -1201,37 +1173,27 @@ public class TreeView<T> : View, ITreeView where T : class
             return false;
         }
 
-        try
+        // BUGBUG: this should move to OnInvokingKeyBindings
+        // If not a keybinding, is the key a searchable key press?
+        if (CollectionNavigatorBase.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation)
         {
-            // BUGBUG: this should move to OnInvokingKeyBindings
-            // If not a keybinding, is the key a searchable key press?
-            if (CollectionNavigatorBase.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation)
-            {
-                IReadOnlyCollection<Branch<T>> map;
-
-                // If there has been a call to InvalidateMap since the last time
-                // we need a new one to reflect the new exposed tree state
-                map = BuildLineMap ();
+            IReadOnlyCollection<Branch<T>> map;
 
-                // Find the current selected object within the tree
-                int current = map.IndexOf (b => b.Model == SelectedObject);
-                int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)keyEvent);
+            // If there has been a call to InvalidateMap since the last time
+            // we need a new one to reflect the new exposed tree state
+            map = BuildLineMap ();
 
-                if (newIndex is int && newIndex != -1)
-                {
-                    SelectedObject = map.ElementAt ((int)newIndex).Model;
-                    EnsureVisible (selectedObject);
-                    SetNeedsDisplay ();
+            // Find the current selected object within the tree
+            int current = map.IndexOf (b => b.Model == SelectedObject);
+            int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)keyEvent);
 
-                    return true;
-                }
-            }
-        }
-        finally
-        {
-            if (IsInitialized)
+            if (newIndex is int && newIndex != -1)
             {
-                PositionCursor ();
+                SelectedObject = map.ElementAt ((int)newIndex).Model;
+                EnsureVisible (selectedObject);
+                SetNeedsDisplay ();
+
+                return true;
             }
         }
 
@@ -1239,7 +1201,7 @@ public class TreeView<T> : View, ITreeView where T : class
     }
 
     /// <summary>Positions the cursor at the start of the selected objects line (if visible).</summary>
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (CanFocus && HasFocus && Visible && SelectedObject is { })
         {
@@ -1250,16 +1212,11 @@ public class TreeView<T> : View, ITreeView where T : class
             if (idx - ScrollOffsetVertical >= 0 && idx - ScrollOffsetVertical < Viewport.Height)
             {
                 Move (0, idx - ScrollOffsetVertical);
+
+                return MultiSelect ? new (0, idx - ScrollOffsetVertical) : null ;
             }
-            else
-            {
-                base.PositionCursor ();
-            }
-        }
-        else
-        {
-            base.PositionCursor ();
         }
+        return base.PositionCursor ();
     }
 
     /// <summary>

+ 6 - 6
Terminal.Gui/Views/Wizard/Wizard.cs

@@ -32,7 +32,7 @@ namespace Terminal.Gui;
 /// var secondStep = new WizardStep ("Second Step");
 /// wizard.AddStep(secondStep);
 /// secondStep.HelpText = "This is the help text for the Second Step.";
-/// var lbl = new Label () { Text = "Name:",  AutoSize = true };
+/// var lbl = new Label () { Text = "Name:" };
 /// secondStep.Add(lbl);
 /// 
 /// var name = new TextField { X = Pos.Right (lbl) + 1, Width = Dim.Fill () - 1 };
@@ -93,10 +93,10 @@ public class Wizard : Dialog
         Add (separator);
 
         // BUGBUG: Space is to work around https://github.com/gui-cs/Terminal.Gui/issues/1812
-        BackButton = new Button { AutoSize = true, Text = Strings.wzBack };
+        BackButton = new () { Text = Strings.wzBack };
         AddButton (BackButton);
 
-        NextFinishButton = new Button { AutoSize = true, Text = Strings.wzFinish };
+        NextFinishButton = new () { Text = Strings.wzFinish };
         NextFinishButton.IsDefault = true;
         AddButton (NextFinishButton);
 
@@ -417,10 +417,10 @@ public class Wizard : Dialog
         {
             if (key == Key.Esc)
             {
-                    var args = new WizardButtonEventArgs ();
-                    Cancelled?.Invoke (this, args);
+                var args = new WizardButtonEventArgs ();
+                Cancelled?.Invoke (this, args);
 
-                    return false;
+                return false;
             }
         }
 

+ 25 - 52
Terminal.sln

@@ -30,54 +30,57 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 		testenvironments.json = testenvironments.json
 	EndProjectSection
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzers", "Analyzers", "{CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Internal", "Analyzers\Terminal.Gui.Analyzers.Internal\Terminal.Gui.Analyzers.Internal.csproj", "{5DE91722-8765-4E2B-97E4-2A18010B5CED}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Internal.Tests", "Analyzers\Terminal.Gui.Analyzers.Internal.Tests\Terminal.Gui.Analyzers.Internal.Tests.csproj", "{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui.Analyzers.Internal.Debugging", "Analyzers\Terminal.Gui.Analyzers.Internal.Debugging\Terminal.Gui.Analyzers.Internal.Debugging.csproj", "{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}"
+EndProject
 Global
+	GlobalSection(NestedProjects) = preSolution
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
+		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2} = {CCADA0BC-61CF-4B4B-96BA-A3B0C0A7F54D}
+	EndGlobalSection
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
-		Debug|x86 = Debug|x86
 		Release|Any CPU = Release|Any CPU
-		Release|x86 = Release|x86
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Debug|x86.Build.0 = Debug|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.ActiveCfg = Release|Any CPU
-		{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}.Release|x86.Build.0 = Release|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5DE91722-8765-4E2B-97E4-2A18010B5CED}.Release|Any CPU.Build.0 = Release|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{715DB4BA-F989-4DF6-B46F-5ED26A32B2DD}.Release|Any CPU.Build.0 = Release|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.Build.0 = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.Build.0 = Release|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.ActiveCfg = Release|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.Build.0 = Release|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{8B901EDE-8974-4820-B100-5226917E2990}.Debug|x86.Build.0 = Debug|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{8B901EDE-8974-4820-B100-5226917E2990}.Release|Any CPU.Build.0 = Release|Any CPU
-		{8B901EDE-8974-4820-B100-5226917E2990}.Release|x86.ActiveCfg = Release|Any CPU
-		{8B901EDE-8974-4820-B100-5226917E2990}.Release|x86.Build.0 = Release|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Debug|x86.Build.0 = Debug|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|Any CPU.Build.0 = Release|Any CPU
-		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|x86.ActiveCfg = Release|Any CPU
-		{44E15B48-0DB2-4560-82BD-D3B7989811C3}.Release|x86.Build.0 = Release|Any CPU
 		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Debug|x86.Build.0 = Debug|Any CPU
 		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{B0A602CD-E176-449D-8663-64238D54F857}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.ActiveCfg = Release|Any CPU
-		{B0A602CD-E176-449D-8663-64238D54F857}.Release|x86.Build.0 = Release|Any CPU
+		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C2AD09BD-D579-45A7-ACA3-E4EF3BC027D2}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -85,34 +88,4 @@ Global
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {9F8F8A4D-7B8D-4C2A-AC5E-CD7117F74C03}
 	EndGlobalSection
-	GlobalSection(MonoDevelopProperties) = preSolution
-		Policies = $0
-		$0.TextStylePolicy = $1
-		$1.FileWidth = 80
-		$1.scope = text/x-csharp
-		$1.TabWidth = 8
-		$1.IndentWidth = 8
-		$0.CSharpFormattingPolicy = $2
-		$2.scope = text/x-csharp
-		$2.IndentSwitchSection = False
-		$2.NewLinesForBracesInTypes = False
-		$2.NewLinesForBracesInProperties = False
-		$2.NewLinesForBracesInAccessors = False
-		$2.NewLinesForBracesInAnonymousMethods = False
-		$2.NewLinesForBracesInControlBlocks = False
-		$2.NewLinesForBracesInAnonymousTypes = False
-		$2.NewLinesForBracesInObjectCollectionArrayInitializers = False
-		$2.NewLinesForBracesInLambdaExpressionBody = False
-		$2.NewLineForElse = False
-		$2.NewLineForCatch = False
-		$2.NewLineForFinally = False
-		$2.NewLineForMembersInObjectInit = False
-		$2.NewLineForMembersInAnonymousTypes = False
-		$2.NewLineForClausesInQuery = False
-		$2.SpacingAfterMethodDeclarationName = True
-		$2.SpaceAfterMethodCallName = True
-		$2.SpaceBeforeOpenSquareBracket = True
-		$0.DotNetNamingPolicy = $3
-		$0.StandardHeader = $4
-	EndGlobalSection
 EndGlobal

+ 1 - 0
Terminal.sln.DotSettings

@@ -387,6 +387,7 @@
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PublicFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=236f7aa5_002D7b06_002D43ca_002Dbf2a_002D9b31bfcff09a/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=53eecf85_002Dd821_002D40e8_002Dac97_002Dfdb734542b84/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=70345118_002D4b40_002D4ece_002D937c_002Dbbeb7a0b2e70/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
 	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=c873eafb_002Dd57f_002D481d_002D8c93_002D77f6863c2f88/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>

+ 2 - 6
UICatalog/Scenarios/ASCIICustomButton.cs

@@ -82,8 +82,6 @@ public class ASCIICustomButtonTest : Scenario
         {
             _border = new FrameView { Width = Width, Height = Height };
 
-            AutoSize = false;
-
             var fillText = new StringBuilder ();
 
             for (var i = 0; i < Viewport.Height; i++)
@@ -198,7 +196,6 @@ public class ASCIICustomButtonTest : Scenario
 
                 var button = new ASCIICustomButton
                 {
-                    AutoSize = false,
                     Id = j.ToString (),
                     Text = $"section {j}",
                     Y = yPos,
@@ -217,7 +214,6 @@ public class ASCIICustomButtonTest : Scenario
 
             var closeButton = new ASCIICustomButton
             {
-                AutoSize = false,
                 Id = "close",
                 Text = "Close",
                 Y = Pos.Bottom (prevButton),
@@ -273,7 +269,7 @@ public class ASCIICustomButtonTest : Scenario
                 case KeyCode.End:
                     _scrollView.ContentOffset = new Point (
                                                            _scrollView.ContentOffset.X,
-                                                           -(_scrollView.ContentSize.Height
+                                                           -(_scrollView.ContentSize.GetValueOrDefault ().Height
                                                              - _scrollView.Frame.Height
                                                              + (_scrollView.ShowHorizontalScrollIndicator ? 1 : 0))
                                                           );
@@ -291,7 +287,7 @@ public class ASCIICustomButtonTest : Scenario
                                                            Math.Max (
                                                                      _scrollView.ContentOffset.Y
                                                                      - _scrollView.Frame.Height,
-                                                                     -(_scrollView.ContentSize.Height
+                                                                     -(_scrollView.ContentSize.GetValueOrDefault ().Height
                                                                        - _scrollView.Frame.Height
                                                                        + (_scrollView.ShowHorizontalScrollIndicator
                                                                               ? 1

+ 26 - 27
UICatalog/Scenarios/Adornments.cs

@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.ComponentModel;
 using System.Linq;
 using Terminal.Gui;
 
@@ -21,7 +20,7 @@ public class Adornments : Scenario
 
         Window app = new ()
         {
-            Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
+            Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"
         };
 
         var editor = new AdornmentsEditor ();
@@ -31,9 +30,9 @@ public class Adornments : Scenario
         {
             Title = "The _Window",
             Arrangement = ViewArrangement.Movable,
-            X = Pos.Right(editor),
+            X = Pos.Right (editor),
             Width = Dim.Percent (60),
-            Height = Dim.Percent (80),
+            Height = Dim.Percent (80)
         };
         app.Add (window);
 
@@ -72,10 +71,9 @@ public class Adornments : Scenario
 
         var labelAnchorEnd = new Label
         {
-            AutoSize = false,
             Y = Pos.AnchorEnd (),
             Width = 40,
-            Height = Dim.Percent(20),
+            Height = Dim.Percent (20),
             Text = "Label\nY=AnchorEnd(),Height=Dim.Percent(10)",
             ColorScheme = Colors.ColorSchemes ["Error"]
         };
@@ -89,10 +87,9 @@ public class Adornments : Scenario
         window.Padding.Data = "Padding";
         window.Padding.Thickness = new (3);
 
-        var longLabel = new Label ()
+        var longLabel = new Label
         {
-            X = 40, Y = 5, Title = "This is long text (in a label) that should clip.",
-
+            X = 40, Y = 5, Title = "This is long text (in a label) that should clip."
         };
         longLabel.TextFormatter.WordWrap = true;
         window.Add (tf1, color, button, label, btnButtonInWindow, labelAnchorEnd, longLabel);
@@ -100,19 +97,20 @@ public class Adornments : Scenario
         editor.Initialized += (s, e) => { editor.ViewToEdit = window; };
 
         window.Initialized += (s, e) =>
-                            {
-                                var labelInPadding = new Label () { X = 1, Y = 0, Title = "_Text:" };
-                                window.Padding.Add (labelInPadding);
+                              {
+                                  var labelInPadding = new Label { X = 1, Y = 0, Title = "_Text:" };
+                                  window.Padding.Add (labelInPadding);
 
-                                var textFieldInPadding = new TextField () { X = Pos.Right (labelInPadding) + 1, Y = Pos.Top (labelInPadding), Width = 15, Text = "some text" };
-                                textFieldInPadding.Accept += (s, e) => MessageBox.Query (20, 7, "TextField", textFieldInPadding.Text, "Ok");
-                                window.Padding.Add (textFieldInPadding);
+                                  var textFieldInPadding = new TextField
+                                      { X = Pos.Right (labelInPadding) + 1, Y = Pos.Top (labelInPadding), Width = 15, Text = "some text" };
+                                  textFieldInPadding.Accept += (s, e) => MessageBox.Query (20, 7, "TextField", textFieldInPadding.Text, "Ok");
+                                  window.Padding.Add (textFieldInPadding);
 
-                                var btnButtonInPadding = new Button { X = Pos.Center (), Y = 0, Text = "_Button in Padding" };
-                                btnButtonInPadding.Accept += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
-                                btnButtonInPadding.BorderStyle = LineStyle.Dashed;
-                                btnButtonInPadding.Border.Thickness = new (1, 1, 1, 1);
-                                window.Padding.Add (btnButtonInPadding);
+                                  var btnButtonInPadding = new Button { X = Pos.Center (), Y = 0, Text = "_Button in Padding" };
+                                  btnButtonInPadding.Accept += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
+                                  btnButtonInPadding.BorderStyle = LineStyle.Dashed;
+                                  btnButtonInPadding.Border.Thickness = new (1, 1, 1, 1);
+                                  window.Padding.Add (btnButtonInPadding);
 
 #if SUBVIEW_BASED_BORDER
                                 btnButtonInPadding.Border.CloseButton.Visible = true;
@@ -126,7 +124,7 @@ public class Adornments : Scenario
 
                                 view.Accept += (s, e) => MessageBox.Query (20, 7, "Hi", "Window Close Button Pressed!", "Ok");
 #endif
-                            };
+                              };
 
         app.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;
 
@@ -137,7 +135,7 @@ public class Adornments : Scenario
     }
 
     /// <summary>
-    /// Provides a composable UI for editing the settings of an Adornment.
+    ///     Provides a composable UI for editing the settings of an Adornment.
     /// </summary>
     public class AdornmentEditor : View
     {
@@ -172,6 +170,7 @@ public class Adornments : Scenario
             BorderStyle = LineStyle.Double;
             Initialized += AdornmentEditor_Initialized;
         }
+
         public Attribute Color
         {
             get => new (_foregroundColorPicker.SelectedColor, _backgroundColorPicker.SelectedColor);
@@ -338,7 +337,7 @@ public class Adornments : Scenario
     }
 
     /// <summary>
-    /// Provides an editor UI for the Margin, Border, and Padding of a View.
+    ///     Provides an editor UI for the Margin, Border, and Padding of a View.
     /// </summary>
     public class AdornmentsEditor : View
     {
@@ -471,19 +470,19 @@ public class Adornments : Scenario
                 _paddingEditor.AttributeChanged += Editor_AttributeChanged;
                 Add (_paddingEditor);
 
-                _diagCheckBox = new CheckBox { Text = "_Diagnostics", Y = Pos.Bottom (_paddingEditor) };
-                _diagCheckBox.Checked = View.Diagnostics != ViewDiagnosticFlags.Off;
+                _diagCheckBox = new() { Text = "_Diagnostics", Y = Pos.Bottom (_paddingEditor) };
+                _diagCheckBox.Checked = Diagnostics != ViewDiagnosticFlags.Off;
 
                 _diagCheckBox.Toggled += (s, e) =>
                                          {
                                              if (e.NewValue == true)
                                              {
-                                                 View.Diagnostics =
+                                                 Diagnostics =
                                                      ViewDiagnosticFlags.Padding | ViewDiagnosticFlags.Ruler;
                                              }
                                              else
                                              {
-                                                 View.Diagnostics = ViewDiagnosticFlags.Off;
+                                                 Diagnostics = ViewDiagnosticFlags.Off;
                                              }
                                          };
 

+ 43 - 38
UICatalog/Scenarios/AllViewsTester.cs

@@ -12,7 +12,7 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Top Level Windows")]
 public class AllViewsTester : Scenario
 {
-    private readonly List<string> _dimNames = new () { "Factor", "Fill", "Absolute" };
+    private readonly List<string> _dimNames = new () { "Auto", "Factor", "Fill", "Absolute" };
 
     // TODO: This is missing some
     private readonly List<string> _posNames = new () { "Factor", "AnchorEnd", "Center", "Absolute" };
@@ -208,7 +208,7 @@ public class AllViewsTester : Scenario
             Title = "Size (Dim)"
         };
 
-        radioItems = new [] { "_Percent(width)", "_Fill(width)", "_Sized(width)" };
+        radioItems = new [] { "Auto (min)", "_Percent(width)", "_Fill(width)", "_Sized(width)" };
         label = new Label { X = 0, Y = 0, Text = "Width:" };
         _sizeFrame.Add (label);
         _wRadioGroup = new RadioGroup { X = 0, Y = Pos.Bottom (label), RadioLabels = radioItems };
@@ -221,12 +221,13 @@ public class AllViewsTester : Scenario
                                   {
                                       switch (_wRadioGroup.SelectedItem)
                                       {
-                                          case 0:
+                                          case 1:
                                               _wVal = Math.Min (int.Parse (_wText.Text), 100);
 
                                               break;
-                                          case 1:
+                                          case 0:
                                           case 2:
+                                          case 3:
                                               _wVal = int.Parse (_wText.Text);
 
                                               break;
@@ -240,7 +241,7 @@ public class AllViewsTester : Scenario
         _sizeFrame.Add (_wText);
         _sizeFrame.Add (_wRadioGroup);
 
-        radioItems = new [] { "P_ercent(height)", "F_ill(height)", "Si_zed(height)" };
+        radioItems = new [] { "_Auto (min)", "P_ercent(height)", "F_ill(height)", "Si_zed(height)" };
         label = new Label { X = Pos.Right (_wRadioGroup) + 1, Y = 0, Text = "Height:" };
         _sizeFrame.Add (label);
         _hText = new TextField { X = Pos.Right (label) + 1, Y = 0, Width = 4, Text = $"{_hVal}" };
@@ -251,12 +252,13 @@ public class AllViewsTester : Scenario
                                   {
                                       switch (_hRadioGroup.SelectedItem)
                                       {
-                                          case 0:
+                                          case 1:
                                               _hVal = Math.Min (int.Parse (_hText.Text), 100);
 
                                               break;
-                                          case 1:
+                                          case 0:
                                           case 2:
+                                          case 3:
                                               _hVal = int.Parse (_hText.Text);
 
                                               break;
@@ -386,38 +388,40 @@ public class AllViewsTester : Scenario
             //view.LayoutStyle = LayoutStyle.Absolute;
 
             view.X = _xRadioGroup.SelectedItem switch
-                     {
-                         0 => Pos.Percent (_xVal),
-                         1 => Pos.AnchorEnd (),
-                         2 => Pos.Center (),
-                         3 => Pos.At (_xVal),
-                         _ => view.X
-                     };
+            {
+                0 => Pos.Percent (_xVal),
+                1 => Pos.AnchorEnd (),
+                2 => Pos.Center (),
+                3 => Pos.At (_xVal),
+                _ => view.X
+            };
 
             view.Y = _yRadioGroup.SelectedItem switch
-                     {
-                         0 => Pos.Percent (_yVal),
-                         1 => Pos.AnchorEnd (),
-                         2 => Pos.Center (),
-                         3 => Pos.At (_yVal),
-                         _ => view.Y
-                     };
+            {
+                0 => Pos.Percent (_yVal),
+                1 => Pos.AnchorEnd (),
+                2 => Pos.Center (),
+                3 => Pos.At (_yVal),
+                _ => view.Y
+            };
 
             view.Width = _wRadioGroup.SelectedItem switch
-                         {
-                             0 => Dim.Percent (_wVal),
-                             1 => Dim.Fill (_wVal),
-                             2 => Dim.Sized (_wVal),
-                             _ => view.Width
-                         };
+            {
+                0 => Dim.Auto (min: _wVal),
+                1 => Dim.Percent (_wVal),
+                2 => Dim.Fill (_wVal),
+                3 => Dim.Sized (_wVal),
+                _ => view.Width
+            };
 
             view.Height = _hRadioGroup.SelectedItem switch
-                          {
-                              0 => Dim.Percent (_hVal),
-                              1 => Dim.Fill (_hVal),
-                              2 => Dim.Sized (_hVal),
-                              _ => view.Height
-                          };
+            {
+                0 => Dim.Auto (min: _hVal),
+                1 => Dim.Percent (_hVal),
+                2 => Dim.Fill (_hVal),
+                3 => Dim.Sized (_hVal),
+                _ => view.Height
+            };
         }
         catch (Exception e)
         {
@@ -474,16 +478,17 @@ public class AllViewsTester : Scenario
 
     private void View_Initialized (object sender, EventArgs e)
     {
-        var view = sender as View;
+        if (sender is not View view)
+        {
+            return;
+        }
 
-        //view.X = Pos.Center ();
-        //view.Y = Pos.Center ();
-        if (view.Width == null || view.Frame.Width == 0)
+        if (view.Width is not Dim.DimAuto && (view.Width is null || view.Frame.Width == 0))
         {
             view.Width = Dim.Fill ();
         }
 
-        if (view.Height == null || view.Frame.Height == 0)
+        if (view.Width is not Dim.DimAuto && (view.Height is null || view.Frame.Height == 0))
         {
             view.Height = Dim.Fill ();
         }

+ 0 - 114
UICatalog/Scenarios/AutoSizeAndDirectionText.cs

@@ -1,114 +0,0 @@
-using Terminal.Gui;
-
-namespace UICatalog.Scenarios;
-
-[ScenarioMetadata ("Text Direction and AutoSize", "Demos TextFormatter Direction and View AutoSize.")]
-[ScenarioCategory ("Text and Formatting")]
-public class AutoSizeAndDirectionText : Scenario
-{
-    public override void Setup ()
-    {
-        var text = "Hello World";
-        var wideText = "Hello World 你";
-        ColorScheme color = Colors.ColorSchemes ["Dialog"];
-
-        var labelH = new Label
-        {
-            X = 1,
-            Y = 1,
-
-            //    Width = 11,
-            //    Height = 1,
-            ColorScheme = color,
-            Text = text,
-            TextDirection = TextDirection.LeftRight_TopBottom
-        };
-        Win.Add (labelH);
-
-        var labelV = new Label
-        {
-            X = 70,
-            Y = 1,
-
-            //    Width = 1,
-            //    Height = 11,
-            ColorScheme = color,
-            Text = text,
-            TextDirection = TextDirection.TopBottom_LeftRight
-        };
-        Win.Add (labelV);
-
-        var editText = new TextView
-        {
-            X = Pos.Center (),
-            Y = Pos.Center (),
-            Width = 20,
-            Height = 5,
-            Text = text
-        };
-
-        editText.SetFocus ();
-
-        Win.Add (editText);
-
-        var ckbDirection = new CheckBox { Text = "Toggle Direction", X = Pos.Center (), Y = Pos.Center () + 3 };
-
-        ckbDirection.Toggled += (s, e) =>
-                                {
-                                    if (labelH.TextDirection == TextDirection.LeftRight_TopBottom)
-                                    {
-                                        labelH.TextDirection = TextDirection.TopBottom_LeftRight;
-                                        labelV.TextDirection = TextDirection.LeftRight_TopBottom;
-                                    }
-                                    else
-                                    {
-                                        labelH.TextDirection = TextDirection.LeftRight_TopBottom;
-                                        labelV.TextDirection = TextDirection.TopBottom_LeftRight;
-                                    }
-                                };
-        Win.Add (ckbDirection);
-
-        var ckbAutoSize = new CheckBox
-        {
-            Text = "Auto Size", X = Pos.Center (), Y = Pos.Center () + 5, Checked = labelH.AutoSize = labelV.AutoSize
-        };
-        ckbAutoSize.Toggled += (s, e) => labelH.AutoSize = labelV.AutoSize = (bool)ckbAutoSize.Checked;
-        Win.Add (ckbAutoSize);
-
-        var ckbPreserveTrailingSpaces = new CheckBox
-        {
-            Text = "Preserve Trailing Spaces",
-            X = Pos.Center (),
-            Y = Pos.Center () + 7,
-            Checked = labelH.PreserveTrailingSpaces =
-                          labelV.PreserveTrailingSpaces
-        };
-
-        ckbPreserveTrailingSpaces.Toggled += (s, e) =>
-                                                 labelH.PreserveTrailingSpaces = labelV.PreserveTrailingSpaces = (bool)ckbPreserveTrailingSpaces.Checked;
-        Win.Add (ckbPreserveTrailingSpaces);
-
-        var ckbWideText = new CheckBox { Text = "Use wide runes", X = Pos.Center (), Y = Pos.Center () + 9 };
-
-        ckbWideText.Toggled += (s, e) =>
-                               {
-                                   if (ckbWideText.Checked == true)
-                                   {
-                                       labelH.Text = labelV.Text = editText.Text = wideText;
-                                       labelH.Width = 14;
-                                       labelV.Height = 13;
-                                   }
-                                   else
-                                   {
-                                       labelH.Text = labelV.Text = editText.Text = text;
-                                       labelH.Width = 11;
-                                       labelV.Width = 1;
-                                       labelV.Height = 11;
-                                   }
-                               };
-        Win.Add (ckbWideText);
-
-        Win.KeyUp += (s, e) =>
-                         labelH.Text = labelV.Text = text = editText.Text;
-    }
-}

+ 0 - 2
UICatalog/Scenarios/BasicColors.cs

@@ -28,7 +28,6 @@ public class BasicColors : Scenario
 
             var vl = new Label
             {
-                AutoSize = false,
                 X = vx,
                 Y = 0,
                 Width = 1,
@@ -42,7 +41,6 @@ public class BasicColors : Scenario
 
             var hl = new Label
             {
-                AutoSize = false,
                 X = 15,
                 Y = y,
                 Width = 13,

+ 17 - 30
UICatalog/Scenarios/Buttons.cs

@@ -33,7 +33,14 @@ public class Buttons : Scenario
         defaultButton.Accept += (s, e) => Application.RequestStop ();
         main.Add (defaultButton);
 
-        var swapButton = new Button { X = 50, Text = "S_wap Default (Absolute Layout)" };
+        var swapButton = new Button
+        {
+            X = 50,
+            Width = 45,
+            Height = 3,
+            Text = "S_wap Default (Size = 45, 3)",
+            ColorScheme = Colors.ColorSchemes ["Error"]
+        };
 
         swapButton.Accept += (s, e) =>
                              {
@@ -51,29 +58,23 @@ public class Buttons : Scenario
                              };
         }
 
-        var colorButtonsLabel = new Label { X = 0, Y = Pos.Bottom (editLabel) + 1, Text = "Color Buttons:" };
+        var colorButtonsLabel = new Label { X = 0, Y = Pos.Bottom (swapButton) + 1, Text = "Color Buttons: " };
         main.Add (colorButtonsLabel);
 
         View prev = colorButtonsLabel;
 
-        //With this method there is no need to call Application.TopReady += () => Application.TopRedraw (Top.Bounds);
-        Pos x = Pos.Right (colorButtonsLabel) + 2;
-
         foreach (KeyValuePair<string, ColorScheme> colorScheme in Colors.ColorSchemes)
         {
             var colorButton = new Button
             {
-                ColorScheme = colorScheme.Value,
-                X = Pos.Right (prev) + 2,
+                X = Pos.Right (prev),
                 Y = Pos.Y (colorButtonsLabel),
-                Text = $"_{colorScheme.Key}"
+                Text = $"_{colorScheme.Key}",
+                ColorScheme = colorScheme.Value,
             };
             DoMessage (colorButton, colorButton.Text);
             main.Add (colorButton);
             prev = colorButton;
-
-            // BUGBUG: AutoSize is true and the X doesn't change
-            //x += colorButton.Frame.Width + 2;
         }
 
         Button button;
@@ -91,7 +92,7 @@ public class Buttons : Scenario
 
         // Note the 'N' in 'Newline' will be the hotkey
         main.Add (
-                  button = new () { X = 2, Y = Pos.Bottom (button) + 1, Text = "a Newline\nin the button" }
+                  button = new () { X = 2, Y = Pos.Bottom (button) + 1, Height = 2, Text = "a Newline\nin the button" }
                  );
         button.Accept += (s, e) => MessageBox.Query ("Message", "Question?", "Yes", "No");
 
@@ -110,16 +111,14 @@ public class Buttons : Scenario
 
         var removeButton = new Button
         {
-            X = 2, Y = Pos.Bottom (button) + 1, ColorScheme = Colors.ColorSchemes ["Error"], Text = "Remove this button"
+            X = 2, Y = Pos.Bottom (button) + 1,
+            ColorScheme = Colors.ColorSchemes ["Error"], Text = "Remove this button"
         };
         main.Add (removeButton);
 
         // This in interesting test case because `moveBtn` and below are laid out relative to this one!
         removeButton.Accept += (s, e) =>
                                {
-                                   // Now this throw a InvalidOperationException on the TopologicalSort method as is expected.
-                                   //main.Remove (removeButton);
-
                                    removeButton.Visible = false;
                                };
 
@@ -138,7 +137,6 @@ public class Buttons : Scenario
         {
             X = 0,
             Y = Pos.Center () - 1,
-            AutoSize = false,
             Width = 30,
             Height = 1,
             ColorScheme = Colors.ColorSchemes ["Error"],
@@ -148,29 +146,23 @@ public class Buttons : Scenario
         moveBtn.Accept += (s, e) =>
                           {
                               moveBtn.X = moveBtn.Frame.X + 5;
-
-                              // This is already fixed with the call to SetNeedDisplay() in the Pos Dim.
-                              //computedFrame.LayoutSubviews (); // BUGBUG: This call should not be needed. View.X is not causing relayout correctly
                           };
         computedFrame.Add (moveBtn);
 
         // Demonstrates how changing the View.Frame property can SIZE Views (#583)
         var sizeBtn = new Button
         {
-            X = 0,
             Y = Pos.Center () + 1,
-            AutoSize = false,
+            X = 0,
             Width = 30,
             Height = 1,
+            Text = "Grow This \u263a Button _via Pos",
             ColorScheme = Colors.ColorSchemes ["Error"],
-            Text = "Size This \u263a Button _via Pos"
         };
 
         sizeBtn.Accept += (s, e) =>
                           {
                               sizeBtn.Width = sizeBtn.Frame.Width + 5;
-
-                              //computedFrame.LayoutSubviews (); // FIXED: This call should not be needed. View.X is not causing relayout correctly
                           };
         computedFrame.Add (sizeBtn);
 
@@ -268,7 +260,6 @@ public class Buttons : Scenario
         {
             X = 2,
             Y = Pos.Bottom (radioGroup) + 1,
-            AutoSize = false,
             Height = 1,
             Width = Dim.Width (computedFrame) - 2,
             ColorScheme = Colors.ColorSchemes ["TopLevel"],
@@ -283,7 +274,6 @@ public class Buttons : Scenario
         {
             X = Pos.Left (absoluteFrame) + 1,
             Y = Pos.Bottom (radioGroup) + 1,
-            AutoSize = false,
             Height = 1,
             Width = Dim.Width (absoluteFrame) - 2, // BUGBUG: Not always the width isn't calculated correctly.
             ColorScheme = Colors.ColorSchemes ["TopLevel"],
@@ -434,7 +424,6 @@ public class Buttons : Scenario
 
             _down = new ()
             {
-                AutoSize = false,
                 Height = 1,
                 Width = 1,
                 NoPadding = true,
@@ -447,7 +436,6 @@ public class Buttons : Scenario
             _number = new ()
             {
                 Text = Value.ToString (),
-                AutoSize = false,
                 X = Pos.Right (_down),
                 Y = Pos.Top (_down),
                 Width = Dim.Function (() => Digits),
@@ -458,7 +446,6 @@ public class Buttons : Scenario
 
             _up = new ()
             {
-                AutoSize = false,
                 X = Pos.AnchorEnd (),
                 Y = Pos.Top (_number),
                 Height = 1,

+ 20 - 40
UICatalog/Scenarios/CharacterMap.cs

@@ -109,7 +109,7 @@ public class CharacterMap : Scenario
         // if user clicks the mouse in TableView
         _categoryList.MouseClick += (s, e) =>
                                     {
-                                        _categoryList.ScreenToCell (e.MouseEvent.X, e.MouseEvent.Y, out int? clickedCol);
+                                        _categoryList.ScreenToCell (e.MouseEvent.Position, out int? clickedCol);
 
                                         if (clickedCol != null && e.MouseEvent.Flags.HasFlag (MouseFlags.Button1Clicked))
                                         {
@@ -315,7 +315,6 @@ public class CharacterMap : Scenario
 
 internal class CharMap : View
 {
-    private const CursorVisibility _cursor = CursorVisibility.Default;
     private const int COLUMN_WIDTH = 3;
 
     private ContextMenu _contextMenu = new ();
@@ -327,6 +326,7 @@ internal class CharMap : View
     {
         ColorScheme = Colors.ColorSchemes ["Dialog"];
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
 
         ContentSize = new (RowWidth, (MaxCodePoint / 16 + 2) * _rowHeight);
 
@@ -472,7 +472,6 @@ internal class CharMap : View
 
         var up = new Button
         {
-            AutoSize = false,
             X = Pos.AnchorEnd (1),
             Y = 0,
             Height = 1,
@@ -487,7 +486,6 @@ internal class CharMap : View
 
         var down = new Button
         {
-            AutoSize = false,
             X = Pos.AnchorEnd (1),
             Y = Pos.AnchorEnd (2),
             Height = 1,
@@ -502,7 +500,6 @@ internal class CharMap : View
 
         var left = new Button
         {
-            AutoSize = false,
             X = 0,
             Y = Pos.AnchorEnd (1),
             Height = 1,
@@ -517,7 +514,6 @@ internal class CharMap : View
 
         var right = new Button
         {
-            AutoSize = false,
             X = Pos.AnchorEnd (2),
             Y = Pos.AnchorEnd (1),
             Height = 1,
@@ -807,24 +803,7 @@ internal class CharMap : View
         }
     }
 
-    public override bool OnEnter (View view)
-    {
-        if (IsInitialized)
-        {
-            Application.Driver.SetCursorVisibility (_cursor);
-        }
-
-        return base.OnEnter (view);
-    }
-
-    public override bool OnLeave (View view)
-    {
-        Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnLeave (view);
-    }
-
-    public override void PositionCursor ()
+    public override Point? PositionCursor ()
     {
         if (HasFocus
             && Cursor.X >= RowLabelWidth
@@ -832,13 +811,14 @@ internal class CharMap : View
             && Cursor.Y > 0
             && Cursor.Y < Viewport.Height)
         {
-            Driver.SetCursorVisibility (_cursor);
             Move (Cursor.X, Cursor.Y);
         }
         else
         {
-            Driver.SetCursorVisibility (CursorVisibility.Invisible);
+            return null;
         }
+
+        return Cursor;
     }
 
     public event EventHandler<ListViewItemEventArgs> SelectedCodePointChanged;
@@ -870,23 +850,18 @@ internal class CharMap : View
             return;
         }
 
-        args.Handled = true;
-
-        if (me.Y == 0)
+        if (me.Position.Y == 0)
         {
-            me.Y = Cursor.Y;
+            me.Position = me.Position with { Y = Cursor.Y };
         }
 
-        if (me.Y > 0)
-        { }
-
-        if (me.X < RowLabelWidth || me.X > RowLabelWidth + 16 * COLUMN_WIDTH - 1)
+        if (me.Position.X < RowLabelWidth || me.Position.X > RowLabelWidth + 16 * COLUMN_WIDTH - 1)
         {
-            me.X = Cursor.X;
+            me.Position = me.Position with { X = Cursor.X };
         }
 
-        int row = (me.Y - 1 - -Viewport.Y) / _rowHeight; // -1 for header
-        int col = (me.X - RowLabelWidth - -Viewport.X) / COLUMN_WIDTH;
+        int row = (me.Position.Y - 1 - -Viewport.Y) / _rowHeight; // -1 for header
+        int col = (me.Position.X - RowLabelWidth - -Viewport.X) / COLUMN_WIDTH;
 
         if (col > 15)
         {
@@ -905,10 +880,16 @@ internal class CharMap : View
             Hover?.Invoke (this, new (val, null));
         }
 
+        if (!HasFocus && CanFocus)
+        {
+            SetFocus ();
+        }
+
+        args.Handled = true;
+
         if (me.Flags == MouseFlags.Button1Clicked)
         {
             SelectedCodePoint = val;
-
             return;
         }
 
@@ -926,7 +907,7 @@ internal class CharMap : View
 
             _contextMenu = new ()
             {
-                Position = new (me.X + 1, me.Y + 1),
+                Position = new (me.Position.X + 1, me.Position.Y + 1),
                 MenuItems = new (
                                  new MenuItem []
                                  {
@@ -973,7 +954,6 @@ internal class CharMap : View
         var errorLabel = new Label
         {
             Text = UcdApiClient.BaseUrl,
-            AutoSize = false,
             X = 0,
             Y = 1,
             Width = Dim.Fill (),

+ 0 - 2
UICatalog/Scenarios/CollectionNavigatorTester.cs

@@ -145,7 +145,6 @@ public class CollectionNavigatorTester : Scenario
             TextAlignment = TextAlignment.Centered,
             X = 0,
             Y = 1, // for menu
-            AutoSize = false,
             Width = Dim.Percent (50),
             Height = 1
         };
@@ -175,7 +174,6 @@ public class CollectionNavigatorTester : Scenario
             TextAlignment = TextAlignment.Centered,
             X = Pos.Right (_listView) + 2,
             Y = 1, // for menu
-            AutoSize = false,
             Width = Dim.Percent (50),
             Height = 1
         };

+ 1 - 2
UICatalog/Scenarios/ComboBoxIteration.cs

@@ -12,7 +12,7 @@ public class ComboBoxIteration : Scenario
     {
         List<string> items = new () { "one", "two", "three" };
 
-        var lbListView = new Label { AutoSize = false, Width = 10, Height = 1 };
+        var lbListView = new Label { Width = 10, Height = 1 };
         Win.Add (lbListView);
 
         var listview = new ListView
@@ -25,7 +25,6 @@ public class ComboBoxIteration : Scenario
         {
             ColorScheme = Colors.ColorSchemes ["TopLevel"],
             X = Pos.Right (lbListView) + 1,
-            AutoSize = false,
             Width = Dim.Percent (40)
         };
 

+ 0 - 12
UICatalog/Scenarios/ComputedLayout.cs

@@ -27,7 +27,6 @@ public class ComputedLayout : Scenario
 
         var horizontalRuler = new Label
         {
-            AutoSize = false,
             X = 0,
             Y = 0,
             Width = Dim.Fill (),
@@ -43,7 +42,6 @@ public class ComputedLayout : Scenario
 
         var verticalRuler = new Label
         {
-            AutoSize = false,
             X = 0,
             Y = 0,
             Width = 1,
@@ -93,7 +91,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Left,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -106,7 +103,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Right,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -119,7 +115,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Centered,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -132,7 +127,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Justified,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -159,7 +153,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Left,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -172,7 +165,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Right,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -185,7 +177,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Centered,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -198,7 +189,6 @@ public class ComputedLayout : Scenario
                        new Label
                        {
                            TextAlignment = TextAlignment.Justified,
-                           AutoSize = false,
                            Width = Dim.Fill (),
                            X = 0,
                            Y = Pos.Bottom (labelList.LastOrDefault ()),
@@ -335,7 +325,6 @@ public class ComputedLayout : Scenario
             Text = "This Label should be the 2nd to last line (AnchorEnd (2)).",
             TextAlignment = TextAlignment.Centered,
             ColorScheme = Colors.ColorSchemes ["Menu"],
-            AutoSize = false,
             Width = Dim.Fill (5),
             X = 5,
             Y = Pos.AnchorEnd (2)
@@ -350,7 +339,6 @@ public class ComputedLayout : Scenario
                 "This TextField should be the 3rd to last line (AnchorEnd (2) - 1).",
             TextAlignment = TextAlignment.Left,
             ColorScheme = Colors.ColorSchemes ["Menu"],
-            AutoSize = false,
             Width = Dim.Fill (5),
             X = 5,
             Y = Pos.AnchorEnd (2) - 1 // Pos.Combine

+ 20 - 6
UICatalog/Scenarios/ContentScrolling.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.ComponentModel;
 using System.Linq;
 using Terminal.Gui;
@@ -45,7 +46,7 @@ public class ContentScrolling : Scenario
 
             // Add a status label to the border that shows Viewport and ContentSize values. Bit of a hack.
             // TODO: Move to Padding with controls
-            Border.Add (new Label { AutoSize = false, X = 20 });
+            Border.Add (new Label { X = 20 });
             LayoutComplete += VirtualDemoView_LayoutComplete;
 
             MouseEvent += VirtualDemoView_MouseEvent;
@@ -114,7 +115,7 @@ public class ContentScrolling : Scenario
         var view = new ScrollingDemoView
         {
             Title = "Demo View",
-            X = Pos.Right(editor),
+            X = Pos.Right (editor),
             Width = Dim.Fill (),
             Height = Dim.Fill ()
         };
@@ -226,7 +227,7 @@ public class ContentScrolling : Scenario
 
         var contentSizeWidth = new Buttons.NumericUpDown<int>
         {
-            Value = view.ContentSize.Width,
+            Value = view.ContentSize.GetValueOrDefault ().Width,
             X = Pos.Right (labelContentSize) + 1,
             Y = Pos.Top (labelContentSize)
         };
@@ -241,7 +242,7 @@ public class ContentScrolling : Scenario
                 return;
             }
 
-            view.ContentSize = view.ContentSize with { Width = e.NewValue };
+            view.ContentSize = view.ContentSize.GetValueOrDefault () with { Width = e.NewValue };
         }
 
         var labelComma = new Label
@@ -253,7 +254,7 @@ public class ContentScrolling : Scenario
 
         var contentSizeHeight = new Buttons.NumericUpDown<int>
         {
-            Value = view.ContentSize.Height,
+            Value = view.ContentSize.GetValueOrDefault ().Height,
             X = Pos.Right (labelComma) + 1,
             Y = Pos.Top (labelContentSize),
             CanFocus = false
@@ -269,7 +270,7 @@ public class ContentScrolling : Scenario
                 return;
             }
 
-            view.ContentSize = view.ContentSize with { Height = e.NewValue };
+            view.ContentSize = view.ContentSize.GetValueOrDefault () with { Height = e.NewValue };
         }
 
         var cbClearOnlyVisible = new CheckBox
@@ -384,6 +385,19 @@ public class ContentScrolling : Scenario
         longLabel.TextFormatter.WordWrap = true;
         view.Add (longLabel);
 
+        List<object> options = new () { "Option 1", "Option 2", "Option 3" };
+        Slider slider = new (options)
+        {
+            X = 0,
+            Y = Pos.Bottom (textField) + 1,
+            Orientation = Orientation.Vertical,
+            Type = SliderType.Multiple,
+            AllowEmpty = false,
+            BorderStyle = LineStyle.Double,
+            Title = "_Slider"
+        };
+        view.Add (slider);
+
         editor.Initialized += (s, e) => { editor.ViewToEdit = view; };
 
         app.Closed += (s, e) => View.Diagnostics = _diagnosticFlags;

+ 2 - 2
UICatalog/Scenarios/ContextMenus.cs

@@ -67,14 +67,14 @@ public class ContextMenus : Scenario
                           {
                               if (e.MouseEvent.Flags == _contextMenu.MouseFlags)
                               {
-                                  ShowContextMenu (e.MouseEvent.X, e.MouseEvent.Y);
+                                  ShowContextMenu (e.MouseEvent.Position.X, e.MouseEvent.Position.Y);
                                   e.Handled = true;
                               }
                           };
 
         Application.MouseEvent += ApplicationMouseEvent;
 
-        void ApplicationMouseEvent (object sender, MouseEvent a) { mousePos = new Point (a.X, a.Y); }
+        void ApplicationMouseEvent (object sender, MouseEvent a) { mousePos = a.Position; }
 
         Win.WantMousePositionReports = true;
 

+ 64 - 66
UICatalog/Scenarios/Dialogs.cs

@@ -21,10 +21,10 @@ public class Dialogs : Scenario
             Text = "_Number of Buttons:"
         };
 
-        var label = new Label {
-            X = 0, 
+        var label = new Label
+        {
+            X = 0,
             Y = 0,
-            AutoSize = false,
             Width = Dim.Width (numButtonsLabel),
             Height = 1,
             TextAlignment = TextAlignment.Right,
@@ -42,9 +42,8 @@ public class Dialogs : Scenario
         };
         frame.Add (widthEdit);
 
-        label = new Label
+        label = new()
         {
-            AutoSize = false,
             X = 0,
             Y = Pos.Bottom (label),
             Width = Dim.Width (numButtonsLabel),
@@ -77,9 +76,8 @@ public class Dialogs : Scenario
                    }
                   );
 
-        label = new Label
+        label = new()
         {
-            AutoSize = false,
             X = 0,
             Y = Pos.Bottom (label),
             Width = Dim.Width (numButtonsLabel),
@@ -122,9 +120,8 @@ public class Dialogs : Scenario
         };
         frame.Add (glyphsNotWords);
 
-        label = new Label
+        label = new()
         {
-            AutoSize = false,
             X = 0,
             Y = Pos.Bottom (glyphsNotWords),
             Width = Dim.Width (numButtonsLabel),
@@ -133,6 +130,7 @@ public class Dialogs : Scenario
             Text = "Button St_yle:"
         };
         frame.Add (label);
+
         var styleRadioGroup = new RadioGroup
         {
             X = Pos.Right (label) + 1,
@@ -159,7 +157,7 @@ public class Dialogs : Scenario
 
         Win.Add (frame);
 
-        label = new Label
+        label = new()
         {
             X = Pos.Center (), Y = Pos.Bottom (frame) + 4, TextAlignment = TextAlignment.Right, Text = "Button Pressed:"
         };
@@ -181,19 +179,19 @@ public class Dialogs : Scenario
         };
 
         showDialogButton.Accept += (s, e) =>
-                                    {
-                                        Dialog dlg = CreateDemoDialog (
-                                                                       widthEdit,
-                                                                       heightEdit,
-                                                                       titleEdit,
-                                                                       numButtonsEdit,
-                                                                       glyphsNotWords,
-                                                                       styleRadioGroup,
-                                                                       buttonPressedLabel
-                                                                      );
-                                        Application.Run (dlg);
-                                        dlg.Dispose ();
-                                    };
+                                   {
+                                       Dialog dlg = CreateDemoDialog (
+                                                                      widthEdit,
+                                                                      heightEdit,
+                                                                      titleEdit,
+                                                                      numButtonsEdit,
+                                                                      glyphsNotWords,
+                                                                      styleRadioGroup,
+                                                                      buttonPressedLabel
+                                                                     );
+                                       Application.Run (dlg);
+                                       dlg.Dispose ();
+                                   };
 
         Win.Add (showDialogButton);
 
@@ -233,7 +231,7 @@ public class Dialogs : Scenario
                 {
                     buttonId = i;
 
-                    button = new Button
+                    button = new()
                     {
                         Text = NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
                         IsDefault = buttonId == 0
@@ -241,14 +239,14 @@ public class Dialogs : Scenario
                 }
                 else
                 {
-                    button = new Button { Text = NumberToWords.Convert (buttonId), IsDefault = buttonId == 0 };
+                    button = new() { Text = NumberToWords.Convert (buttonId), IsDefault = buttonId == 0 };
                 }
 
                 button.Accept += (s, e) =>
-                                  {
-                                      clicked = buttonId;
-                                      Application.RequestStop ();
-                                  };
+                                 {
+                                     clicked = buttonId;
+                                     Application.RequestStop ();
+                                 };
                 buttons.Add (button);
             }
 
@@ -262,7 +260,7 @@ public class Dialogs : Scenario
 
             // This tests dynamically adding buttons; ensuring the dialog resizes if needed and 
             // the buttons are laid out correctly
-            dialog = new Dialog
+            dialog = new()
             {
                 Title = titleEdit.Text,
                 ButtonAlignment = (Dialog.ButtonAlignments)styleRadioGroup.SelectedItem,
@@ -278,36 +276,36 @@ public class Dialogs : Scenario
             var add = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "_Add a button" };
 
             add.Accept += (s, e) =>
-                           {
-                               int buttonId = buttons.Count;
-                               Button button;
+                          {
+                              int buttonId = buttons.Count;
+                              Button button;
 
-                               if (glyphsNotWords.Checked == true)
-                               {
-                                   button = new Button
-                                   {
-                                       Text = NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
-                                       IsDefault = buttonId == 0
-                                   };
-                               }
-                               else
-                               {
-                                   button = new Button { Text = NumberToWords.Convert (buttonId), IsDefault = buttonId == 0 };
-                               }
-
-                               button.Accept += (s, e) =>
-                                                 {
-                                                     clicked = buttonId;
-                                                     Application.RequestStop ();
-                                                 };
-                               buttons.Add (button);
-                               dialog.AddButton (button);
-
-                               if (buttons.Count > 1)
-                               {
-                                   button.TabIndex = buttons [buttons.Count - 2].TabIndex + 1;
-                               }
-                           };
+                              if (glyphsNotWords.Checked == true)
+                              {
+                                  button = new()
+                                  {
+                                      Text = NumberToWords.Convert (buttonId) + " " + char.ConvertFromUtf32 (buttonId + CODE_POINT),
+                                      IsDefault = buttonId == 0
+                                  };
+                              }
+                              else
+                              {
+                                  button = new() { Text = NumberToWords.Convert (buttonId), IsDefault = buttonId == 0 };
+                              }
+
+                              button.Accept += (s, e) =>
+                                               {
+                                                   clicked = buttonId;
+                                                   Application.RequestStop ();
+                                               };
+                              buttons.Add (button);
+                              dialog.AddButton (button);
+
+                              if (buttons.Count > 1)
+                              {
+                                  button.TabIndex = buttons [buttons.Count - 2].TabIndex + 1;
+                              }
+                          };
             dialog.Add (add);
 
             var addChar = new Button
@@ -318,14 +316,14 @@ public class Dialogs : Scenario
             };
 
             addChar.Accept += (s, e) =>
-                               {
-                                   foreach (Button button in buttons)
-                                   {
-                                       button.Text += char.ConvertFromUtf32 (CODE_POINT);
-                                   }
+                              {
+                                  foreach (Button button in buttons)
+                                  {
+                                      button.Text += char.ConvertFromUtf32 (CODE_POINT);
+                                  }
 
-                                   dialog.LayoutSubviews ();
-                               };
+                                  dialog.LayoutSubviews ();
+                              };
             dialog.Closed += (s, e) => { buttonPressedLabel.Text = $"{clicked}"; };
             dialog.Add (addChar);
         }

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels