Table of Contents

Class CollapsiblePanel

Namespace
SharpConsoleUI.Controls
Assembly
SharpConsoleUI.dll

A container control that hosts a flat list of child controls beneath a clickable header. The header shows an indicator and an optional title, and the body can be expanded or collapsed. This is a DOM-layout container: it stores and exposes its children, and the layout engine paints them — the panel itself only paints its own header chrome.

public class CollapsiblePanel : BaseControl, IDOMPaintable, INotifyPropertyChanged, IContainer, IContainerControl, IControlHost, IMouseAwareControl, IInteractiveControl, IFocusableControl, IWindowControl, IDisposable, IFocusableContainerWithHeader, ILogicalCursorProvider, IColorRoleableControl
Inheritance
CollapsiblePanel
Implements
Derived
Inherited Members
Extension Methods

Remarks

This is a partial class. Header rendering, state toggling, mouse and keyboard activation, and the optional height animation are implemented in companion partials added by later tasks.

Properties

AnimationMode

Gets or sets whether expand/collapse animates the body height. Defaults to None (instant re-layout). When set to Height, the body height tweens open/closed over CollapsiblePanelAnimationDurationMs milliseconds. In headless contexts (no parent window / animation manager) the toggle remains instant.

public CollapsibleAnimationMode AnimationMode { get; set; }

Property Value

CollapsibleAnimationMode

BackgroundColor

Gets or sets the background color for the container and its child controls.

public Color BackgroundColor { get; set; }

Property Value

Color

BorderColor

Gets or sets the color used for the header separator and the body border. When null, the resolved foreground color is used.

public Color? BorderColor { get; set; }

Property Value

Color?

CanFocusWithMouse

Whether this control can receive focus via mouse clicks

public bool CanFocusWithMouse { get; }

Property Value

bool

CanReceiveFocus

Whether this control can receive focus

public bool CanReceiveFocus { get; }

Property Value

bool

Remarks

A collapsible panel's header is a Tab focus stop so it can be toggled with Enter/Space. A non-collapsible panel is a transparent focus container (like a ColumnContainer): it is not itself a stop, so focus passes straight through to its focusable body children.

Children

Gets the current child controls in the order they were added.

public IReadOnlyList<IWindowControl> Children { get; }

Property Value

IReadOnlyList<IWindowControl>

CollapsedIcon

Gets or sets the indicator glyph shown in the header when the panel is collapsed. When null or empty, no indicator is drawn.

public string? CollapsedIcon { get; set; }

Property Value

string

Collapsible

Gets or sets whether the panel can be collapsed/expanded by the user. Defaults to true (current behavior). When false the panel is locked expanded, draws no expand/collapse indicator, ignores header clicks and Enter/Space, and is not itself a Tab stop — focus passes through to its body children (the panel behaves as a plain container).

public virtual bool Collapsible { get; set; }

Property Value

bool

ColorRole

The semantic color role. Default = no role (normal resolution).

public ColorRole ColorRole { get; set; }

Property Value

ColorRole

ColorRoleMode

Optional ThemeMode override for role-colour derivation. When non-null, the role's dark/light seed colours are resolved as if the theme were in this mode, regardless of the theme's own Mode. When null (the default), the active theme's mode is used.

public ThemeMode? ColorRoleMode { get; set; }

Property Value

ThemeMode?

ContentWidth

Gets the minimum width needed to display the control's content, including margins. Returns null if width cannot be determined. This is calculated based on content (text length, child controls, etc.) and represents the natural/intrinsic size.

public override int? ContentWidth { get; }

Property Value

int?

ExpandedIcon

Gets or sets the indicator glyph shown in the header when the panel is expanded. When null or empty, no indicator is drawn.

public string? ExpandedIcon { get; set; }

Property Value

string

FocusedBackgroundColor

Gets or sets the header background color used when the panel has keyboard focus. When null, the color is resolved from the theme (CollapsibleHeaderFocusedBackgroundColor).

public Color? FocusedBackgroundColor { get; set; }

Property Value

Color?

FocusedForegroundColor

Gets or sets the header foreground color used when the panel has keyboard focus. When null, the color is resolved from the theme (CollapsibleHeaderFocusedForegroundColor).

public Color? FocusedForegroundColor { get; set; }

Property Value

Color?

ForegroundColor

Gets or sets the foreground (text) color for the container and its child controls.

public Color ForegroundColor { get; set; }

Property Value

Color

GetConsoleWindowSystem

Gets the console window system instance, or null if not attached to a window system.

