Compare commits

..

2 Commits

Author SHA1 Message Date
Dustin L. Howett
8fe6c21ef8 Keep the font size delta across settings reloads (#20230)
This is a trivial fix for an issue we get a somewhat outsized number of
complaints about.

When the user has adjusted the font size in any direction, we'll just
keep track of the magnitude and apply it every time the settings change.

Yes, this means that if you zoom once and then change your real font
size it's going to zoom even more.

That probably doesn't matter.

Refs #11522
2026-05-15 13:56:48 -05:00
aarushi singh
abeac1b135 Use PlaySoundW for profile bell sounds (#20031)
We believed that this would fix an issue on Windows 10, where the volume
mixer would forget Windows Terminal after every relaunch. It turns out
that it does not.

Still, this code is much more concise and doesn't require yet another
WinRT object. Story of our lives.

Refs #17733
2026-05-15 20:51:01 +02:00
27 changed files with 492 additions and 1605 deletions

View File

@@ -1075,6 +1075,7 @@ NOCONTEXTHELP
NOCOPYBITS
nodiscard
NODUP
NODEFAULT
noexcepts
NOFONT
NOHIDDENTEXT
@@ -1561,6 +1562,7 @@ SMARTQUOTE
SMTO
snapcx
snapcy
SND
snk
SOLIDBOX
Solutiondir

View File

@@ -71,18 +71,6 @@ namespace winrt::TerminalApp::implementation
_removeControlEvents();
_control.Close();
// Clear out our media player callbacks, and stop any playing media. This
// will prevent the callback from being triggered after we've closed, and
// also make sure that our sound stops when we're closed.
if (_bellPlayer)
{
_bellPlayer.Pause();
_bellPlayer.Source(nullptr);
_bellPlayer.Close();
_bellPlayer = nullptr;
_bellPlayerCreated = false;
}
}
winrt::hstring TerminalPaneContent::Icon() const
@@ -275,14 +263,15 @@ namespace winrt::TerminalApp::implementation
auto sounds{ _profile.BellSound() };
if (sounds && sounds.Size() > 0)
{
winrt::hstring soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
winrt::Windows::Foundation::Uri uri{ soundPath };
_playBellSound(uri);
// Sound paths are resolved and validated by CascadiaSettings
// before we reach this point.
auto soundPath{ sounds.GetAt(rand() % sounds.Size()).Resolved() };
PlaySoundW(soundPath.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_SENTRY | SND_NODEFAULT);
}
else
{
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
const auto soundAlias = reinterpret_cast<LPCWSTR>(SND_ALIAS_SYSTEMHAND);
PlaySoundW(soundAlias, nullptr, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
}
}
@@ -300,33 +289,6 @@ namespace winrt::TerminalApp::implementation
}
}
safe_void_coroutine TerminalPaneContent::_playBellSound(winrt::Windows::Foundation::Uri uri)
{
auto weakThis{ get_weak() };
co_await wil::resume_foreground(_control.Dispatcher());
if (auto pane{ weakThis.get() })
{
if (!_bellPlayerCreated)
{
// The MediaPlayer might not exist on Windows N SKU.
try
{
_bellPlayerCreated = true;
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
_bellPlayer.CommandManager().IsEnabled(false);
}
CATCH_LOG();
}
if (_bellPlayer)
{
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
_bellPlayer.Source(item);
_bellPlayer.Play();
}
}
}
void TerminalPaneContent::_closeTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{

View File

@@ -76,9 +76,6 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<TerminalSettingsCache> _cache{};
bool _isDefTermSession{ false };
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
bool _bellPlayerCreated{ false };
struct ControlEventTokens
{
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
@@ -96,8 +93,6 @@ namespace winrt::TerminalApp::implementation
void _setupControlEvents();
void _removeControlEvents();
safe_void_coroutine _playBellSound(winrt::Windows::Foundation::Uri uri);
safe_void_coroutine _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);

View File

@@ -925,7 +925,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Manually turn off acrylic if they turn off transparency.
_runtimeUseAcrylic = _settings.Opacity() < 1.0 && _settings.UseAcrylic();
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize());
const auto sizeChanged = _setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta);
// Update the terminal core with its new Core settings
_terminal->UpdateSettings(_settings);
@@ -1163,11 +1163,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - none
void ControlCore::ResetFontSize()
{
const auto lock = _terminal->LockForWriting();
if (_setFontSizeUnderLock(_settings.FontSize()))
if (std::exchange(_accumulatedFontSizeDelta, 0.f) != 0.f)
{
_refreshSizeUnderLock();
// No point in doing this if there was no delta.
AdjustFontSize(0);
}
}
@@ -1177,9 +1176,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - fontSizeDelta: The amount to increase or decrease the font size by.
void ControlCore::AdjustFontSize(float fontSizeDelta)
{
_accumulatedFontSizeDelta += fontSizeDelta;
const auto lock = _terminal->LockForWriting();
if (_setFontSizeUnderLock(_desiredFont.GetFontSize() + fontSizeDelta))
if (_setFontSizeUnderLock(_settings.FontSize() + _accumulatedFontSizeDelta))
{
_refreshSizeUnderLock();
}

View File

@@ -391,6 +391,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _colorGlyphs = true;
CSSLengthPercentage _cellWidth;
CSSLengthPercentage _cellHeight;
float _accumulatedFontSizeDelta = 0.f; // Preserved across reloads to prevent user zoom from being overwritten.
// Rendering stuff.
winrt::handle _lastSwapChainHandle{ nullptr };

View File

@@ -81,7 +81,7 @@
CurrentValueAccessibleName="{x:Bind Appearance.CurrentColorScheme.Name, Mode=OneWay}"
HasSettingValue="{x:Bind Appearance.HasDarkColorSchemeName, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.DarkColorSchemeNameOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:SettingContainer.CurrentValue>
<ComboBox Padding="4"
ItemsSource="{x:Bind Appearance.SchemesList, Mode=OneWay}"
@@ -220,7 +220,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasForeground, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.ForegroundOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:NullableColorPicker x:Uid="Profile_Foreground_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.Foreground, Mode=TwoWay}"
@@ -236,7 +236,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasBackground, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.BackgroundOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:NullableColorPicker x:Uid="Profile_Background_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.Background, Mode=TwoWay}"
@@ -252,7 +252,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasSelectionBackground, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.SelectionBackgroundOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:NullableColorPicker x:Uid="Profile_SelectionBackground_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.SelectionBackground, Mode=TwoWay}"
@@ -536,7 +536,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Appearance.HasCursorColor, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.CursorColorOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:NullableColorPicker x:Uid="Profile_CursorColor_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.CursorColor, Mode=TwoWay}"

View File

@@ -8,9 +8,8 @@
xmlns:mtu="using:Microsoft.Terminal.UI"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls">
<!-- Merge SettingsControls and SettingContainer styles here to give every page access to them -->
<!-- Merge SettingContainerStyle here to give every page access to the SettingContainer -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="SettingsControlsStyle.xaml" />
<ResourceDictionary Source="SettingContainerStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
@@ -1201,6 +1200,87 @@
</Setter>
</Style>
<Style x:Key="NavigatorButtonStyle"
TargetType="Button">
<Setter Property="Background" Value="{ThemeResource ExpanderHeaderBackground}" />
<Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
<Setter Property="MinHeight" Value="64" />
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderHeaderBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderHeaderBorderBrush}" />
<Setter Property="Padding" Value="16,0,8,0" />
<Setter Property="Margin" Value="0,4,0,0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="Grid"
Padding="{TemplateBinding Padding}"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="ContentPresenter"
Grid.Column="0"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
<FontIcon Grid.Column="1"
Margin="20,0,8,0"
HorizontalAlignment="Right"
FontSize="10"
FontWeight="Black"
Glyph="&#xE76C;" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ToggleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="NewInfoBadge"
TargetType="muxc:InfoBadge">
<Setter Property="Padding" Value="5,1,5,2" />

View File

@@ -79,7 +79,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void Extensions::ExtensionNavigator_Click(const IInspectable& sender, const RoutedEventArgs& /*args*/)
{
const auto extPkgVM = sender.as<FrameworkElement>().Tag().as<Editor::ExtensionPackageViewModel>();
const auto extPkgVM = sender.as<Controls::Button>().Tag().as<Editor::ExtensionPackageViewModel>();
_ViewModel.CurrentExtensionPackage(extPkgVM);
}

View File

