public/controls/inputs/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 and a live value label. -IsSnapToTick makes the thumb land on ticks. The label takes a format string (percentage, decimal) and -EnabledWhen gates the control like any other input. .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 Snaps the thumb to tick values. Does nothing unless -TickFrequency is above 0. .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 EnabledWhen Conditional enabling based on another control's state. Accepts either: - A control proxy (e.g., $toggleControl) - enables when that control is truthy - A scriptblock (e.g., { $toggle -and $userName }) - enables when expression is true Truthy values: CheckBox=checked, TextBox=non-empty, ComboBox=has selection. .PARAMETER ClearIfDisabled When used with -EnabledWhen, resets the slider to its Minimum when the control becomes disabled. .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 -ShowValueLabel -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()] [object]$EnabledWhen, [switch]$ClearIfDisabled, [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 if ($EnabledWhen) { Register-UiCondition -TargetControl $slider -Condition $EnabledWhen -ClearIfDisabled:$ClearIfDisabled } } |