Public/Layout.ps1
|
function New-RichLayout { <# .SYNOPSIS Creates a new Rich Layout object. .DESCRIPTION Initializes a layout container that can be split into rows or columns to create complex console UIs. .PARAMETER Name The name of the layout region. .PARAMETER Ratio The relative size ratio of this region compared to its siblings. .PARAMETER Size An optional fixed size for the region. .PARAMETER Content The content to display in this region (text or other Rich objects). #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$Name = "root", [Parameter(Mandatory = $false)] [int]$Ratio = 1, [Parameter(Mandatory = $false)] $Size, [Parameter(Mandatory = $false)] [PSObject]$Content = $null ) $layout = [PSCustomObject]@{ _Type = "RichLayout" Name = $Name Title = $Name Ratio = $Ratio Size = $Size Content = $Content Children = @() Direction = "Vertical" # Vertical (rows) or Horizontal (columns) } return $layout } function Split-RichLayout { <# .SYNOPSIS Splits a layout region into multiple sub-regions. .DESCRIPTION Divides a layout region either vertically (into rows) or horizontally (into columns). .PARAMETER Layout The layout object to split. .PARAMETER Direction The direction of the split: "Vertical" (rows) or "Horizontal" (columns). .PARAMETER Names The names of the new sub-regions to create. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSObject]$Layout, [Parameter(Mandatory = $true)] [ValidateSet("Vertical", "Horizontal")] [string]$Direction, [Parameter(Mandatory = $true)] [string[]]$Names ) $Layout.Direction = $Direction foreach ($name in $Names) { $child = New-RichLayout -Name $name $Layout.Children += $child } } function Update-RichLayout { <# .SYNOPSIS Updates the content of a named region in a layout. .DESCRIPTION Recursively searches for a region by name and updates its content. .PARAMETER Layout The root layout object. .PARAMETER Name The name of the region to update. .PARAMETER Content The new content for the region. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSObject]$Layout, [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $false)] [PSObject]$Content, [Parameter(Mandatory = $false)] [string]$Title ) if ($Layout.Name -eq $Name) { if ($PSBoundParameters.ContainsKey('Content')) { $Layout.Content = $Content } if ($PSBoundParameters.ContainsKey('Title')) { $Layout.Title = $Title } return $true } foreach ($child in $Layout.Children) { $updateParams = @{ Layout = $child Name = $Name } if ($PSBoundParameters.ContainsKey('Content')) { $updateParams.Content = $Content } if ($PSBoundParameters.ContainsKey('Title')) { $updateParams.Title = $Title } if (Update-RichLayout @updateParams) { return $true } } return $false } function Format-RichLayout { <# .SYNOPSIS Renders a layout to a list of strings. .DESCRIPTION Calculates the dimensions of all regions and renders them into a list of strings that can be printed to the console. .PARAMETER Layout The layout object to render. .PARAMETER Width The total width for rendering. Defaults to the console window width. .PARAMETER Height The total height for rendering. Defaults to 20. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [PSObject]$Layout, [Parameter(Mandatory = $false)] $Width, [Parameter(Mandatory = $false)] $Height ) if ($null -eq $Width) { $Width = [Console]::WindowWidth } if ($null -eq $Height) { $Height = 20 } # Default height if not specified # Recursive rendering logic # This is complex because we need to return a list of strings (lines) if ($Layout.Children.Count -eq 0) { # Leaf node: render content if ($null -ne $Layout.Content) { $panel = New-RichPanel -Text $Layout.Content -Title $Layout.Title -Width $Width -Height $Height return $panel -split "`r?`n" } else { # Empty region with border $panel = New-RichPanel -Text "" -Title $Layout.Title -Width $Width -Height $Height return $panel -split "`r?`n" } } # Split space among children $lines = @() if ($Layout.Direction -eq "Vertical") { # Rows $totalRatio = 0 foreach ($child in $Layout.Children) { $totalRatio += $child.Ratio } $remainingHeight = $Height for ($i = 0; $i -lt $Layout.Children.Count; $i++) { $child = $Layout.Children[$i] $childHeight = [int][Math]::Round($Height * ($child.Ratio / $totalRatio), [MidpointRounding]::AwayFromZero) if ($i -eq $Layout.Children.Count - 1) { $childHeight = $remainingHeight } $remainingHeight -= $childHeight if ($childHeight -gt 0) { $lines += Format-RichLayout -Layout $child -Width $Width -Height $childHeight } } } else { # Columns $totalRatio = 0 foreach ($child in $Layout.Children) { $totalRatio += $child.Ratio } $childLines = @() $childWidths = @() $remainingWidth = $Width for ($i = 0; $i -lt $Layout.Children.Count; $i++) { $child = $Layout.Children[$i] $childWidth = [int][Math]::Round($Width * ($child.Ratio / $totalRatio), [MidpointRounding]::AwayFromZero) if ($i -eq $Layout.Children.Count - 1) { $childWidth = $remainingWidth } $remainingWidth -= $childWidth if ($childWidth -gt 0) { $childLines += , (Format-RichLayout -Layout $child -Width $childWidth -Height $Height) $childWidths += $childWidth } } # Combine column lines side-by-side for ($y = 0; $y -lt $Height; $y++) { $line = "" for ($i = 0; $i -lt $childLines.Count; $i++) { $col = $childLines[$i] $w = $childWidths[$i] if ($y -lt $col.Count) { $line += $col[$y] } else { $line += " " * $w } } $lines += $line } } return $lines } |