public ConsoleWindowSystem? GetConsoleWindowSystem { get; }

Property Value

ConsoleWindowSystem

HasFocus

public bool HasFocus { get; }

Property Value

bool

HeaderAlignment

Gets or sets the horizontal alignment of the indicator + title within the header row. Defaults to Left.

public HorizontalAlignment HeaderAlignment { get; set; }

Property Value

HorizontalAlignment

HeaderStyle

Gets or sets how the panel header (and, when expanded, the body frame) is drawn. Defaults to Borderless.

public CollapsibleHeaderStyle HeaderStyle { get; set; }

Property Value

CollapsibleHeaderStyle

IsEnabled

Gets or sets whether this control is enabled and can receive input.

public bool IsEnabled { get; set; }

Property Value

bool

IsExpanded

Gets or sets whether the body is expanded (visible). Default true.

public virtual bool IsExpanded { get; set; }

Property Value

bool

MaxContentHeight

Gets or sets the maximum height in rows allotted to the expanded body before it scrolls. When null, the body is sized to its content. Consumed by the layout engine in a later task.

public int? MaxContentHeight { get; set; }

Property Value

int?

Outline

When true and a role is set, renders outline style (role color on text + border, surface fill).

public bool Outline { get; set; }

Property Value

bool

Padding

Gets or sets the padding applied to the body region, inside the border. Default (0, 0, 0, 0) (no inset), so existing panels are unaffected. Body children are arranged within the border- and padding-inset region; the measured body overhead accounts for it too.

public Padding Padding { get; set; }

Property Value

Padding

ShowHeader

Gets or sets whether the header row is drawn. Defaults to true. When false and the panel is non-collapsible, the header is fully suppressed: a borderless panel shows only its body, and a bordered panel draws a clean box (titleless top border) around the body. A collapsible panel always shows its header regardless of this flag (see Collapsible), since the header is the only affordance for toggling it.

public virtual bool ShowHeader { get; set; }

Property Value

bool

ShowHeaderSeparator

Gets or sets whether a horizontal separator line is drawn beneath a borderless header. Has no effect on the bordered header style. Defaults to false.

public virtual bool ShowHeaderSeparator { get; set; }

Property Value

bool

Title

Gets or sets the header title text shown next to the expand/collapse indicator.

public string? Title { get; set; }

Property Value

string

Remarks

Upgraded with richer behavior in a later task; backed by SetProperty so changes invalidate the container.

UseSafeBorder

Gets or sets whether the border is drawn with ASCII characters (+ - |) instead of Unicode box-drawing characters. Default false. When true, the chosen HeaderStyle (Bordered/Rounded/DoubleLine) renders with safe ASCII chars — useful for terminals or fonts that mis-render box-drawing glyphs. Orthogonal to the style: the style is remembered and restored when this is set back to false.

public bool UseSafeBorder { get; set; }

Property Value

bool

WantsMouseEvents

Whether this control wants to receive mouse events

public bool WantsMouseEvents { get; }

Property Value

bool

Methods

AddControl(IWindowControl)

Adds a child control to the host.

public void AddControl(IWindowControl control)

Parameters

control IWindowControl

ClearControls()

Removes all child controls from the host.

public void ClearControls()

Collapse()

Collapses the body, leaving only the header visible.

public virtual void Collapse()

Expand()

Expands the body.

public virtual void Expand()

GetChildren()

Gets the direct child controls of this container. Does not recursively include grandchildren - recursion happens in caller.

public IReadOnlyList<IWindowControl> GetChildren()

Returns

IReadOnlyList<IWindowControl>

Read-only list of direct child controls (may include other containers)

Remarks

IMPORTANT: For HorizontalGridControl, this should return columns AND splitters in order: [Column1, Splitter1, Column2, Splitter2, Column3]

Splitters are IInteractiveControl and should be included in Tab navigation.

GetLogicalCursorPosition()

Gets the logical cursor position within the control's content coordinate system. This should be the raw position without any visual adjustments for margins, scrolling, etc.

public Point? GetLogicalCursorPosition()

Returns

Point?

Logical cursor position or null if no cursor.

GetVisibleHeightForControl(IWindowControl)

Gets the actual visible height for a control within the container viewport. Returns null if the control is not found or visibility cannot be determined.

public int? GetVisibleHeightForControl(IWindowControl control)

Parameters

control IWindowControl

The control to check

Returns

int?

The number of visible lines, or null if unknown

Remarks