@@ -127,58 +127,78 @@
<DataTemplate x:Key="DefaultExtensionNavigatorTemplate"
x:DataType="local:ExtensionPackageViewModel">
<local:SettingsCard AutomationProperties.Name="{x:Bind AccessibleName}"
Click="ExtensionNavigator_Click"
Header="{x:Bind Package.Source}"
IsClickEnabled="True"
Tag="{x:Bind}">
<local:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE74C;" />
</local:SettingsCard.HeaderIcon>
<ToggleSwitch HorizontalAlignment="Right"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind AccessibleName}"
IsOn="{x:Bind Enabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingsCard>
<Button AutomationProperties.Name="{x:Bind AccessibleName}"
Click="ExtensionNavigator_Click"
Style="{StaticResource NavigatorButtonStyle}"
Tag="{x:Bind}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Content="{x:Bind}"
ContentTemplate="{StaticResource DefaultExtensionIdentifierTemplate}" />
<ToggleSwitch Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind AccessibleName}"
IsOn="{x:Bind Enabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</Grid>
</Button>
</DataTemplate>
<DataTemplate x:Key="ComplexExtensionNavigatorTemplate"
x:DataType="local:ExtensionPackageViewModel">
<local:SettingsCard AutomationProperties.Name="{x:Bind AccessibleName}"
Click="ExtensionNavigator_Click"
Description="{x:Bind Package.Source}"
Header="{x:Bind Package.DisplayName}"
IsClickEnabled="True"
Tag="{x:Bind}">
<local:SettingsCard.HeaderIcon>
<IconSourceElement IconSource="{x:Bind mtu:IconPathConverter.IconSourceWUX(Package.Icon)}" />
</local:SettingsCard.HeaderIcon>
<ToggleSwitch HorizontalAlignment="Right"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind AccessibleName}"
IsOn="{x:Bind Enabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingsCard>
<Button AutomationProperties.Name="{x:Bind AccessibleName}"
Click="ExtensionNavigator_Click"
Style="{StaticResource NavigatorButtonStyle}"
Tag="{x:Bind}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Content="{x:Bind}"
ContentTemplate="{StaticResource ComplexExtensionIdentifierTemplate}" />
<ToggleSwitch Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind AccessibleName}"
IsOn="{x:Bind Enabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</Grid>
</Button>
</DataTemplate>
<DataTemplate x:Key="ComplexExtensionNavigatorTemplateWithFontIcon"
x:DataType="local:ExtensionPackageViewModel">
<local:SettingsCard AutomationProperties.Name="{x:Bind AccessibleName}"
Click="ExtensionNavigator_Click"
Description="{x:Bind Package.Source}"
Header="{x:Bind Package.DisplayName}"
IsClickEnabled="True"
Tag="{x:Bind}">
<local:SettingsCard.HeaderIcon>
<FontIcon Glyph="{x:Bind Package.Icon}" />
</local:SettingsCard.HeaderIcon>
<ToggleSwitch HorizontalAlignment="Right"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind AccessibleName}"
IsOn="{x:Bind Enabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</local:SettingsCard>
<Button AutomationProperties.Name="{x:Bind AccessibleName}"
Click="ExtensionNavigator_Click"
Style="{StaticResource NavigatorButtonStyle}"
Tag="{x:Bind}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Content="{x:Bind}"
ContentTemplate="{StaticResource ComplexExtensionIdentifierTemplateWithFontIcon}" />
<ToggleSwitch Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
AutomationProperties.Name="{x:Bind AccessibleName}"
IsOn="{x:Bind Enabled, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
</Grid>
</Button>
</DataTemplate>
<DataTemplate x:Key="FragmentProfileViewModelTemplate"
@@ -482,11 +502,9 @@
<!-- Scope -->
<local:SettingContainer x:Name="Scope"
x:Uid="Extensions_Scope"
IsTabStop="False">
<TextBlock VerticalAlignment="Center"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind ViewModel.CurrentExtensionPackage.Scope, Mode=OneWay}" />
</local:SettingContainer>
Content="{x:Bind ViewModel.CurrentExtensionPackage.Scope, Mode=OneWay}"
IsTabStop="False"
Style="{StaticResource SettingContainerWithTextContent}" />
<!-- JSON -->
<ItemsControl IsTabStop="False"
ItemTemplate="{StaticResource JsonTemplate}"

View File

@@ -173,15 +173,6 @@
<ClInclude Include="SettingContainer.h">
<DependentUpon>SettingContainer.idl</DependentUpon>
</ClInclude>
<ClInclude Include="SettingsCard.h">
<DependentUpon>SettingsCard.idl</DependentUpon>
</ClInclude>
<ClInclude Include="SettingsExpander.h">
<DependentUpon>SettingsExpander.idl</DependentUpon>
</ClInclude>
<ClInclude Include="StringDefaultTemplateSelector.h">
<DependentUpon>StringDefaultTemplateSelector.idl</DependentUpon>
</ClInclude>
<ClInclude Include="Utils.h" />
<ClInclude Include="PreviewConnection.h" />
<ClInclude Include="$(GeneratedFilesDir)GeneratedSettingsIndex.g.h" />
@@ -261,9 +252,6 @@
<Page Include="SettingContainerStyle.xaml">
<Type>DefaultStyle</Type>
</Page>
<Page Include="SettingsControlsStyle.xaml">
<Type>DefaultStyle</Type>
</Page>
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
@@ -397,15 +385,6 @@
<ClCompile Include="SettingContainer.cpp">
<DependentUpon>SettingContainer.idl</DependentUpon>
</ClCompile>
<ClCompile Include="SettingsCard.cpp">
<DependentUpon>SettingsCard.idl</DependentUpon>
</ClCompile>
<ClCompile Include="SettingsExpander.cpp">
<DependentUpon>SettingsExpander.idl</DependentUpon>
</ClCompile>
<ClCompile Include="StringDefaultTemplateSelector.cpp">
<DependentUpon>StringDefaultTemplateSelector.idl</DependentUpon>
</ClCompile>
<ClCompile Include="Utils.cpp" />
<ClCompile Include="PreviewConnection.cpp">
<DependentUpon>PreviewConnection.h</DependentUpon>
@@ -513,15 +492,6 @@
<Midl Include="SettingContainer.idl">
<SubType>Code</SubType>
</Midl>
<Midl Include="SettingsCard.idl">
<SubType>Code</SubType>
</Midl>
<Midl Include="SettingsExpander.idl">
<SubType>Code</SubType>
</Midl>
<Midl Include="StringDefaultTemplateSelector.idl">
<SubType>Code</SubType>
</Midl>
</ItemGroup>
<!-- ========================= Misc Files ======================== -->
<ItemGroup>

View File

@@ -30,9 +30,6 @@
<Midl Include="LaunchViewModel.idl" />
<Midl Include="EnumEntry.idl" />
<Midl Include="SettingContainer.idl" />
<Midl Include="SettingsCard.idl" />
<Midl Include="SettingsExpander.idl" />
<Midl Include="StringDefaultTemplateSelector.idl" />
<Midl Include="TerminalColorConverters.idl" />
<Midl Include="NewTabMenuViewModel.idl" />
</ItemGroup>
@@ -55,7 +52,6 @@
<Page Include="Actions.xaml" />
<Page Include="EditAction.xaml" />
<Page Include="SettingContainerStyle.xaml" />
<Page Include="SettingsControlsStyle.xaml" />
<Page Include="AddProfile.xaml" />
<Page Include="KeyChordListener.xaml" />
<Page Include="NullableColorPicker.xaml" />

View File

@@ -332,7 +332,7 @@
<local:SettingContainer x:Name="CurrentFolderIcon"
x:Uid="NewTabMenu_CurrentFolderIcon"
CurrentValueAccessibleName="{x:Bind ViewModel.CurrentFolderLocalizedIcon, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:SettingContainer.CurrentValue>
<Grid>
<ContentControl Width="16"
@@ -378,7 +378,8 @@
<!-- Add Profile -->
<local:SettingContainer x:Name="AddProfile"
x:Uid="NewTabMenu_AddProfile"
FontIconGlyph="&#xE756;">
FontIconGlyph="&#xE756;"
Style="{StaticResource SettingContainerWithIcon}">
<StackPanel Orientation="Horizontal"
Spacing="4">
@@ -427,7 +428,8 @@
<!-- Add Separator -->
<local:SettingContainer x:Name="AddSeparator"
x:Uid="NewTabMenu_AddSeparator"
FontIconGlyph="&#xE76f;">
FontIconGlyph="&#xE76f;"
Style="{StaticResource SettingContainerWithIcon}">
<Button x:Name="AddSeparatorButton"
x:Uid="NewTabMenu_AddSeparatorButton"
HorizontalAlignment="Stretch"
@@ -443,7 +445,8 @@
<!-- Add Folder -->
<local:SettingContainer x:Name="AddFolder"
x:Uid="NewTabMenu_AddFolder"
FontIconGlyph="&#xF12B;">
FontIconGlyph="&#xF12B;"
Style="{StaticResource SettingContainerWithIcon}">
<StackPanel Orientation="Horizontal"
Spacing="5">
<TextBox x:Name="FolderNameTextBox"
@@ -470,7 +473,7 @@
<local:SettingContainer x:Name="AddMatchProfiles"
x:Uid="NewTabMenu_AddMatchProfiles"
FontIconGlyph="&#xE748;"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithIcon}">
<StackPanel Spacing="8">
<HyperlinkButton x:Uid="NewTabMenu_AddMatchProfiles_Help"
NavigateUri="https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference" />
@@ -497,7 +500,8 @@
<!-- Add Remaining Profiles -->
<local:SettingContainer x:Name="AddRemainingProfiles"
x:Uid="NewTabMenu_AddRemainingProfiles"
FontIconGlyph="&#xE902;">
FontIconGlyph="&#xE902;"
Style="{StaticResource SettingContainerWithIcon}">
<Button x:Name="AddRemainingProfilesButton"
x:Uid="NewTabMenu_AddRemainingProfilesButton"
HorizontalAlignment="Stretch"

View File

@@ -22,9 +22,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value<hstring>(startingDirCheckboxTooltip));
Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
AppearanceNavigator().Header(box_value(RS_(L"Profile_Appearance/Header")));
TerminalNavigator().Header(box_value(RS_(L"Profile_Terminal/Header")));
AdvancedNavigator().Header(box_value(RS_(L"Profile_Advanced/Header")));
AppearanceNavigator().Content(box_value(RS_(L"Profile_Appearance/Header")));
TerminalNavigator().Content(box_value(RS_(L"Profile_Terminal/Header")));
AdvancedNavigator().Content(box_value(RS_(L"Profile_Advanced/Header")));
}
void Profiles_Base::OnNavigatedTo(const NavigationEventArgs& e)

