From a1188871f43f9e2b9df8d5572aff1c329b39b78f Mon Sep 17 00:00:00 2001 From: MyDrift Date: Fri, 27 Sep 2024 22:54:07 +0200 Subject: [PATCH 01/45] initial visual implementation - remove idiotic border logic from Invoke-WPFUIElements - add "application" type & style - add "radiobutton" type & style - remove prefer choco checkbox (did not modify logic outside of xaml, so i currently get errors due to that) --- config/applications.json | 17 ++ functions/public/Invoke-WPFUIElements.ps1 | 181 +++++++++++++++++----- scripts/main.ps1 | 105 ++++++++++++- xaml/inputXML.xaml | 16 +- 4 files changed, 273 insertions(+), 46 deletions(-) diff --git a/config/applications.json b/config/applications.json index 9563fb39..83ed606f 100644 --- a/config/applications.json +++ b/config/applications.json @@ -171,6 +171,7 @@ "category": "Browsers", "choco": "brave", "content": "Brave", + "Type": "application", "description": "Brave is a privacy-focused web browser that blocks ads and trackers, offering a faster and safer browsing experience.", "link": "https://www.brave.com", "winget": "Brave.Brave" @@ -233,6 +234,7 @@ }, "chrome": { "category": "Browsers", + "Type": "application", "choco": "googlechrome", "content": "Chrome", "description": "Google Chrome is a widely used web browser known for its speed, simplicity, and seamless integration with Google services.", @@ -241,6 +243,7 @@ }, "chromium": { "category": "Browsers", + "Type": "application", "choco": "chromium", "content": "Chromium", "description": "Chromium is the open-source project that serves as the foundation for various web browsers, including Chrome.", @@ -249,6 +252,7 @@ }, "arc": { "category": "Browsers", + "Type": "application", "choco": "na", "content": "Arc", "description": "Arc is a Chromium based browser, known for it's clean and modern design.", @@ -473,6 +477,7 @@ }, "edge": { "category": "Browsers", + "Type": "application", "choco": "microsoft-edge", "content": "Edge", "description": "Microsoft Edge is a modern web browser built on Chromium, offering performance, security, and integration with Microsoft services.", @@ -529,6 +534,7 @@ }, "falkon": { "category": "Browsers", + "Type": "application", "choco": "falkon", "content": "Falkon", "description": "Falkon is a lightweight and fast web browser with a focus on user privacy and efficiency.", @@ -585,6 +591,7 @@ }, "firefox": { "category": "Browsers", + "Type": "application", "choco": "firefox", "content": "Firefox", "description": "Mozilla Firefox is an open-source web browser known for its customization options, privacy features, and extensions.", @@ -593,6 +600,7 @@ }, "firefoxesr": { "category": "Browsers", + "Type": "application", "choco": "FirefoxESR", "content": "Firefox ESR", "description": "Mozilla Firefox is an open-source web browser known for its customization options, privacy features, and extensions. Firefox ESR (Extended Support Release) receives major updates every 42 weeks with minor updates such as crash fixes, security fixes and policy updates as needed, but at least every four weeks.", @@ -617,6 +625,7 @@ }, "floorp": { "category": "Browsers", + "Type": "application", "choco": "na", "content": "Floorp", "description": "Floorp is an open-source web browser project that aims to provide a simple and fast browsing experience.", @@ -1089,6 +1098,7 @@ }, "librewolf": { "category": "Browsers", + "Type": "application", "choco": "librewolf", "content": "LibreWolf", "description": "LibreWolf is a privacy-focused web browser based on Firefox, with additional privacy and security enhancements.", @@ -1281,6 +1291,7 @@ }, "mullvadbrowser": { "category": "Browsers", + "Type": "application", "choco": "na", "content": "Mullvad Browser", "description": "Mullvad Browser is a privacy-focused web browser, developed in partnership with the Tor Project.", @@ -2193,6 +2204,7 @@ }, "thorium": { "category": "Browsers", + "Type": "application", "choco": "na", "content": "Thorium Browser AVX2", "description": "Browser built for speed over vanilla chromium. It is built with AVX2 optimizations and is the fastest browser on the market.", @@ -2225,6 +2237,7 @@ }, "tor": { "category": "Browsers", + "Type": "application", "choco": "tor-browser", "content": "Tor Browser", "description": "Tor Browser is designed for anonymous web browsing, utilizing the Tor network to protect user privacy and security.", @@ -2273,6 +2286,7 @@ }, "ungoogled": { "category": "Browsers", + "Type": "application", "choco": "ungoogled-chromium", "content": "Ungoogled", "description": "Ungoogled Chromium is a version of Chromium without Google's integration for enhanced privacy and control.", @@ -2353,6 +2367,7 @@ }, "vivaldi": { "category": "Browsers", + "Type": "application", "choco": "vivaldi", "content": "Vivaldi", "description": "Vivaldi is a highly customizable web browser with a focus on user personalization and productivity features.", @@ -2409,6 +2424,7 @@ }, "waterfox": { "category": "Browsers", + "Type": "application", "choco": "waterfox", "content": "Waterfox", "description": "Waterfox is a fast, privacy-focused web browser based on Firefox, designed to preserve user choice and privacy.", @@ -2881,6 +2897,7 @@ }, "PaleMoon": { "category": "Browsers", + "Type": "application", "choco": "paleMoon", "content": "PaleMoon", "description":"Pale Moon is an Open Source, Goanna-based web browser available for Microsoft Windows and Linux (with other operating systems in development), focusing on efficiency and ease of use.", diff --git a/functions/public/Invoke-WPFUIElements.ps1 b/functions/public/Invoke-WPFUIElements.ps1 index 3851536d..41270958 100644 --- a/functions/public/Invoke-WPFUIElements.ps1 +++ b/functions/public/Invoke-WPFUIElements.ps1 @@ -120,25 +120,6 @@ function Invoke-WPFUIElements { foreach ($category in ($organizedData[$panelKey].Keys | Sort-Object)) { $count++ - if ($targetGridName -eq "appspanel" -and $columncount -gt 0) { - $panelcount2 = [Int](($count) / $maxcount - 0.5) - if ($panelcount -eq $panelcount2) { - # Create a new Border for the new column - $border = New-Object Windows.Controls.Border - $border.VerticalAlignment = "Stretch" # Ensure the border stretches vertically - [System.Windows.Controls.Grid]::SetColumn($border, $panelcount) - $border.style = $borderstyle - $targetGrid.Children.Add($border) | Out-Null - - # Create a new StackPanel inside the Border - $stackPanel = New-Object Windows.Controls.StackPanel - $stackPanel.Background = [Windows.Media.Brushes]::Transparent - $stackPanel.SnapsToDevicePixels = $true - $stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically - $border.Child = $stackPanel - $panelcount++ - } - } $label = New-Object Windows.Controls.Label $label.Content = $category -replace ".*__", "" @@ -152,25 +133,6 @@ function Invoke-WPFUIElements { $entries = $organizedData[$panelKey][$category] | Sort-Object Order, Name foreach ($entryInfo in $entries) { $count++ - if ($targetGridName -eq "appspanel" -and $columncount -gt 0) { - $panelcount2 = [Int](($count) / $maxcount - 0.5) - if ($panelcount -eq $panelcount2) { - # Create a new Border for the new column - $border = New-Object Windows.Controls.Border - $border.VerticalAlignment = "Stretch" # Ensure the border stretches vertically - [System.Windows.Controls.Grid]::SetColumn($border, $panelcount) - $border.style = $borderstyle - $targetGrid.Children.Add($border) | Out-Null - - # Create a new StackPanel inside the Border - $stackPanel = New-Object Windows.Controls.StackPanel - $stackPanel.Background = [Windows.Media.Brushes]::Transparent - $stackPanel.SnapsToDevicePixels = $true - $stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically - $border.Child = $stackPanel - $panelcount++ - } - } switch ($entryInfo.Type) { "Toggle" { @@ -282,6 +244,149 @@ function Invoke-WPFUIElements { $sync[$entryInfo.Name] = $button } + "RadioButton" { + $radioButton = New-Object Windows.Controls.RadioButton + $radioButton.Name = $entryInfo.Name + $radioButton.GroupName = $entryInfo.GroupName + $radioButton.Content = $entryInfo.Content + $radioButton.HorizontalAlignment = "Left" + $radioButton.Margin = $theme.CheckBoxMargin + $radioButton.FontSize = $theme.ButtonFontSize + $radioButton.ToolTip = $entryInfo.Description + + if ($entryInfo.Checked -eq $true) { + $radioButton.IsChecked = $true + } + + $stackPanel.Children.Add($radioButton) | Out-Null + $sync[$entryInfo.Name] = $radioButton + } + + "application" { + # Create the outer Border for the application type + $border = New-Object Windows.Controls.Border + $border.BorderBrush = [Windows.Media.Brushes]::Gray + $border.BorderThickness = 1 + $border.CornerRadius = 5 + $border.Padding = New-Object Windows.Thickness(10) + $border.HorizontalAlignment = "Stretch" + $border.VerticalAlignment = "Top" + $border.Margin = New-Object Windows.Thickness(0, 10, 0, 0) + + # Create a DockPanel inside the Border + $dockPanel = New-Object Windows.Controls.DockPanel + $dockPanel.LastChildFill = $true + $border.Child = $dockPanel + + # Create the CheckBox, vertically centered + $checkBox = New-Object Windows.Controls.CheckBox + $checkBox.Name = $entryInfo.Name + $checkBox.HorizontalAlignment = "Left" + $checkBox.VerticalAlignment = "Center" + $checkBox.Margin = New-Object Windows.Thickness(5, 0, 10, 0) + [Windows.Controls.DockPanel]::SetDock($checkBox, [Windows.Controls.Dock]::Left) + $dockPanel.Children.Add($checkBox) | Out-Null + + # Create a StackPanel for the image and name (for better alignment) + $imageAndNamePanel = New-Object Windows.Controls.StackPanel + $imageAndNamePanel.Orientation = "Horizontal" + $imageAndNamePanel.VerticalAlignment = "Center" + + # Create the Image and load it from the local path + $image = New-Object Windows.Controls.Image + $image.Width = 40 + $image.Height = 40 + $image.Margin = New-Object Windows.Thickness(0, 0, 10, 0) + $image.Source = [Windows.Media.Imaging.BitmapImage]::new([Uri]::new("file:///$env:LOCALAPPDATA/winutil/cttlogo.ico")) + $imageAndNamePanel.Children.Add($image) | Out-Null + + # Create the TextBlock for the application name (bigger and bold) + $appName = New-Object Windows.Controls.TextBlock + $appName.Text = $entryInfo.Content + $appName.FontSize = 16 + $appName.FontWeight = [Windows.FontWeights]::Bold + $appName.VerticalAlignment = "Center" + $appName.Margin = New-Object Windows.Thickness(5, 0, 0, 0) + $imageAndNamePanel.Children.Add($appName) | Out-Null + + # Add the image and name panel to the dock panel (after the checkbox) + [Windows.Controls.DockPanel]::SetDock($imageAndNamePanel, [Windows.Controls.Dock]::Left) + $dockPanel.Children.Add($imageAndNamePanel) | Out-Null + + # Create the StackPanel for the buttons and dock it to the right + $buttonPanel = New-Object Windows.Controls.StackPanel + $buttonPanel.Orientation = "Horizontal" + $buttonPanel.HorizontalAlignment = "Right" + $buttonPanel.VerticalAlignment = "Center" + $buttonPanel.Margin = New-Object Windows.Thickness(10, 0, 0, 0) + [Windows.Controls.DockPanel]::SetDock($buttonPanel, [Windows.Controls.Dock]::Right) + + # Create the "Install" button with the install icon from Segoe MDL2 Assets + $button1 = New-Object Windows.Controls.Button + $button1.Width = 45 + $button1.Height = 35 + $button1.Margin = New-Object Windows.Thickness(0, 0, 10, 0) + + $installIcon = New-Object Windows.Controls.TextBlock + $installIcon.Text = [char]0xE118 # Install Icon + $installIcon.FontFamily = "Segoe MDL2 Assets" + $installIcon.FontSize = 20 + $installIcon.Foreground = $theme.MainForegroundColor + $installIcon.Background = "Transparent" + $installIcon.HorizontalAlignment = "Center" + $installIcon.VerticalAlignment = "Center" + + $button1.Content = $installIcon + $buttonPanel.Children.Add($button1) | Out-Null + + # Create the "Uninstall" button with the uninstall icon from Segoe MDL2 Assets + $button2 = New-Object Windows.Controls.Button + $button2.Width = 45 + $button2.Height = 35 + + $uninstallIcon = New-Object Windows.Controls.TextBlock + $uninstallIcon.Text = [char]0xE10A # Uninstall Icon + $uninstallIcon.FontFamily = "Segoe MDL2 Assets" + $uninstallIcon.FontSize = 20 + $uninstallIcon.Foreground = $theme.MainForegroundColor + $uninstallIcon.Background = "Transparent" + $uninstallIcon.HorizontalAlignment = "Center" + $uninstallIcon.VerticalAlignment = "Center" + + $button2.Content = $uninstallIcon + $buttonPanel.Children.Add($button2) | Out-Null + + # Create the "Info" button with the info icon from Segoe MDL2 Assets + $infoButton = New-Object Windows.Controls.Button + $infoButton.Width = 45 + $infoButton.Height = 35 + $infoButton.Margin = New-Object Windows.Thickness(10, 0, 0, 0) + + $infoIcon = New-Object Windows.Controls.TextBlock + $infoIcon.Text = [char]0xE946 # Info Icon + $infoIcon.FontFamily = "Segoe MDL2 Assets" + $infoIcon.FontSize = 20 + $infoIcon.Foreground = $theme.MainForegroundColor + $infoIcon.Background = "Transparent" + $infoIcon.HorizontalAlignment = "Center" + $infoIcon.VerticalAlignment = "Center" + + $infoButton.Content = $infoIcon + $buttonPanel.Children.Add($infoButton) | Out-Null + + # Add the button panel to the DockPanel + $dockPanel.Children.Add($buttonPanel) | Out-Null + + # Add the border to the main stack panel in the grid + $stackPanel.Children.Add($border) | Out-Null + + # Sync the CheckBox, buttons, and info to the sync object for further use + $sync[$entryInfo.Name] = $checkBox + $sync[$entryInfo.Name + "_InstallButton"] = $button1 + $sync[$entryInfo.Name + "_UninstallButton"] = $button2 + $sync[$entryInfo.Name + "_InfoButton"] = $infoButton + } + default { $horizontalStackPanel = New-Object Windows.Controls.StackPanel $horizontalStackPanel.Orientation = "Horizontal" diff --git a/scripts/main.ps1 b/scripts/main.ps1 index 873aab4d..74ec8df6 100644 --- a/scripts/main.ps1 +++ b/scripts/main.ps1 @@ -111,8 +111,109 @@ $sync.Form.Add_Loaded({ Invoke-WinutilThemeChange -init $true # Load the configuration files -#Invoke-WPFUIElements -configVariable $sync.configs.nav -targetGridName "WPFMainGrid" -Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "appspanel" -columncount 5 + + +Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "appspanel" -columncount 1 + +# Extract unique categories from the applications configuration +$uniqueCategories = $sync.configs.applications.PSObject.Properties.Value | + Where-Object { $_.Category } | + Select-Object -Unique -ExpandProperty Category + +# Create a custom PSCustomObject to simulate category-level checkboxes +$categoryConfig = @{} + +foreach ($category in $uniqueCategories) { + # Sanitize the category name for use in the Name property (remove spaces, special characters) + $sanitizedCategoryName = $category -replace '\W', '_' + + $categoryConfig[$sanitizedCategoryName] = [PSCustomObject]@{ + Category = "Categories" + Content = $category # Keep original category name for display + } +} + +# Adding dynamically two radiobuttons for "Package Manager" category with GroupName +$packageManagerConfig = @{ + "WPFWingetRadioButton" = [PSCustomObject]@{ + Name = "WingetRadioButton" + Content = "Winget" + Category = "__Package Manager" + Type = "RadioButton" + GroupName = "PackageManagerGroup" + Checked = $true + Order = "1" + Description = "Use Winget for package management" + } + "WPFChocoRadioButton" = [PSCustomObject]@{ + Name = "ChocoRadioButton" + Content = "Chocolatey" + Category = "__Package Manager" + Type = "RadioButton" + GroupName = "PackageManagerGroup" + Checked = $false + Order = "2" + Description = "Use Chocolatey for package management" + } + "WPFautofallback" = [PSCustomObject]@{ + Name = "AutoRadioButton" + Content = "Auto Fallback" + Category = "__Package Manager" + Checked = $true + Order = "3" + Description = "If the selected package manager fails, automatically switch to the other one" + } + "WPFDefaultScope" = [PSCustomObject]@{ + Name = "DefaultScope" + Content = "Default" + Category = "_Installation Scope" + Type = "RadioButton" + GroupName = "InstallationScopeGroup" + Checked = $true + Order = "1" + Description = "Use the default scope of the application" + } + "WPFUserScope" = [PSCustomObject]@{ + Name = "UserScope" + Content = "User" + Category = "_Installation Scope" + Type = "RadioButton" + GroupName = "InstallationScopeGroup" + Checked = $false + Order = "2" + Description = "If possible, install the application only for the current user" + } + "WPFGlobalMachineScope" = [PSCustomObject]@{ + Name = "GlobalMachineScope" + Content = "Global (Machine)" + Category = "_Installation Scope" + Type = "RadioButton" + GroupName = "InstallationScopeGroup" + Checked = $false + Order = "3" + Description = "If possible, install the application globally for all users" + } +} + +# Merge the packageManagerConfig with the existing category config +$finalConfig = @{} +$categoryConfig.Keys | ForEach-Object { + $finalConfig[$_] = $categoryConfig[$_] +} +$packageManagerConfig.Keys | ForEach-Object { + $finalConfig[$_] = $packageManagerConfig[$_] +} + +# Convert to PSCustomObject for function input +$finalConfigObject = [PSCustomObject]@{} +$finalConfig.Keys | ForEach-Object { + Add-Member -InputObject $finalConfigObject -MemberType NoteProperty -Name $_ -Value $finalConfig[$_] +} + +# Now call the function with the final merged config +Invoke-WPFUIElements -configVariable $finalConfigObject -targetGridName "appscategory" -columncount 1 + + Invoke-WPFUIElements -configVariable $sync.configs.tweaks -targetGridName "tweakspanel" -columncount 2 Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "featurespanel" -columncount 2 diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index d2baa016..67b681a3 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -927,14 +927,18 @@