public/controls/New-UiSlider.ps1
|
function New-UiSlider { <# .SYNOPSIS Creates a slider control for numeric value selection. .DESCRIPTION Renders a horizontal or vertical slider with optional tick marks, snap-to-tick behavior, and a live value label. Supports format strings for the label (e.g. percentage, decimal) and can be bound to EnabledWhen for conditional state. .PARAMETER Variable Variable name to store the slider value. .PARAMETER Label Label text displayed above the slider. .PARAMETER Minimum Minimum value (default: 0). .PARAMETER Maximum Maximum value (default: 100). .PARAMETER Default Initial value (default: 50). .PARAMETER TickFrequency Interval between tick marks. Set to 0 to hide ticks. .PARAMETER IsSnapToTick If true, slider snaps to tick values. .PARAMETER ShowValueLabel If true, displays the current value next to the slider. .PARAMETER ValueLabelFormat Format string for the value label (e.g., "{0:N0}" for integers, "{0:P0}" for percentage). .PARAMETER Vertical If true, creates a vertical slider instead of horizontal. .PARAMETER Height Height of vertical slider (default: 100). Only valid with -Vertical. .PARAMETER MaxHeight Maximum height for vertical slider. Only valid with -Vertical. .PARAMETER MaxWidth Maximum width for horizontal slider. Only valid without -Vertical. .PARAMETER FullWidth If true, expands to fill available width. .PARAMETER WPFProperties Hashtable of additional WPF properties to set on the control. .EXAMPLE New-UiSlider -Variable "volume" -Label "Volume" -Minimum 0 -Maximum 100 -Default 50 .EXAMPLE New-UiSlider -Variable "opacity" -Label "Opacity" -Minimum 0 -Maximum 1 -Default 1 -TickFrequency 0.1 -ValueLabelFormat "{0:P0}" .EXAMPLE New-UiSlider -Variable "level" -Vertical -Height 150 -Minimum 0 -Maximum 10 -Default 5 #> [CmdletBinding(DefaultParameterSetName = 'Horizontal')] param( [Parameter(Mandatory)] [string]$Variable, [string]$Label, [double]$Minimum = 0, [double]$Maximum = 100, [double]$Default = 50, [double]$TickFrequency = 0, [switch]$IsSnapToTick, [switch]$ShowValueLabel, [string]$ValueLabelFormat = "{0:N0}", [Parameter(ParameterSetName = 'Vertical', Mandatory)] [switch]$Vertical, [Parameter(ParameterSetName = 'Vertical')] [int]$Height = 100, [Parameter(ParameterSetName = 'Vertical')] [int]$MaxHeight, [Parameter(ParameterSetName = 'Horizontal')] [int]$MaxWidth, [switch]$FullWidth, [Parameter()] [hashtable]$WPFProperties ) $session = Assert-UiSession -CallerName 'New-UiSlider' Write-Debug "Variable='$Variable', Min=$Minimum, Max=$Maximum, Default=$Default" $colors = Get-ThemeColors $parent = $session.CurrentParent Write-Debug "Parent: $($parent.GetType().Name)" $stack = [System.Windows.Controls.StackPanel]::new() $stack.Margin = [System.Windows.Thickness]::new(4, 4, 4, 8) # Apply MaxWidth/MaxHeight constraints based on orientation if ($Vertical -and $MaxHeight -gt 0) { $stack.MaxHeight = $MaxHeight } elseif (!$Vertical) { # Horizontal sliders should stretch to fill available width $stack.HorizontalAlignment = 'Stretch' if ($MaxWidth -gt 0) { $stack.MaxWidth = $MaxWidth } } if ($Label) { $labelBlock = [System.Windows.Controls.TextBlock]@{ Text = $Label FontSize = 12 Foreground = ConvertTo-UiBrush $colors.ControlFg Margin = [System.Windows.Thickness]::new(0, 0, 0, 4) Tag = 'ControlFgBrush' } [PsUi.ThemeEngine]::RegisterElement($labelBlock) [void]$stack.Children.Add($labelBlock) } # Slider with optional value display if ($ShowValueLabel) { if ($Vertical) { # For vertical sliders, put value label below the slider $sliderPanel = [System.Windows.Controls.StackPanel]::new() $sliderPanel.Orientation = 'Vertical' $sliderPanel.HorizontalAlignment = 'Center' $slider = [System.Windows.Controls.Slider]::new() $slider.Minimum = $Minimum $slider.Maximum = $Maximum $slider.Value = $Default $slider.Orientation = 'Vertical' $slider.HorizontalAlignment = 'Center' if ($TickFrequency -gt 0) { $slider.TickFrequency = $TickFrequency $slider.TickPlacement = 'TopLeft' $slider.IsSnapToTickEnabled = $IsSnapToTick } Set-SliderStyle -Slider $slider # Override: Explicit height for vertical slider sizing $slider.Height = $Height [void]$sliderPanel.Children.Add($slider) $valueLabel = [System.Windows.Controls.TextBlock]::new() $valueLabel.Text = $ValueLabelFormat -f $Default $valueLabel.FontSize = 11 $valueLabel.Foreground = ConvertTo-UiBrush $colors.ControlFg $valueLabel.HorizontalAlignment = 'Center' $valueLabel.Margin = [System.Windows.Thickness]::new(0, 4, 0, 0) $valueLabel.Tag = 'ControlFgBrush' [PsUi.ThemeEngine]::RegisterElement($valueLabel) [void]$sliderPanel.Children.Add($valueLabel) # Update value label when slider changes $slider.Add_ValueChanged({ param($sender, $eventArgs) $valueLabel.Text = $ValueLabelFormat -f $eventArgs.NewValue }.GetNewClosure()) [void]$stack.Children.Add($sliderPanel) } else { # For horizontal sliders, put value label to the right $sliderPanel = [System.Windows.Controls.Grid]::new() $sliderPanel.ColumnDefinitions.Add([System.Windows.Controls.ColumnDefinition]::new()) $sliderPanel.ColumnDefinitions[0].Width = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star) $sliderPanel.ColumnDefinitions.Add([System.Windows.Controls.ColumnDefinition]::new()) $sliderPanel.ColumnDefinitions[1].Width = [System.Windows.GridLength]::Auto $slider = [System.Windows.Controls.Slider]::new() $slider.Minimum = $Minimum $slider.Maximum = $Maximum $slider.Value = $Default $slider.VerticalAlignment = 'Center' if ($TickFrequency -gt 0) { $slider.TickFrequency = $TickFrequency $slider.TickPlacement = 'BottomRight' $slider.IsSnapToTickEnabled = $IsSnapToTick } Set-SliderStyle -Slider $slider [System.Windows.Controls.Grid]::SetColumn($slider, 0) [void]$sliderPanel.Children.Add($slider) $valueLabel = [System.Windows.Controls.TextBlock]::new() $valueLabel.Text = $ValueLabelFormat -f $Default $valueLabel.FontSize = 12 $valueLabel.Foreground = ConvertTo-UiBrush $colors.ControlFg $valueLabel.VerticalAlignment = 'Center' $valueLabel.Margin = [System.Windows.Thickness]::new(8, 0, 0, 0) $valueLabel.MinWidth = 40 $valueLabel.TextAlignment = 'Right' $valueLabel.Tag = 'ControlFgBrush' [PsUi.ThemeEngine]::RegisterElement($valueLabel) [System.Windows.Controls.Grid]::SetColumn($valueLabel, 1) [void]$sliderPanel.Children.Add($valueLabel) # Update value label when slider changes $slider.Add_ValueChanged({ param($sender, $eventArgs) $valueLabel.Text = $ValueLabelFormat -f $eventArgs.NewValue }.GetNewClosure()) [void]$stack.Children.Add($sliderPanel) } } else { $slider = [System.Windows.Controls.Slider]::new() $slider.Minimum = $Minimum $slider.Maximum = $Maximum $slider.Value = $Default if ($Vertical) { $slider.Orientation = 'Vertical' $slider.HorizontalAlignment = 'Center' } if ($TickFrequency -gt 0) { $slider.TickFrequency = $TickFrequency $slider.TickPlacement = if ($Vertical) { 'TopLeft' } else { 'BottomRight' } $slider.IsSnapToTickEnabled = $IsSnapToTick } Set-SliderStyle -Slider $slider # Override: Explicit height for vertical slider sizing if ($Vertical) { $slider.Height = $Height } [void]$stack.Children.Add($slider) } # Tag wrapper for FormLayout unwrapping (when label exists) if ($Label) { $controlElement = if ($ShowValueLabel) { $sliderPanel } else { $slider } Set-UiFormControlTag -Wrapper $stack -Label $labelBlock -Control $controlElement } # FullWidth in WrapPanel contexts Set-FullWidthConstraint -Control $stack -Parent $parent -FullWidth:$FullWidth # Apply custom WPF properties if specified if ($WPFProperties) { Set-UiProperties -Control $stack -Properties $WPFProperties } Write-Debug "Adding to $($parent.GetType().Name)" [void]$parent.Children.Add($stack) # Register control in all session registries Register-UiControlComplete -Name $Variable -Control $slider -InitialValue $slider.Value } |