View File

@@ -106,7 +106,7 @@
CurrentValueAccessibleName="{x:Bind Profile.LocalizedIcon, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.IconOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:SettingContainer.CurrentValue>
<Grid>
<ContentControl Width="16"
@@ -150,7 +150,7 @@
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Profile.HasTabColor, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabColorOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
<local:NullableColorPicker x:Uid="Profile_TabColor_NullableColorPicker"
ColorSchemeVM="{x:Bind Profile.DefaultAppearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Profile.TabColor, Mode=TwoWay}"
@@ -179,15 +179,15 @@
Margin="0,32,0,4"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<local:SettingsCard x:Name="AppearanceNavigator"
Click="Appearance_Click"
IsClickEnabled="True" />
<local:SettingsCard x:Name="TerminalNavigator"
Click="Terminal_Click"
IsClickEnabled="True" />
<local:SettingsCard x:Name="AdvancedNavigator"
Click="Advanced_Click"
IsClickEnabled="True" />
<Button x:Name="AppearanceNavigator"
Click="Appearance_Click"
Style="{StaticResource NavigatorButtonStyle}" />
<Button x:Name="TerminalNavigator"
Click="Terminal_Click"
Style="{StaticResource NavigatorButtonStyle}" />
<Button x:Name="AdvancedNavigator"
Click="Advanced_Click"
Style="{StaticResource NavigatorButtonStyle}" />
<!-- Delete Button -->
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
<Button x:Name="DeleteButton"

View File

@@ -3,7 +3,6 @@
#include "pch.h"
#include "SettingContainer.h"
#include "SettingsExpander.h"
#include "SettingContainer.g.cpp"
using namespace winrt::Windows::UI::Xaml;
@@ -55,7 +54,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
L"FontIconGlyph",
xaml_typename<hstring>(),
xaml_typename<Editor::SettingContainer>(),
PropertyMetadata{ box_value(L""), PropertyChangedCallback{ &SettingContainer::_OnFontIconGlyphChanged } });
PropertyMetadata{ box_value(L"") });
}
if (!_CurrentValueProperty)
{
@@ -140,7 +139,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
base.reserve(2);
if (const auto& child{ GetTemplateChild(L"Expander") })
{
if (const auto& expander{ child.try_as<Editor::SettingsExpander>() })
if (const auto& expander{ child.try_as<Microsoft::UI::Xaml::Controls::Expander>() })
{
base.push_back(child);
}
@@ -224,47 +223,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_UpdateOverrideSystem();
_UpdateHelpText();
_UpdateHeaderIcon();
}
void SettingContainer::_UpdateHeaderIcon()
{
Controls::IconElement icon{ nullptr };
if (const auto glyph{ FontIconGlyph() }; !glyph.empty())
{
Controls::FontIcon fi;
fi.Glyph(glyph);
icon = fi;
}
if (const auto& cardChild{ GetTemplateChild(L"Card") })
{
if (const auto& card{ cardChild.try_as<Editor::SettingsCard>() })
{
card.HeaderIcon(icon);
return;
}
}
if (const auto& expanderChild{ GetTemplateChild(L"Expander") })
{
if (const auto& expander{ expanderChild.try_as<Editor::SettingsExpander>() })
{
expander.HeaderIcon(icon);
}
}
}
void SettingContainer::_OnFontIconGlyphChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*args*/)
{
const auto& obj{ d.try_as<Editor::SettingContainer>() };
get_self<SettingContainer>(obj)->_UpdateHeaderIcon();
}
void SettingContainer::SetExpanded(bool expanded)
{
if (const auto& child{ GetTemplateChild(L"Expander") })
{
if (const auto& expander{ child.try_as<Editor::SettingsExpander>() })
if (const auto& expander{ child.try_as<Microsoft::UI::Xaml::Controls::Expander>() })
{
expander.IsExpanded(expanded);
}
@@ -306,7 +271,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
if (const auto& child{ GetTemplateChild(L"Expander") })
{
if (const auto& expander{ child.try_as<Editor::SettingsExpander>() })
if (const auto& expander{ child.try_as<Microsoft::UI::Xaml::Controls::Expander>() })
{
Automation::AutomationProperties::SetName(expander, _GenerateAccessibleName());
}

View File

@@ -48,13 +48,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
static void _OnCurrentValueChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnHasSettingValueChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnHelpTextChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnFontIconGlyphChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static hstring _GenerateOverrideMessage(const IInspectable& settingOrigin);
hstring _GenerateAccessibleName();
void _UpdateOverrideSystem();
void _UpdateHelpText();
void _UpdateCurrentValueAutoProp();
void _UpdateHeaderIcon();
};
}

View File

@@ -18,6 +18,8 @@
</Style>
<SolidColorBrush x:Key="SubgroupHeaderBrush"
Color="{StaticResource TextFillColorSecondary}" />
<StaticResource x:Key="ExpanderHeaderBorderBrush"
ResourceKey="CardStrokeColorDefaultBrush" />
<StaticResource x:Key="SettingContainerErrorSeverityBackgroundBrush"
ResourceKey="SystemFillColorCriticalBackgroundBrush" />
@@ -41,12 +43,16 @@
<StaticResource x:Key="SettingContainerResetButtonIconForeground"
ResourceKey="SystemAccentColorDark2" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Style x:Key="SecondaryTextBlockStyle"
TargetType="TextBlock" />
<!-- Do not mess with the foreground color for High Contrast. Let it ride as is. -->
<SolidColorBrush x:Key="SubgroupHeaderBrush"
Color="{ThemeResource SystemColorWindowTextColor}" />
<StaticResource x:Key="ExpanderHeaderBorderBrush"
ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="SettingContainerErrorSeverityBackgroundBrush"
ResourceKey="SystemColorWindowColorBrush" />
@@ -78,6 +84,8 @@
</Style>
<SolidColorBrush x:Key="SubgroupHeaderBrush"
Color="{StaticResource TextFillColorSecondary}" />
<StaticResource x:Key="ExpanderHeaderBorderBrush"
ResourceKey="CardStrokeColorDefaultBrush" />
<StaticResource x:Key="SettingContainerErrorSeverityBackgroundBrush"
ResourceKey="SystemFillColorCriticalBackgroundBrush" />
@@ -113,6 +121,12 @@
<Thickness x:Key="SettingContainerIconMargin">0,4,8,4</Thickness>
<x:Double x:Key="SettingContainerIconFontSize">16</x:Double>
<Style x:Key="StackPanelInExpanderStyle"
TargetType="StackPanel">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Padding" Value="0,12,0,12" />
</Style>
<Style x:Key="SettingContainerResetButtonStyle"
BasedOn="{StaticResource DefaultButtonStyle}"
TargetType="Button">
@@ -131,6 +145,18 @@
<Setter Property="FontFamily" Value="{ThemeResource SymbolThemeFontFamily}" />
</Style>
<Style x:Key="NonExpanderGrid"
TargetType="Grid">
<Setter Property="Background" Value="{ThemeResource ExpanderHeaderBackground}" />
<Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
<Setter Property="MinHeight" Value="64" />
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderHeaderBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderHeaderBorderBrush}" />
<Setter Property="Padding" Value="16,0,8,0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
</Style>
<Style x:Key="SettingsPageItemHeaderStyle"
BasedOn="{StaticResource BodyTextBlockStyle}"
TargetType="TextBlock">
@@ -152,7 +178,7 @@
BasedOn="{StaticResource SettingsPageItemDescriptionStyle}"
TargetType="TextBlock">
<Setter Property="MaxWidth" Value="248" />
<Setter Property="Margin" Value="0" />
<Setter Property="Margin" Value="0,0,-16,0" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets" />
@@ -163,9 +189,7 @@
Text="{Binding}" />
</DataTemplate>
<local:StringDefaultTemplateSelector x:Key="ExpanderPreviewTemplateSelector"
StringTemplate="{StaticResource ExpanderSettingContainerStringPreviewTemplate}" />
<!-- A setting container for a setting that has no additional options -->
<Style TargetType="local:SettingContainer">
<Setter Property="Margin" Value="0,4,0,0" />
<Setter Property="IsTabStop" Value="False" />
@@ -173,9 +197,14 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<local:SettingsCard x:Name="Card"
Content="{TemplateBinding Content}">
<local:SettingsCard.Header>
<Grid AutomationProperties.Name="{TemplateBinding Header}"
Style="{StaticResource NonExpanderGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
@@ -185,61 +214,257 @@
Style="{StaticResource SettingContainerFontIconStyle}" />
</Button>
</StackPanel>
</local:SettingsCard.Header>
<local:SettingsCard.Description>
<TextBlock x:Name="HelpTextBlock"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</local:SettingsCard.Description>
</local:SettingsCard>
</StackPanel>
<ContentPresenter Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ExpanderSettingContainerStyle"
<!-- A basic setting container displaying immutable text as content -->
<Style x:Key="SettingContainerWithTextContent"
TargetType="local:SettingContainer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<Grid AutomationProperties.Name="{TemplateBinding Header}"
Style="{StaticResource NonExpanderGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
<Button x:Name="ResetButton"
Style="{StaticResource SettingContainerResetButtonStyle}">
<FontIcon Glyph="&#xE845;"
Style="{StaticResource SettingContainerFontIconStyle}" />
</Button>
</StackPanel>
<TextBlock x:Name="HelpTextBlock"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</StackPanel>
<TextBlock Grid.Column="1"
Margin="0,0,8,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--
A setting container for a setting that has no additional options.
Includes space for an icon on the left side of the header.
XAML applies the margin/padding of the icon regardless of its
existence (which caused inconsistent padding). It's easier to just create
another style and move on.
-->
<Style x:Key="SettingContainerWithIcon"
TargetType="local:SettingContainer">
<Setter Property="Margin" Value="0,4,0,0" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<Grid AutomationProperties.Name="{TemplateBinding Header}"
Style="{StaticResource NonExpanderGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<FontIcon Grid.Column="0"
Glyph="{TemplateBinding FontIconGlyph}" />
<StackPanel Grid.Column="1"
Padding="14,12,0,12"
Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
<Button x:Name="ResetButton"
Style="{StaticResource SettingContainerResetButtonStyle}">
<FontIcon Glyph="&#xE845;"
Style="{StaticResource SettingContainerFontIconStyle}" />
</Button>
</StackPanel>
<TextBlock x:Name="HelpTextBlock"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</StackPanel>
<ContentPresenter Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- A setting container which can expand -->
<Style x:Key="ExpanderSettingContainerStyle"
TargetType="local:SettingContainer">
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<local:SettingsExpander x:Name="Expander"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsExpanded="{TemplateBinding StartExpanded}">
<local:SettingsExpander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
<Button x:Name="ResetButton"
Style="{StaticResource SettingContainerResetButtonStyle}">
<FontIcon Glyph="&#xE845;"
Style="{StaticResource SettingContainerFontIconStyle}" />
</Button>
</StackPanel>
</local:SettingsExpander.Header>
<local:SettingsExpander.Description>
<TextBlock x:Name="HelpTextBlock"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</local:SettingsExpander.Description>
<local:SettingsExpander.Content>
<ContentControl MaxWidth="248"
VerticalAlignment="Center"
HorizontalContentAlignment="Right"
Content="{TemplateBinding CurrentValue}"
ContentTemplate="{TemplateBinding CurrentValueTemplate}"
ContentTemplateSelector="{StaticResource ExpanderPreviewTemplateSelector}"
IsTabStop="False" />
</local:SettingsExpander.Content>
<local:SettingsExpander.ItemsHeader>
<ContentPresenter Padding="16,12,16,16"
Content="{TemplateBinding Content}" />
</local:SettingsExpander.ItemsHeader>
</local:SettingsExpander>
<muxc:Expander x:Name="Expander"
Margin="0,4,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Content="{TemplateBinding Content}"
IsExpanded="{TemplateBinding StartExpanded}">
<muxc:Expander.Header>
<Grid MinHeight="64">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<ContentPresenter Content="{TemplateBinding Header}" />
<Button x:Name="ResetButton"
Style="{StaticResource SettingContainerResetButtonStyle}">
<FontIcon Glyph="&#xE845;"
Style="{StaticResource SettingContainerFontIconStyle}" />
</Button>
</StackPanel>
<TextBlock x:Name="HelpTextBlock"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</StackPanel>
<ContentPresenter Grid.Column="1"
Content="{TemplateBinding CurrentValue}"
ContentTemplate="{StaticResource ExpanderSettingContainerStringPreviewTemplate}" />
</Grid>
</muxc:Expander.Header>
</muxc:Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--
A setting container which can expand. Includes space for an icon on the left side of the header.
XAML applies the margin/padding of the icon regardless of its
existence (which caused inconsistent padding). It's easier to just create
another style and move on.
-->
<Style x:Key="ExpanderSettingContainerStyleWithIcon"
TargetType="local:SettingContainer">
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<muxc:Expander x:Name="Expander"
Margin="0,4,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Content="{TemplateBinding Content}"
IsExpanded="{TemplateBinding StartExpanded}">
<muxc:Expander.Header>
<Grid MinHeight="64">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<FontIcon Grid.Column="0"
Glyph="{TemplateBinding FontIconGlyph}" />
<StackPanel Grid.Column="1"
Padding="14,12,0,12"
Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
<Button x:Name="ResetButton"
Style="{StaticResource SettingContainerResetButtonStyle}">
<FontIcon Glyph="&#xE845;"
Style="{StaticResource SettingContainerFontIconStyle}" />
</Button>
</StackPanel>
<TextBlock x:Name="HelpTextBlock"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</StackPanel>
<ContentPresenter Grid.Column="2"
Content="{TemplateBinding CurrentValue}"
ContentTemplate="{StaticResource ExpanderSettingContainerStringPreviewTemplate}" />
</Grid>
</muxc:Expander.Header>
</muxc:Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- A setting container which can expand. Supports data template override for preview -->
<Style x:Key="ExpanderSettingContainerStyleWithComplexPreview"
TargetType="local:SettingContainer">
<Setter Property="MaxWidth" Value="1000" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<muxc:Expander x:Name="Expander"
Margin="0,4,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Content="{TemplateBinding Content}"
IsExpanded="{TemplateBinding StartExpanded}">
<muxc:Expander.Header>
<Grid MinHeight="64">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
<Button x:Name="ResetButton"
Style="{StaticResource SettingContainerResetButtonStyle}">
<FontIcon Glyph="&#xE845;"
Style="{StaticResource SettingContainerFontIconStyle}" />
</Button>
</StackPanel>
<TextBlock x:Name="HelpTextBlock"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</StackPanel>
<ContentPresenter Grid.Column="1"
MaxWidth="248"
Margin="0,0,-16,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="{TemplateBinding CurrentValue}"
ContentTemplate="{TemplateBinding CurrentValueTemplate}" />
</Grid>
</muxc:Expander.Header>
</muxc:Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
@@ -254,8 +479,14 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<local:SettingsCard Background="{ThemeResource SettingContainerWarningSeverityBackgroundBrush}">
<local:SettingsCard.Header>
<Grid AutomationProperties.Name="{TemplateBinding Header}"
Background="{ThemeResource SettingContainerWarningSeverityBackgroundBrush}"
Style="{StaticResource NonExpanderGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<Grid>
<TextBlock x:Name="IconBackground"
@@ -267,6 +498,7 @@
FontSize="{StaticResource SettingContainerIconFontSize}"
Foreground="{ThemeResource SettingContainerWarningSeverityIconBackground}"
Text="{StaticResource SettingContainerIconBackgroundGlyph}" />
<TextBlock x:Name="StandardIcon"
Grid.Column="0"
Margin="{StaticResource SettingContainerIconMargin}"
@@ -282,14 +514,12 @@
Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
</StackPanel>
</local:SettingsCard.Header>
<local:SettingsCard.Description>
<TextBlock x:Name="HelpTextBlock"
Foreground="{ThemeResource SettingContainerMessageForeground}"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</local:SettingsCard.Description>
</local:SettingsCard>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
@@ -304,8 +534,14 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingContainer">
<local:SettingsCard Background="{ThemeResource SettingContainerErrorSeverityBackgroundBrush}">
<local:SettingsCard.Header>
<Grid AutomationProperties.Name="{TemplateBinding Header}"
Background="{ThemeResource SettingContainerErrorSeverityBackgroundBrush}"
Style="{StaticResource NonExpanderGrid}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Style="{StaticResource StackPanelInExpanderStyle}">
<StackPanel Orientation="Horizontal">
<Grid>
<TextBlock x:Name="IconBackground"
@@ -317,6 +553,7 @@
FontSize="{StaticResource SettingContainerIconFontSize}"
Foreground="{ThemeResource SettingContainerErrorSeverityIconBackground}"
Text="{StaticResource SettingContainerIconBackgroundGlyph}" />
<TextBlock x:Name="StandardIcon"
Grid.Column="0"
Margin="{StaticResource SettingContainerIconMargin}"
@@ -332,14 +569,12 @@
Style="{StaticResource SettingsPageItemHeaderStyle}"
Text="{TemplateBinding Header}" />
</StackPanel>
</local:SettingsCard.Header>
<local:SettingsCard.Description>
<TextBlock x:Name="HelpTextBlock"
Foreground="{ThemeResource SettingContainerMessageForeground}"
Style="{StaticResource SettingsPageItemDescriptionStyle}"
Text="{TemplateBinding HelpText}" />
</local:SettingsCard.Description>
</local:SettingsCard>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

