private/Controls/New-TaskbarOverlayIcon.ps1
|
function New-TaskbarOverlayIcon { <# .SYNOPSIS Creates a small circular overlay icon from a glyph character for taskbar badge display. This is useful for showing status on the taskbar button and over dialogs. #> [CmdletBinding()] param( [Parameter(Mandatory)] [char]$GlyphChar, [Parameter(Mandatory)] [string]$Color, [string]$BackgroundColor = '#FFFFFF', [int]$Size = 16 ) try { $iconVisual = [System.Windows.Media.DrawingVisual]::new() $dc = $iconVisual.RenderOpen() # Parse foreground color for the glyph $fgBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Colors]::White) if ($Color -match '#([0-9A-Fa-f]{6})') { $red = [Convert]::ToByte($matches[1].Substring(0, 2), 16) $green = [Convert]::ToByte($matches[1].Substring(2, 2), 16) $blue = [Convert]::ToByte($matches[1].Substring(4, 2), 16) $fgBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Color]::FromRgb($red, $green, $blue)) } # Parse background color (defaults to white for taskbar visibility) $bgBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Colors]::White) if ($BackgroundColor -match '#([0-9A-Fa-f]{6})') { $red = [Convert]::ToByte($matches[1].Substring(0, 2), 16) $green = [Convert]::ToByte($matches[1].Substring(2, 2), 16) $blue = [Convert]::ToByte($matches[1].Substring(4, 2), 16) $bgBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Color]::FromRgb($red, $green, $blue)) } # Draw shadow ring for contrast against any taskbar color $center = [System.Windows.Point]::new($Size / 2, $Size / 2) $radius = ($Size / 2) - 0.5 $shadowPen = [System.Windows.Media.Pen]::new( [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.Color]::FromArgb(100, 0, 0, 0)), 1.0 ) $dc.DrawEllipse($null, $shadowPen, $center, $radius, $radius) # Draw the filled background circle $innerRadius = $radius - 0.5 $dc.DrawEllipse($bgBrush, $null, $center, $innerRadius, $innerRadius) # Create typeface for glyph rendering $typeface = [System.Windows.Media.Typeface]::new( [System.Windows.Media.FontFamily]::new('Segoe MDL2 Assets'), [System.Windows.FontStyles]::Normal, [System.Windows.FontWeights]::Normal, [System.Windows.FontStretches]::Normal ) # Create formatted text sized to fit within the circle $fontSize = $Size * 0.60 $formattedText = [System.Windows.Media.FormattedText]::new( [string]$GlyphChar, [System.Globalization.CultureInfo]::CurrentCulture, [System.Windows.FlowDirection]::LeftToRight, $typeface, $fontSize, $fgBrush, 96 ) # Center the glyph in the icon $x = ($Size - $formattedText.Width) / 2 $y = ($Size - $formattedText.Height) / 2 $dc.DrawText($formattedText, [System.Windows.Point]::new($x, $y)) $dc.Close() # Render to bitmap and freeze for thread safety $renderTarget = [System.Windows.Media.Imaging.RenderTargetBitmap]::new( $Size, $Size, 96, 96, [System.Windows.Media.PixelFormats]::Pbgra32 ) $renderTarget.Render($iconVisual) $renderTarget.Freeze() return $renderTarget } catch { Write-Verbose "Failed to create overlay icon: $_" return $null } } |