8 Commits

Author SHA1 Message Date
Raphire
69354d823e Fix: block window resizing beyond min. height/width 2026-04-04 22:34:49 +02:00
Raphire
c0d00e640d Bump version 2026-04-04 22:09:53 +02:00
Raphire
d372b00072 Improve Window controls 2026-04-04 14:43:15 +02:00
Raphire
fbdc5740db Update Checkbox style 2026-04-04 14:11:39 +02:00
Raphire
cbd61902ed Set default launch mode to CLI for deployment-targeted parameters 2026-04-02 00:03:26 +02:00
Raphire
54edf224a3 Improve Window controls 2026-04-02 00:00:32 +02:00
Natan Heringer
3eade4ddba Add drive letter position and visibility options (#527) (#533) 2026-03-29 00:25:12 +01:00
Raphire
487b1fbee9 Prevent Window Snapping 2026-03-27 21:14:22 +01:00
17 changed files with 500 additions and 333 deletions

View File

@@ -187,6 +187,7 @@
"Label": "Open File Explorer to",
"ToolTip": "This setting allows you to choose the default location that File Explorer opens to.",
"Category": "File Explorer",
"Priority": 1,
"Values": [
{
"Label": "Home",
@@ -214,6 +215,39 @@
}
]
},
{
"GroupId": "DriveLetterPosition",
"Label": "Drive letter position",
"ToolTip": "This setting allows you to choose where drive letters are shown in File Explorer.",
"Category": "File Explorer",
"Priority": 20,
"Values": [
{
"Label": "Show drive letters after drive label (Default)",
"FeatureIds": [
"ShowDriveLettersLast"
]
},
{
"Label": "Show drive letters before drive label",
"FeatureIds": [
"ShowDriveLettersFirst"
]
},
{
"Label": "Show network drive letters before drive label",
"FeatureIds": [
"ShowNetworkDriveLettersFirst"
]
},
{
"Label": "Hide all drive letters",
"FeatureIds": [
"HideDriveLetters"
]
}
]
},
{
"GroupId": "ShowTabsInAltTab",
"Label": "Show tabs from apps when snapping or pressing Alt+Tab",
@@ -1220,6 +1254,7 @@
"Label": "file extensions for known file types",
"ToolTip": "This will show file extensions for known file types. By default, Windows hides file extensions for known file types which can lead to confusion and security risks.",
"Category": "File Explorer",
"Priority": 2,
"Action": "Show",
"RegistryKey": "Show_Extensions_For_Known_File_Types.reg",
"ApplyText": "Enabling file extensions for known file types...",
@@ -1233,6 +1268,7 @@
"Label": "hidden files, folders and drives",
"ToolTip": "By default, Windows hides certain files, folders and drives to prevent accidental modification or deletion. Turn this on to show all files in File Explorer.",
"Category": "File Explorer",
"Priority": 3,
"Action": "Show",
"RegistryKey": "Show_Hidden_Folders.reg",
"ApplyText": "Unhiding hidden files, folders and drives...",
@@ -1246,6 +1282,7 @@
"Label": "'Home' from navigation pane",
"ToolTip": "Hides the 'Home' section from the File Explorer navigation pane.",
"Category": "File Explorer",
"Priority": 4,
"Action": "Hide",
"RegistryKey": "Hide_Home_from_Explorer.reg",
"ApplyText": "Hiding the home section from the File Explorer navigation pane...",
@@ -1259,6 +1296,7 @@
"Label": "'Gallery' from navigation pane",
"ToolTip": "Hides the 'Gallery' section from the File Explorer navigation pane.",
"Category": "File Explorer",
"Priority": 5,
"Action": "Hide",
"RegistryKey": "Hide_Gallery_from_Explorer.reg",
"ApplyText": "Hiding the gallery section from the File Explorer navigation pane...",
@@ -1272,6 +1310,7 @@
"Label": "duplicate removable drive entries",
"ToolTip": "By default, Windows shows removable drives both under 'This PC' and in the navigation pane with its own entry. Enable this setting to only show removable drives under 'This PC'.",
"Category": "File Explorer",
"Priority": 6,
"Action": "Hide",
"RegistryKey": "Hide_duplicate_removable_drives_from_navigation_pane_of_File_Explorer.reg",
"ApplyText": "Hiding duplicate removable drive entries from the File Explorer navigation pane...",
@@ -1285,6 +1324,7 @@
"Label": "common folders back to 'This PC' page",
"ToolTip": "This setting will add common folders like Desktop, Documents, Downloads, Music, Pictures and Videos back to the 'This PC' page in File Explorer.",
"Category": "File Explorer",
"Priority": 7,
"Action": "Add",
"RegistryKey": "Add_All_Folders_Under_This_PC.reg",
"ApplyText": "Adding all common folders (Desktop, Downloads, etc.) back to 'This PC' in File Explorer...",
@@ -1376,6 +1416,7 @@
"Label": "'Include in library' option in the context menu",
"ToolTip": "Hides the 'Include in library' option from the File Explorer context menu.",
"Category": "File Explorer",
"Priority": 8,
"Action": "Hide",
"RegistryKey": "Disable_Include_in_library_from_context_menu.reg",
"ApplyText": "Hiding 'Include in library' in the context menu...",
@@ -1389,6 +1430,7 @@
"Label": "'Give access to' option in the context menu",
"ToolTip": "Hides the 'Give access to' option from the File Explorer context menu.",
"Category": "File Explorer",
"Priority": 9,
"Action": "Hide",
"RegistryKey": "Disable_Give_access_to_context_menu.reg",
"ApplyText": "Hiding 'Give access to' in the context menu...",
@@ -1402,6 +1444,7 @@
"Label": "'Share' option in the context menu",
"ToolTip": "Hides the 'Share' option from the File Explorer context menu.",
"Category": "File Explorer",
"Priority": 10,
"Action": "Hide",
"RegistryKey": "Disable_Share_from_context_menu.reg",
"ApplyText": "Hiding 'Share' in the context menu...",
@@ -1415,6 +1458,7 @@
"Label": "'OneDrive' folder from navigation pane",
"ToolTip": "Hides the 'OneDrive' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
"Priority": 11,
"Action": "Hide",
"RegistryKey": "Hide_Onedrive_Folder.reg",
"ApplyText": "Hiding the OneDrive folder from the File Explorer navigation pane...",
@@ -1428,6 +1472,7 @@
"Label": "'3D objects' folder under 'This PC'",
"ToolTip": "Hides the '3D objects' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
"Priority": 12,
"Action": "Hide",
"RegistryKey": "Hide_3D_Objects_Folder.reg",
"ApplyText": "Hiding the 3D objects folder from the File Explorer navigation pane...",
@@ -1441,6 +1486,7 @@
"Label": "'Music' folder under 'This PC'",
"ToolTip": "Hides the 'Music' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
"Priority": 13,
"Action": "Hide",
"RegistryKey": "Hide_Music_Folder.reg",
"ApplyText": "Hiding the music folder from the File Explorer navigation pane...",
@@ -1489,6 +1535,58 @@
"RequiresReboot": true,
"MinVersion": 22000,
"MaxVersion": null
},
{
"FeatureId": "ShowDriveLettersFirst",
"Label": "show drive letters before drive label",
"ToolTip": "This setting will show drive letters before the drive label in File Explorer.",
"Category": "File Explorer",
"Action": "Show first",
"RegistryKey": "Show_Drive_Letters_First.reg",
"ApplyText": "Showing drive letters before drive label...",
"UndoAction": "Show last",
"RegistryUndoKey": "Undo/Show_Drive_Letters_Last.reg",
"MinVersion": null,
"MaxVersion": null
},
{
"FeatureId": "ShowDriveLettersLast",
"Label": "show drive letters after drive label",
"ToolTip": "This setting will show drive letters after the drive label in File Explorer (Default Windows behavior).",
"Category": "File Explorer",
"Action": "Show last",
"RegistryKey": "Show_Drive_Letters_Last.reg",
"ApplyText": "Showing drive letters after drive label...",
"UndoAction": null,
"RegistryUndoKey": null,
"MinVersion": null,
"MaxVersion": null
},
{
"FeatureId": "ShowNetworkDriveLettersFirst",
"Label": "show network drive letters before drive label",
"ToolTip": "This setting will show only network drive letters before the drive label in File Explorer.",
"Category": "File Explorer",
"Action": "Show network first",
"RegistryKey": "Show_Network_Drive_Letters_First.reg",
"ApplyText": "Showing network drive letters before drive label...",
"UndoAction": "Show last",
"RegistryUndoKey": "Undo/Show_Drive_Letters_Last.reg",
"MinVersion": null,
"MaxVersion": null
},
{
"FeatureId": "HideDriveLetters",
"Label": "hide all drive letters",
"ToolTip": "This setting will hide all drive letters from the File Explorer navigation pane and 'This PC'.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Hide_Drive_Letters.reg",
"ApplyText": "Hiding all drive letters...",
"UndoAction": "Show last",
"RegistryUndoKey": "Undo/Show_Drive_Letters_Last.reg",
"MinVersion": null,
"MaxVersion": null
}
]
}