View File

@@ -1,472 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "SettingsCard.h"
#include "SettingsCard.g.cpp"
#include "SettingsCardAutomationPeer.g.cpp"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Automation;
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Controls::Primitives;
using namespace winrt::Windows::UI::Xaml::Input;
using namespace winrt::Windows::UI::Xaml::Media;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
DependencyProperty SettingsCard::_HeaderProperty{ nullptr };
DependencyProperty SettingsCard::_DescriptionProperty{ nullptr };
DependencyProperty SettingsCard::_HeaderIconProperty{ nullptr };
DependencyProperty SettingsCard::_ActionIconProperty{ nullptr };
DependencyProperty SettingsCard::_ActionIconToolTipProperty{ nullptr };
DependencyProperty SettingsCard::_IsClickEnabledProperty{ nullptr };
DependencyProperty SettingsCard::_IsActionIconVisibleProperty{ nullptr };
DependencyProperty SettingsCard::_ContentAlignmentProperty{ nullptr };
static constexpr std::wstring_view NormalState{ L"Normal" };
static constexpr std::wstring_view PointerOverState{ L"PointerOver" };
static constexpr std::wstring_view PressedState{ L"Pressed" };
static constexpr std::wstring_view DisabledState{ L"Disabled" };
static constexpr std::wstring_view RightState{ L"Right" };
static constexpr std::wstring_view LeftState{ L"Left" };
static constexpr std::wstring_view VerticalState{ L"Vertical" };
static constexpr std::wstring_view ActionIconPresenterHolder{ L"PART_ActionIconPresenterHolder" };
static constexpr std::wstring_view HeaderPresenter{ L"PART_HeaderPresenter" };
static constexpr std::wstring_view DescriptionPresenter{ L"PART_DescriptionPresenter" };
static constexpr std::wstring_view HeaderIconPresenterHolder{ L"PART_HeaderIconPresenterHolder" };
SettingsCard::SettingsCard()
{
_InitializeProperties();
}
void SettingsCard::_InitializeProperties()
{
if (!_HeaderProperty)
{
_HeaderProperty = DependencyProperty::Register(
L"Header",
xaml_typename<IInspectable>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ nullptr, PropertyChangedCallback{ &SettingsCard::_OnHeaderChanged } });
}
if (!_DescriptionProperty)
{
_DescriptionProperty = DependencyProperty::Register(
L"Description",
xaml_typename<IInspectable>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ nullptr, PropertyChangedCallback{ &SettingsCard::_OnDescriptionChanged } });
}
if (!_HeaderIconProperty)
{
_HeaderIconProperty = DependencyProperty::Register(
L"HeaderIcon",
xaml_typename<IconElement>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ nullptr, PropertyChangedCallback{ &SettingsCard::_OnHeaderIconChanged } });
}
if (!_ActionIconProperty)
{
_ActionIconProperty = DependencyProperty::Register(
L"ActionIcon",
xaml_typename<IInspectable>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ nullptr });
}
if (!_ActionIconToolTipProperty)
{
_ActionIconToolTipProperty = DependencyProperty::Register(
L"ActionIconToolTip",
xaml_typename<hstring>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ box_value(hstring{}) });
}
if (!_IsClickEnabledProperty)
{
_IsClickEnabledProperty = DependencyProperty::Register(
L"IsClickEnabled",
xaml_typename<bool>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ box_value(false), PropertyChangedCallback{ &SettingsCard::_OnIsClickEnabledChanged } });
}
if (!_IsActionIconVisibleProperty)
{
_IsActionIconVisibleProperty = DependencyProperty::Register(
L"IsActionIconVisible",
xaml_typename<bool>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ box_value(true), PropertyChangedCallback{ &SettingsCard::_OnIsActionIconVisibleChanged } });
}
if (!_ContentAlignmentProperty)
{
_ContentAlignmentProperty = DependencyProperty::Register(
L"ContentAlignment",
xaml_typename<Editor::SettingsCardContentAlignment>(),
xaml_typename<Editor::SettingsCard>(),
PropertyMetadata{ box_value(Editor::SettingsCardContentAlignment::Right), PropertyChangedCallback{ &SettingsCard::_OnContentAlignmentChanged } });
}
}
AutomationPeer SettingsCard::OnCreateAutomationPeer()
{
return winrt::make<implementation::SettingsCardAutomationPeer>(*this);
}
void SettingsCard::OnApplyTemplate()
{
// Drop any handlers from a previous template.
_isEnabledChangedRevoker.revoke();
_DisableButtonInteraction();
if (_contentChangedToken != 0)
{
UnregisterPropertyChangedCallback(ContentControl::ContentProperty(), _contentChangedToken);
_contentChangedToken = 0;
}
_UpdateActionIconVisibility();
_UpdateHeaderVisibility();
_UpdateDescriptionVisibility();
_UpdateHeaderIconVisibility();
// Initial visual states.
_CheckInitialVisualState();
_SetAccessibleContentName();
// Watch for Content changing later (we may need to refresh the AutomationProperties.Name on it).
_contentChangedToken = RegisterPropertyChangedCallback(ContentControl::ContentProperty(), [weakThis = get_weak()](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
strongThis->_SetAccessibleContentName();
}
});
// Apply click-interaction state.
if (IsClickEnabled())
{
_EnableButtonInteraction();
}
_isEnabledChangedRevoker = IsEnabledChanged(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
strongThis->_GoToCommonState(strongThis->IsEnabled() ? NormalState : DisabledState, true);
}
});
}
void SettingsCard::_CheckInitialVisualState()
{
VisualStateManager::GoToState(*this, IsEnabled() ? hstring{ NormalState } : hstring{ DisabledState }, true);
_UpdateContentAlignmentState();
}
void SettingsCard::_SetAccessibleContentName()
{
// If Header is a string and the inner Content lacks an AutomationProperties.Name, propagate the header
// into the content so screen readers can announce something meaningful when focus lands there.
const auto headerObj{ Header() };
if (!headerObj)
{
return;
}
const auto headerString{ unbox_value_or<hstring>(headerObj, hstring{}) };
if (headerString.empty())
{
return;
}
const auto contentObj{ Content() };
if (const auto element{ contentObj.try_as<UIElement>() })
{
if (Automation::AutomationProperties::GetName(element).empty())
{
// Don't override ButtonBase content (would clobber its own name) or plain text blocks.
if (!element.try_as<ButtonBase>() && !element.try_as<TextBlock>())
{
Automation::AutomationProperties::SetName(element, headerString);
}
}
}
}
void SettingsCard::_EnableButtonInteraction()
{
if (_interactionEnabled)
{
return;
}
_interactionEnabled = true;
IsTabStop(true);
_pointerEnteredRevoker = PointerEntered(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
strongThis->_GoToCommonState(PointerOverState, true);
}
});
_pointerExitedRevoker = PointerExited(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
strongThis->_GoToCommonState(NormalState, true);
}
});
_pointerCaptureLostRevoker = PointerCaptureLost(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
strongThis->_GoToCommonState(NormalState, true);
}
});
_pointerCanceledRevoker = PointerCanceled(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
strongThis->_GoToCommonState(NormalState, true);
}
});
_previewKeyDownRevoker = PreviewKeyDown(winrt::auto_revoke, [weakThis = get_weak()](auto&&, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e) {
const auto strongThis = weakThis.get();
if (!strongThis)
{
return;
}
const auto key = e.Key();
if (key == Windows::System::VirtualKey::Enter || key == Windows::System::VirtualKey::Space || key == Windows::System::VirtualKey::GamepadA)
{
const auto focused{ strongThis->_GetFocusedElement() };
if (focused && focused.try_as<Editor::SettingsCard>() == strongThis.as<Editor::SettingsCard>())
{
strongThis->_GoToCommonState(PressedState, true);
}
}
});
_previewKeyUpRevoker = PreviewKeyUp(winrt::auto_revoke, [weakThis = get_weak()](auto&&, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e) {
const auto strongThis = weakThis.get();
if (!strongThis)
{
return;
}
const auto key = e.Key();
if (key == Windows::System::VirtualKey::Enter || key == Windows::System::VirtualKey::Space || key == Windows::System::VirtualKey::GamepadA)
{
strongThis->_GoToCommonState(NormalState, true);
}
});
}
void SettingsCard::_DisableButtonInteraction()
{
_interactionEnabled = false;
IsTabStop(false);
_pointerEnteredRevoker.revoke();
_pointerExitedRevoker.revoke();
_pointerCaptureLostRevoker.revoke();
_pointerCanceledRevoker.revoke();
_previewKeyDownRevoker.revoke();
_previewKeyUpRevoker.revoke();
}
void SettingsCard::_GoToCommonState(const std::wstring_view& state, bool useTransitions)
{
VisualStateManager::GoToState(*this, hstring{ state }, useTransitions);
}
FrameworkElement SettingsCard::_GetFocusedElement()
{
if (const auto root{ XamlRoot() })
{
return FocusManager::GetFocusedElement(root).try_as<FrameworkElement>();
}
return FocusManager::GetFocusedElement().try_as<FrameworkElement>();
}
void SettingsCard::_UpdateActionIconVisibility()
{
if (const auto child{ GetTemplateChild(hstring{ ActionIconPresenterHolder }) })
{
if (const auto frameworkChild{ child.try_as<FrameworkElement>() })
{
frameworkChild.Visibility((IsClickEnabled() && IsActionIconVisible()) ? Visibility::Visible : Visibility::Collapsed);
}
}
}
// Returns true if the given object is null, or is a string that is empty.
// Non-string non-null objects (e.g. a TextBlock) are considered "non-empty".
static bool _isNullOrEmpty(const winrt::Windows::Foundation::IInspectable& obj)
{
if (!obj)
{
return true;
}
if (const auto pv{ obj.try_as<IPropertyValue>() }; pv && pv.Type() == PropertyType::String)
{
return unbox_value_or<hstring>(obj, hstring{}).empty();
}
return false;
}
void SettingsCard::_UpdateHeaderVisibility()
{
if (const auto child{ GetTemplateChild(hstring{ HeaderPresenter }) })
{
if (const auto frameworkChild{ child.try_as<FrameworkElement>() })
{
frameworkChild.Visibility(_isNullOrEmpty(Header()) ? Visibility::Collapsed : Visibility::Visible);
}
}
}
void SettingsCard::_UpdateDescriptionVisibility()
{
if (const auto child{ GetTemplateChild(hstring{ DescriptionPresenter }) })
{
if (const auto frameworkChild{ child.try_as<FrameworkElement>() })
{
frameworkChild.Visibility(_isNullOrEmpty(Description()) ? Visibility::Collapsed : Visibility::Visible);
}
}
}
void SettingsCard::_UpdateHeaderIconVisibility()
{
if (const auto child{ GetTemplateChild(hstring{ HeaderIconPresenterHolder }) })
{
if (const auto frameworkChild{ child.try_as<FrameworkElement>() })
{
frameworkChild.Visibility(HeaderIcon() ? Visibility::Visible : Visibility::Collapsed);
}
}
}
void SettingsCard::_UpdateContentAlignmentState()
{
std::wstring_view state{ RightState };
switch (ContentAlignment())
{
case Editor::SettingsCardContentAlignment::Left:
state = LeftState;
break;
case Editor::SettingsCardContentAlignment::Vertical:
state = VerticalState;
break;
default:
state = RightState;
break;
}
VisualStateManager::GoToState(*this, hstring{ state }, true);
}
void SettingsCard::_OnHeaderChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto obj{ d.try_as<Editor::SettingsCard>() };
const auto self = get_self<SettingsCard>(obj);
self->_UpdateHeaderVisibility();
self->_SetAccessibleContentName();
}
void SettingsCard::_OnDescriptionChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto obj{ d.try_as<Editor::SettingsCard>() };
get_self<SettingsCard>(obj)->_UpdateDescriptionVisibility();
}
void SettingsCard::_OnHeaderIconChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto obj{ d.try_as<Editor::SettingsCard>() };
get_self<SettingsCard>(obj)->_UpdateHeaderIconVisibility();
}
void SettingsCard::_OnIsClickEnabledChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto obj{ d.try_as<Editor::SettingsCard>() };
const auto self = get_self<SettingsCard>(obj);
self->_UpdateActionIconVisibility();
if (self->IsClickEnabled())
{
self->_EnableButtonInteraction();
}
else
{
self->_DisableButtonInteraction();
}
}
void SettingsCard::_OnIsActionIconVisibleChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto obj{ d.try_as<Editor::SettingsCard>() };
get_self<SettingsCard>(obj)->_UpdateActionIconVisibility();
}
void SettingsCard::_OnContentAlignmentChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto obj{ d.try_as<Editor::SettingsCard>() };
get_self<SettingsCard>(obj)->_UpdateContentAlignmentState();
}
SettingsCardAutomationPeer::SettingsCardAutomationPeer(const Editor::SettingsCard& owner) :
SettingsCardAutomationPeerT<SettingsCardAutomationPeer>(owner)
{
}
AutomationControlType SettingsCardAutomationPeer::GetAutomationControlTypeCore() const
{
if (const auto card{ Owner().try_as<Editor::SettingsCard>() })
{
if (card.IsClickEnabled())
{
return AutomationControlType::Button;
}
}
return AutomationControlType::Group;
}
hstring SettingsCardAutomationPeer::GetClassNameCore() const
{
return hstring{ L"SettingsCard" };
}
hstring SettingsCardAutomationPeer::GetNameCore() const
{
if (const auto card{ Owner().try_as<Editor::SettingsCard>() })
{
if (card.IsClickEnabled())
{
if (const auto manualName{ AutomationProperties::GetName(card) }; !manualName.empty())
{
return manualName;
}
if (const auto headerString{ unbox_value_or<hstring>(card.Header(), hstring{}) }; !headerString.empty())
{
return headerString;
}
}
// Not clickable, or no header text: fall back to AutomationProperties.Name (matching
// FrameworkElementAutomationPeer's default behavior).
return AutomationProperties::GetName(card);
}
return {};
}
winrt::Windows::Foundation::IInspectable SettingsCardAutomationPeer::GetPatternCore(PatternInterface patternInterface) const
{
if (patternInterface == PatternInterface::Invoke)
{
if (const auto card{ Owner().try_as<Editor::SettingsCard>() })
{
if (card.IsClickEnabled())
{
// Only provide Invoke pattern if the card is clickable.
return *this;
}
}
return nullptr;
}
// ButtonBaseAutomationPeer only provides Invoke; everything else returns null.
return nullptr;
}
}

