Add tab color setting to settings UI

This commit is contained in:
Carlos Zamora 2025-08-28 11:38:00 -07:00
parent 642a2aa41e
commit 82c49c8913
5 changed files with 110 additions and 4 deletions

View File

@ -151,6 +151,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{ {
_NotifyChanges(L"AnswerbackMessagePreview"); _NotifyChanges(L"AnswerbackMessagePreview");
} }
else if (viewModelProperty == L"TabThemeColorPreview")
{
_NotifyChanges(L"TabColorPreview");
}
});
_defaultAppearanceViewModel.PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
const auto viewModelProperty{ args.PropertyName() };
if (viewModelProperty == L"DarkColorSchemeName" || viewModelProperty == L"LightColorSchemeName")
{
_NotifyChanges(L"TabThemeColorPreview");
}
}); });
// Do the same for the starting directory // Do the same for the starting directory
@ -437,7 +449,77 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return RS_(L"Profile_AnswerbackMessageNone"); return RS_(L"Profile_AnswerbackMessageNone");
} }
Editor::AppearanceViewModel ProfileViewModel::DefaultAppearance() Windows::UI::Color ProfileViewModel::TabColorPreview() const
{
if (const auto modelVal = _profile.TabColor())
{
// user defined an override value
return Windows::UI::Color{
.A = 255,
.R = modelVal.Value().R,
.G = modelVal.Value().G,
.B = modelVal.Value().B
};
}
// set to null --> deduce value from theme
return TabThemeColorPreview();
}
Windows::UI::Color ProfileViewModel::TabThemeColorPreview() const
{
if (const auto currentTheme = _appSettings.GlobalSettings().CurrentTheme())
{
if (const auto tabTheme = currentTheme.Tab())
{
if (const auto tabBackground = tabTheme.Background())
{
const auto tabColor = DefaultAppearance().CurrentColorScheme().BackgroundColor().Color();
tabColor;
const auto& tabBrush = tabBackground.Evaluate(Application::Current().Resources(),
Windows::UI::Xaml::Media::SolidColorBrush{ DefaultAppearance().CurrentColorScheme().BackgroundColor().Color() },
false);
if (const auto& tabColorBrush = tabBrush.try_as<Windows::UI::Xaml::Media::SolidColorBrush>())
{
const auto brushColor = tabColorBrush.Color();
return brushColor;
}
}
}
}
// XAML default color for tab
// TODO CARLOS: I keep getting #FFFFFFFF
// - TabViewItemHeaderBackground: gives value above, is incorrect
// - LayerOnMicaBaseAltFillColorTransparentBrush: resolved value for TabViewItemHeaderBackground (from XAML GH); same issue
//
// I think the problem is that TabViewItemHeaderBackground is set on the TabViewItem, but I don't have access to that
// NEXT STEPS: allow NullableColorPicker to show color preview OR just text
// - add template selector
// - 2 templates:
// - color? --> ColorPreviewTemplate (in CommonResources.xaml)
// - else --> String/TextBlock
// - pass in string for when template selector fails?
if (const auto tabHeaderBackground = Application::Current().Resources().Lookup(box_value(L"TabViewItemHeaderBackground")))
{
if (const auto brush = tabHeaderBackground.try_as<Windows::UI::Xaml::Media::SolidColorBrush>())
{
// Fill the alpha so that the color can actually be displayed in the preview
auto brushColor = brush.Color();
brushColor.A = static_cast<uint8_t>(255);
return brushColor;
}
}
// This should never happen, but if it does, return Transparent so it's obvious
assert(false);
return Windows::UI::Colors::Transparent();
}
Editor::AppearanceViewModel ProfileViewModel::DefaultAppearance() const
{ {
return _defaultAppearanceViewModel; return _defaultAppearanceViewModel;
} }
@ -476,7 +558,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_NotifyChanges(L"UnfocusedAppearance", L"HasUnfocusedAppearance", L"ShowUnfocusedAppearance"); _NotifyChanges(L"UnfocusedAppearance", L"HasUnfocusedAppearance", L"ShowUnfocusedAppearance");
} }
Editor::AppearanceViewModel ProfileViewModel::UnfocusedAppearance() Editor::AppearanceViewModel ProfileViewModel::UnfocusedAppearance() const
{ {
return _unfocusedAppearanceViewModel; return _unfocusedAppearanceViewModel;
} }