View File

@@ -160,6 +160,7 @@ Below is an overview of the key features and functionality offered by Win11Deblo
- Add all common folders (Desktop, Downloads, etc.) back to 'This PC' in File Explorer.
- Hide the 3D objects, music or OneDrive folder from the File Explorer navigation pane.
- Hide the 'Include in library', 'Give access to' and 'Share' options from the context menu.
- Change drive letter position or visibility in File Explorer.
#### Multi-tasking

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000002

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000004

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000000

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000001

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000002

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000004

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000000

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000001

View File

@@ -0,0 +1,4 @@
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
"ShowDriveLettersFirst"=dword:00000000

View File

@@ -9,55 +9,6 @@
Background="Transparent"
Foreground="{DynamicResource FgColor}">
<Window.Resources>
<!-- CheckBox Style -->
<Style TargetType="CheckBox">
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Border Background="{TemplateBinding Background}" BorderThickness="0" CornerRadius="4" Padding="{TemplateBinding Padding}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="CheckBoxBorder" Grid.Column="0" Width="18" Height="18" Background="{DynamicResource CheckBoxBgColor}" BorderBrush="{DynamicResource CheckBoxBorderColor}" BorderThickness="1" CornerRadius="4" Margin="0,0,8,0">
<TextBlock x:Name="CheckMark" Text="&#xE73E;" FontFamily="Segoe MDL2 Assets" FontSize="12" Foreground="{DynamicResource ButtonBg}" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed"/>
</Border>
<ContentPresenter Grid.Column="1" VerticalAlignment="Center" Margin="0,0,0,1"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource CheckBoxHoverColor}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="CheckMark" Property="Visibility" Value="Visible"/>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckMark" Property="Foreground" Value="White"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonHover}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonHover}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- CheckBox style for apps panels -->
<Style x:Key="AppsPanelCheckBoxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="2,3,2,3"/>
</Style>
<!-- Title Bar Button Style -->
<Style x:Key="TitleBarButton" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>

View File