View File

@@ -1,95 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- SettingsCard
Abstract:
- A base control for building consistent settings experiences. Based
on the Windows Community Toolkit's SettingsCard.
Author(s):
- Carlos Zamora - 2026 May
--*/
#pragma once
#include "SettingsCard.g.h"
#include "SettingsCardAutomationPeer.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct SettingsCard : SettingsCardT<SettingsCard>
{
public:
SettingsCard();
void OnApplyTemplate();
// Automation peer override.
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, Header);
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, Description);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::IconElement, HeaderIcon);
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, ActionIcon);
DEPENDENCY_PROPERTY(hstring, ActionIconToolTip);
DEPENDENCY_PROPERTY(bool, IsClickEnabled);
DEPENDENCY_PROPERTY(bool, IsActionIconVisible);
DEPENDENCY_PROPERTY(Editor::SettingsCardContentAlignment, ContentAlignment);
private:
static void _InitializeProperties();
static void _OnHeaderChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnDescriptionChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnHeaderIconChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnIsClickEnabledChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnIsActionIconVisibleChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _OnContentAlignmentChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
void _EnableButtonInteraction();
void _DisableButtonInteraction();
void _GoToCommonState(const std::wstring_view& state, bool useTransitions);
void _UpdateActionIconVisibility();
void _UpdateHeaderVisibility();
void _UpdateDescriptionVisibility();
void _UpdateHeaderIconVisibility();
void _UpdateContentAlignmentState();
void _CheckInitialVisualState();
void _SetAccessibleContentName();
Windows::UI::Xaml::FrameworkElement _GetFocusedElement();
bool _interactionEnabled{ false };
Windows::UI::Xaml::Controls::Control::IsEnabledChanged_revoker _isEnabledChangedRevoker;
Windows::UI::Xaml::UIElement::PointerEntered_revoker _pointerEnteredRevoker;
Windows::UI::Xaml::UIElement::PointerExited_revoker _pointerExitedRevoker;
Windows::UI::Xaml::UIElement::PointerCaptureLost_revoker _pointerCaptureLostRevoker;
Windows::UI::Xaml::UIElement::PointerCanceled_revoker _pointerCanceledRevoker;
Windows::UI::Xaml::UIElement::PreviewKeyDown_revoker _previewKeyDownRevoker;
Windows::UI::Xaml::UIElement::PreviewKeyUp_revoker _previewKeyUpRevoker;
int64_t _contentChangedToken{ 0 };
};
// AutomationPeer for SettingsCard. Mirrors the Community Toolkit's
// SettingsCardAutomationPeer: only exposes Invoke + Button control type when
// the card has IsClickEnabled=true; otherwise reports as a Group.
struct SettingsCardAutomationPeer : SettingsCardAutomationPeerT<SettingsCardAutomationPeer>
{
public:
SettingsCardAutomationPeer(const Editor::SettingsCard& owner);
Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() const;
hstring GetClassNameCore() const;
hstring GetNameCore() const;
winrt::Windows::Foundation::IInspectable GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface) const;
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(SettingsCard);
BASIC_FACTORY(SettingsCardAutomationPeer);
}

