Skip to content

Commit 4ec113d

Browse files
committed
Add ActualX, ActualY, ActualWidth, ActualHeight properties to all controls
- Implemented Actual* properties across 26 controls (24 main + 2 nested/plugin) - Properties expose actual rendered position and size from PaintDOM - Renamed existing ActualHeight to ContentHeight in 5 controls (ListControl, TableControl, DropdownControl, ScrollablePanelControl, MenuControl) - Zero build warnings and errors in library
1 parent a846d40 commit 4ec113d

27 files changed

Lines changed: 652 additions & 100 deletions

SharpConsoleUI/Controls/BarGraphControl.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ public class BarGraphControl : IWindowControl, IDOMPaintable
5858
// Gradient support
5959
private ColorGradient? _smoothGradient;
6060

61+
private int _actualX;
62+
private int _actualY;
63+
private int _actualWidth;
64+
private int _actualHeight;
65+
6166
/// <summary>
6267
/// Initializes a new instance of the <see cref="BarGraphControl"/> class.
6368
/// </summary>
@@ -277,7 +282,19 @@ public ColorGradient? SmoothGradient
277282
#region IWindowControl Implementation
278283

279284
/// <inheritdoc/>
280-
public int? ActualWidth => _width;
285+
public int? ContentWidth => _width;
286+
287+
/// <inheritdoc/>
288+
public int ActualX => _actualX;
289+
290+
/// <inheritdoc/>
291+
public int ActualY => _actualY;
292+
293+
/// <inheritdoc/>
294+
public int ActualWidth => _actualWidth;
295+
296+
/// <inheritdoc/>
297+
public int ActualHeight => _actualHeight;
281298

