[WIP] Represent Invert for Cursor Color in SUI

This commit is contained in:
Carlos Zamora 2025-10-08 12:00:23 -07:00
parent 4600c4791b
commit 171daf47a7
9 changed files with 194 additions and 7 deletions

View File

@ -10,6 +10,8 @@
#include "EnumEntry.h"
#include "ProfileViewModel.h"
#include "CursorColorTemplateSelector.g.cpp"
#include "AppearanceViewModel.g.cpp"
#include "Appearances.g.cpp"
using namespace winrt::Windows::UI::Text;
@ -203,6 +205,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _isFontFeature;
}
DataTemplate CursorColorTemplateSelector::SelectTemplateCore(const IInspectable& item, const DependencyObject& /*container*/)
{
return SelectTemplateCore(item);
}
DataTemplate CursorColorTemplateSelector::SelectTemplateCore(const IInspectable& item)
{
if (const auto maybeCursorColor = item.try_as<Windows::UI::Color>())
{
const auto cursorColor = *maybeCursorColor;
if (cursorColor.R == 0xFF && cursorColor.G == 0xFF && cursorColor.B == 0xFF)
{
return InvertColorTemplate();
}
return DefaultTemplate();
}
assert(false);
return nullptr;
}
AppearanceViewModel::AppearanceViewModel(const Model::AppearanceConfig& appearance) :
_appearance{ appearance }
{
@ -1036,11 +1058,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (modelVal)
{
// user defined an override value
const auto color = modelVal.Value();
return Windows::UI::Color{
.A = 255,
.R = modelVal.Value().R,
.G = modelVal.Value().G,
.B = modelVal.Value().B
.R = color.R,
.G = color.G,
.B = color.B
};
}
// set to null --> deduce value from color scheme

View File

@ -19,6 +19,7 @@ Author(s):
#include "Font.g.h"
#include "FontKeyValuePair.g.h"
#include "Appearances.g.h"
#include "CursorColorTemplateSelector.g.h"
#include "AppearanceViewModel.g.h"
#include "Utils.h"
#include "ViewModelHelpers.h"
@ -60,6 +61,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
bool _isFontFeature;
};
struct CursorColorTemplateSelector : public CursorColorTemplateSelectorT<CursorColorTemplateSelector>
{
public:
CursorColorTemplateSelector() = default;
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const Windows::Foundation::IInspectable& item, const Windows::UI::Xaml::DependencyObject& container);
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const Windows::Foundation::IInspectable& item);
WINRT_PROPERTY(Windows::UI::Xaml::DataTemplate, DefaultTemplate, nullptr);
WINRT_PROPERTY(Windows::UI::Xaml::DataTemplate, InvertColorTemplate, nullptr);
WINRT_PROPERTY(Editor::ColorSchemeViewModel, ColorScheme, nullptr);
};
struct AppearanceViewModel : AppearanceViewModelT<AppearanceViewModel>, ViewModelHelper<AppearanceViewModel>
{
enum FontSettingIndex
@ -247,5 +261,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(CursorColorTemplateSelector);
BASIC_FACTORY(Appearances);
}

View File

@ -30,6 +30,14 @@ namespace Microsoft.Terminal.Settings.Editor
Single Value;
}
runtimeclass CursorColorTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
{
CursorColorTemplateSelector();
Windows.UI.Xaml.DataTemplate DefaultTemplate;
Windows.UI.Xaml.DataTemplate InvertColorTemplate;
ColorSchemeViewModel ColorScheme;
}
runtimeclass AppearanceViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Boolean IsDefault;

View File

@ -61,6 +61,62 @@
</Button>
</Grid>
</DataTemplate>
<DataTemplate x:Key="InvertCursorColorPreviewTemplate"
x:DataType="Color">
<Grid ColumnSpacing="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Display the text "ABC" where the first half is white on black, and the second half is black on white -->
<!--TODO CARLOS: Replace Black/White below with binding to color scheme foreground/background-->
<Border Grid.Column="0"
CornerRadius="2">
<Grid>
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="{Binding ColorScheme.BackgroundColor.Color, Source={StaticResource CursorColorTemplateSelector}}" Offset="0.0" />
<GradientStop Color="{Binding ColorScheme.BackgroundColor.Color, Source={StaticResource CursorColorTemplateSelector}}" Offset="0.5" />
<GradientStop Color="{Binding ColorScheme.ForegroundColor.Color, Source={StaticResource CursorColorTemplateSelector}}" Offset="0.5" />
<GradientStop Color="{Binding ColorScheme.ForegroundColor.Color, Source={StaticResource CursorColorTemplateSelector}}" Offset="1.0" />
</LinearGradientBrush>
</Border.Background>
</Border>
<TextBlock Text="ABC"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="Cascadia Code, Consolas, 'Courier New', monospace"
FontWeight="Bold"
FontSize="12"
Padding="2,0">
<TextBlock.Foreground>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="White" Offset="0.0" />
<GradientStop Color="White" Offset="0.5" />
<GradientStop Color="Black" Offset="0.5" />
<GradientStop Color="Black" Offset="1.0" />
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>
</Grid>
</Border>
<TextBlock x:Uid="Profile_CursorColor_InvertTextBlock"
Grid.Column="1"
Margin="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
Style="{StaticResource SettingsPageItemDescriptionStyle}" />
</Grid>
</DataTemplate>
<local:CursorColorTemplateSelector
x:Key="CursorColorTemplateSelector"
DefaultTemplate="{StaticResource ColorPreviewTemplate}"
InvertColorTemplate="{StaticResource InvertCursorColorPreviewTemplate}"
ColorScheme="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}" />
</ResourceDictionary>
</UserControl.Resources>
@ -514,10 +570,10 @@
ClearSettingValue="{x:Bind Appearance.ClearCursorColor}"
CurrentValue="{x:Bind Appearance.CursorColorPreview, Mode=OneWay}"
CurrentValueAccessibleName="{x:Bind Appearance.CursorColorPreview, Converter={StaticResource ColorToStringConverter}, Mode=OneWay}"
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
CurrentValueTemplateSelector="{StaticResource CursorColorTemplateSelector}"
HasSettingValue="{x:Bind Appearance.HasCursorColor, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.CursorColorOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyleWithComplexPreview}">
Style="{StaticResource ExpanderSettingContainerStyleWithTemplateSelector}">
<local:NullableColorPicker x:Uid="Profile_CursorColor_NullableColorPicker"
ColorSchemeVM="{x:Bind Appearance.CurrentColorScheme, Mode=OneWay}"
CurrentColor="{x:Bind Appearance.CursorColor, Mode=TwoWay}"