View File

@@ -1,46 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft.Terminal.Settings.Editor
{
enum SettingsCardContentAlignment
{
Right,
Left,
Vertical
};
[default_interface] runtimeclass SettingsCard : Windows.UI.Xaml.Controls.Primitives.ButtonBase
{
SettingsCard();
Object Header;
static Windows.UI.Xaml.DependencyProperty HeaderProperty { get; };
Object Description;
static Windows.UI.Xaml.DependencyProperty DescriptionProperty { get; };
Windows.UI.Xaml.Controls.IconElement HeaderIcon;
static Windows.UI.Xaml.DependencyProperty HeaderIconProperty { get; };
Object ActionIcon;
static Windows.UI.Xaml.DependencyProperty ActionIconProperty { get; };
String ActionIconToolTip;
static Windows.UI.Xaml.DependencyProperty ActionIconToolTipProperty { get; };
Boolean IsClickEnabled;
static Windows.UI.Xaml.DependencyProperty IsClickEnabledProperty { get; };
Boolean IsActionIconVisible;
static Windows.UI.Xaml.DependencyProperty IsActionIconVisibleProperty { get; };
SettingsCardContentAlignment ContentAlignment;
static Windows.UI.Xaml.DependencyProperty ContentAlignmentProperty { get; };
};
[default_interface] runtimeclass SettingsCardAutomationPeer : Windows.UI.Xaml.Automation.Peers.ButtonBaseAutomationPeer
{
SettingsCardAutomationPeer(SettingsCard owner);
};
}

View File

