Public/Show-FluenceDialog.ps1
|
<# Copyright (c) 2026, Dan Cunningham. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #> function Show-FluenceDialog { <# .SYNOPSIS Shows a themed Fluent dialog built from prompts and buttons, and returns the user's input. .DESCRIPTION Renders a FluenceWindow with an optional message, a stack of input prompts, and a row of buttons. Returns a Fluence.DialogResult object with a property per named prompt and a boolean per button, plus Cancelled and TimedOut flags. .PARAMETER Title The window title. -TitleBarText is an alias. .PARAMETER TitleBarIcon Title bar icon from a local file path, file: URI, or pack: URI. Other schemes and missing local files are rejected before UI dispatch. This does not change a message severity icon. .PARAMETER Message One or more message lines shown above the prompts. .PARAMETER Icon Optional severity icon shown to the left of the message. None (default) renders the message as plain text. Info, Success, Warning, Error, and Question each map to a Segoe Fluent glyph and themed brush (Question uses the Help glyph with the Informational brush). .PARAMETER Prompts Strings or Fluence.Prompt objects (see New-FluencePrompt). A bare string becomes a Text prompt. .PARAMETER Buttons Strings or Fluence.Button objects (see New-FluenceButton). Defaults to a single OK button. A bare 'Cancel' string is treated as a cancel button (closes on Esc, no validation); any other bare string (for example 'No' or 'Close') is a plain button, so build it with New-FluenceButton -IsCancel if you want it to act as the Esc/cancel affordance. .PARAMETER Timeout Seconds after which the dialog closes on its own with TimedOut set to $true and no button flag set. Between 1 and 86400. .PARAMETER Countdown Show the remaining seconds in the caption of the default button (or the first button when none is default), refreshed every second. Requires -Timeout. .PARAMETER Image An image shown above the message at up to 120 device-independent pixels high: a file path, a file: URI, or a pack: URI (pack://application:,,,/Assembly;component/path). Other schemes are rejected before the dialog opens. .PARAMETER MessageAlignment Left (default) or Center. Applies to the image and the message lines. .PARAMETER Position Center (default), TopRight, or BottomRight of the primary work area. With -ParentWindow, Center gives way to centering over the owner, but TopRight and BottomRight still win: they are applied from the window's Loaded handler, which runs after WPF has placed it. .PARAMETER Theme Auto, Light, Dark, or HighContrast. Omit it to keep the theme already applied to the process; the first Fluence call in a process applies Auto. .PARAMETER Backdrop Mica, Acrylic, Tabbed, None, or Auto. Omit it to keep the backdrop already applied to the process; the first Fluence call in a process applies Mica. .PARAMETER Accent Optional accent color (System.Windows.Media.Color or a parseable string). Defaults to system accent. .PARAMETER MinWidth Minimum window width (default 360). .PARAMETER Topmost Show above other windows. .PARAMETER ParentWindow An owning System.Windows.Window for modal parenting. .EXAMPLE Show-FluenceDialog -Title 'Setup' -Prompts 'Your name?' -Buttons OK .EXAMPLE $r = Show-FluenceDialog -Message 'Installation starts in one minute.' -Buttons 'Start now', 'Defer' -Timeout 60 -Countdown if ($r.TimedOut -or $r.'Start now') { Start-Install } Counts down on the first button and proceeds when the user clicks it or the minute elapses. .OUTPUTS Fluence.DialogResult .NOTES Uses the calling STA thread or a module-owned STA runspace. An existing host application is supported only when the command already runs on its dispatcher thread. Blocks until the dialog closes. #> [CmdletBinding()] [OutputType('Fluence.DialogResult')] param ( [Parameter()] [Alias('TitleBarText')] [string]$Title = 'Fluence', [Parameter()] [string]$TitleBarIcon, [Parameter()] [string[]]$Message, [Parameter()] [ValidateSet('None', 'Info', 'Success', 'Warning', 'Error', 'Question')] [string]$Icon = 'None', [Parameter()] [object[]]$Prompts, [Parameter()] [object[]]$Buttons = @('OK'), [Parameter()] [ValidateRange(1, 86400)] [int]$Timeout, [Parameter()] [switch]$Countdown, [Parameter()] [string]$Image, [Parameter()] [ValidateSet('Left', 'Center')] [string]$MessageAlignment = 'Left', [Parameter()] [ValidateSet('Center', 'TopRight', 'BottomRight')] [string]$Position = 'Center', [Parameter()] [ValidateSet('Auto', 'Light', 'Dark', 'HighContrast')] [string]$Theme, [Parameter()] [ValidateSet('Mica', 'Acrylic', 'Tabbed', 'None', 'Auto')] [string]$Backdrop, [Parameter()] [System.Windows.Media.Color]$Accent, [Parameter()] [int]$MinWidth = 360, [Parameter()] [switch]$Topmost, [Parameter()] [System.Windows.Window]$ParentWindow ) # Caller-thread work: normalize and pre-validate the specification (no UI here). if ($Countdown -and -not $PSBoundParameters.ContainsKey('Timeout')) { throw '-Countdown requires -Timeout.' } $promptList = @() if ($null -ne $Prompts) { $promptList = ConvertTo-FluencePromptList -InputObject $Prompts } $buttonList = ConvertTo-FluenceButtonList -InputObject $Buttons Test-FluenceResultName -Prompts @($promptList) -Buttons @($buttonList) $imageSource = $null if ($PSBoundParameters.ContainsKey('Image')) { $imageSource = Resolve-FluenceImageSource -Image $Image } $titleBarIconSource = $null if ($PSBoundParameters.ContainsKey('TitleBarIcon')) { $titleBarIconSource = Resolve-FluenceImageSource -Image $TitleBarIcon -ParameterName 'TitleBarIcon' } $accentColor = $null if ($PSBoundParameters.ContainsKey('Accent')) { $accentColor = $Accent } $spec = @{ Title = $Title Message = $Message Icon = $Icon Prompts = $promptList Buttons = $buttonList AccentColor = $accentColor MinWidth = $MinWidth Topmost = [bool]$Topmost ParentWindow = $ParentWindow Countdown = [bool]$Countdown Image = $imageSource TitleBarIcon = $titleBarIconSource MessageAlignment = $MessageAlignment Position = $Position CallerRunspaceId = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace.InstanceId } if ($PSBoundParameters.ContainsKey('Timeout')) { $spec['Timeout'] = $Timeout } # Theme and backdrop reach the spec only when the caller asked for one. An absent key tells # Initialize-FluenceApplication to leave the applied theming alone, which is what makes # Set-FluenceTheme and Set-FluenceBackdrop survive a later dialog. foreach ($name in @('Theme', 'Backdrop')) { if ($PSBoundParameters.ContainsKey($name)) { $spec[$name] = $PSBoundParameters[$name] } } $result = Invoke-OnFluenceUi -Script { param($s) Invoke-FluenceWindow -Spec $s } -ArgumentList @($spec) # Invoke-OnFluenceUi yields the bare result hashtable. A $null result means the UI returned # nothing (for example a swallowed fault on an MTA host); surface a cancelled result instead of # passing $null to ConvertTo-FluenceResult's Mandatory [hashtable] parameter, which would raise a # confusing parameter-binding error far from the real cause. if ($null -eq $result) { return ConvertTo-FluenceResult -Result @{ Cancelled = $true; TimedOut = $false } } return ConvertTo-FluenceResult -Result $result } |