View File

@ -2463,4 +2463,8 @@
<data name="Settings_ResetApplicationStateConfirmationButton.Content" xml:space="preserve">
<value>Yes, clear the cache</value>
</data>
<data name="Profile_CursorColor_InvertTextBlock.Text" xml:space="preserve">
<value>Invert</value>
<comment>Label displayed when the selected cursor color value inverts the selected text's color.</comment>
</data>
</root>

View File

@ -15,6 +15,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
DependencyProperty SettingContainer::_FontIconGlyphProperty{ nullptr };
DependencyProperty SettingContainer::_CurrentValueProperty{ nullptr };
DependencyProperty SettingContainer::_CurrentValueTemplateProperty{ nullptr };
DependencyProperty SettingContainer::_CurrentValueTemplateSelectorProperty{ nullptr };
DependencyProperty SettingContainer::_CurrentValueAccessibleNameProperty{ nullptr };
DependencyProperty SettingContainer::_HasSettingValueProperty{ nullptr };
DependencyProperty SettingContainer::_SettingOverrideSourceProperty{ nullptr };
@ -75,6 +76,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
xaml_typename<Editor::SettingContainer>(),
PropertyMetadata{ nullptr });
}
if (!_CurrentValueTemplateSelectorProperty)
{
_CurrentValueTemplateSelectorProperty =
DependencyProperty::Register(
L"CurrentValueTemplateSelector",
xaml_typename<Windows::UI::Xaml::Controls::DataTemplateSelector>(),
xaml_typename<Editor::SettingContainer>(),
PropertyMetadata{ nullptr });
}
if (!_CurrentValueAccessibleNameProperty)
{
_CurrentValueAccessibleNameProperty =
@ -116,7 +126,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SettingContainer::_OnCurrentValueChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& /*e*/)
{
const auto& obj{ d.try_as<Editor::SettingContainer>() };
get_self<SettingContainer>(obj)->_UpdateCurrentValueAutoProp();
const auto& settingContainer = get_self<SettingContainer>(obj);
settingContainer->_UpdateCurrentValueAutoProp();
settingContainer->_UpdateCurrentValueTemplate();
}
void SettingContainer::_OnHasSettingValueChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*args*/)
@ -279,6 +291,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
void SettingContainer::_UpdateCurrentValueTemplate()
{
if (const auto& child{ GetTemplateChild(L"CurrentValuePresenter") })
{
if (const auto& contentPresenter{ child.try_as<Controls::ContentPresenter>() })
{
const auto newTemplate = contentPresenter.ContentTemplateSelector().SelectTemplate(CurrentValue());
contentPresenter.ContentTemplate(newTemplate);
}
}
}
// Method Description:
// - Helper function for generating the override message
// Arguments:

View File

@ -38,6 +38,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
DEPENDENCY_PROPERTY(hstring, FontIconGlyph);
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, CurrentValue);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::DataTemplate, CurrentValueTemplate);
DEPENDENCY_PROPERTY(Windows::UI::Xaml::Controls::DataTemplateSelector, CurrentValueTemplateSelector);
DEPENDENCY_PROPERTY(hstring, CurrentValueAccessibleName);
DEPENDENCY_PROPERTY(bool, HasSettingValue);
DEPENDENCY_PROPERTY(bool, StartExpanded);
@ -53,6 +54,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void _UpdateOverrideSystem();
void _UpdateHelpText();
void _UpdateCurrentValueAutoProp();
void _UpdateCurrentValueTemplate();
};
}

View File

@ -24,6 +24,9 @@ namespace Microsoft.Terminal.Settings.Editor
Windows.UI.Xaml.DataTemplate CurrentValueTemplate;
static Windows.UI.Xaml.DependencyProperty CurrentValueTemplateProperty { get; };
Windows.UI.Xaml.Controls.DataTemplateSelector CurrentValueTemplateSelector;
static Windows.UI.Xaml.DependencyProperty CurrentValueTemplateSelectorProperty { get; };
String CurrentValueAccessibleName;
static Windows.UI.Xaml.DependencyProperty CurrentValueAccessibleNameProperty { get; };

View File

@ -470,6 +470,58 @@
</Setter>
</Style>
<!-- A setting container which can expand. Supports data template override for preview -->
<Style x:Key="ExpanderSettingContainerStyleWithTemplateSelector"
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 x:Name="CurrentValuePresenter"
Grid.Column="1"
MaxWidth="248"
Margin="0,0,-16,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Content="{TemplateBinding CurrentValue}"
ContentTemplateSelector="{TemplateBinding CurrentValueTemplateSelector}" />
</Grid>
</muxc:Expander.Header>
</muxc:Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- A setting container that displays a warning with an icon -->
<Style x:Key="SettingContainerWarningStyle"
TargetType="local:SettingContainer">