@@ -1,409 +0,0 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
Default styles for SettingsCard and SettingsExpander.
These were ported from the Windows Community Toolkit
(components/SettingsControls) and trimmed for use in this project:
- The Card's responsive RightWrapped/RightWrappedNoIcon visual states are
omitted (they depend on tk:ControlSizeTrigger).
- The Expander uses muxc:Expander's built-in template rather than the
custom 500+ line template the toolkit ships.
-->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="SettingsCardBackground"
ResourceKey="CardBackgroundFillColorDefaultBrush" />
<StaticResource x:Key="SettingsCardBackgroundPointerOver"
ResourceKey="ControlFillColorSecondaryBrush" />
<StaticResource x:Key="SettingsCardBackgroundPressed"
ResourceKey="ControlFillColorTertiaryBrush" />
<StaticResource x:Key="SettingsCardBackgroundDisabled"
ResourceKey="ControlFillColorDisabledBrush" />
<StaticResource x:Key="SettingsCardForeground"
ResourceKey="TextFillColorPrimaryBrush" />
<StaticResource x:Key="SettingsCardForegroundPointerOver"
ResourceKey="TextFillColorPrimaryBrush" />
<StaticResource x:Key="SettingsCardForegroundPressed"
ResourceKey="TextFillColorSecondaryBrush" />
<StaticResource x:Key="SettingsCardForegroundDisabled"
ResourceKey="TextFillColorDisabledBrush" />
<StaticResource x:Key="SettingsCardBorderBrush"
ResourceKey="CardStrokeColorDefaultBrush" />
<StaticResource x:Key="SettingsCardBorderBrushPointerOver"
ResourceKey="ControlElevationBorderBrush" />
<StaticResource x:Key="SettingsCardBorderBrushPressed"
ResourceKey="ControlStrokeColorDefaultBrush" />
<StaticResource x:Key="SettingsCardBorderBrushDisabled"
ResourceKey="ControlStrokeColorDefaultBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="SettingsCardBackground"
ResourceKey="CardBackgroundFillColorDefaultBrush" />
<StaticResource x:Key="SettingsCardBackgroundPointerOver"
ResourceKey="ControlFillColorSecondaryBrush" />
<StaticResource x:Key="SettingsCardBackgroundPressed"
ResourceKey="ControlFillColorTertiaryBrush" />
<StaticResource x:Key="SettingsCardBackgroundDisabled"
ResourceKey="ControlFillColorDisabledBrush" />
<StaticResource x:Key="SettingsCardForeground"
ResourceKey="TextFillColorPrimaryBrush" />
<StaticResource x:Key="SettingsCardForegroundPointerOver"
ResourceKey="TextFillColorPrimaryBrush" />
<StaticResource x:Key="SettingsCardForegroundPressed"
ResourceKey="TextFillColorSecondaryBrush" />
<StaticResource x:Key="SettingsCardForegroundDisabled"
ResourceKey="TextFillColorDisabledBrush" />
<StaticResource x:Key="SettingsCardBorderBrush"
ResourceKey="CardStrokeColorDefaultBrush" />
<StaticResource x:Key="SettingsCardBorderBrushPointerOver"
ResourceKey="ControlElevationBorderBrush" />
<StaticResource x:Key="SettingsCardBorderBrushPressed"
ResourceKey="ControlStrokeColorDefaultBrush" />
<StaticResource x:Key="SettingsCardBorderBrushDisabled"
ResourceKey="ControlStrokeColorDefaultBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="SettingsCardBackground"
ResourceKey="SystemColorButtonFaceColorBrush" />
<StaticResource x:Key="SettingsCardBackgroundPointerOver"
ResourceKey="SystemColorHighlightTextColorBrush" />
<StaticResource x:Key="SettingsCardBackgroundPressed"
ResourceKey="SystemColorHighlightTextColorBrush" />
<StaticResource x:Key="SettingsCardBackgroundDisabled"
ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="SettingsCardForeground"
ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="SettingsCardForegroundPointerOver"
ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SettingsCardForegroundPressed"
ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SettingsCardForegroundDisabled"
ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
<StaticResource x:Key="SettingsCardBorderBrush"
ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="SettingsCardBorderBrushPointerOver"
ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SettingsCardBorderBrushPressed"
ResourceKey="SystemColorHighlightTextColorBrush" />
<StaticResource x:Key="SettingsCardBorderBrushDisabled"
ResourceKey="SystemControlDisabledTransparentBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Thickness x:Key="SettingsCardBorderThickness">1</Thickness>
<Thickness x:Key="SettingsCardPadding">16,16,16,16</Thickness>
<x:Double x:Key="SettingsCardMinWidth">148</x:Double>
<x:Double x:Key="SettingsCardMinHeight">68</x:Double>
<x:Double x:Key="SettingsCardDescriptionFontSize">12</x:Double>
<x:Double x:Key="SettingsCardHeaderIconMaxSize">20</x:Double>
<x:Double x:Key="SettingsCardContentMinWidth">120</x:Double>
<Thickness x:Key="SettingsCardHeaderIconMargin">2,0,20,0</Thickness>
<Thickness x:Key="SettingsCardActionIconMargin">14,0,0,0</Thickness>
<x:Double x:Key="SettingsCardActionIconMaxSize">13</x:Double>
<Thickness x:Key="SettingsExpanderItemPadding">58,8,44,8</Thickness>
<Thickness x:Key="SettingsExpanderItemBorderThickness">0,1,0,0</Thickness>
<x:Double x:Key="SettingsExpanderContentMinHeight">16</x:Double>
<!-- ============ SettingsCard ============ -->
<!--
Card style for items that live inside a SettingsExpander:
no left/right rounded corners, a 1-pixel top border between siblings,
deeper left padding to line up with the parent expander's content.
-->
<Style x:Key="SettingsExpanderItemCardStyle"
BasedOn="{StaticResource DefaultSettingsCardStyle}"
TargetType="local:SettingsCard">
<Setter Property="BorderThickness" Value="{StaticResource SettingsExpanderItemBorderThickness}" />
<Setter Property="MinHeight" Value="52" />
<Setter Property="Padding" Value="{StaticResource SettingsExpanderItemPadding}" />
<Setter Property="CornerRadius" Value="0" />
</Style>
<Style BasedOn="{StaticResource DefaultSettingsCardStyle}"
TargetType="local:SettingsCard" />
<Style x:Key="DefaultSettingsCardStyle"
TargetType="local:SettingsCard">
<Setter Property="Background" Value="{ThemeResource SettingsCardBackground}" />
<Setter Property="Foreground" Value="{ThemeResource SettingsCardForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SettingsCardBorderBrush}" />
<Setter Property="BorderThickness" Value="{StaticResource SettingsCardBorderThickness}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="MinHeight" Value="{StaticResource SettingsCardMinHeight}" />
<Setter Property="MinWidth" Value="{StaticResource SettingsCardMinWidth}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Padding" Value="{StaticResource SettingsCardPadding}" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="ActionIcon" Value="&#xE974;" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingsCard">
<Grid x:Name="PART_RootGrid"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
MaxWidth="{TemplateBinding MaxWidth}"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Background="{TemplateBinding Background}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Viewbox x:Name="PART_HeaderIconPresenterHolder"
Grid.RowSpan="1"
MaxWidth="{StaticResource SettingsCardHeaderIconMaxSize}"
MaxHeight="{StaticResource SettingsCardHeaderIconMaxSize}"
Margin="{StaticResource SettingsCardHeaderIconMargin}">
<ContentPresenter x:Name="PART_HeaderIconPresenter"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding HeaderIcon}" />
</Viewbox>
<StackPanel x:Name="HeaderPanel"
Grid.Column="1"
Margin="0,0,24,0"
VerticalAlignment="Center"
Orientation="Vertical">
<ContentPresenter x:Name="PART_HeaderPresenter"
HorizontalAlignment="Left"
Content="{TemplateBinding Header}"
TextWrapping="Wrap" />
<ContentPresenter x:Name="PART_DescriptionPresenter"
Content="{TemplateBinding Description}"
FontSize="{StaticResource SettingsCardDescriptionFontSize}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap">
<ContentPresenter.Resources>
<Style BasedOn="{StaticResource CaptionTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</StackPanel>
<ContentPresenter x:Name="PART_ContentPresenter"
Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Content="{TemplateBinding Content}" />
<Viewbox x:Name="PART_ActionIconPresenterHolder"
Grid.RowSpan="2"
Grid.Column="3"
MaxWidth="{StaticResource SettingsCardActionIconMaxSize}"
MaxHeight="{StaticResource SettingsCardActionIconMaxSize}"
Margin="{StaticResource SettingsCardActionIconMargin}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="Collapsed">
<ContentPresenter x:Name="PART_ActionIconPresenter"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding ActionIcon}"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
ToolTipService.ToolTip="{TemplateBinding ActionIconToolTip}" />
</Viewbox>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_RootGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_RootGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_HeaderPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_RootGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_RootGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_HeaderPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_DescriptionPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_ActionIconPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_HeaderIconPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_HeaderPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PART_DescriptionPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ContentAlignmentStates">
<VisualState x:Name="Right" />
<VisualState x:Name="Left">
<VisualState.Setters>
<Setter Target="PART_HeaderIconPresenterHolder.Visibility" Value="Collapsed" />
<Setter Target="PART_HeaderPresenter.Visibility" Value="Collapsed" />
<Setter Target="PART_DescriptionPresenter.Visibility" Value="Collapsed" />
<Setter Target="PART_ContentPresenter.(Grid.Row)" Value="1" />
<Setter Target="PART_ContentPresenter.(Grid.Column)" Value="1" />
<Setter Target="PART_ContentPresenter.HorizontalAlignment" Value="Left" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Vertical">
<VisualState.Setters>
<Setter Target="PART_ContentPresenter.(Grid.Row)" Value="1" />
<Setter Target="PART_ContentPresenter.(Grid.Column)" Value="1" />
<Setter Target="PART_ContentPresenter.HorizontalAlignment" Value="Stretch" />
<Setter Target="PART_RootGrid.RowSpacing" Value="8" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ============ SettingsExpander ============ -->
<Style BasedOn="{StaticResource DefaultSettingsExpanderStyle}"
TargetType="local:SettingsExpander" />
<Style x:Key="DefaultSettingsExpanderStyle"
TargetType="local:SettingsExpander">
<Setter Property="Background" Value="{ThemeResource SettingsCardBackground}" />
<Setter Property="Foreground" Value="{ThemeResource SettingsCardForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SettingsCardBorderBrush}" />
<Setter Property="BorderThickness" Value="{StaticResource SettingsCardBorderThickness}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="MinHeight" Value="{StaticResource SettingsCardMinHeight}" />
<Setter Property="MinWidth" Value="{StaticResource SettingsCardMinWidth}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SettingsExpander">
<muxc:Expander x:Name="PART_Expander"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
CornerRadius="{TemplateBinding CornerRadius}"
IsExpanded="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
<muxc:Expander.Header>
<local:SettingsCard MinHeight="52"
Padding="0,8,0,8"
VerticalAlignment="Center"
Background="Transparent"
BorderThickness="0"
Content="{TemplateBinding Content}"
Description="{TemplateBinding Description}"
FontFamily="{TemplateBinding FontFamily}"
Header="{TemplateBinding Header}"
HeaderIcon="{TemplateBinding HeaderIcon}"
IsClickEnabled="False" />
</muxc:Expander.Header>
<muxc:Expander.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentPresenter Content="{TemplateBinding ItemsHeader}" />
<ContentPresenter Grid.Row="1"
Content="{TemplateBinding ItemsFooter}" />
</Grid>
</muxc:Expander.Content>
</muxc:Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -1,150 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "SettingsExpander.h"
#include "SettingsExpander.g.cpp"
#include "SettingsExpanderAutomationPeer.g.cpp"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Automation;
using namespace winrt::Windows::UI::Xaml::Automation::Peers;
using namespace winrt::Windows::UI::Xaml::Controls;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
DependencyProperty SettingsExpander::_HeaderProperty{ nullptr };
DependencyProperty SettingsExpander::_DescriptionProperty{ nullptr };
DependencyProperty SettingsExpander::_HeaderIconProperty{ nullptr };
DependencyProperty SettingsExpander::_ContentProperty{ nullptr };
DependencyProperty SettingsExpander::_IsExpandedProperty{ nullptr };
DependencyProperty SettingsExpander::_ItemsHeaderProperty{ nullptr };
DependencyProperty SettingsExpander::_ItemsFooterProperty{ nullptr };
SettingsExpander::SettingsExpander()
{
_InitializeProperties();
}
void SettingsExpander::_InitializeProperties()
{
if (!_HeaderProperty)
{
_HeaderProperty = DependencyProperty::Register(
L"Header",
xaml_typename<IInspectable>(),
xaml_typename<Editor::SettingsExpander>(),
PropertyMetadata{ nullptr });
}
if (!_DescriptionProperty)
{
_DescriptionProperty = DependencyProperty::Register(
L"Description",
xaml_typename<IInspectable>(),
xaml_typename<Editor::SettingsExpander>(),
PropertyMetadata{ nullptr });
}
if (!_HeaderIconProperty)
{
_HeaderIconProperty = DependencyProperty::Register(
L"HeaderIcon",
xaml_typename<IconElement>(),
xaml_typename<Editor::SettingsExpander>(),
PropertyMetadata{ nullptr });
}
if (!_ContentProperty)
{
_ContentProperty = DependencyProperty::Register(
L"Content",
xaml_typename<IInspectable>(),
xaml_typename<Editor::SettingsExpander>(),
PropertyMetadata{ nullptr });
}
if (!_IsExpandedProperty)
{
_IsExpandedProperty = DependencyProperty::Register(
L"IsExpanded",
xaml_typename<bool>(),
xaml_typename<Editor::SettingsExpander>(),
PropertyMetadata{ box_value(false), PropertyChangedCallback{ &SettingsExpander::_OnIsExpandedChanged } });
}
if (!_ItemsHeaderProperty)
{
_ItemsHeaderProperty = DependencyProperty::Register(
L"ItemsHeader",
xaml_typename<UIElement>(),
xaml_typename<Editor::SettingsExpander>(),
PropertyMetadata{ nullptr });
}
if (!_ItemsFooterProperty)
{
_ItemsFooterProperty = DependencyProperty::Register(
L"ItemsFooter",
xaml_typename<UIElement>(),
xaml_typename<Editor::SettingsExpander>(),
PropertyMetadata{ nullptr });
}
}
AutomationPeer SettingsExpander::OnCreateAutomationPeer()
{
return winrt::make<implementation::SettingsExpanderAutomationPeer>(*this);
}
void SettingsExpander::OnApplyTemplate()
{
// No template-part lookups required: our template uses regular bindings
// through TemplateBinding / x:Bind. The DPs do their own work.
}
void SettingsExpander::_OnIsExpandedChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& e)
{
const auto obj{ d.try_as<Editor::SettingsExpander>() };
if (!obj)
{
return;
}
const auto self = get_self<SettingsExpander>(obj);
const auto newValue = unbox_value_or<bool>(e.NewValue(), false);
if (newValue)
{
self->Expanded.raise(obj, nullptr);
}
else
{
self->Collapsed.raise(obj, nullptr);
}
}
SettingsExpanderAutomationPeer::SettingsExpanderAutomationPeer(const Editor::SettingsExpander& owner) :
SettingsExpanderAutomationPeerT<SettingsExpanderAutomationPeer>(owner)
{
}
AutomationControlType SettingsExpanderAutomationPeer::GetAutomationControlTypeCore() const
{
return AutomationControlType::Group;
}
hstring SettingsExpanderAutomationPeer::GetClassNameCore() const
{
return hstring{ L"SettingsExpander" };
}
hstring SettingsExpanderAutomationPeer::GetNameCore() const
{
if (const auto expander{ Owner().try_as<Editor::SettingsExpander>() })
{
if (const auto manualName{ AutomationProperties::GetName(expander) }; !manualName.empty())
{
return manualName;
}
if (const auto headerString{ unbox_value_or<hstring>(expander.Header(), hstring{}) }; !headerString.empty())
{
return headerString;
}
}
return {};
}
}

