terminal/src/cascadia/TerminalSettingsEditor/Profiles.xaml
Leonard Hecker e49d180e13 Allow generated profiles to be deleted (#11007)
Re-enables the delete button for generated profiles in the settings UI.
Additionally fixes "Startup Profiles" to only list active profiles.

Profiles are considered deleted if they're absent from settings.json, but their
GUID has been encountered before. Or in other words, from a user's perspective:
Generated profiles are added to the settings.json automatically only once.
Thus if the user chooses to delete the profile (e.g. using the delete button)
they aren't re-added automatically and thus appear to have been deleted.

Meanwhile those generated profiles are actually only marked as "hidden"
as well as "deleted", but still exist in internal profile lists.
The "hidden" attribute hides them from all existing menus. The "deleted" one
hides them from the settings UI and prevents them from being written to disk.

It would've been preferrable of course to just not generate and
add deleted profile to internal profile lists in the first place.
But this would've required far more wide-reaching changes.
The settings UI for instance requires a list of _all_ profiles in order to
allow a user to re-create previously deleted profiles. Such an approach was
attempted but discarded because of it's current complexity overhead.

* Part of #9997
* A sequel to 5d36e5d

* [x] Closes #10960
* [x] I work here
* [x] Tests added/passed

* "Startup Profiles" doesn't list deleted profiles ✔️
* Manually removing an item from settings.json removes the profile ✔️
* Removing cmd.exe and saving doesn't create empty objects (#10960) ✔️
* "Add a new profile" lists deleted profiles ✔️
* "Duplicate" recreates previously deleted profiles ✔️
* Profiles are always created with GUIDs ✔️
2021-08-25 18:00:41 -05:00

407 lines
28 KiB
XML

<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<Page x:Class="Microsoft.Terminal.Settings.Editor.Profiles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:Microsoft.Terminal.Settings.Model"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="EnumRadioButtonTemplate"
x:DataType="local:EnumEntry">
<RadioButton Content="{x:Bind EnumName, Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="EnumComboBoxItemTemplate"
x:DataType="local:EnumEntry">
<TextBlock Text="{x:Bind EnumName, Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="FontFaceComboBoxItemTemplate"
x:DataType="local:Font">
<TextBlock FontFamily="{x:Bind Name}"
Text="{x:Bind LocalizedName}" />
</DataTemplate>
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<local:PercentageConverter x:Key="PercentageConverter" />
<local:PercentageSignConverter x:Key="PercentageSignConverter" />
<local:FontWeightConverter x:Key="FontWeightConverter" />
<local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
<local:StringIsEmptyConverter x:Key="StringIsEmptyConverter" />
<local:PaddingConverter x:Key="PaddingConverter" />
<local:StringIsNotDesktopConverter x:Key="StringIsNotDesktopConverter" />
<local:DesktopWallpaperToEmptyStringConverter x:Key="DesktopWallpaperToEmptyStringConverter" />
</ResourceDictionary>
</Page.Resources>
<!-- Use a Grid instead of a StackPanel. StackPanel suppresses the inner ScrollViewer. -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Profile_BaseLayerDisclaimer"
Grid.Row="0"
Margin="{StaticResource StandardIndentMargin}"
Style="{StaticResource DisclaimerStyle}"
Visibility="{x:Bind State.Profile.IsBaseLayer}" />
<Pivot x:Name="ProfilesPivot"
Grid.Row="1"
Margin="1,0,0,0"
HorizontalAlignment="Left"
SelectionChanged="Pivot_SelectionChanged">
<!-- General Tab -->
<PivotItem x:Uid="Profile_General">
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource PivotStackStyle}">
<!-- Name -->
<!--
NOTE: Has/Clear is not bound because we don't want the reset button & override text to appear.
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
so the name will always be overridden.
-->
<local:SettingContainer x:Uid="Profile_Name"
Margin="0,0,0,24"
Visibility="{x:Bind State.Profile.IsBaseLayer, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Commandline -->
<local:SettingContainer x:Name="CommandlineContainer"
x:Uid="Profile_Commandline"
Margin="0,0,0,24"
ClearSettingValue="{x:Bind State.Profile.ClearCommandline}"
HasSettingValue="{x:Bind State.Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.CommandlineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.IsBaseLayer, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
<StackPanel Orientation="Horizontal">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
Click="Commandline_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Starting Directory -->
<local:SettingContainer x:Name="StartingDirectoryContainer"
x:Uid="Profile_StartingDirectory"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearStartingDirectory}"
HasSettingValue="{x:Bind State.Profile.HasStartingDirectory, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.StartingDirectoryOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.StartingDirectory, Mode=TwoWay}" />
<Button x:Name="StartingDirectoryBrowse"
x:Uid="Profile_StartingDirectoryBrowse"
Click="StartingDirectory_Click"
IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
<CheckBox x:Name="StartingDirectoryUseParentCheckbox"
x:Uid="Profile_StartingDirectoryUseParentCheckbox"
IsChecked="{x:Bind State.Profile.UseParentProcessDirectory, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Icon -->
<local:SettingContainer x:Uid="Profile_Icon"
ClearSettingValue="{x:Bind State.Profile.ClearIcon}"
HasSettingValue="{x:Bind State.Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.IconOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<TextBox FontFamily="Segoe UI, Segoe MDL2 Assets"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Icon, Mode=TwoWay}" />
<Button x:Uid="Profile_IconBrowse"
Click="Icon_Click"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
</local:SettingContainer>
<!-- Tab Title -->
<local:SettingContainer x:Uid="Profile_TabTitle"
ClearSettingValue="{x:Bind State.Profile.ClearTabTitle}"
HasSettingValue="{x:Bind State.Profile.HasTabTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.TabTitleOverrideSource, Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Hidden -->
<local:SettingContainer x:Uid="Profile_Hidden"
Visibility="{x:Bind State.Profile.IsBaseLayer, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
<ToggleSwitch IsOn="{x:Bind State.Profile.Hidden, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Delete Button -->
<Button x:Name="DeleteButton"
Margin="{StaticResource StandardControlMargin}"
Style="{StaticResource DeleteButtonStyle}"
Visibility="{x:Bind State.Profile.CanDeleteProfile}">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonBackground"
Color="Firebrick" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#C23232" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#A21212" />
<SolidColorBrush x:Key="ButtonForeground"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="White" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="White" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="ButtonBackground"
Color="{ThemeResource SystemColorButtonFaceColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="ButtonForeground"
Color="{ThemeResource SystemColorButtonTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="{ThemeResource SystemColorHighlightTextColor}" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="{ThemeResource SystemColorHighlightTextColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Button.Resources>
<Button.Content>
<StackPanel Orientation="Horizontal">
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE74D;" />
<TextBlock x:Uid="Profile_DeleteButton"
Margin="10,0,0,0" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock x:Uid="Profile_DeleteConfirmationMessage"
Style="{StaticResource CustomFlyoutTextStyle}" />
<Button x:Uid="Profile_DeleteConfirmationButton"
Click="DeleteConfirmation_Click" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</ScrollViewer>
</PivotItem>
<!-- Appearance Tab -->
<PivotItem x:Uid="Profile_Appearance">
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel>
<!-- Control Preview -->
<Border x:Name="ControlPreview"
Width="350"
Height="160"
Margin="0,0,0,12"
HorizontalAlignment="Left"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
BorderThickness="1" />
<local:Appearances Appearance="{x:Bind State.Profile.DefaultAppearance, Mode=OneWay}"
SourceProfile="{x:Bind State.Profile, Mode=OneWay}" />
<!-- Grouping: Acrylic -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_AcrylicHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Use Acrylic -->
<local:SettingContainer x:Uid="Profile_UseAcrylic"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearUseAcrylic}"
HasSettingValue="{x:Bind State.Profile.HasUseAcrylic, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.UseAcrylicOverrideSource, Mode=OneWay}">
<ToggleSwitch x:Name="UseAcrylicToggleSwitch"
IsOn="{x:Bind State.Profile.UseAcrylic, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Acrylic Opacity -->
<local:SettingContainer x:Name="AcrylicOpacityContainer"
x:Uid="Profile_AcrylicOpacity"
ClearSettingValue="{x:Bind State.Profile.ClearAcrylicOpacity}"
HasSettingValue="{x:Bind State.Profile.HasAcrylicOpacity, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.AcrylicOpacityOverrideSource, Mode=OneWay}"
Visibility="{Binding ElementName=UseAcrylicToggleSwitch, Path=IsOn, Mode=OneWay}">
<StackPanel x:Name="AcrylicOpacityControl">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="AcrylicOpacitySlider"
Grid.Column="0"
Value="{x:Bind State.Profile.AcrylicOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=AcrylicOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
</Grid>
</StackPanel>
</local:SettingContainer>
</StackPanel>
<!-- Grouping: Window -->
<StackPanel Style="{StaticResource PivotStackStyle}">
<TextBlock x:Uid="Profile_WindowHeader"
Style="{StaticResource SubtitleTextBlockStyle}" />
<!-- Padding -->
<local:SettingContainer x:Uid="Profile_Padding"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearPadding}"
HasSettingValue="{x:Bind State.Profile.HasPadding, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.PaddingOverrideSource, Mode=OneWay}">
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Slider x:Name="PaddingSlider"
Grid.Column="0"
Value="{x:Bind State.Profile.Padding, Converter={StaticResource PaddingConverter}, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=PaddingSlider, Path=Value, Mode=OneWay}" />
</Grid>
</local:SettingContainer>
<!-- Scrollbar Visibility -->
<local:SettingContainer x:Uid="Profile_ScrollbarVisibility"
ClearSettingValue="{x:Bind State.Profile.ClearScrollState}"
HasSettingValue="{x:Bind State.Profile.HasScrollState, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.ScrollStateOverrideSource, Mode=OneWay}">
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind ScrollStateList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentScrollState, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
</StackPanel>
</ScrollViewer>
</PivotItem>
<!-- Advanced Tab -->
<PivotItem x:Uid="Profile_Advanced">
<ScrollViewer ViewChanging="ViewChanging">
<StackPanel Style="{StaticResource PivotStackStyle}">
<!-- Suppress Application Title -->
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
Margin="0"
ClearSettingValue="{x:Bind State.Profile.ClearSuppressApplicationTitle}"
HasSettingValue="{x:Bind State.Profile.HasSuppressApplicationTitle, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.SuppressApplicationTitleOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.SuppressApplicationTitle, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Antialiasing Mode -->
<local:SettingContainer x:Uid="Profile_AntialiasingMode"
ClearSettingValue="{x:Bind State.Profile.ClearAntialiasingMode}"
HasSettingValue="{x:Bind State.Profile.HasAntialiasingMode, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.AntialiasingModeOverrideSource, Mode=OneWay}">
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind AntiAliasingModeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentAntiAliasingMode, Mode=TwoWay}" />
</local:SettingContainer>
<!-- AltGr Aliasing -->
<local:SettingContainer x:Uid="Profile_AltGrAliasing"
ClearSettingValue="{x:Bind State.Profile.ClearAltGrAliasing}"
HasSettingValue="{x:Bind State.Profile.HasAltGrAliasing, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.AltGrAliasingOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.AltGrAliasing, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Snap On Input -->
<local:SettingContainer x:Uid="Profile_SnapOnInput"
ClearSettingValue="{x:Bind State.Profile.ClearSnapOnInput}"
HasSettingValue="{x:Bind State.Profile.HasSnapOnInput, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.SnapOnInputOverrideSource, Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.SnapOnInput, Mode=TwoWay}" />
</local:SettingContainer>
<!-- History Size -->
<local:SettingContainer x:Uid="Profile_HistorySize"
ClearSettingValue="{x:Bind State.Profile.ClearHistorySize}"
HasSettingValue="{x:Bind State.Profile.HasHistorySize, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.HistorySizeOverrideSource, Mode=OneWay}">
<muxc:NumberBox LargeChange="100"
Minimum="0"
SmallChange="10"
Style="{StaticResource NumberBoxSettingStyle}"
Value="{x:Bind State.Profile.HistorySize, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Close On Exit -->
<local:SettingContainer x:Uid="Profile_CloseOnExit"
ClearSettingValue="{x:Bind State.Profile.ClearCloseOnExit}"
HasSettingValue="{x:Bind State.Profile.HasCloseOnExit, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.CloseOnExitOverrideSource, Mode=OneWay}">
<muxc:RadioButtons ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
ItemsSource="{x:Bind CloseOnExitModeList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentCloseOnExitMode, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Bell Style -->
<local:SettingContainer x:Uid="Profile_BellStyle"
ClearSettingValue="{x:Bind State.Profile.ClearBellStyle}"
HasSettingValue="{x:Bind State.Profile.HasBellStyle, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.BellStyleOverrideSource, Mode=OneWay}">
<StackPanel>
<CheckBox x:Uid="Profile_BellStyleAudible"
IsChecked="{x:Bind IsBellStyleFlagSet(1), BindBack=SetBellStyleAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleWindow"
IsChecked="{x:Bind IsBellStyleFlagSet(2), BindBack=SetBellStyleWindow, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_BellStyleTaskbar"
IsChecked="{x:Bind IsBellStyleFlagSet(4), BindBack=SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
</StackPanel>
</ScrollViewer>
</PivotItem>
</Pivot>
</Grid>
</Page>