2024-09-20 15:34:10 +02:00
function Invoke-WinutilThemeChange {
<#
. SYNOPSIS
Toggles between light and dark themes for a Windows utility application.
. DESCRIPTION
This function toggles the theme of the user interface between 'Light' and 'Dark' modes,
modifying various UI elements such as colors, margins, corner radii, font families, etc.
If the '-init' switch is used, it initializes the theme based on the system's current dark mode setting.
.PARAMETER init
A switch parameter. If set to $true, the function initializes the theme based on the system’ s current dark mode setting.
. EXAMPLE
Invoke-WinutilThemeChange
# Toggles the theme between 'Light' and 'Dark'.
. EXAMPLE
Invoke-WinutilThemeChange -init
# Initializes the theme based on the system's dark mode and applies the shared theme.
#>
param (
[ switch ] $init = $false ,
[ string ] $theme
)
function Set-WinutilTheme {
<#
. SYNOPSIS
Applies the specified theme to the application's user interface.
. DESCRIPTION
This internal function applies the given theme by setting the relevant properties
like colors, font families, corner radii, etc., in the UI. It uses the
'Set-ThemeResourceProperty' helper function to modify the application's resources.
.PARAMETER currentTheme
The name of the theme to be applied. Common values are "Light", "Dark", or "shared".
#>
param (
[ string ] $currentTheme
)
function Set-ThemeResourceProperty {
<#
. SYNOPSIS
Sets a specific UI property in the application's resources.
. DESCRIPTION
This helper function sets a property (e.g., color, margin, corner radius) in the
application's resources, based on the provided type and value. It includes
error handling to manage potential issues while setting a property.
.PARAMETER Name
The name of the resource property to modify (e.g., "MainBackgroundColor", "ButtonBackgroundMouseoverColor").
.PARAMETER Value
The value to assign to the resource property (e.g., "#FFFFFF" for a color).
.PARAMETER Type
The type of the resource, such as "ColorBrush", "CornerRadius", "GridLength", or "FontFamily".
#>
param ( $Name , $Value , $Type )
try {
# Set the resource property based on its type
$sync . Form . Resources [ $Name ] = switch ( $Type ) {
"ColorBrush" { [ Windows.Media.SolidColorBrush ]:: new ( $Value ) }
"Color" {
# Convert hex string to RGB values
$hexColor = $Value . TrimStart ( "#" )
$r = [ Convert ]:: ToInt32 ( $hexColor . Substring ( 0 , 2 ), 16 )
$g = [ Convert ]:: ToInt32 ( $hexColor . Substring ( 2 , 2 ), 16 )
$b = [ Convert ]:: ToInt32 ( $hexColor . Substring ( 4 , 2 ), 16 )
[ Windows.Media.Color ]:: FromRgb ( $r , $g , $b )
}
"CornerRadius" { [ System.Windows.CornerRadius ]:: new ( $Value ) }
"GridLength" { [ System.Windows.GridLength ]:: new ( $Value ) }
"Thickness" {
# Parse the Thickness value (supports 1, 2, or 4 inputs)
$values = $Value -split ","
switch ( $values . Count ) {
1 { [ System.Windows.Thickness ]:: new ([ double ] $values [ 0 ]) }
2 { [ System.Windows.Thickness ]:: new ([ double ] $values [ 0 ], [ double ] $values [ 1 ]) }
4 { [ System.Windows.Thickness ]:: new ([ double ] $values [ 0 ], [ double ] $values [ 1 ], [ double ] $values [ 2 ], [ double ] $values [ 3 ]) }
}
}
"FontFamily" { [ Windows.Media.FontFamily ]:: new ( $Value ) }
"Double" { [ double ] $Value }
default { $Value }
}
}
catch {
# Log a warning if there's an issue setting the property
Write-Warning "Failed to set property $( $Name ) : $_ "
}
}
# Retrieve all theme properties from the theme configuration
$themeProperties = $sync . configs . themes . $currentTheme . PSObject . Properties
foreach ( $_ in $themeProperties ) {
# Apply properties that deal with colors
if ( $_ . Name -like "*color*" ) {
Set-ThemeResourceProperty -Name $_ . Name -Value $_ . Value -Type "ColorBrush"
# For certain color properties, also set complementary values (e.g., BorderColor -> CBorderColor) This is required because e.g DropShadowEffect requires a <Color> and not a <SolidColorBrush> object
if ( $_ . Name -in @ ( "BorderColor" , "ButtonBackgroundMouseoverColor" )) {
Set-ThemeResourceProperty -Name "C $( $_ . Name ) " -Value $_ . Value -Type "Color"
}
}
# Apply corner radius properties
elseif ( $_ . Name -like "*Radius*" ) {
Set-ThemeResourceProperty -Name $_ . Name -Value $_ . Value -Type "CornerRadius"
}
# Apply row height properties
elseif ( $_ . Name -like "*RowHeight*" ) {
Set-ThemeResourceProperty -Name $_ . Name -Value $_ . Value -Type "GridLength"
}
# Apply thickness or margin properties
elseif (( $_ . Name -like "*Thickness*" ) -or ( $_ . Name -like "*margin" )) {
Set-ThemeResourceProperty -Name $_ . Name -Value $_ . Value -Type "Thickness"
}
# Apply font family properties
elseif ( $_ . Name -like "*FontFamily*" ) {
Set-ThemeResourceProperty -Name $_ . Name -Value $_ . Value -Type "FontFamily"
}
# Apply any other properties as doubles (numerical values)
else {
Set-ThemeResourceProperty -Name $_ . Name -Value $_ . Value -Type "Double"
}
}
}
$LightPreferencePath = " $env:LOCALAPPDATA \winutil\LightTheme.ini"
$DarkPreferencePath = " $env:LOCALAPPDATA \winutil\DarkTheme.ini"
if ( $init ) {
Set-WinutilTheme -currentTheme "shared"
if ( Test-Path $LightPreferencePath ) {
$theme = "Light"
}
elseif ( Test-Path $DarkPreferencePath ) {
$theme = "Dark"
}
else {
$theme = "Auto"
}
}
switch ( $theme ) {
"Auto" {
$systemUsesDarkMode = Get-WinUtilToggleStatus WPFToggleDarkMode
2024-09-20 09:03:18 -05:00
if ( $systemUsesDarkMode ) {
2024-09-20 15:34:10 +02:00
Set-WinutilTheme -currentTheme "Dark"
}
else {
Set-WinutilTheme -currentTheme "Light"
}
2024-09-20 09:03:18 -05:00
2024-09-20 15:34:10 +02:00
$themeButtonIcon = [ char ] 0xF08C
Remove-Item $LightPreferencePath -Force -ErrorAction SilentlyContinue
Remove-Item $DarkPreferencePath -Force -ErrorAction SilentlyContinue
}
"Dark" {
Set-WinutilTheme -currentTheme $theme
$themeButtonIcon = [ char ] 0xE708
$null = New-Item $DarkPreferencePath -Force
Remove-Item $LightPreferencePath -Force -ErrorAction SilentlyContinue
}
"Light" {
Set-WinutilTheme -currentTheme $theme
$themeButtonIcon = [ char ] 0xE706
$null = New-Item $LightPreferencePath -Force
Remove-Item $DarkPreferencePath -Force -ErrorAction SilentlyContinue
}
}
# Update the theme selector button with the appropriate icon
$ThemeButton = $sync . Form . FindName ( "ThemeButton" )
$ThemeButton . Content = [ string ] $themeButtonIcon
}