@@ -1,15 +1,22 @@
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
Title="Win11Debloat"
MinWidth="1130" MinHeight="600"
MaxWidth="1400"
ResizeMode="CanResize"
SnapsToDevicePixels="True"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent"
AllowsTransparency="False"
Background="{DynamicResource BgColor}"
Foreground="{DynamicResource FgColor}">
<shell:WindowChrome.WindowChrome>
<shell:WindowChrome ResizeBorderThickness="5"
CaptionHeight="32"
CornerRadius="8"
GlassFrameThickness="0"
UseAeroCaptionButtons="False"/>
</shell:WindowChrome.WindowChrome>
<Window.Resources>
<!-- Sort column header hover style -->
<Style x:Key="SortHeaderBtnStyle" TargetType="StackPanel">
@@ -336,89 +343,6 @@
</Style.Triggers>
</Style>
<!-- CheckBox Style -->
<Style TargetType="CheckBox">
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Border Background="{TemplateBinding Background}" BorderThickness="0" CornerRadius="4" Padding="{TemplateBinding Padding}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="CheckBoxBorder" Grid.Column="0" Width="18" Height="18" Background="{DynamicResource CheckBoxBgColor}" BorderBrush="{DynamicResource CheckBoxBorderColor}" BorderThickness="1" CornerRadius="4" Margin="0,0,8,0">
<Grid>
<TextBlock x:Name="CheckMark" Text="&#xE73E;" FontFamily="Segoe Fluent Icons" FontSize="12" Foreground="{DynamicResource ButtonBg}" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed"/>
<TextBlock x:Name="IndeterminateMark" Text="&#xE738;" FontFamily="Segoe Fluent Icons" FontSize="11" Foreground="{DynamicResource ButtonBg}" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed" Margin="1,1,0,0" />
</Grid>
</Border>
<ContentPresenter Grid.Column="1" VerticalAlignment="Center" Margin="0,0,0,2"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource CheckBoxHoverColor}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="CheckMark" Property="Visibility" Value="Visible"/>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckMark" Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter TargetName="IndeterminateMark" Property="Visibility" Value="Visible"/>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckBoxBorder" Property="Opacity" Value="0.8"/>
<Setter TargetName="IndeterminateMark" Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonDisabled}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource BorderColor}"/>
<Setter Property="Foreground" Value="{DynamicResource ButtonTextDisabled}"/>
<Setter Property="Opacity" Value="0.6"/>
<Setter TargetName="CheckMark" Property="Foreground" Value="{DynamicResource ButtonTextDisabled}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonHover}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonHover}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="{x:Null}"/>
</MultiTrigger.Conditions>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonHover}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonHover}"/>
<Setter TargetName="CheckBoxBorder" Property="Opacity" Value="0.8"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- CheckBox style for feature toggles -->
<Style x:Key="FeatureCheckboxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="-4,-2,-4,10"/>
<Setter Property="Padding" Value="4,2"/>
</Style>
<!-- CheckBox style for apps panels -->
<Style x:Key="AppsPanelCheckBoxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="2,3,2,3"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<!-- TextBlock style for App ID column in apps table -->
<Style x:Key="AppIdTextStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource AppIdColor}"/>
@@ -458,11 +382,6 @@
<Setter Property="Margin" Value="0,1,0,0"/>
</Style>
<!-- Style for dynamically-created preset checkboxes in the Quick Select popup -->
<Style x:Key="PresetCheckBoxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="8,4"/>
</Style>
<!-- Progress step indicator fill colors -->
<SolidColorBrush x:Key="ProgressActiveColor" Color="#0067c0"/>
<SolidColorBrush x:Key="ProgressInactiveColor" Color="#808080"/>
@@ -601,38 +520,30 @@
</Style>
</Window.Resources>
<Border BorderBrush="{DynamicResource BorderColor}"
<Border x:Name="MainBorder" BorderBrush="{DynamicResource BorderColor}"
BorderThickness="1"
CornerRadius="8"
Background="{DynamicResource BgColor}"
Margin="25">
<Border.Effect>
<DropShadowEffect Color="Black"
Opacity="0.15"
BlurRadius="20"
ShadowDepth="0"
Direction="0"/>
</Border.Effect>
Margin="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Resize Borders -->
<Rectangle x:Name="ResizeLeft" Width="5" HorizontalAlignment="Left" Fill="Transparent" Cursor="SizeWE" Grid.Row="0" Grid.RowSpan="3" Panel.ZIndex="100"/>
<Rectangle x:Name="ResizeRight" Width="5" HorizontalAlignment="Right" Fill="Transparent" Cursor="SizeWE" Grid.Row="0" Grid.RowSpan="3" Panel.ZIndex="100"/>
<Rectangle x:Name="ResizeTop" Height="5" VerticalAlignment="Top" Fill="Transparent" Cursor="SizeNS" Grid.Row="0" Panel.ZIndex="100"/>
<Rectangle x:Name="ResizeBottom" Height="5" VerticalAlignment="Bottom" Fill="Transparent" Cursor="SizeNS" Grid.Row="2" Panel.ZIndex="100"/>
<Rectangle x:Name="ResizeTopLeft" Width="8" Height="8" HorizontalAlignment="Left" VerticalAlignment="Top" Fill="Transparent" Cursor="SizeNWSE" Grid.Row="0" Panel.ZIndex="101"/>
<Rectangle x:Name="ResizeTopRight" Width="8" Height="8" HorizontalAlignment="Right" VerticalAlignment="Top" Fill="Transparent" Cursor="SizeNESW" Grid.Row="0" Panel.ZIndex="101"/>
<Rectangle x:Name="ResizeBottomLeft" Width="8" Height="8" HorizontalAlignment="Left" VerticalAlignment="Bottom" Fill="Transparent" Cursor="SizeNESW" Grid.Row="2" Panel.ZIndex="101"/>
<Rectangle x:Name="ResizeBottomRight" Width="8" Height="8" HorizontalAlignment="Right" VerticalAlignment="Bottom" Fill="Transparent" Cursor="SizeNWSE" Grid.Row="2" Panel.ZIndex="101"/>
<Rectangle x:Name="ResizeLeft" Width="5" HorizontalAlignment="Left" Fill="Transparent" Cursor="SizeWE" Grid.Row="0" Grid.RowSpan="2" Panel.ZIndex="100" Visibility="Collapsed" IsHitTestVisible="False"/>
<Rectangle x:Name="ResizeRight" Width="5" HorizontalAlignment="Right" Fill="Transparent" Cursor="SizeWE" Grid.Row="0" Grid.RowSpan="2" Panel.ZIndex="100" Visibility="Collapsed" IsHitTestVisible="False"/>
<Rectangle x:Name="ResizeTop" Height="5" VerticalAlignment="Top" Fill="Transparent" Cursor="SizeNS" Grid.Row="0" Panel.ZIndex="100" Visibility="Collapsed" IsHitTestVisible="False"/>
<Rectangle x:Name="ResizeBottom" Height="5" VerticalAlignment="Bottom" Fill="Transparent" Cursor="SizeNS" Grid.Row="1" Panel.ZIndex="100" Visibility="Collapsed" IsHitTestVisible="False"/>
<Rectangle x:Name="ResizeTopLeft" Width="8" Height="8" HorizontalAlignment="Left" VerticalAlignment="Top" Fill="Transparent" Cursor="SizeNWSE" Grid.Row="0" Panel.ZIndex="101" Visibility="Collapsed" IsHitTestVisible="False"/>
<Rectangle x:Name="ResizeTopRight" Width="8" Height="8" HorizontalAlignment="Right" VerticalAlignment="Top" Fill="Transparent" Cursor="SizeNESW" Grid.Row="0" Panel.ZIndex="101" Visibility="Collapsed" IsHitTestVisible="False"/>
<Rectangle x:Name="ResizeBottomLeft" Width="8" Height="8" HorizontalAlignment="Left" VerticalAlignment="Bottom" Fill="Transparent" Cursor="SizeNESW" Grid.Row="1" Panel.ZIndex="101" Visibility="Collapsed" IsHitTestVisible="False"/>
<Rectangle x:Name="ResizeBottomRight" Width="8" Height="8" HorizontalAlignment="Right" VerticalAlignment="Bottom" Fill="Transparent" Cursor="SizeNWSE" Grid.Row="1" Panel.ZIndex="101" Visibility="Collapsed" IsHitTestVisible="False"/>
<!-- Custom Title Bar -->
<Grid Grid.Row="0" x:Name="TitleBar">
<Border Background="{DynamicResource BgColor}" CornerRadius="8,8,0,0">
<Border x:Name="TitleBarBackground" Background="{DynamicResource BgColor}" CornerRadius="8,8,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
@@ -645,8 +556,8 @@
Margin="12,0,0,0"
FontSize="12"/>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button x:Name="KofiBtn" Content="&#xEB52;" FontFamily="Segoe Fluent Icons" FontSize="15" Style="{StaticResource TitlebarButton}" ToolTip="Support the creator" AutomationProperties.Name="Support the creator"/>
<Button x:Name="MenuBtn" Content="&#xE700;" FontFamily="Segoe Fluent Icons" FontSize="15" Style="{StaticResource TitlebarButton}" ToolTip="Options" AutomationProperties.Name="Options">
<Button x:Name="KofiBtn" shell:WindowChrome.IsHitTestVisibleInChrome="True" Content="&#xEB52;" FontFamily="Segoe Fluent Icons" FontSize="15" Style="{StaticResource TitlebarButton}" ToolTip="Support the creator" AutomationProperties.Name="Support the creator"/>
<Button x:Name="MenuBtn" shell:WindowChrome.IsHitTestVisibleInChrome="True" Content="&#xE700;" FontFamily="Segoe Fluent Icons" FontSize="15" Style="{StaticResource TitlebarButton}" ToolTip="Options" AutomationProperties.Name="Options">
<Button.ContextMenu>
<ContextMenu x:Name="MainMenu">
<ContextMenu.Resources>
@@ -695,14 +606,20 @@
</ContextMenu>
</Button.ContextMenu>
</Button>
<Button x:Name="CloseBtn" Content="&#xE8BB;" Style="{StaticResource CloseButton}" ToolTip="Close" AutomationProperties.Name="Close"/>
<Button x:Name="CloseBtn" shell:WindowChrome.IsHitTestVisibleInChrome="True" Content="&#xE8BB;" Style="{StaticResource CloseButton}" ToolTip="Close" AutomationProperties.Name="Close"/>
</StackPanel>
</Grid>
</Border>
</Grid>
<!-- Main Content with Tabs -->
<TabControl Grid.Row="1" Background="Transparent" BorderThickness="0" Margin="0" Padding="0" Name="MainTabControl">
<Grid Grid.Row="1" x:Name="ContentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0" Background="Transparent" BorderThickness="0" Margin="0" Padding="0" Name="MainTabControl">
<TabControl.Resources>
<Style TargetType="TabItem">
<Setter Property="Template">
@@ -1129,12 +1046,12 @@
<!-- Restore Point Option -->
<StackPanel>
<CheckBox x:Name="RestorePointCheckBox" Style="{StaticResource FeatureCheckboxStyle}" IsChecked="True" Content="Create a system restore point (Recommended)" AutomationProperties.Name="Create a system restore point (Recommended)"/>
<CheckBox x:Name="RestorePointCheckBox" Style="{DynamicResource FeatureCheckboxStyle}" IsChecked="True" Content="Create a system restore point (Recommended)" AutomationProperties.Name="Create a system restore point (Recommended)"/>
</StackPanel>
<!-- Restart Explorer Option -->
<StackPanel>
<CheckBox x:Name="RestartExplorerCheckBox" Style="{StaticResource FeatureCheckboxStyle}" Content="Restart the Windows Explorer process to apply all changes immediately" AutomationProperties.Name="Restart the Windows Explorer process to apply all changes immediately"/>
<CheckBox x:Name="RestartExplorerCheckBox" Style="{DynamicResource FeatureCheckboxStyle}" Content="Restart the Windows Explorer process to apply all changes immediately" AutomationProperties.Name="Restart the Windows Explorer process to apply all changes immediately"/>
</StackPanel>
</StackPanel>
</Border>
@@ -1191,7 +1108,7 @@
</TabControl>
<!-- Bottom Navigation Buttons -->
<Grid Grid.Row="2" Height="56" x:Name="BottomNavGrid">
<Grid Grid.Row="1" Height="56" x:Name="BottomNavGrid">
<Grid Margin="20,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
@@ -1222,10 +1139,11 @@
<Ellipse x:Name="ProgressIndicator3" Width="10" Height="10" Margin="4,0" Fill="#808080" ToolTip="Deployment Settings"/>
</StackPanel>
</Grid>
</Grid>
<!-- Modal Overlay for MessageBoxes -->
<Rectangle x:Name="ModalOverlay"
Grid.RowSpan="3"
Grid.RowSpan="2"
Fill="#80000000"
Visibility="Collapsed"
Panel.ZIndex="1000"