View File

@ -109,8 +109,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// general profile knowledge // general profile knowledge
winrt::guid OriginalProfileGuid() const noexcept; winrt::guid OriginalProfileGuid() const noexcept;
bool CanDeleteProfile() const; bool CanDeleteProfile() const;
Editor::AppearanceViewModel DefaultAppearance(); Editor::AppearanceViewModel DefaultAppearance() const;
Editor::AppearanceViewModel UnfocusedAppearance(); Editor::AppearanceViewModel UnfocusedAppearance() const;
bool HasUnfocusedAppearance(); bool HasUnfocusedAppearance();
bool EditableUnfocusedAppearance() const noexcept; bool EditableUnfocusedAppearance() const noexcept;
bool ShowUnfocusedAppearance(); bool ShowUnfocusedAppearance();
@ -124,6 +124,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
bool Orphaned() const; bool Orphaned() const;
hstring TabTitlePreview() const; hstring TabTitlePreview() const;
hstring AnswerbackMessagePreview() const; hstring AnswerbackMessagePreview() const;
Windows::UI::Color TabColorPreview() const;
Windows::UI::Color TabThemeColorPreview() const;
til::typed_event<Editor::ProfileViewModel, Editor::DeleteProfileEventArgs> DeleteProfileRequested; til::typed_event<Editor::ProfileViewModel, Editor::DeleteProfileEventArgs> DeleteProfileRequested;

View File

@ -123,6 +123,8 @@ namespace Microsoft.Terminal.Settings.Editor
String TabTitlePreview { get; }; String TabTitlePreview { get; };
String AnswerbackMessagePreview { get; }; String AnswerbackMessagePreview { get; };
Windows.UI.Color TabColorPreview { get; };
Windows.UI.Color TabThemeColorPreview { get; };
void CreateUnfocusedAppearance(); void CreateUnfocusedAppearance();
void DeleteUnfocusedAppearance(); void DeleteUnfocusedAppearance();

View File

@ -208,6 +208,22 @@
Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" /> Text="{x:Bind Profile.TabTitle, Mode=TwoWay}" />
</local:SettingContainer> </local:SettingContainer>
<!-- Tab Color -->
<local:SettingContainer x:Name="TabColor"
x:Uid="Profile_TabColor"
ClearSettingValue="{x:Bind Profile.ClearTabColor}"
CurrentValue="{x:Bind Profile.TabColorPreview, Mode=OneWay}"
CurrentValueAccessibleName="{x:Bind Profile.TabColorPreview, Converter={StaticResource ColorToStringConverter}, Mode=OneWay}"
CurrentValueTemplate="{StaticResource ColorPreviewTemplate}"
HasSettingValue="{x:Bind Profile.HasTabColor, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.TabColorOverrideSource, Mode=OneWay}"
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}"
NullColorPreview="{x:Bind Profile.TabThemeColorPreview, Mode=OneWay}" />
</local:SettingContainer>
<!-- Elevate --> <!-- Elevate -->
<local:SettingContainer x:Uid="Profile_Elevate" <local:SettingContainer x:Uid="Profile_Elevate"
ClearSettingValue="{x:Bind Profile.ClearElevate}" ClearSettingValue="{x:Bind Profile.ClearElevate}"

View File

@ -2080,6 +2080,10 @@
<value>Use scheme color</value> <value>Use scheme color</value>
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment> <comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
</data> </data>
<data name="Profile_TabColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
<value>Use theme color</value>
<comment>Label for a button directing the user to use the tab color defined in the terminal's current theme.</comment>
</data>
<data name="Profile_IconTypeNone" xml:space="preserve"> <data name="Profile_IconTypeNone" xml:space="preserve">
<value>None</value> <value>None</value>
<comment>An option to choose from for the "icon style" dropdown. When selected, there will be no icon for the profile.</comment> <comment>An option to choose from for the "icon style" dropdown. When selected, there will be no icon for the profile.</comment>