Repository: gui-cs/Terminal.Gui (2026-03-27T14:46:12Z)

Issue:
OptionSelector Dim.Auto width not recalculated when Labels/Values set after construction
## Describe the bug

When using the non-generic `OptionSelector` with `Orientation = Orientation.Horizontal`, setting `Labels` and `Values` after construction doesn't trigger a width recalculation. The selector's `Dim.Auto(DimAutoStyle.Content)` (the default) computes width from the initially-empty content and never updates, so labels get truncated.

The generic `OptionSelector<TEnum>` isn't affected because it populates labels in the constructor, before the first layout pass.

## To reproduce

```csharp
using Terminal.Gui.App;
using Terminal.Gui.ViewBase;
using Terminal.Gui.Views;

var app = Application.Create();
app.Init();

using var win = new Window { Title = "Repro" };

var selector = new OptionSelector
{
    Y = 2,
    Orientation = Orientation.Horizontal,
};

// Labels set after construction (e.g. driven by a reactive binding)
selector.Labels = ["IMDb (Recommended)", "TMDb"];
selector.Values = [0, 1];

win.Add(selector);
app.Run(win);
```

**Expected:** Both labels fully visible on first render.

**Actual:** The second label is truncated (e.g. "TMDb" shows as "TM"). Navigating to the second option with arrow keys and pressing Space causes a re-layout that reveals the full text, so the data is there but the width is wrong.

## Root cause (suspected)

`SelectorBase` sets `Width = Dim.Auto(DimAutoStyle.Content)` in the constructor (line 38). The `Labels` setter calls `CreateSubViews()` which rebuilds child checkboxes, but the parent's auto width doesn't pick up the new content size until a focus-driven layout pass. Setting `Visible = false` before setting labels (common in conditional UI) makes it worse since hidden views skip layout entirely.

## Workaround

Setting `Width = Dim.Fill()` on the selector avoids the issue by not relying on content-based sizing.

## Environment

- OS: Linux (Ubuntu)
- .NET: 10.0.104
- Terminal.Gui: 2.0.0-beta.11


Discussion:

Patch:
diff --git a/Terminal.Gui/Views/Selectors/SelectorBase.cs b/Terminal.Gui/Views/Selectors/SelectorBase.cs
index f1f7ed1dc0..96975930cb 100644
--- a/Terminal.Gui/Views/Selectors/SelectorBase.cs
+++ b/Terminal.Gui/Views/Selectors/SelectorBase.cs
@@ -529,6 +529,19 @@ protected void SetLayout ()
                 SubViews.ElementAt (i).Width = Dim.Auto ();
             }
         }
+
+        // Pre-calculate each subview's Frame.Width for horizontal layout so that
+        // Dim.Auto (DimAutoStyle.Content) on the selector can correctly compute its
+        // total width via PosAlign.CalculateMinDimension, which reads Frame.Width.
+        // Without this, newly-created subviews have Frame.Width == 0 on the first
+        // layout pass, causing the selector to be sized too narrow.
+        if (Orientation == Orientation.Horizontal && SubViews.Count > 0)
+        {
+            foreach (View sv in SubViews)
+            {
+                sv.SetRelativeLayout (GetContainerSize ());
+            }
+        }
     }
 
     /// <summary>


Test patch:
diff --git a/Tests/UnitTestsParallelizable/Views/SelectorBaseTests.cs b/Tests/UnitTestsParallelizable/Views/SelectorBaseTests.cs
index 219e9bd873..6d9c6acba0 100644
--- a/Tests/UnitTestsParallelizable/Views/SelectorBaseTests.cs
+++ b/Tests/UnitTestsParallelizable/Views/SelectorBaseTests.cs
@@ -417,6 +417,31 @@ public void Orientation_Change_TriggersLayout ()
         Assert.Equal (0, newYDiff); // Both should be at Y=0 now
     }
 
+    // Copilot
+    [Fact]
+    public void Horizontal_Labels_SetAfterConstruction_SelectorWidthAccommodatesAllCheckBoxes ()
+    {
+        // Arrange: create selector with horizontal orientation, no labels yet
+        OptionSelector selector = new () { Orientation = Orientation.Horizontal };
+
+        // Act: set labels/values after construction (simulates reactive-binding scenario)
+        selector.Labels = ["IMDb (Recommended)", "TMDb"];
+        selector.Values = [0, 1];
+        selector.Layout ();
+
+        // Assert: selector width must be wide enough to fully contain every checkbox
+        CheckBox [] checkBoxes = selector.SubViews.OfType<CheckBox> ().ToArray ();
+        Assert.Equal (2, checkBoxes.Length);
+
+        foreach (CheckBox cb in checkBoxes)
+        {
+            Assert.True (
+                          cb.Frame.X + cb.Frame.Width <= selector.Frame.Width,
+                          $"CheckBox '{cb.Title}' right edge ({cb.Frame.X + cb.Frame.Width}) exceeds selector width ({selector.Frame.Width})"
+                         );
+        }
+    }
+
     #endregion
 
     #region HorizontalSpace Tests