282299
/// <inheritdoc/>
283300
public IContainer? Container
@@ -389,6 +406,11 @@ public LayoutSize MeasureDOM(LayoutConstraints constraints)
389406
/// <inheritdoc/>
390407
public void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect, Color defaultFg, Color defaultBg)
391408
{
409+
_actualX = bounds.X;
410+
_actualY = bounds.Y;
411+
_actualWidth = bounds.Width;
412+
_actualHeight = bounds.Height;
413+
392414
// Resolve colors
393415
Color bgColor = _backgroundColorValue ?? Container?.BackgroundColor ?? defaultBg;
394416
Color fgColor = _foregroundColorValue ?? Container?.ForegroundColor ?? defaultFg;

SharpConsoleUI/Controls/ButtonControl.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ namespace SharpConsoleUI.Controls
2525
/// </summary>
2626
public class ButtonControl : IWindowControl, IInteractiveControl, IFocusableControl, IMouseAwareControl, IDOMPaintable
2727
{
28+
private int _actualX;
29+
private int _actualY;
30+
private int _actualWidth;
31+
private int _actualHeight;
2832
private HorizontalAlignment _horizontalAlignment = HorizontalAlignment.Left;
2933
private VerticalAlignment _verticalAlignment = VerticalAlignment.Top;
3034
private bool _enabled = true;
@@ -45,7 +49,12 @@ public ButtonControl()
4549
/// <summary>
4650
/// Gets the actual rendered width of the button in characters.
4751
/// </summary>
48-
public int? ActualWidth => GetButtonWidth() + _margin.Left + _margin.Right;
52+
public int? ContentWidth => GetButtonWidth() + _margin.Left + _margin.Right;
53+
54+
public int ActualX => _actualX;
55+
public int ActualY => _actualY;
56+
public int ActualWidth => _actualWidth;
57+
public int ActualHeight => _actualHeight;
4958

5059
private int GetButtonWidth()
5160
{
@@ -141,8 +150,9 @@ public void Dispose()
141150
/// <inheritdoc/>
142151
public System.Drawing.Size GetLogicalContentSize()
143152
{
144-
int buttonWidth = GetButtonWidth();
145-
return new System.Drawing.Size(buttonWidth + _margin.Left + _margin.Right, 1 + _margin.Top + _margin.Bottom);
153+
int width = ContentWidth ?? 0;
154+
int height = 1 + _margin.Top + _margin.Bottom;
155+
return new System.Drawing.Size(width, height);
146156
}
147157

148158
/// <inheritdoc/>
@@ -288,6 +298,11 @@ public LayoutSize MeasureDOM(LayoutConstraints constraints)
288298
/// <inheritdoc/>
289299
public void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect, Color defaultFg, Color defaultBg)
290300
{
301+
_actualX = bounds.X;
302+
_actualY = bounds.Y;
303+
_actualWidth = bounds.Width;
304+
_actualHeight = bounds.Height;
305+
291306
Color backgroundColor = Container?.BackgroundColor ?? defaultBg;
292307
Color foregroundColor = Container?.ForegroundColor ?? defaultFg;
293308
Color windowBackground = Container?.BackgroundColor ?? defaultBg;

SharpConsoleUI/Controls/CheckboxControl.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ namespace SharpConsoleUI.Controls
2626
public class CheckboxControl : IWindowControl, IInteractiveControl,
2727
IFocusableControl, IMouseAwareControl, IDOMPaintable
2828
{
29+
private int _actualX;
30+
private int _actualY;
31+
private int _actualWidth;
32+
private int _actualHeight;
2933
private HorizontalAlignment _horizontalAlignment = HorizontalAlignment.Left;
3034
private VerticalAlignment _verticalAlignment = VerticalAlignment.Top;
3135
private Color? _backgroundColorValue;
@@ -95,7 +99,12 @@ public CheckboxControl(string label = "Checkbox", bool isChecked = false)
9599
/// <summary>
96100
/// Gets the actual rendered width of the control based on content.
97101
/// </summary>
98-
public int? ActualWidth => GetCheckboxWidth() + _margin.Left + _margin.Right;
102+
public int? ContentWidth => GetCheckboxWidth() + _margin.Left + _margin.Right;
103+
104+
public int ActualX => _actualX;
105+
public int ActualY => _actualY;
106+
public int ActualWidth => _actualWidth;
107+
public int ActualHeight => _actualHeight;
99108

100109
private int GetCheckboxWidth()
101110
{
@@ -328,8 +337,9 @@ public void Dispose()
328337
/// <inheritdoc/>
329338
public System.Drawing.Size GetLogicalContentSize()
330339
{
331-
int width = GetCheckboxWidth() + _margin.Left + _margin.Right;
332-
return new System.Drawing.Size(width, 1 + _margin.Top + _margin.Bottom);
340+
int width = ContentWidth ?? 0;
341+
int height = 1 + _margin.Top + _margin.Bottom;
342+
return new System.Drawing.Size(width, height);
333343
}
334344

335345
/// <summary>
@@ -504,6 +514,11 @@ public LayoutSize MeasureDOM(LayoutConstraints constraints)
504514
/// <inheritdoc/>
505515
public void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect, Color defaultFg, Color defaultBg)
506516
{
517+
_actualX = bounds.X;
518+
_actualY = bounds.Y;
519+
_actualWidth = bounds.Width;
520+
_actualHeight = bounds.Height;
521+
507522
// Store bounds for mouse handling
508523
_lastLayoutBounds = bounds;
509524

SharpConsoleUI/Controls/ColumnContainer.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ public class ColumnContainer : IContainer, IInteractiveControl, IFocusableContro
4949
private int _doubleClickThresholdMs = Configuration.ControlDefaults.DefaultDoubleClickThresholdMs;
5050
private bool _doubleClickEnabled = true;
5151

52+
private int _actualX;
53+
private int _actualY;
54+
private int _actualWidth;
55+
private int _actualHeight;
56+
5257
/// <summary>
5358
/// Initializes a new instance of the <see cref="ColumnContainer"/> class.
5459
/// </summary>
@@ -293,7 +298,19 @@ public void OnLayoutAllocated(LayoutAllocation allocation)
293298
#endregion
294299

295300
/// <inheritdoc/>
296-
public int? ActualWidth => GetActualWidth();
301+
public int? ContentWidth => GetContentWidth();
302+
303+
/// <inheritdoc/>
304+
public int ActualX => _actualX;
305+
306+
/// <inheritdoc/>
307+
public int ActualY => _actualY;
308+
309+
/// <inheritdoc/>
310+
public int ActualWidth => _actualWidth;
311+
312+
/// <inheritdoc/>
313+
public int ActualHeight => _actualHeight;
297314

298315
/// <inheritdoc/>
299316
public HorizontalAlignment HorizontalAlignment
@@ -407,7 +424,7 @@ public void AddContent(IWindowControl content)
407424
/// Gets the actual rendered width of this column based on content.
408425
/// </summary>
409426
/// <returns>The maximum width required by content, or null if no content.</returns>
410-
public int? GetActualWidth()
427+
public int? GetContentWidth()
411428
{
412429
// If explicit width is set, return that (includes margins already accounted for in Width)
413430
if (_width.HasValue)
@@ -419,7 +436,7 @@ public void AddContent(IWindowControl content)
419436
int maxWidth = 0;
420437
foreach (var content in _contents.Where(c => c.Visible))
421438
{
422-
int contentWidth = content.ActualWidth ?? content.Width ?? 0;
439+
int contentWidth = content.ContentWidth ?? content.Width ?? 0;
423440
maxWidth = Math.Max(maxWidth, contentWidth);
424441
}
425442
return maxWidth + _margin.Left + _margin.Right;
@@ -840,6 +857,11 @@ public LayoutSize MeasureDOM(LayoutConstraints constraints)
840857
/// <inheritdoc/>
841858
public void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect, Color defaultFg, Color defaultBg)
842859
{
860+
_actualX = bounds.X;
861+
_actualY = bounds.Y;
862+
_actualWidth = bounds.Width;
863+
_actualHeight = bounds.Height;
864+
843865
// NOTE: Container controls should NOT paint their children here.
844866
// Children are painted by the DOM tree's child LayoutNodes.
845867
// This method only paints the container's own content (background, margins).

SharpConsoleUI/Controls/DropdownControl.cs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ namespace SharpConsoleUI.Controls
3030
/// </summary>
3131
public class DropdownControl : IWindowControl, IInteractiveControl, IFocusableControl, IMouseAwareControl, IDOMPaintable
3232
{
33+
private int _actualX;
34+
private int _actualY;
35+
private int _actualWidth;
36+
private int _actualHeight;
3337
private readonly TimeSpan _searchResetDelay = TimeSpan.FromSeconds(1.5);
3438
private HorizontalAlignment _horizontalAlignment = HorizontalAlignment.Left;
3539
private VerticalAlignment _verticalAlignment = VerticalAlignment.Top;
@@ -184,7 +188,7 @@ public DropdownControl(string prompt)
184188
/// Gets the actual rendered height of the control based on cached content.
185189
/// </summary>
186190
/// <returns>The total number of lines including header, items, and margins, or null if not rendered.</returns>
187-
public int? ActualHeight
191+
public int? ContentHeight
188192
{
189193
get
190194
{
@@ -198,7 +202,7 @@ public int? ActualHeight
198202
/// Gets the actual rendered width of the control based on cached content.
199203
/// </summary>
200204
/// <returns>The maximum line width in characters, or null if content has not been rendered.</returns>
201-
public int? ActualWidth
205+
public int? ContentWidth
202206
{
203207
get
204208
{
@@ -217,6 +221,11 @@ public int? ActualWidth
217221
}
218222
}
219223

224+
public int ActualX => _actualX;
225+
public int ActualY => _actualY;
226+
public int ActualWidth => _actualWidth;
227+
public int ActualHeight => _actualHeight;
228+
220229
/// <inheritdoc/>
221230
public HorizontalAlignment HorizontalAlignment
222231
{ get => _horizontalAlignment; set { _horizontalAlignment = value; Container?.Invalidate(true); } }
@@ -662,8 +671,8 @@ public void Dispose()
662671
/// <inheritdoc/>
663672
public System.Drawing.Size GetLogicalContentSize()
664673
{
665-
int width = ActualWidth ?? 0;
666-
int height = ActualHeight ?? 1;
674+
int width = ContentWidth ?? 0;
675+
int height = ContentHeight ?? 1;
667676
return new System.Drawing.Size(width, height);
668677
}
669678

@@ -1116,6 +1125,11 @@ public LayoutSize MeasureDOM(LayoutConstraints constraints)
11161125
/// <inheritdoc/>
11171126
public void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect, Color defaultFg, Color defaultBg)
11181127
{
1128+
_actualX = bounds.X;
1129+
_actualY = bounds.Y;
1130+
_actualWidth = bounds.Width;
1131+
_actualHeight = bounds.Height;
1132+
11191133
// Store bounds for portal positioning
11201134
_lastLayoutBounds = bounds;
11211135

@@ -1745,6 +1759,10 @@ public DropdownItem(string text, string? icon = null, Color? iconColor = null)
17451759
/// </summary>
17461760
internal class DropdownPortalContent : IWindowControl, IDOMPaintable, IMouseAwareControl
17471761
{
1762+
private int _actualX;
1763+
private int _actualY;
1764+
private int _actualWidth;
1765+
private int _actualHeight;
17481766
private readonly DropdownControl _owner;
17491767

17501768
public DropdownPortalContent(DropdownControl owner)
@@ -1787,8 +1805,14 @@ public bool ProcessMouseEvent(MouseEventArgs args)
17871805

17881806
#region IWindowControl Implementation
17891807

1790-
public int? ActualWidth => _owner.GetPortalBounds().Width;
1791-
public int? ActualHeight => _owner.GetPortalBounds().Height;
1808+
public int? ContentWidth => _owner.GetPortalBounds().Width;
1809+
public int? ContentHeight => _owner.GetPortalBounds().Height;
1810+
1811+
public int ActualX => _actualX;
1812+
public int ActualY => _actualY;
1813+
public int ActualWidth => _actualWidth;
1814+
public int ActualHeight => _actualHeight;
1815+
17921816
public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Left;
17931817
public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Top;
17941818
public IContainer? Container { get; set; }
@@ -1836,6 +1860,11 @@ public LayoutSize MeasureDOM(LayoutConstraints constraints)
18361860
public void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect,
18371861
Color defaultFg, Color defaultBg)
18381862
{
1863+
_actualX = bounds.X;
1864+
_actualY = bounds.Y;
1865+
_actualWidth = bounds.Width;
1866+
_actualHeight = bounds.Height;
1867+
18391868
_owner.PaintDropdownListInternal(buffer, clipRect);
18401869
}
18411870

SharpConsoleUI/Controls/FigleControl.cs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public class FigleControl : IWindowControl, IDOMPaintable
5353
private FigletFont? _customFont;
5454
private string? _fontPath;
5555

56+
private int _actualX;
57+
private int _actualY;
58+
private int _actualWidth;
59+
private int _actualHeight;
60+
5661
/// <summary>
5762
/// Initializes a new instance of the <see cref="FigleControl"/> class.
5863
/// </summary>
@@ -61,7 +66,7 @@ public FigleControl()
6166
}
6267

6368
/// <inheritdoc/>
64-
public int? ActualWidth
69+
public int? ContentWidth
6570
{
6671
get
6772
{
@@ -82,6 +87,18 @@ public int? ActualWidth
8287
}
8388
}
8489

90+
/// <inheritdoc/>
91+
public int ActualX => _actualX;
92+
93+
/// <inheritdoc/>
94+
public int ActualY => _actualY;
95+
96+
/// <inheritdoc/>
97+
public int ActualWidth => _actualWidth;
98+
99+
/// <inheritdoc/>
100+
public int ActualHeight => _actualHeight;
101+
85102
/// <inheritdoc/>
86103
public HorizontalAlignment HorizontalAlignment
87104
{ get => _horizontalAlignment; set { _horizontalAlignment = value; Container?.Invalidate(true); } }
@@ -191,13 +208,13 @@ public System.Drawing.Size GetLogicalContentSize()
191208
if (string.IsNullOrEmpty(_text))
192209
return new System.Drawing.Size(_margin.Left + _margin.Right, _margin.Top + _margin.Bottom);
193210

194-
// For Figlet text, we need to render to get the size
211+
// Reuse ContentWidth for width calculation
212+
int width = ContentWidth ?? 0;
213+
214+
// Calculate height by rendering
195215
FigletText figletText = new FigletText(GetFont(), _text);
196216
var bgColor = Container?.BackgroundColor ?? Spectre.Console.Color.Black;
197217
var content = AnsiConsoleHelper.ConvertSpectreRenderableToAnsi(figletText, _width ?? 80, null, bgColor);
198-
199-
int maxWidth = content.Max(line => AnsiConsoleHelper.StripAnsiStringLength(line));
200-
int width = maxWidth + _margin.Left + _margin.Right;
201218
int height = content.Count + _margin.Top + _margin.Bottom;
202219

203220
return new System.Drawing.Size(width, height);
@@ -317,6 +334,11 @@ public LayoutSize MeasureDOM(LayoutConstraints constraints)
317334
/// <inheritdoc/>
318335
public void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect, Color defaultFg, Color defaultBg)
319336
{
337+
_actualX = bounds.X;
338+
_actualY = bounds.Y;
339+
_actualWidth = bounds.Width;
340+
_actualHeight = bounds.Height;
341+
320342
var bgColor = Container?.BackgroundColor ?? defaultBg;
321343
var fgColor = _color ?? Container?.ForegroundColor ?? defaultFg;
322344
int targetWidth = bounds.Width - _margin.Left - _margin.Right;

0 commit comments

Comments
 (0)