View File

@@ -1,67 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- SettingsExpander
Abstract:
- A collapsable container for grouping multiple SettingsCards. Based
on the Windows Community Toolkit's SettingsExpander.
Author(s):
- Carlos Zamora - 2026 (port from CommunityToolkit.WinUI.Controls.SettingsExpander)
--*/
#pragma once
#include "SettingsExpander.g.h"
#include "SettingsExpanderAutomationPeer.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct SettingsExpander : SettingsExpanderT<SettingsExpander>
{
public:
SettingsExpander();
void OnApplyTemplate();
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
til::typed_event<Editor::SettingsExpander, Windows::Foundation::IInspectable> Expanded;
til::typed_event<Editor::SettingsExpander, Windows::Foundation::IInspectable> Collapsed;
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, Header);
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, Description);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::IconElement, HeaderIcon);
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, Content);
DEPENDENCY_PROPERTY(bool, IsExpanded);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::UIElement, ItemsHeader);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::UIElement, ItemsFooter);
private:
static void _InitializeProperties();
static void _OnIsExpandedChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
};
// AutomationPeer for SettingsExpander. Reports class name and falls back to
// Header text for the name when AutomationProperties.Name is unset.
struct SettingsExpanderAutomationPeer : SettingsExpanderAutomationPeerT<SettingsExpanderAutomationPeer>
{
public:
SettingsExpanderAutomationPeer(const Editor::SettingsExpander& owner);
Windows::UI::Xaml::Automation::Peers::AutomationControlType GetAutomationControlTypeCore() const;
hstring GetClassNameCore() const;
hstring GetNameCore() const;
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(SettingsExpander);
BASIC_FACTORY(SettingsExpanderAutomationPeer);
}

View File

@@ -1,39 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass SettingsExpander : Windows.UI.Xaml.Controls.Control
{
SettingsExpander();
Object Header;
static Windows.UI.Xaml.DependencyProperty HeaderProperty { get; };
Object Description;
static Windows.UI.Xaml.DependencyProperty DescriptionProperty { get; };
Windows.UI.Xaml.Controls.IconElement HeaderIcon;
static Windows.UI.Xaml.DependencyProperty HeaderIconProperty { get; };
Object Content;
static Windows.UI.Xaml.DependencyProperty ContentProperty { get; };
Boolean IsExpanded;
static Windows.UI.Xaml.DependencyProperty IsExpandedProperty { get; };
Windows.UI.Xaml.UIElement ItemsHeader;
static Windows.UI.Xaml.DependencyProperty ItemsHeaderProperty { get; };
Windows.UI.Xaml.UIElement ItemsFooter;
static Windows.UI.Xaml.DependencyProperty ItemsFooterProperty { get; };
event Windows.Foundation.TypedEventHandler<SettingsExpander, Object> Expanded;
event Windows.Foundation.TypedEventHandler<SettingsExpander, Object> Collapsed;
};
[default_interface] runtimeclass SettingsExpanderAutomationPeer : Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer
{
SettingsExpanderAutomationPeer(SettingsExpander owner);
};
}

View File

@@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "StringDefaultTemplateSelector.h"
#include "StringDefaultTemplateSelector.g.cpp"
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
DataTemplate StringDefaultTemplateSelector::SelectTemplateCore(const IInspectable& item, const DependencyObject& /*container*/)
{
return SelectTemplateCore(item);
}
DataTemplate StringDefaultTemplateSelector::SelectTemplateCore(const IInspectable& item)
{
if (const auto pv{ item.try_as<IPropertyValue>() }; pv && pv.Type() == PropertyType::String)
{
return _StringTemplate;
}
return nullptr;
}
}

View File

@@ -1,24 +0,0 @@
// Copyright (c) Microsoft Corporation
// Licensed under the MIT license.
#pragma once
#include "StringDefaultTemplateSelector.g.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct StringDefaultTemplateSelector : StringDefaultTemplateSelectorT<StringDefaultTemplateSelector>
{
StringDefaultTemplateSelector() = default;
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const winrt::Windows::Foundation::IInspectable& item, const winrt::Windows::UI::Xaml::DependencyObject& container);
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const winrt::Windows::Foundation::IInspectable& item);
WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, StringTemplate, nullptr);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(StringDefaultTemplateSelector);
}

View File

@@ -1,12 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace Microsoft.Terminal.Settings.Editor
{
[default_interface] runtimeclass StringDefaultTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
{
StringDefaultTemplateSelector();
Windows.UI.Xaml.DataTemplate StringTemplate;
}
}