mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2025-08-06 12:06:22 -05:00

* Disable "Microsoft account" notification source * [WinPE] Remove driver addition block for WinPE WE DO NOT TOUCH THE DRIVERS IN WinPE. There are reports of people getting "Install driver to show hardware" screens all over this repository, and on Discord; and the less drivers we touch in WinPE, the better. Drivers can still be added to Preinstallation Environments in the following ways: - Using the driver installation screens - Firing up "drvload.exe <driver>" in cmd * [Fix] Added fallback for DISM export command This is a port of the fix in #3305 * [Cleanup] Removed some comments that no longer make sense * [Fix] Same DISM export image fallback fix * Merge branch 'main' into microwin-202506 * [Fix] Improve UI consistency for instructions Fixes #3394 * Merge branch 'main' into microwin-202506 * [Unattended answer file] Remove it from drive root The answer file, on the drive root, is not necessary for us to apply it. In fact, it's not even used there * Merge branch 'main' into microwin-202506 * [MicroWin] June-August 2025 Update (#3) -- Contributions from Callum * Allow people without compatible hardware or a USB to use MicroWin. * Update functions/microwin/Microwin-NewUnattend.ps1 Co-authored-by: CodingWonders <101426328+CodingWonders@users.noreply.github.com> * Update Invoke-Microwin.ps1 * Update Microwin-NewUnattend.ps1 * Update Microwin-NewUnattend.ps1 * Add error pop up if ISO Creation fails. Issue 2653 * Add Disable WPBT Execution to MicroWin. * Update functions/microwin/Invoke-Microwin.ps1 Co-authored-by: CodingWonders <101426328+CodingWonders@users.noreply.github.com> * modified: functions/microwin/Invoke-Microwin.ps1 modified: xaml/inputXML.xaml --------- Co-authored-by: CodingWonders <101426328+CodingWonders@users.noreply.github.com> * Add conversion to ESD (#4) * Add conversion to ESD Issue - #3450 * Update Invoke-Microwin.ps1 Added quotes to the file paths. Put all the arguments in 1 string (as that also works fine) --------- Co-authored-by: CodingWonders <101426328+CodingWonders@users.noreply.github.com> * Update MicroWin contributor list * Merge branch 'main' into microwin-202506 * Merge branch 'main' into microwin-202506 * [MicroWin] Add automatic configuration settings Originally implemented in #2618. Adapted to follow the new file structure. And it works. Though there are issues that will be detailed very soon * [Fix] Fixed typos, updated descriptions * Re-add WinPE driver addition We're not yet sure if that is the actual problem of missing storage controllers. Logs can tell us more about this. Maybe for a future PR? * [Fix/WPBT] Add spaces to reg key path Avoid REG failure * [Fix/XAML] Fix word wrapping issue for checkboxes
543 lines
20 KiB
PowerShell
543 lines
20 KiB
PowerShell
# Create enums
|
|
Add-Type @"
|
|
public enum PackageManagers
|
|
{
|
|
Winget,
|
|
Choco
|
|
}
|
|
"@
|
|
|
|
# SPDX-License-Identifier: MIT
|
|
# Set the maximum number of threads for the RunspacePool to the number of threads on the machine
|
|
$maxthreads = [int]$env:NUMBER_OF_PROCESSORS
|
|
|
|
# Create a new session state for parsing variables into our runspace
|
|
$hashVars = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'sync',$sync,$Null
|
|
$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
|
|
|
|
# Add the variable to the session state
|
|
$InitialSessionState.Variables.Add($hashVars)
|
|
|
|
# Get every private function and add them to the session state
|
|
$functions = Get-ChildItem function:\ | Where-Object { $_.Name -imatch 'winutil|Microwin|WPF' }
|
|
foreach ($function in $functions) {
|
|
$functionDefinition = Get-Content function:\$($function.name)
|
|
$functionEntry = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $($function.name), $functionDefinition
|
|
|
|
$initialSessionState.Commands.Add($functionEntry)
|
|
}
|
|
|
|
# Create the runspace pool
|
|
$sync.runspace = [runspacefactory]::CreateRunspacePool(
|
|
1, # Minimum thread count
|
|
$maxthreads, # Maximum thread count
|
|
$InitialSessionState, # Initial session state
|
|
$Host # Machine to create runspaces on
|
|
)
|
|
|
|
# Open the RunspacePool instance
|
|
$sync.runspace.Open()
|
|
|
|
# Create classes for different exceptions
|
|
|
|
class WingetFailedInstall : Exception {
|
|
[string]$additionalData
|
|
WingetFailedInstall($Message) : base($Message) {}
|
|
}
|
|
|
|
class ChocoFailedInstall : Exception {
|
|
[string]$additionalData
|
|
ChocoFailedInstall($Message) : base($Message) {}
|
|
}
|
|
|
|
class GenericException : Exception {
|
|
[string]$additionalData
|
|
GenericException($Message) : base($Message) {}
|
|
}
|
|
|
|
$inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^<Win.*', '<Window'
|
|
|
|
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
|
|
[xml]$XAML = $inputXML
|
|
|
|
# Read the XAML file
|
|
$readerOperationSuccessful = $false # There's more cases of failure then success.
|
|
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
|
|
try {
|
|
$sync["Form"] = [Windows.Markup.XamlReader]::Load( $reader )
|
|
$readerOperationSuccessful = $true
|
|
} catch [System.Management.Automation.MethodInvocationException] {
|
|
Write-Host "We ran into a problem with the XAML code. Check the syntax for this control..." -ForegroundColor Red
|
|
Write-Host $error[0].Exception.Message -ForegroundColor Red
|
|
|
|
If ($error[0].Exception.Message -like "*button*") {
|
|
write-Host "Ensure your <button in the `$inputXML does NOT have a Click=ButtonClick property. PS can't handle this`n`n`n`n" -ForegroundColor Red
|
|
}
|
|
} catch {
|
|
Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed." -ForegroundColor Red
|
|
}
|
|
|
|
if (-NOT ($readerOperationSuccessful)) {
|
|
Write-Host "Failed to parse xaml content using Windows.Markup.XamlReader's Load Method." -ForegroundColor Red
|
|
Write-Host "Quitting winutil..." -ForegroundColor Red
|
|
$sync.runspace.Dispose()
|
|
$sync.runspace.Close()
|
|
[System.GC]::Collect()
|
|
exit 1
|
|
}
|
|
|
|
# Setup the Window to follow listen for windows Theme Change events and update the winutil theme
|
|
# throttle logic needed, because windows seems to send more than one theme change event per change
|
|
$lastThemeChangeTime = [datetime]::MinValue
|
|
$debounceInterval = [timespan]::FromSeconds(2)
|
|
$sync.Form.Add_Loaded({
|
|
$interopHelper = New-Object System.Windows.Interop.WindowInteropHelper $sync.Form
|
|
$hwndSource = [System.Windows.Interop.HwndSource]::FromHwnd($interopHelper.Handle)
|
|
$hwndSource.AddHook({
|
|
param (
|
|
[System.IntPtr]$hwnd,
|
|
[int]$msg,
|
|
[System.IntPtr]$wParam,
|
|
[System.IntPtr]$lParam,
|
|
[ref]$handled
|
|
)
|
|
# Check for the Event WM_SETTINGCHANGE (0x1001A) and validate that Button shows the icon for "Auto" => [char]0xF08C
|
|
if (($msg -eq 0x001A) -and $sync.ThemeButton.Content -eq [char]0xF08C) {
|
|
$currentTime = [datetime]::Now
|
|
if ($currentTime - $lastThemeChangeTime -gt $debounceInterval) {
|
|
Invoke-WinutilThemeChange -theme "Auto"
|
|
$script:lastThemeChangeTime = $currentTime
|
|
$handled = $true
|
|
}
|
|
}
|
|
return 0
|
|
})
|
|
})
|
|
|
|
Invoke-WinutilThemeChange -init $true
|
|
# Load the configuration files
|
|
|
|
$sync.configs.applicationsHashtable = @{}
|
|
$sync.configs.applications.PSObject.Properties | ForEach-Object {
|
|
$sync.configs.applicationsHashtable[$_.Name] = $_.Value
|
|
}
|
|
|
|
# Now call the function with the final merged config
|
|
Invoke-WPFUIElements -configVariable $sync.configs.appnavigation -targetGridName "appscategory" -columncount 1
|
|
Initialize-WPFUI -targetGridName "appscategory"
|
|
|
|
Initialize-WPFUI -targetGridName "appspanel"
|
|
|
|
Invoke-WPFUIElements -configVariable $sync.configs.tweaks -targetGridName "tweakspanel" -columncount 2
|
|
|
|
Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "featurespanel" -columncount 2
|
|
|
|
# Future implementation: Add Windows Version to updates panel
|
|
#Invoke-WPFUIElements -configVariable $sync.configs.updates -targetGridName "updatespanel" -columncount 1
|
|
|
|
#===========================================================================
|
|
# Store Form Objects In PowerShell
|
|
#===========================================================================
|
|
|
|
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)}
|
|
|
|
#Persist Package Manager preference across winutil restarts
|
|
$sync.ChocoRadioButton.Add_Checked({Set-PackageManagerPreference Choco})
|
|
$sync.WingetRadioButton.Add_Checked({Set-PackageManagerPreference Winget})
|
|
Set-PackageManagerPreference
|
|
|
|
switch ($sync["ManagerPreference"]) {
|
|
"Choco" {$sync.ChocoRadioButton.IsChecked = $true; break}
|
|
"Winget" {$sync.WingetRadioButton.IsChecked = $true; break}
|
|
}
|
|
|
|
$sync.keys | ForEach-Object {
|
|
if($sync.$psitem) {
|
|
if($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "ToggleButton") {
|
|
$sync["$psitem"].Add_Click({
|
|
[System.Object]$Sender = $args[0]
|
|
Invoke-WPFButton $Sender.name
|
|
})
|
|
}
|
|
|
|
if($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "Button") {
|
|
$sync["$psitem"].Add_Click({
|
|
[System.Object]$Sender = $args[0]
|
|
Invoke-WPFButton $Sender.name
|
|
})
|
|
}
|
|
|
|
if ($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "TextBlock") {
|
|
if ($sync["$psitem"].Name.EndsWith("Link")) {
|
|
$sync["$psitem"].Add_MouseUp({
|
|
[System.Object]$Sender = $args[0]
|
|
Start-Process $Sender.ToolTip -ErrorAction Stop
|
|
Write-Debug "Opening: $($Sender.ToolTip)"
|
|
})
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#===========================================================================
|
|
# Setup background config
|
|
#===========================================================================
|
|
|
|
# Load computer information in the background
|
|
Invoke-WPFRunspace -ScriptBlock {
|
|
try {
|
|
$ProgressPreference = "SilentlyContinue"
|
|
$sync.ConfigLoaded = $False
|
|
$sync.ComputerInfo = Get-ComputerInfo
|
|
$sync.ConfigLoaded = $True
|
|
}
|
|
finally{
|
|
$ProgressPreference = $oldProgressPreference
|
|
}
|
|
|
|
} | Out-Null
|
|
|
|
#===========================================================================
|
|
# Setup and Show the Form
|
|
#===========================================================================
|
|
|
|
# Print the logo
|
|
Show-CTTLogo
|
|
|
|
# Progress bar in taskbaritem > Set-WinUtilProgressbar
|
|
$sync["Form"].TaskbarItemInfo = New-Object System.Windows.Shell.TaskbarItemInfo
|
|
Set-WinUtilTaskbaritem -state "None"
|
|
|
|
# Set the titlebar
|
|
$sync["Form"].title = $sync["Form"].title + " " + $sync.version
|
|
# Set the commands that will run when the form is closed
|
|
$sync["Form"].Add_Closing({
|
|
$sync.runspace.Dispose()
|
|
$sync.runspace.Close()
|
|
[System.GC]::Collect()
|
|
})
|
|
|
|
# Attach the event handler to the Click event
|
|
$sync.SearchBarClearButton.Add_Click({
|
|
$sync.SearchBar.Text = ""
|
|
$sync.SearchBarClearButton.Visibility = "Collapsed"
|
|
|
|
# Focus the search bar after clearing the text
|
|
$sync.SearchBar.Focus()
|
|
$sync.SearchBar.SelectAll()
|
|
})
|
|
|
|
# add some shortcuts for people that don't like clicking
|
|
$commonKeyEvents = {
|
|
# Prevent shortcuts from executing if a process is already running
|
|
if ($sync.ProcessRunning -eq $true) {
|
|
return
|
|
}
|
|
|
|
# Handle key presses of single keys
|
|
switch ($_.Key) {
|
|
"Escape" { $sync.SearchBar.Text = "" }
|
|
}
|
|
# Handle Alt key combinations for navigation
|
|
if ($_.KeyboardDevice.Modifiers -eq "Alt") {
|
|
$keyEventArgs = $_
|
|
switch ($_.SystemKey) {
|
|
"I" { Invoke-WPFButton "WPFTab1BT"; $keyEventArgs.Handled = $true } # Navigate to Install tab and suppress Windows Warning Sound
|
|
"T" { Invoke-WPFButton "WPFTab2BT"; $keyEventArgs.Handled = $true } # Navigate to Tweaks tab
|
|
"C" { Invoke-WPFButton "WPFTab3BT"; $keyEventArgs.Handled = $true } # Navigate to Config tab
|
|
"U" { Invoke-WPFButton "WPFTab4BT"; $keyEventArgs.Handled = $true } # Navigate to Updates tab
|
|
"M" { Invoke-WPFButton "WPFTab5BT"; $keyEventArgs.Handled = $true } # Navigate to MicroWin tab
|
|
}
|
|
}
|
|
# Handle Ctrl key combinations for specific actions
|
|
if ($_.KeyboardDevice.Modifiers -eq "Ctrl") {
|
|
switch ($_.Key) {
|
|
"F" { $sync.SearchBar.Focus() } # Focus on the search bar
|
|
"Q" { $this.Close() } # Close the application
|
|
}
|
|
}
|
|
}
|
|
$sync["Form"].Add_PreViewKeyDown($commonKeyEvents)
|
|
|
|
$sync["Form"].Add_MouseLeftButtonDown({
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Settings", "Theme", "FontScaling")
|
|
$sync["Form"].DragMove()
|
|
})
|
|
|
|
$sync["Form"].Add_MouseDoubleClick({
|
|
if ($_.OriginalSource.Name -eq "NavDockPanel" -or
|
|
$_.OriginalSource.Name -eq "GridBesideNavDockPanel") {
|
|
if ($sync["Form"].WindowState -eq [Windows.WindowState]::Normal) {
|
|
$sync["Form"].WindowState = [Windows.WindowState]::Maximized
|
|
}
|
|
else{
|
|
$sync["Form"].WindowState = [Windows.WindowState]::Normal
|
|
}
|
|
}
|
|
})
|
|
|
|
$sync["Form"].Add_Deactivated({
|
|
Write-Debug "WinUtil lost focus"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Settings", "Theme", "FontScaling")
|
|
})
|
|
|
|
$sync["Form"].Add_ContentRendered({
|
|
# Load the Windows Forms assembly
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
$primaryScreen = [System.Windows.Forms.Screen]::PrimaryScreen
|
|
# Check if the primary screen is found
|
|
if ($primaryScreen) {
|
|
# Extract screen width and height for the primary monitor
|
|
$screenWidth = $primaryScreen.Bounds.Width
|
|
$screenHeight = $primaryScreen.Bounds.Height
|
|
|
|
# Print the screen size
|
|
Write-Debug "Primary Monitor Width: $screenWidth pixels"
|
|
Write-Debug "Primary Monitor Height: $screenHeight pixels"
|
|
|
|
# Compare with the primary monitor size
|
|
if ($sync.Form.ActualWidth -gt $screenWidth -or $sync.Form.ActualHeight -gt $screenHeight) {
|
|
Write-Debug "The specified width and/or height is greater than the primary monitor size."
|
|
$sync.Form.Left = 0
|
|
$sync.Form.Top = 0
|
|
$sync.Form.Width = $screenWidth
|
|
$sync.Form.Height = $screenHeight
|
|
} else {
|
|
Write-Debug "The specified width and height are within the primary monitor size limits."
|
|
}
|
|
} else {
|
|
Write-Debug "Unable to retrieve information about the primary monitor."
|
|
}
|
|
|
|
Invoke-WPFTab "WPFTab1BT"
|
|
$sync["Form"].Focus()
|
|
|
|
# maybe this is not the best place to load and execute config file?
|
|
# maybe community can help?
|
|
if ($PARAM_CONFIG -and -not [string]::IsNullOrWhiteSpace($PARAM_CONFIG)) {
|
|
Invoke-WPFImpex -type "import" -Config $PARAM_CONFIG
|
|
if ($PARAM_RUN) {
|
|
# Wait for any existing process to complete before starting
|
|
while ($sync.ProcessRunning) {
|
|
Start-Sleep -Seconds 5
|
|
}
|
|
Start-Sleep -Seconds 5
|
|
|
|
Write-Host "Applying tweaks..."
|
|
if (-not $sync.ProcessRunning) {
|
|
Invoke-WPFtweaksbutton
|
|
while ($sync.ProcessRunning) {
|
|
Start-Sleep -Seconds 5
|
|
}
|
|
}
|
|
Start-Sleep -Seconds 5
|
|
|
|
Write-Host "Installing features..."
|
|
if (-not $sync.ProcessRunning) {
|
|
Invoke-WPFFeatureInstall
|
|
while ($sync.ProcessRunning) {
|
|
Start-Sleep -Seconds 5
|
|
}
|
|
}
|
|
Start-Sleep -Seconds 5
|
|
|
|
Write-Host "Installing applications..."
|
|
if (-not $sync.ProcessRunning) {
|
|
Invoke-WPFInstall
|
|
while ($sync.ProcessRunning) {
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
}
|
|
Start-Sleep -Seconds 5
|
|
|
|
Write-Host "Done."
|
|
}
|
|
}
|
|
|
|
})
|
|
|
|
# Add event handlers for the RadioButtons
|
|
$sync["ISOdownloader"].add_Checked({
|
|
$sync["ISORelease"].Visibility = [System.Windows.Visibility]::Visible
|
|
$sync["ISOLanguage"].Visibility = [System.Windows.Visibility]::Visible
|
|
})
|
|
|
|
$sync["ISOmanual"].add_Checked({
|
|
$sync["ISORelease"].Visibility = [System.Windows.Visibility]::Collapsed
|
|
$sync["ISOLanguage"].Visibility = [System.Windows.Visibility]::Collapsed
|
|
})
|
|
|
|
$sync["ISORelease"].Items.Add("24H2") | Out-Null
|
|
$sync["ISORelease"].SelectedItem = "24H2"
|
|
|
|
$sync["ISOLanguage"].Items.Add("System Language ($(Microwin-GetLangFromCulture -langName $((Get-Culture).Name)))") | Out-Null
|
|
if ($currentCulture -ne "English International") {
|
|
$sync["ISOLanguage"].Items.Add("English International") | Out-Null
|
|
}
|
|
if ($currentCulture -ne "English") {
|
|
$sync["ISOLanguage"].Items.Add("English") | Out-Null
|
|
}
|
|
if ($sync["ISOLanguage"].Items.Count -eq 1) {
|
|
$sync["ISOLanguage"].IsEnabled = $false
|
|
}
|
|
$sync["ISOLanguage"].SelectedIndex = 0
|
|
|
|
# The SearchBarTimer is used to delay the search operation until the user has stopped typing for a short period
|
|
# This prevents the ui from stuttering when the user types quickly as it dosnt need to update the ui for every keystroke
|
|
|
|
$searchBarTimer = New-Object System.Windows.Threading.DispatcherTimer
|
|
$searchBarTimer.Interval = [TimeSpan]::FromMilliseconds(300)
|
|
$searchBarTimer.IsEnabled = $false
|
|
|
|
$searchBarTimer.add_Tick({
|
|
$searchBarTimer.Stop()
|
|
switch ($sync.currentTab) {
|
|
"Install" {
|
|
Find-AppsByNameOrDescription -SearchString $sync.SearchBar.Text
|
|
}
|
|
"Tweaks" {
|
|
Find-TweaksByNameOrDescription -SearchString $sync.SearchBar.Text
|
|
}
|
|
}
|
|
})
|
|
$sync["SearchBar"].Add_TextChanged({
|
|
if ($sync.SearchBar.Text -ne "") {
|
|
$sync.SearchBarClearButton.Visibility = "Visible"
|
|
} else {
|
|
$sync.SearchBarClearButton.Visibility = "Collapsed"
|
|
}
|
|
if ($searchBarTimer.IsEnabled) {
|
|
$searchBarTimer.Stop()
|
|
}
|
|
$searchBarTimer.Start()
|
|
})
|
|
|
|
$sync["Form"].Add_Loaded({
|
|
param($e)
|
|
$sync.Form.MinWidth = "1000"
|
|
$sync["Form"].MaxWidth = [Double]::PositiveInfinity
|
|
$sync["Form"].MaxHeight = [Double]::PositiveInfinity
|
|
})
|
|
|
|
$NavLogoPanel = $sync["Form"].FindName("NavLogoPanel")
|
|
$NavLogoPanel.Children.Add((Invoke-WinUtilAssets -Type "logo" -Size 25)) | Out-Null
|
|
|
|
# Initialize the hashtable
|
|
$winutildir = @{}
|
|
|
|
# Set the path for the winutil directory
|
|
$winutildir["path"] = "$env:LOCALAPPDATA\winutil\"
|
|
[System.IO.Directory]::CreateDirectory($winutildir["path"]) | Out-Null
|
|
|
|
$winutildir["logo.ico"] = $winutildir["path"] + "cttlogo.ico"
|
|
|
|
if (Test-Path $winutildir["logo.ico"]) {
|
|
$sync["logorender"] = $winutildir["logo.ico"]
|
|
} else {
|
|
$sync["logorender"] = (Invoke-WinUtilAssets -Type "Logo" -Size 90 -Render)
|
|
}
|
|
$sync["checkmarkrender"] = (Invoke-WinUtilAssets -Type "checkmark" -Size 512 -Render)
|
|
$sync["warningrender"] = (Invoke-WinUtilAssets -Type "warning" -Size 512 -Render)
|
|
|
|
Set-WinUtilTaskbaritem -overlay "logo"
|
|
|
|
$sync["Form"].Add_Activated({
|
|
Set-WinUtilTaskbaritem -overlay "logo"
|
|
})
|
|
|
|
$sync["ThemeButton"].Add_Click({
|
|
Write-Debug "ThemeButton clicked"
|
|
Invoke-WPFPopup -PopupActionTable @{ "Settings" = "Hide"; "Theme" = "Toggle"; "FontScaling" = "Hide" }
|
|
})
|
|
$sync["AutoThemeMenuItem"].Add_Click({
|
|
Write-Debug "About clicked"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Theme")
|
|
Invoke-WinutilThemeChange -theme "Auto"
|
|
})
|
|
$sync["DarkThemeMenuItem"].Add_Click({
|
|
Write-Debug "Dark Theme clicked"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Theme")
|
|
Invoke-WinutilThemeChange -theme "Dark"
|
|
})
|
|
$sync["LightThemeMenuItem"].Add_Click({
|
|
Write-Debug "Light Theme clicked"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Theme")
|
|
Invoke-WinutilThemeChange -theme "Light"
|
|
})
|
|
|
|
$sync["SettingsButton"].Add_Click({
|
|
Write-Debug "SettingsButton clicked"
|
|
Invoke-WPFPopup -PopupActionTable @{ "Settings" = "Toggle"; "Theme" = "Hide"; "FontScaling" = "Hide" }
|
|
})
|
|
$sync["ImportMenuItem"].Add_Click({
|
|
Write-Debug "Import clicked"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
|
|
Invoke-WPFImpex -type "import"
|
|
})
|
|
$sync["ExportMenuItem"].Add_Click({
|
|
Write-Debug "Export clicked"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
|
|
Invoke-WPFImpex -type "export"
|
|
})
|
|
$sync["AboutMenuItem"].Add_Click({
|
|
Write-Debug "About clicked"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
|
|
|
|
$authorInfo = @"
|
|
Author : <a href="https://github.com/ChrisTitusTech">@christitustech</a>
|
|
UI : <a href="https://github.com/MyDrift-user">@MyDrift-user</a>, <a href="https://github.com/Marterich">@Marterich</a>
|
|
Runspace : <a href="https://github.com/DeveloperDurp">@DeveloperDurp</a>, <a href="https://github.com/Marterich">@Marterich</a>
|
|
MicroWin : <a href="https://github.com/KonTy">@KonTy</a>, <a href="https://github.com/CodingWonders">@CodingWonders</a>, <a href="https://github.com/Real-MullaC">@Real-MullaC</a>
|
|
GitHub : <a href="https://github.com/ChrisTitusTech/winutil">ChrisTitusTech/winutil</a>
|
|
Version : <a href="https://github.com/ChrisTitusTech/winutil/releases/tag/$($sync.version)">$($sync.version)</a>
|
|
"@
|
|
Show-CustomDialog -Title "About" -Message $authorInfo
|
|
})
|
|
$sync["SponsorMenuItem"].Add_Click({
|
|
Write-Debug "Sponsors clicked"
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
|
|
|
|
$authorInfo = @"
|
|
<a href="https://github.com/sponsors/ChrisTitusTech">Current sponsors for ChrisTitusTech:</a>
|
|
"@
|
|
$authorInfo += "`n"
|
|
try {
|
|
$sponsors = Invoke-WinUtilSponsors
|
|
foreach ($sponsor in $sponsors) {
|
|
$authorInfo += "<a href=`"https://github.com/sponsors/ChrisTitusTech`">$sponsor</a>`n"
|
|
}
|
|
} catch {
|
|
$authorInfo += "An error occurred while fetching or processing the sponsors: $_`n"
|
|
}
|
|
Show-CustomDialog -Title "Sponsors" -Message $authorInfo -EnableScroll $true
|
|
})
|
|
|
|
# Font Scaling Event Handlers
|
|
$sync["FontScalingButton"].Add_Click({
|
|
Write-Debug "FontScalingButton clicked"
|
|
Invoke-WPFPopup -PopupActionTable @{ "Settings" = "Hide"; "Theme" = "Hide"; "FontScaling" = "Toggle" }
|
|
})
|
|
|
|
$sync["FontScalingSlider"].Add_ValueChanged({
|
|
param($slider)
|
|
$percentage = [math]::Round($slider.Value * 100)
|
|
$sync.FontScalingValue.Text = "$percentage%"
|
|
})
|
|
|
|
$sync["FontScalingResetButton"].Add_Click({
|
|
Write-Debug "FontScalingResetButton clicked"
|
|
$sync.FontScalingSlider.Value = 1.0
|
|
$sync.FontScalingValue.Text = "100%"
|
|
})
|
|
|
|
$sync["FontScalingApplyButton"].Add_Click({
|
|
Write-Debug "FontScalingApplyButton clicked"
|
|
$scaleFactor = $sync.FontScalingSlider.Value
|
|
Invoke-WinUtilFontScaling -ScaleFactor $scaleFactor
|
|
Invoke-WPFPopup -Action "Hide" -Popups @("FontScaling")
|
|
})
|
|
|
|
$sync["Form"].ShowDialog() | out-null
|
|
Stop-Transcript
|