View File

@@ -125,6 +125,138 @@
<Setter Property="TextAlignment" Value="Center"/>
</Style>
<!-- Base CheckBox style used across windows -->
<Style TargetType="CheckBox">
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="4,2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Border Background="{TemplateBinding Background}" BorderThickness="0" CornerRadius="4" Padding="{TemplateBinding Padding}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="CheckBoxBorder" Grid.Column="0" Width="18" Height="18" Background="{DynamicResource CheckBoxBgColor}" BorderBrush="{DynamicResource CheckBoxBorderColor}" BorderThickness="1" CornerRadius="4" Margin="0,0,8,0">
<Grid>
<TextBlock x:Name="CheckMark" Text="&#xE73E;" FontFamily="Segoe Fluent Icons" FontSize="12" Foreground="{DynamicResource ButtonBg}" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0">
<TextBlock.Clip>
<RectangleGeometry x:Name="CheckMarkClip" Rect="0,0,0,16"/>
</TextBlock.Clip>
</TextBlock>
<TextBlock x:Name="IndeterminateMark" Text="&#xE738;" FontFamily="Segoe Fluent Icons" FontSize="11" Foreground="{DynamicResource ButtonBg}" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0" Margin="1,1,0,0">
<TextBlock.Clip>
<RectangleGeometry x:Name="IndeterminateMarkClip" Rect="0,0,0,16"/>
</TextBlock.Clip>
</TextBlock>
</Grid>
</Border>
<ContentPresenter Grid.Column="1" VerticalAlignment="Center" Margin="0,0,0,2"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource CheckBoxHoverColor}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckMark" Property="Foreground" Value="White"/>
<Setter TargetName="CheckMark" Property="Opacity" Value="1"/>
<Setter TargetName="IndeterminateMark" Property="Opacity" Value="0"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CheckMark" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.25" FillBehavior="HoldEnd"/>
<RectAnimation Storyboard.TargetName="CheckMarkClip" Storyboard.TargetProperty="Rect" From="0,0,0,16" To="0,0,16,16" Duration="0:0:0.25" FillBehavior="HoldEnd"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<RectAnimation Storyboard.TargetName="CheckMarkClip" Storyboard.TargetProperty="Rect" From="0,0,16,16" To="16,0,0,16" Duration="0:0:0.15" FillBehavior="HoldEnd"/>
<DoubleAnimation Storyboard.TargetName="CheckMark" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.15" FillBehavior="HoldEnd"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonBg}"/>
<Setter TargetName="CheckBoxBorder" Property="Opacity" Value="0.8"/>
<Setter TargetName="IndeterminateMark" Property="Foreground" Value="White"/>
<Setter TargetName="IndeterminateMark" Property="Opacity" Value="1"/>
<Setter TargetName="CheckMark" Property="Opacity" Value="0"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="IndeterminateMark" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.25" FillBehavior="HoldEnd"/>
<RectAnimation Storyboard.TargetName="IndeterminateMarkClip" Storyboard.TargetProperty="Rect" From="0,0,0,16" To="0,0,16,16" Duration="0:0:0.25" FillBehavior="HoldEnd"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<RectAnimation Storyboard.TargetName="IndeterminateMarkClip" Storyboard.TargetProperty="Rect" From="0,0,16,16" To="16,0,0,16" Duration="0:0:0.15" FillBehavior="HoldEnd"/>
<DoubleAnimation Storyboard.TargetName="IndeterminateMark" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.15" FillBehavior="HoldEnd"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="CheckMark" Property="Opacity" Value="0"/>
<Setter TargetName="IndeterminateMark" Property="Opacity" Value="0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonDisabled}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource BorderColor}"/>
<Setter Property="Opacity" Value="0.4"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonHover}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonHover}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="{x:Null}"/>
</MultiTrigger.Conditions>
<Setter TargetName="CheckBoxBorder" Property="Background" Value="{DynamicResource ButtonHover}"/>
<Setter TargetName="CheckBoxBorder" Property="BorderBrush" Value="{DynamicResource ButtonHover}"/>
<Setter TargetName="CheckBoxBorder" Property="Opacity" Value="0.8"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Shared checkbox style used for feature toggles across windows -->
<Style x:Key="FeatureCheckboxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="-4,-2,-4,10"/>
<Setter Property="Padding" Value="4,2"/>
</Style>
<!-- Shared CheckBox style for app list items -->
<Style x:Key="AppsPanelCheckBoxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="2,3,2,3"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<!-- Shared CheckBox style for preset picker entries -->
<Style x:Key="PresetCheckBoxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="Margin" Value="8,4"/>
</Style>
<!-- ScrollBar Style -->
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Background" Value="Transparent"/>