For a direct body child, reports the arranged body region height (the real on-screen space the layout allotted the body) so scroll-aware children derive a correct viewport. Falls back to delegating to the parent container when the region is not yet known or the control is not a direct child.

Invalidate(Invalidation, IWindowControl?)

Marks this container as needing the specified work on the next frame. The request propagates up the container chain and folds into the owning window's frame-intent accumulator.

public void Invalidate(Invalidation work, IWindowControl? callerControl = null)

Parameters

work Invalidation

The kind of work requested: Repaint (appearance-only, Measure skipped) or Relayout (full layout).

callerControl IWindowControl

The control that triggered the invalidation, if any (cycle guard).

MeasureDOM(LayoutConstraints)

Measures the control's desired size given the available constraints.

public override LayoutSize MeasureDOM(LayoutConstraints constraints)

Parameters

constraints LayoutConstraints

The layout constraints (min/max width/height).

Returns

LayoutSize

The desired size of the control.

PaintDOM(CharacterBuffer, LayoutRect, LayoutRect, Color, Color)

Paints the control's content directly to a CharacterBuffer.

public override void PaintDOM(CharacterBuffer buffer, LayoutRect bounds, LayoutRect clipRect, Color defaultForeground, Color defaultBackground)

Parameters

buffer CharacterBuffer

The buffer to paint to.

bounds LayoutRect

The absolute bounds where the control should paint.

clipRect LayoutRect

The clipping rectangle (visible area).

defaultForeground Color

The default foreground color from the container.

defaultBackground Color

The default background color from the container.

Remarks

Paints the borderless header (indicator + title + optional separator). The bordered style and the body children are painted by the layout partial added in a later task.

ProcessKey(ConsoleKeyInfo)

Processes a keyboard input event.

public bool ProcessKey(ConsoleKeyInfo key)

Parameters

key ConsoleKeyInfo

The key information for the pressed key.

Returns

bool

True if the key was handled by this control; otherwise, false.

Remarks

Toggles the expanded state when the panel is focused and Enter or Space is pressed. Returns false for any other key (or when not focused/disabled) so the key can bubble to focus traversal.

ProcessMouseEvent(MouseEventArgs)

Processes a mouse event for this control

public bool ProcessMouseEvent(MouseEventArgs args)

Parameters

args MouseEventArgs

Mouse event arguments with control-relative coordinates

Returns

bool

True if the event was handled and should not propagate further

Remarks

Handles a left click on the header row by focusing the panel and toggling its expanded state. A click on the expanded body is forwarded to the body child under the cursor (focusing it when it is focusable) so that mouse focus reaches body controls even when the panel is hosted inside a self-painting forwarding container (e.g. a ScrollablePanelControl) whose DOM hit-test resolves the panel rather than the deep body child. When the panel is a direct DOM child of the window the dispatcher already targets the body child directly, so this forwarding is a harmless no-op there.

RemoveControl(IWindowControl)

Removes a child control from the host.

public void RemoveControl(IWindowControl control)

Parameters

control IWindowControl

SetLogicalCursorPosition(Point)

Sets the logical cursor position within the control's content coordinate system.

public void SetLogicalCursorPosition(Point position)

Parameters

position Point

Toggle()

Toggles between expanded and collapsed.

public virtual void Toggle()

Events

ExpandedChanged

Fired once each time the expanded state actually changes. Arg is the new expanded value.

public event EventHandler<bool>? ExpandedChanged

Event Type

EventHandler<bool>

MouseClick

Fired on a left click — on a collapsible header (which also toggles the panel) or on the expanded body when no body child consumes the click.

public event EventHandler<MouseEventArgs>? MouseClick

Event Type

EventHandler<MouseEventArgs>

MouseDoubleClick

Event fired when the control is double-clicked

public event EventHandler<MouseEventArgs>? MouseDoubleClick

Event Type

EventHandler<MouseEventArgs>

MouseEnter

Event fired when the mouse enters the control area

public event EventHandler<MouseEventArgs>? MouseEnter

Event Type

EventHandler<MouseEventArgs>

MouseLeave

Event fired when the mouse leaves the control area

public event EventHandler<MouseEventArgs>? MouseLeave

Event Type

EventHandler<MouseEventArgs>

MouseMove

Event fired when the mouse moves over the control

public event EventHandler<MouseEventArgs>? MouseMove

Event Type

EventHandler<MouseEventArgs>

MouseRightClick

Event fired when the control is right-clicked (Button3)

public event EventHandler<MouseEventArgs>? MouseRightClick

Event Type

EventHandler<MouseEventArgs>