add virtualisation & layouting fixes

- commented out prefer choco logic
- add virtualisation
- layouting improvements
This commit is contained in:
MyDrift 2024-10-01 18:55:27 +02:00
parent f576d57ffc
commit 7d90ab8660
2 changed files with 89 additions and 73 deletions

View File

@ -11,23 +11,23 @@ function Invoke-WPFUIElements {
.EXAMPLE .EXAMPLE
Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "install" -columncount 5 Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "install" -columncount 5
.NOTES .NOTES
Future me/contributer: If possible please wrap this into a runspace to make it load all panels at the same time. Future me/contributor: If possible, please wrap this into a runspace to make it load all panels at the same time.
#> #>
param( param(
[Parameter(Mandatory, position=0)] [Parameter(Mandatory, Position = 0)]
[PSCustomObject]$configVariable, [PSCustomObject]$configVariable,
[Parameter(Mandatory, position=1)] [Parameter(Mandatory, Position = 1)]
[string]$targetGridName, [string]$targetGridName,
[Parameter(Mandatory, position=2)] [Parameter(Mandatory, Position = 2)]
[int]$columncount [int]$columncount
) )
$window = $sync["Form"] $window = $sync.form
$theme = $sync.Form.Resources $theme = $window.Resources
$borderstyle = $window.FindResource("BorderStyle") $borderstyle = $window.FindResource("BorderStyle")
$HoverTextBlockStyle = $window.FindResource("HoverTextBlockStyle") $HoverTextBlockStyle = $window.FindResource("HoverTextBlockStyle")
$ColorfulToggleSwitchStyle = $window.FindResource("ColorfulToggleSwitchStyle") $ColorfulToggleSwitchStyle = $window.FindResource("ColorfulToggleSwitchStyle")
@ -66,19 +66,20 @@ function Invoke-WPFUIElements {
# Create an object for the application # Create an object for the application
$entryObject = [PSCustomObject]@{ $entryObject = [PSCustomObject]@{
Name = $entry Name = $entry
Order = $entryInfo.order Order = $entryInfo.order
Category = $entryInfo.Category Category = $entryInfo.Category
Content = $entryInfo.Content Content = $entryInfo.Content
Choco = $entryInfo.choco Choco = $entryInfo.choco
Winget = $entryInfo.winget Winget = $entryInfo.winget
Panel = if ($entryInfo.Panel) { $entryInfo.Panel } else { "0" } Panel = if ($entryInfo.Panel) { $entryInfo.Panel } else { "0" }
Link = $entryInfo.link Link = $entryInfo.link
Description = $entryInfo.description Description = $entryInfo.description
Type = $entryInfo.type Type = $entryInfo.type
ComboItems = $entryInfo.ComboItems ComboItems = $entryInfo.ComboItems
Checked = $entryInfo.Checked Checked = $entryInfo.Checked
ButtonWidth = $entryInfo.ButtonWidth ButtonWidth = $entryInfo.ButtonWidth
GroupName = $entryInfo.GroupName # Added for RadioButton groupings
} }
if (-not $organizedData.ContainsKey($entryObject.Panel)) { if (-not $organizedData.ContainsKey($entryObject.Panel)) {
@ -100,6 +101,9 @@ function Invoke-WPFUIElements {
} }
} }
# Initialize panel count
$panelcount = 0
# Iterate through 'organizedData' by panel, category, and application # Iterate through 'organizedData' by panel, category, and application
$count = 0 $count = 0
foreach ($panelKey in ($organizedData.Keys | Sort-Object)) { foreach ($panelKey in ($organizedData.Keys | Sort-Object)) {
@ -160,22 +164,32 @@ function Invoke-WPFUIElements {
$scrollViewer.HorizontalScrollBarVisibility = 'Auto' $scrollViewer.HorizontalScrollBarVisibility = 'Auto'
$scrollViewer.HorizontalAlignment = 'Stretch' $scrollViewer.HorizontalAlignment = 'Stretch'
$scrollViewer.VerticalAlignment = 'Stretch' $scrollViewer.VerticalAlignment = 'Stretch'
$scrollViewer.CanContentScroll = $true # Enable virtualization
# Create a StackPanel inside the ScrollViewer for application content # Create an ItemsControl inside the ScrollViewer for application content
$stackPanel = New-Object Windows.Controls.StackPanel $itemsControl = New-Object Windows.Controls.ItemsControl
$stackPanel.Orientation = "Vertical" $itemsControl.HorizontalAlignment = 'Stretch'
$stackPanel.HorizontalAlignment = 'Stretch' $itemsControl.VerticalAlignment = 'Stretch'
$stackPanel.VerticalAlignment = 'Stretch'
# Add the StackPanel to the ScrollViewer # Set the ItemsPanel to a VirtualizingStackPanel
$scrollViewer.Content = $stackPanel $itemsPanelTemplate = New-Object Windows.Controls.ItemsPanelTemplate
$factory = New-Object Windows.FrameworkElementFactory ([Windows.Controls.VirtualizingStackPanel])
$itemsPanelTemplate.VisualTree = $factory
$itemsControl.ItemsPanel = $itemsPanelTemplate
# Set virtualization properties
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::IsVirtualizingProperty, $true)
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::VirtualizationModeProperty, [Windows.Controls.VirtualizationMode]::Recycling)
# Add the ItemsControl to the ScrollViewer
$scrollViewer.Content = $itemsControl
# Add the ScrollViewer to the DockPanel (it will be below the top buttons StackPanel) # Add the ScrollViewer to the DockPanel (it will be below the top buttons StackPanel)
[Windows.Controls.DockPanel]::SetDock($scrollViewer, [Windows.Controls.Dock]::Bottom) [Windows.Controls.DockPanel]::SetDock($scrollViewer, [Windows.Controls.Dock]::Bottom)
$dockPanelContainer.Children.Add($scrollViewer) | Out-Null $dockPanelContainer.Children.Add($scrollViewer) | Out-Null
$panelcount++ $panelcount++
# Now proceed with adding category labels and entries to $stackPanel (as before) # Now proceed with adding category labels and entries to $itemsControl
foreach ($category in ($organizedData[$panelKey].Keys | Sort-Object)) { foreach ($category in ($organizedData[$panelKey].Keys | Sort-Object)) {
$count++ $count++
@ -183,11 +197,11 @@ function Invoke-WPFUIElements {
$label.Content = $category -replace ".*__", "" $label.Content = $category -replace ".*__", ""
$label.FontSize = $theme.FontSizeHeading $label.FontSize = $theme.FontSizeHeading
$label.FontFamily = $theme.HeaderFontFamily $label.FontFamily = $theme.HeaderFontFamily
$stackPanel.Children.Add($label) | Out-Null $itemsControl.Items.Add($label) | Out-Null
$sync[$category] = $label $sync[$category] = $label
# Sort entries by Order and then by Name, but only display Name # Sort entries by Order and then by Name
$entries = $organizedData[$panelKey][$category] | Sort-Object Order, Name $entries = $organizedData[$panelKey][$category] | Sort-Object Order, Name
foreach ($entryInfo in $entries) { foreach ($entryInfo in $entries) {
$count++ $count++
@ -218,37 +232,20 @@ function Invoke-WPFUIElements {
[Windows.Controls.DockPanel]::SetDock($checkBox, [Windows.Controls.Dock]::Left) [Windows.Controls.DockPanel]::SetDock($checkBox, [Windows.Controls.Dock]::Left)
$dockPanel.Children.Add($checkBox) | Out-Null $dockPanel.Children.Add($checkBox) | Out-Null
# Create a StackPanel for the image and name (for better alignment) # Create a StackPanel for the image and name
$imageAndNamePanel = New-Object Windows.Controls.StackPanel $imageAndNamePanel = New-Object Windows.Controls.StackPanel
$imageAndNamePanel.Orientation = "Horizontal" $imageAndNamePanel.Orientation = "Horizontal"
$imageAndNamePanel.VerticalAlignment = "Center" $imageAndNamePanel.VerticalAlignment = "Center"
# Create the Image and load it from the local path # Create the Image and set a placeholder
$image = New-Object Windows.Controls.Image $image = New-Object Windows.Controls.Image
$image.Name = "wpfapplogo" + $entryInfo.Name $image.Name = "wpfapplogo" + $entryInfo.Name
$image.Width = 40 $image.Width = 40
$image.Height = 40 $image.Height = 40
$image.Margin = New-Object Windows.Thickness(0, 0, 10, 0) $image.Margin = New-Object Windows.Thickness(0, 0, 10, 0)
$image.Source = $noimage $image.Source = $noimage # Ensure $noimage is defined in your script
if (-not [string]::IsNullOrEmpty($kaka)) { # replace kaka with $entryInfo.choco to get images, takes a lot longer but works for many packages
try {
$packageinfo = (choco info $entryInfo.choco --limit-output).Split(' ')[0]
$packageinfo = $packageinfo -replace '\|', '.'
$iconlink = "https://community.chocolatey.org/content/packageimages/" + $packageinfo
$finishediconlink = $iconlink + ".png"
$webimage = Invoke-WebRequest -Uri $finishediconlink -Method Head -ErrorAction SilentlyContinue
if ($webimage.StatusCode -eq 200) {
$image.Source = [Windows.Media.Imaging.BitmapImage]::new([Uri]::new($finishediconlink))
} else {
# TODO: use UniGetUI's image db as a fallback
$image.Source = $noimage
}
} catch {
$image.Source = $noimage
}
}
#$image.Source = $noimage # Clip the image corners
$image.Clip = New-Object Windows.Media.RectangleGeometry $image.Clip = New-Object Windows.Media.RectangleGeometry
$image.Clip.Rect = New-Object Windows.Rect(0, 0, $image.Width, $image.Height) $image.Clip.Rect = New-Object Windows.Rect(0, 0, $image.Width, $image.Height)
$image.Clip.RadiusX = 5 $image.Clip.RadiusX = 5
@ -256,7 +253,7 @@ function Invoke-WPFUIElements {
$imageAndNamePanel.Children.Add($image) | Out-Null $imageAndNamePanel.Children.Add($image) | Out-Null
# Create the TextBlock for the application name (bigger and bold) # Create the TextBlock for the application name
$appName = New-Object Windows.Controls.TextBlock $appName = New-Object Windows.Controls.TextBlock
$appName.Text = $entryInfo.Content $appName.Text = $entryInfo.Content
$appName.FontSize = 16 $appName.FontSize = 16
@ -265,7 +262,7 @@ function Invoke-WPFUIElements {
$appName.Margin = New-Object Windows.Thickness(5, 0, 0, 0) $appName.Margin = New-Object Windows.Thickness(5, 0, 0, 0)
$imageAndNamePanel.Children.Add($appName) | Out-Null $imageAndNamePanel.Children.Add($appName) | Out-Null
# Add the image and name panel to the dock panel (after the checkbox) # Add the image and name panel to the dock panel
[Windows.Controls.DockPanel]::SetDock($imageAndNamePanel, [Windows.Controls.Dock]::Left) [Windows.Controls.DockPanel]::SetDock($imageAndNamePanel, [Windows.Controls.Dock]::Left)
$dockPanel.Children.Add($imageAndNamePanel) | Out-Null $dockPanel.Children.Add($imageAndNamePanel) | Out-Null
@ -277,7 +274,7 @@ function Invoke-WPFUIElements {
$buttonPanel.Margin = New-Object Windows.Thickness(10, 0, 0, 0) $buttonPanel.Margin = New-Object Windows.Thickness(10, 0, 0, 0)
[Windows.Controls.DockPanel]::SetDock($buttonPanel, [Windows.Controls.Dock]::Right) [Windows.Controls.DockPanel]::SetDock($buttonPanel, [Windows.Controls.Dock]::Right)
# Create the "Install" button with the install icon from Segoe MDL2 Assets # Create the "Install" button
$installButton = New-Object Windows.Controls.Button $installButton = New-Object Windows.Controls.Button
$installButton.Width = 45 $installButton.Width = 45
$installButton.Height = 35 $installButton.Height = 35
@ -297,10 +294,10 @@ function Invoke-WPFUIElements {
# Add Click event for the "Install" button # Add Click event for the "Install" button
$installButton.Add_Click({ $installButton.Add_Click({
Write-Host "Installing ..." Write-Host "Installing $($entryInfo.Name) ..."
}) })
# Create the "Uninstall" button with the uninstall icon from Segoe MDL2 Assets # Create the "Uninstall" button
$uninstallButton = New-Object Windows.Controls.Button $uninstallButton = New-Object Windows.Controls.Button
$uninstallButton.Width = 45 $uninstallButton.Width = 45
$uninstallButton.Height = 35 $uninstallButton.Height = 35
@ -318,10 +315,10 @@ function Invoke-WPFUIElements {
$buttonPanel.Children.Add($uninstallButton) | Out-Null $buttonPanel.Children.Add($uninstallButton) | Out-Null
$uninstallButton.Add_Click({ $uninstallButton.Add_Click({
Write-Host "Uninstalling ..." Write-Host "Uninstalling $($entryInfo.Name) ..."
}) })
# Create the "Info" button with the info icon from Segoe MDL2 Assets # Create the "Info" button
$infoButton = New-Object Windows.Controls.Button $infoButton = New-Object Windows.Controls.Button
$infoButton.Width = 45 $infoButton.Width = 45
$infoButton.Height = 35 $infoButton.Height = 35
@ -340,20 +337,40 @@ function Invoke-WPFUIElements {
$buttonPanel.Children.Add($infoButton) | Out-Null $buttonPanel.Children.Add($infoButton) | Out-Null
$infoButton.Add_Click({ $infoButton.Add_Click({
Write-Host "Getting info ..." Write-Host "Getting info for $($entryInfo.Name) ..."
}) })
# Add the button panel to the DockPanel # Add the button panel to the DockPanel
$dockPanel.Children.Add($buttonPanel) | Out-Null $dockPanel.Children.Add($buttonPanel) | Out-Null
# Add the border to the main stack panel in the grid # Add the border to the main items control in the grid
$stackPanel.Children.Add($border) | Out-Null $itemsControl.Items.Add($border) | Out-Null
# Sync the CheckBox, buttons, and info to the sync object for further use # Sync the CheckBox, buttons, and info to the sync object for further use
$sync[$entryInfo.Name] = $checkBox $sync[$entryInfo.Name] = $checkBox
$sync[$entryInfo.Name + "_InstallButton"] = $installButton $sync[$entryInfo.Name + "_InstallButton"] = $installButton
$sync[$entryInfo.Name + "_UninstallButton"] = $uninstallButton $sync[$entryInfo.Name + "_UninstallButton"] = $uninstallButton
$sync[$entryInfo.Name + "_InfoButton"] = $infoButton $sync[$entryInfo.Name + "_InfoButton"] = $infoButton
$image.Source = $noimage
if (-not [string]::IsNullOrEmpty($none)) { # replace $none with $entryInfo.choco to get images, takes a lot longer but works for many packages
try {
$packageinfo = (choco info $entryInfo.choco --limit-output).Split(' ')[0]
$packageinfo = $packageinfo -replace '\|', '.'
$iconlink = "https://community.chocolatey.org/content/packageimages/" + $packageinfo
$finishediconlink = $iconlink + ".png"
$webimage = Invoke-WebRequest -Uri $finishediconlink -Method Head -ErrorAction SilentlyContinue
if ($webimage.StatusCode -eq 200) {
$image.Source = [Windows.Media.Imaging.BitmapImage]::new([Uri]::new($finishediconlink))
} else {
# TODO: use UniGetUI's image db as a fallback
$image.Source = $noimage
}
} catch {
$image.Source = $noimage
}
}
} else { } else {
# Create the UI elements based on the entry type # Create the UI elements based on the entry type
switch ($entryInfo.Type) { switch ($entryInfo.Type) {
@ -372,7 +389,7 @@ function Invoke-WPFUIElements {
$label.FontSize = $theme.FontSize $label.FontSize = $theme.FontSize
$label.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor") $label.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$dockPanel.Children.Add($label) | Out-Null $dockPanel.Children.Add($label) | Out-Null
$stackPanel.Children.Add($dockPanel) | Out-Null $itemsControl.Items.Add($dockPanel) | Out-Null
$sync[$entryInfo.Name] = $checkBox $sync[$entryInfo.Name] = $checkBox
@ -387,7 +404,6 @@ function Invoke-WPFUIElements {
"ToggleButton" { "ToggleButton" {
$toggleButton = New-Object Windows.Controls.ToggleButton $toggleButton = New-Object Windows.Controls.ToggleButton
$toggleButton.Name = $entryInfo.Name $toggleButton.Name = $entryInfo.Name
$toggleButton.Name = "WPFTab" + ($stackPanel.Children.Count + 1) + "BT"
$toggleButton.HorizontalAlignment = "Left" $toggleButton.HorizontalAlignment = "Left"
$toggleButton.Height = $theme.TabButtonHeight $toggleButton.Height = $theme.TabButtonHeight
$toggleButton.Width = $theme.TabButtonWidth $toggleButton.Width = $theme.TabButtonWidth
@ -401,17 +417,17 @@ function Invoke-WPFUIElements {
$textBlock.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "ButtonInstallForegroundColor") $textBlock.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "ButtonInstallForegroundColor")
$underline = New-Object Windows.Documents.Underline $underline = New-Object Windows.Documents.Underline
$underline.Inlines.Add($entryInfo.name -replace "(.).*", "`$1") $underline.Inlines.Add($entryInfo.Name -replace "(.).*", "$1")
$run = New-Object Windows.Documents.Run $run = New-Object Windows.Documents.Run
$run.Text = $entryInfo.name -replace "^.", "" $run.Text = $entryInfo.Name -replace "^.", ""
$textBlock.Inlines.Add($underline) $textBlock.Inlines.Add($underline)
$textBlock.Inlines.Add($run) $textBlock.Inlines.Add($run)
$toggleButton.Content = $textBlock $toggleButton.Content = $textBlock
$stackPanel.Children.Add($toggleButton) | Out-Null $itemsControl.Items.Add($toggleButton) | Out-Null
$sync[$entryInfo.Name] = $toggleButton $sync[$entryInfo.Name] = $toggleButton
} }
@ -444,7 +460,7 @@ function Invoke-WPFUIElements {
} }
$horizontalStackPanel.Children.Add($comboBox) | Out-Null $horizontalStackPanel.Children.Add($comboBox) | Out-Null
$stackPanel.Children.Add($horizontalStackPanel) | Out-Null $itemsControl.Items.Add($horizontalStackPanel) | Out-Null
$comboBox.SelectedIndex = 0 $comboBox.SelectedIndex = 0
@ -461,7 +477,7 @@ function Invoke-WPFUIElements {
if ($entryInfo.ButtonWidth) { if ($entryInfo.ButtonWidth) {
$button.Width = $entryInfo.ButtonWidth $button.Width = $entryInfo.ButtonWidth
} }
$stackPanel.Children.Add($button) | Out-Null $itemsControl.Items.Add($button) | Out-Null
$sync[$entryInfo.Name] = $button $sync[$entryInfo.Name] = $button
} }
@ -480,7 +496,7 @@ function Invoke-WPFUIElements {
$radioButton.IsChecked = $true $radioButton.IsChecked = $true
} }
$stackPanel.Children.Add($radioButton) | Out-Null $itemsControl.Items.Add($radioButton) | Out-Null
$sync[$entryInfo.Name] = $radioButton $sync[$entryInfo.Name] = $radioButton
} }
@ -511,7 +527,7 @@ function Invoke-WPFUIElements {
$sync[$textBlock.Name] = $textBlock $sync[$textBlock.Name] = $textBlock
} }
$stackPanel.Children.Add($horizontalStackPanel) | Out-Null $itemsControl.Items.Add($horizontalStackPanel) | Out-Null
$sync[$entryInfo.Name] = $checkBox $sync[$entryInfo.Name] = $checkBox
} }
} }

View File

@ -148,12 +148,12 @@ Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "feat
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)} $xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)}
#Persist the Chocolatey preference across winutil restarts #Persist the Chocolatey preference across winutil restarts
$ChocoPreferencePath = "$env:LOCALAPPDATA\winutil\preferChocolatey.ini" #$ChocoPreferencePath = "$env:LOCALAPPDATA\winutil\preferChocolatey.ini"
$sync.WPFpreferChocolatey.Add_Checked({New-Item -Path $ChocoPreferencePath -Force }) #$sync.WPFpreferChocolatey.Add_Checked({New-Item -Path $ChocoPreferencePath -Force })
$sync.WPFpreferChocolatey.Add_Unchecked({Remove-Item $ChocoPreferencePath -Force}) #$sync.WPFpreferChocolatey.Add_Unchecked({Remove-Item $ChocoPreferencePath -Force})
if (Test-Path $ChocoPreferencePath) { #if (Test-Path $ChocoPreferencePath) {
$sync.WPFpreferChocolatey.IsChecked = $true # $sync.WPFpreferChocolatey.IsChecked = $true
} #}
$sync.keys | ForEach-Object { $sync.keys | ForEach-Object {
if($sync.$psitem) { if($sync.$psitem) {