View File

@@ -1,6 +1,36 @@
function Show-MainWindow {
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase,System.Windows.Forms | Out-Null
# Helper to constrain the maximized window to the monitor working area (respects taskbar).
# Required for WindowStyle=None windows — without this the window extends behind the taskbar.
if (-not ([System.Management.Automation.PSTypeName]'Win11Debloat.MaximizedWindowHelper').Type) {
Add-Type -Namespace Win11Debloat -Name MaximizedWindowHelper `
-ReferencedAssemblies 'PresentationFramework','System.Windows.Forms','System.Drawing' `
-MemberDefinition @'
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct MINMAXINFO {
public POINT ptReserved, ptMaxSize, ptMaxPosition, ptMinTrackSize, ptMaxTrackSize;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct POINT { public int x, y; }
public static System.IntPtr WmGetMinMaxInfoHook(
System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) {
if (msg == 0x0024) { // WM_GETMINMAXINFO
var wa = System.Windows.Forms.Screen.FromHandle(hwnd).WorkingArea;
var mmi = (MINMAXINFO)System.Runtime.InteropServices.Marshal.PtrToStructure(
lParam, typeof(MINMAXINFO));
mmi.ptMaxPosition.x = wa.Left;
mmi.ptMaxPosition.y = wa.Top;
mmi.ptMaxSize.x = wa.Width;
mmi.ptMaxSize.y = wa.Height;
System.Runtime.InteropServices.Marshal.StructureToPtr(mmi, lParam, true);
}
return System.IntPtr.Zero;
}
'@
}
# Get current Windows build version
$WinVersion = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' CurrentBuild
@@ -19,7 +49,8 @@ function Show-MainWindow {
SetWindowThemeResources -window $window -usesDarkMode $usesDarkMode
# Get named elements
$titleBar = $window.FindName('TitleBar')
$mainBorder = $window.FindName('MainBorder')
$titleBarBackground = $window.FindName('TitleBarBackground')
$kofiBtn = $window.FindName('KofiBtn')
$menuBtn = $window.FindName('MenuBtn')
$closeBtn = $window.FindName('CloseBtn')
@@ -30,10 +61,108 @@ function Show-MainWindow {
$importConfigBtn = $window.FindName('ImportConfigBtn')
$exportConfigBtn = $window.FindName('ExportConfigBtn')
# Title bar event handlers
$titleBar.Add_MouseLeftButtonDown({
if ($_.OriginalSource -is [System.Windows.Controls.Grid] -or $_.OriginalSource -is [System.Windows.Controls.Border] -or $_.OriginalSource -is [System.Windows.Controls.TextBlock]) {
$window.DragMove()
$windowStateNormal = [System.Windows.WindowState]::Normal
$windowStateMaximized = [System.Windows.WindowState]::Maximized
$normalWindowShadow = $mainBorder.Effect
$initialNormalMaxWidth = 1400.0
$convertScreenPixelsToDip = {
param(
[double]$width,
[double]$height
)
$source = [System.Windows.PresentationSource]::FromVisual($window)
if ($null -eq $source -or $null -eq $source.CompositionTarget) {
return [System.Windows.Size]::new($width, $height)
}
$topLeft = $source.CompositionTarget.TransformFromDevice.Transform([System.Windows.Point]::new(0, 0))
$bottomRight = $source.CompositionTarget.TransformFromDevice.Transform([System.Windows.Point]::new($width, $height))
return [System.Windows.Size]::new($bottomRight.X - $topLeft.X, $bottomRight.Y - $topLeft.Y)
}
$getWindowScreen = {
$hwnd = (New-Object System.Windows.Interop.WindowInteropHelper($window)).Handle
if ($hwnd -eq [IntPtr]::Zero) {
return $null
}
return [System.Windows.Forms.Screen]::FromHandle($hwnd)
}
$updateWindowChrome = {
$chrome = [System.Windows.Shell.WindowChrome]::GetWindowChrome($window)
if ($window.WindowState -eq $windowStateMaximized) {
$mainBorder.Margin = [System.Windows.Thickness]::new(0)
$mainBorder.BorderThickness = [System.Windows.Thickness]::new(0)
$mainBorder.CornerRadius = [System.Windows.CornerRadius]::new(0)
$mainBorder.Effect = $null
$titleBarBackground.CornerRadius = [System.Windows.CornerRadius]::new(0)
# Zero out resize borders when maximized so the entire title bar row is draggable
if ($chrome) { $chrome.ResizeBorderThickness = [System.Windows.Thickness]::new(0) }
}
else {
$mainBorder.Margin = [System.Windows.Thickness]::new(0)
$mainBorder.BorderThickness = [System.Windows.Thickness]::new(1)
$mainBorder.CornerRadius = [System.Windows.CornerRadius]::new(8)
$mainBorder.Effect = $normalWindowShadow
$titleBarBackground.CornerRadius = [System.Windows.CornerRadius]::new(8, 8, 0, 0)
if ($chrome) { $chrome.ResizeBorderThickness = [System.Windows.Thickness]::new(5) }
}
}
$applyInitialWindowSize = {
if ($window.WindowState -ne $windowStateNormal) {
return
}
$screen = & $getWindowScreen
if ($null -eq $screen) {
return
}
$workingAreaDip = & $convertScreenPixelsToDip $screen.WorkingArea.Width $screen.WorkingArea.Height
$window.Width = [Math]::Min($initialNormalMaxWidth, $workingAreaDip.Width)
$window.Left = $screen.WorkingArea.Left + (($workingAreaDip.Width - $window.Width) / 2)
}
$window.Add_SourceInitialized({
& $applyInitialWindowSize
& $updateWindowChrome
# Register WM_GETMINMAXINFO hook so maximizing respects the working area (taskbar)
$hwndHelper = New-Object System.Windows.Interop.WindowInteropHelper($window)
$hwndSource = [System.Windows.Interop.HwndSource]::FromHwnd($hwndHelper.Handle)
$hookMethod = [Win11Debloat.MaximizedWindowHelper].GetMethod('WmGetMinMaxInfoHook')
$hook = [System.Delegate]::CreateDelegate([System.Windows.Interop.HwndSourceHook], $hookMethod)
$hwndSource.AddHook($hook)
})
$contentGrid = $window.FindName('ContentGrid')
$maxContentWidth = 1600.0
$updateContentMargin = {
$w = $window.ActualWidth
if ($w -gt $maxContentWidth) {
$gutter = [Math]::Floor(($w - $maxContentWidth) / 2)
$contentGrid.Margin = [System.Windows.Thickness]::new($gutter, 0, $gutter, 0)
} else {
$contentGrid.Margin = [System.Windows.Thickness]::new(0)
}
}
$window.Add_SizeChanged({ & $updateContentMargin })
$window.Add_StateChanged({
& $updateWindowChrome
})
$window.Add_LocationChanged({
# Nudge the popup offset to force WPF to recalculate its screen position
if ($script:BubblePopup -and $script:BubblePopup.IsOpen) {
$script:BubblePopup.HorizontalOffset += 1
$script:BubblePopup.HorizontalOffset -= 1
}
})
@@ -94,135 +223,6 @@ function Show-MainWindow {
$script:CancelRequested = $true
})
# Implement window resize functionality
$resizeLeft = $window.FindName('ResizeLeft')
$resizeRight = $window.FindName('ResizeRight')
$resizeTop = $window.FindName('ResizeTop')
$resizeBottom = $window.FindName('ResizeBottom')
$resizeTopLeft = $window.FindName('ResizeTopLeft')
$resizeTopRight = $window.FindName('ResizeTopRight')
$resizeBottomLeft = $window.FindName('ResizeBottomLeft')
$resizeBottomRight = $window.FindName('ResizeBottomRight')
$script:resizing = $false
$script:resizeEdges = $null
$script:resizeStart = $null
$script:windowStart = $null
$script:resizeElement = $null
$resizeHandler = {
param($sender, $e)
$script:resizing = $true
$script:resizeElement = $sender
$script:resizeStart = [System.Windows.Forms.Cursor]::Position
$script:windowStart = @{
Left = $window.Left
Top = $window.Top
Width = $window.ActualWidth
Height = $window.ActualHeight
}
# Parse direction tag into edge flags for cleaner resize logic
$direction = $sender.Tag
$script:resizeEdges = @{
Left = $direction -match 'Left'
Right = $direction -match 'Right'
Top = $direction -match 'Top'
Bottom = $direction -match 'Bottom'
}
$sender.CaptureMouse()
$e.Handled = $true
}
$moveHandler = {
param($sender, $e)
if (-not $script:resizing) { return }
$current = [System.Windows.Forms.Cursor]::Position
$deltaX = $current.X - $script:resizeStart.X
$deltaY = $current.Y - $script:resizeStart.Y
# Handle horizontal resize
if ($script:resizeEdges.Left) {
$newWidth = [Math]::Max($window.MinWidth, $script:windowStart.Width - $deltaX)
if ($newWidth -ne $window.Width) {
$window.Left = $script:windowStart.Left + ($script:windowStart.Width - $newWidth)
$window.Width = $newWidth
}
}
elseif ($script:resizeEdges.Right) {
$window.Width = [Math]::Max($window.MinWidth, $script:windowStart.Width + $deltaX)
}
# Handle vertical resize
if ($script:resizeEdges.Top) {
$newHeight = [Math]::Max($window.MinHeight, $script:windowStart.Height - $deltaY)
if ($newHeight -ne $window.Height) {
$window.Top = $script:windowStart.Top + ($script:windowStart.Height - $newHeight)
$window.Height = $newHeight
}
}
elseif ($script:resizeEdges.Bottom) {
$window.Height = [Math]::Max($window.MinHeight, $script:windowStart.Height + $deltaY)
}
$e.Handled = $true
}
$releaseHandler = {
param($sender, $e)
if ($script:resizing -and $script:resizeElement) {
$script:resizing = $false
$script:resizeEdges = $null
$script:resizeElement.ReleaseMouseCapture()
$script:resizeElement = $null
$e.Handled = $true
}
}
# Set tags and add event handlers for resize borders
$resizeLeft.Tag = 'Left'
$resizeLeft.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeLeft.Add_MouseMove($moveHandler)
$resizeLeft.Add_MouseLeftButtonUp($releaseHandler)
$resizeRight.Tag = 'Right'
$resizeRight.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeRight.Add_MouseMove($moveHandler)
$resizeRight.Add_MouseLeftButtonUp($releaseHandler)
$resizeTop.Tag = 'Top'
$resizeTop.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeTop.Add_MouseMove($moveHandler)
$resizeTop.Add_MouseLeftButtonUp($releaseHandler)
$resizeBottom.Tag = 'Bottom'
$resizeBottom.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeBottom.Add_MouseMove($moveHandler)
$resizeBottom.Add_MouseLeftButtonUp($releaseHandler)
$resizeTopLeft.Tag = 'TopLeft'
$resizeTopLeft.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeTopLeft.Add_MouseMove($moveHandler)
$resizeTopLeft.Add_MouseLeftButtonUp($releaseHandler)
$resizeTopRight.Tag = 'TopRight'
$resizeTopRight.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeTopRight.Add_MouseMove($moveHandler)
$resizeTopRight.Add_MouseLeftButtonUp($releaseHandler)
$resizeBottomLeft.Tag = 'BottomLeft'
$resizeBottomLeft.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeBottomLeft.Add_MouseMove($moveHandler)
$resizeBottomLeft.Add_MouseLeftButtonUp($releaseHandler)
$resizeBottomRight.Tag = 'BottomRight'
$resizeBottomRight.Add_PreviewMouseLeftButtonDown($resizeHandler)
$resizeBottomRight.Add_MouseMove($moveHandler)
$resizeBottomRight.Add_MouseLeftButtonUp($releaseHandler)
# Integrated App Selection UI
$appsPanel = $window.FindName('AppSelectionPanel')
$onlyInstalledAppsBox = $window.FindName('OnlyInstalledAppsBox')
@@ -242,6 +242,32 @@ function Show-MainWindow {
$presetsArrow = $window.FindName('PresetsArrow')
$clearAppSelectionBtn = $window.FindName('ClearAppSelectionBtn')
function NormalizeCheckboxState {
param([System.Windows.Controls.CheckBox]$checkBox)
$isChecked = ($checkBox.IsChecked -eq $true)
if ($null -eq $checkBox.IsChecked) {
$checkBox.IsChecked = $false
return $false
}
return $isChecked
}
function AnimatePresetsArrow {
param([double]$angle)
$animation = New-Object System.Windows.Media.Animation.DoubleAnimation
$animation.To = $angle
$animation.Duration = [System.Windows.Duration]::new([System.TimeSpan]::FromMilliseconds(200))
$ease = New-Object System.Windows.Media.Animation.CubicEase
$ease.EasingMode = 'EaseOut'
$animation.EasingFunction = $ease
$presetsArrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
}
# Load JSON-defined presets and build dynamic preset checkboxes
$script:JsonPresetCheckboxes = @()
foreach ($preset in (LoadAppPresetsFromJson)) {
@@ -256,8 +282,7 @@ function Show-MainWindow {
$checkbox.Add_Click({
if ($script:UpdatingPresets) { return }
$check = ($this.IsChecked -eq $true)
if ($this.IsChecked -eq $null) { $this.IsChecked = $false; $check = $false }
$check = NormalizeCheckboxState -checkBox $this
$presetIds = $this.PresetAppIds
ApplyPresetToApps -MatchFilter { param($c) (@($c.AppIds) | Where-Object { $presetIds -contains $_ }).Count -gt 0 }.GetNewClosure() -Check $check
})
@@ -590,8 +615,8 @@ function Show-MainWindow {
$helpBtn.Tag = (GetWikiUrlForCategory -category $categoryName)
$helpBtn.Style = $window.Resources['CategoryHelpLinkButtonStyle']
$helpBtn.Add_Click({
param($sender, $e)
if ($sender.Tag) { Start-Process $sender.Tag }
param($button, $e)
if ($button.Tag) { Start-Process $button.Tag }
})
$headerRow.Children.Add($helpBtn) | Out-Null
@@ -918,29 +943,19 @@ function Show-MainWindow {
# Animate arrow when popup opens/closes, and lazily update preset states
$presetsPopup.Add_Opened({
UpdatePresetStates
$animation = New-Object System.Windows.Media.Animation.DoubleAnimation
$animation.To = 180
$animation.Duration = [System.Windows.Duration]::new([System.TimeSpan]::FromMilliseconds(200))
$animation.EasingFunction = New-Object System.Windows.Media.Animation.CubicEase
$animation.EasingFunction.EasingMode = 'EaseOut'
$presetsArrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
AnimatePresetsArrow -angle 180
})
$presetsPopup.Add_Closed({
$animation = New-Object System.Windows.Media.Animation.DoubleAnimation
$animation.To = 0
$animation.Duration = [System.Windows.Duration]::new([System.TimeSpan]::FromMilliseconds(200))
$animation.EasingFunction = New-Object System.Windows.Media.Animation.CubicEase
$animation.EasingFunction.EasingMode = 'EaseOut'
$presetsArrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
AnimatePresetsArrow -angle 0
$presetsBtn.IsChecked = $false
})
# Close popup when clicking anywhere outside the popup or the presets button.
$window.Add_PreviewMouseDown({
if (-not $presetsPopup.IsOpen) { return }
if ($presetsPopup.Child -ne $null -and $presetsPopup.Child.IsMouseOver) { return }
if ($null -ne $presetsPopup.Child -and $presetsPopup.Child.IsMouseOver) { return }
$src = $_.OriginalSource -as [System.Windows.DependencyObject]
if ($src -ne $null) {
if ($null -ne $src) {
$inBtn = $presetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($presetsBtn, $src)
if (-not $inBtn) { $presetsPopup.IsOpen = $false }
}
@@ -960,8 +975,7 @@ function Show-MainWindow {
# Preset: Default selection
$presetDefaultApps.Add_Click({
if ($script:UpdatingPresets) { return }
$check = ($this.IsChecked -eq $true)
if ($this.IsChecked -eq $null) { $this.IsChecked = $false; $check = $false }
$check = NormalizeCheckboxState -checkBox $this
ApplyPresetToApps -MatchFilter { param($c) $c.SelectedByDefault -eq $true } -Check $check
})
@@ -1078,7 +1092,7 @@ function Show-MainWindow {
})
$appSearchBox.Add_KeyDown({
param($sender, $e)
param($sourceControl, $e)
if ($e.Key -eq [System.Windows.Input.Key]::Enter -and $script:AppSearchMatches.Count -gt 0) {
# Reset background of current active match
$script:AppSearchMatches[$script:AppSearchMatchIndex].Background = $window.Resources["SearchHighlightColor"]
@@ -1201,7 +1215,7 @@ function Show-MainWindow {
# Add Ctrl+F keyboard shortcut to focus search box on current tab
$window.Add_KeyDown({
param($sender, $e)
param($sourceControl, $e)
# Check if Ctrl+F was pressed
if ($e.Key -eq [System.Windows.Input.Key]::F -and
@@ -1786,8 +1800,7 @@ function Show-MainWindow {
$presetLastUsed.Add_Click({
if ($script:UpdatingPresets) { return }
$check = ($this.IsChecked -eq $true)
if ($this.IsChecked -eq $null) { $this.IsChecked = $false; $check = $false }
$check = NormalizeCheckboxState -checkBox $this
ApplyPresetToApps -MatchFilter { param($c) (@($c.AppIds) | Where-Object { $script:SavedAppIds -contains $_ }).Count -gt 0 } -Check $check
})
}
@@ -1822,5 +1835,12 @@ function Show-MainWindow {
}
# Show the window
return $window.ShowDialog()
$frame = [System.Windows.Threading.DispatcherFrame]::new()
$window.Add_Closed({
$frame.Continue = $false
})
$window.Show() | Out-Null
[System.Windows.Threading.Dispatcher]::PushFrame($frame)
return $null
}

View File

@@ -96,7 +96,11 @@ param (
[switch]$HideMusic,
[switch]$HideIncludeInLibrary,
[switch]$HideGiveAccessTo,
[switch]$HideShare
[switch]$HideShare,
[switch]$ShowDriveLettersFirst,
[switch]$ShowDriveLettersLast,
[switch]$ShowNetworkDriveLettersFirst,
[switch]$HideDriveLetters
)
# Show error if current powershell environment does not have LanguageMode set to FullLanguage

View File

@@ -98,13 +98,17 @@ param (
[switch]$HideMusic,
[switch]$HideIncludeInLibrary,
[switch]$HideGiveAccessTo,
[switch]$HideShare
[switch]$HideShare,
[switch]$ShowDriveLettersFirst,
[switch]$ShowDriveLettersLast,
[switch]$ShowNetworkDriveLettersFirst,
[switch]$HideDriveLetters
)
# Define script-level variables & paths
$script:Version = "2026.03.15"
$script:Version = "2026.04.04"
$script:AppsListFilePath = "$PSScriptRoot/Config/Apps.json"
$script:DefaultSettingsFilePath = "$PSScriptRoot/Config/DefaultSettings.json"
$script:FeaturesFilePath = "$PSScriptRoot/Config/Features.json"
@@ -357,6 +361,9 @@ if ((Test-Path $script:SavedSettingsFilePath) -and ([String]::IsNullOrWhiteSpace
Remove-Item -Path $script:SavedSettingsFilePath -recurse
}
# Default to CLI mode for deployment-targeted parameters.
$launchInCLI = $CLI -or $script:Params.ContainsKey("User") -or $script:Params.ContainsKey("Sysprep") -or $script:Params.ContainsKey("AppRemovalTarget")
# Only run the app selection form if the 'RunAppsListGenerator' parameter was passed to the script
if ($RunAppsListGenerator) {
PrintHeader "Custom Apps List Generator"
@@ -405,7 +412,7 @@ if ((-not $script:Params.Count) -or $RunDefaults -or $RunDefaultsLite -or $RunSa
}
}
else {
if ($CLI) {
if ($launchInCLI) {
$Mode = ShowCLIMenuOptions
}
else {