Skip to content

Commit

Permalink
PRE-MERGE #13743 Update the default themes for 1.16
Browse files Browse the repository at this point in the history
  • Loading branch information
DHowett committed Aug 23, 2022
2 parents 4383741 + dd218d1 commit c1df08e
Show file tree
Hide file tree
Showing 15 changed files with 478 additions and 317 deletions.
13 changes: 11 additions & 2 deletions src/cascadia/TerminalApp/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,13 @@
See GH #12356 for more history on the subject.
-->
<SolidColorBrush x:Key="TabViewBackground"
Color="#0a0a0a" />
Color="#2e2e2e" />

<StaticResource x:Key="UnfocusedBorderBrush"
ResourceKey="ApplicationPageBackgroundThemeBrush" />

<SolidColorBrush x:Key="SettingsUiTabBrush"
Color="#0c0c0c" />
</ResourceDictionary>

<ResourceDictionary x:Key="Light">
Expand All @@ -162,10 +165,13 @@
GH #12398 has more history on this value, as well as GH #12400
-->
<SolidColorBrush x:Key="TabViewBackground"
Color="#dadada" />
Color="#e8e8e8" />

<StaticResource x:Key="UnfocusedBorderBrush"
ResourceKey="ApplicationPageBackgroundThemeBrush" />

<SolidColorBrush x:Key="SettingsUiTabBrush"
Color="#ffffff" />
</ResourceDictionary>

<ResourceDictionary x:Key="HighContrast">
Expand All @@ -183,6 +189,9 @@
-->
<StaticResource x:Key="TabViewBackground"
ResourceKey="SystemColorButtonFaceColorBrush" />

<StaticResource x:Key="SettingsUiTabBrush"
ResourceKey="SystemControlBackgroundBaseLowBrush" />
</ResourceDictionary>

</ResourceDictionary.ThemeDictionaries>
Expand Down
16 changes: 16 additions & 0 deletions src/cascadia/TerminalApp/SettingsTab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ namespace winrt::TerminalApp::implementation
{
auto settingsUI{ Content().as<MainPage>() };
settingsUI.UpdateSettings(settings);

// Stash away the current requested theme of the app. We'll need that in
// _BackgroundBrush() to do a theme-aware resource lookup
_requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme();
}

// Method Description:
Expand Down Expand Up @@ -105,4 +109,16 @@ namespace winrt::TerminalApp::implementation
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph));
}
}

winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush()
{
// Look up the color we should use for the settings tab item from our
// resources. This should only be used for when "terminalBackground" is
// requested.
static const auto key = winrt::box_value(L"SettingsUiTabBrush");
// You can't just do a Application::Current().Resources().TryLookup
// lookup, cause the app theme never changes! Do the hacky version
// instead.
return ThemeLookup(Application::Current().Resources(), _requestedTheme, key).try_as<winrt::Windows::UI::Xaml::Media::Brush>();
}
}
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/SettingsTab.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ namespace winrt::TerminalApp::implementation
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;

private:
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;

void _MakeTabViewItem() override;
winrt::fire_and_forget _CreateIcon();

virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;
};
}
283 changes: 283 additions & 0 deletions src/cascadia/TerminalApp/TabBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <LibraryResources.h>
#include "TabBase.h"
#include "TabBase.g.cpp"
#include "Utils.h"
#include "ColorHelper.h"

using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
Expand Down Expand Up @@ -252,4 +254,285 @@ namespace winrt::TerminalApp::implementation
});
}

std::optional<winrt::Windows::UI::Color> TabBase::GetTabColor()
{
return std::nullopt;
}

void TabBase::ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,
const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& unfocused,
const til::color& tabRowColor)
{
_themeColor = focused;
_unfocusedThemeColor = unfocused;
_tabRowColor = tabRowColor;
_RecalculateAndApplyTabColor();
}

// Method Description:
// - This function dispatches a function to the UI thread to recalculate
// what this tab's current background color should be. If a color is set,
// it will apply the given color to the tab's background. Otherwise, it
// will clear the tab's background color.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_RecalculateAndApplyTabColor()
{
auto weakThis{ get_weak() };

TabViewItem().Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [weakThis]() {
auto ptrTab = weakThis.get();
if (!ptrTab)
return;

auto tab{ ptrTab };

// GetTabColor will return the color set by the color picker, or the
// color specified in the profile. If neither of those were set,
// then look to _themeColor to see if there's a value there.
// Otherwise, clear our color, falling back to the TabView defaults.
auto currentColor = tab->GetTabColor();
if (currentColor.has_value())
{
tab->_ApplyTabColor(currentColor.value());
}
else if (tab->_themeColor != nullptr)
{
// Safely get the active control's brush.
Media::Brush terminalBrush{ tab->_BackgroundBrush() };

if (const auto themeBrush{ tab->_themeColor.Evaluate(Application::Current().Resources(), terminalBrush, false) })
{
// ThemeColor.Evaluate will get us a Brush (because the
// TermControl could have an acrylic BG, for example). Take
// that brush, and get the color out of it. We don't really
// want to have the tab items themselves be acrylic.
tab->_ApplyTabColor(til::color{ ThemeColor::ColorFromBrush(themeBrush) });
}
else
{
tab->_ClearTabBackgroundColor();
}
}
else
{
tab->_ClearTabBackgroundColor();
}
});
}

// Method Description:
// - Applies the given color to the background of this tab's TabViewItem.
// - Sets the tab foreground color depending on the luminance of
// the background color
// - This method should only be called on the UI thread.
// Arguments:
// - color: the color the user picked for their tab
// Return Value:
// - <none>
void TabBase::_ApplyTabColor(const winrt::Windows::UI::Color& color)
{
Media::SolidColorBrush selectedTabBrush{};
Media::SolidColorBrush deselectedTabBrush{};
Media::SolidColorBrush fontBrush{};
Media::SolidColorBrush deselectedFontBrush{};
Media::SolidColorBrush secondaryFontBrush{};
Media::SolidColorBrush hoverTabBrush{};
Media::SolidColorBrush subtleFillColorSecondaryBrush;
Media::SolidColorBrush subtleFillColorTertiaryBrush;
// calculate the luminance of the current color and select a font
// color based on that
// see https://www.w3.org/TR/WCAG20/#relativeluminancedef
if (TerminalApp::ColorHelper::IsBrightColor(color))
{
fontBrush.Color(winrt::Windows::UI::Colors::Black());
auto secondaryFontColor = winrt::Windows::UI::Colors::Black();
// For alpha value see: https://github.com/microsoft/microsoft-ui-xaml/blob/7a33ad772d77d908aa6b316ec24e6d2eb3ebf571/dev/CommonStyles/Common_themeresources_any.xaml#L269
secondaryFontColor.A = 0x9E;
secondaryFontBrush.Color(secondaryFontColor);
auto subtleFillColorSecondary = winrt::Windows::UI::Colors::Black();
subtleFillColorSecondary.A = 0x09;
subtleFillColorSecondaryBrush.Color(subtleFillColorSecondary);
auto subtleFillColorTertiary = winrt::Windows::UI::Colors::Black();
subtleFillColorTertiary.A = 0x06;
subtleFillColorTertiaryBrush.Color(subtleFillColorTertiary);
}
else
{
fontBrush.Color(winrt::Windows::UI::Colors::White());
auto secondaryFontColor = winrt::Windows::UI::Colors::White();
// For alpha value see: https://github.com/microsoft/microsoft-ui-xaml/blob/7a33ad772d77d908aa6b316ec24e6d2eb3ebf571/dev/CommonStyles/Common_themeresources_any.xaml#L14
secondaryFontColor.A = 0xC5;
secondaryFontBrush.Color(secondaryFontColor);
auto subtleFillColorSecondary = winrt::Windows::UI::Colors::White();
subtleFillColorSecondary.A = 0x0F;
subtleFillColorSecondaryBrush.Color(subtleFillColorSecondary);
auto subtleFillColorTertiary = winrt::Windows::UI::Colors::White();
subtleFillColorTertiary.A = 0x0A;
subtleFillColorTertiaryBrush.Color(subtleFillColorTertiary);
}

selectedTabBrush.Color(color);

// Start with the current tab color, set to Opacity=.3
til::color deselectedTabColor{ color };
deselectedTabColor = deselectedTabColor.with_alpha(77); // 255 * .3 = 77
// If we have a unfocused color in the theme:
if (_unfocusedThemeColor != nullptr)
{
// Safely get the active control's brush.
Media::Brush terminalBrush{ _BackgroundBrush() };

// Get the color of the brush.
if (const auto themeBrush{ _unfocusedThemeColor.Evaluate(Application::Current().Resources(), terminalBrush, false) })
{
// We did figure out the brush. Get the color out of it. If it
// was "accent" or "terminalBackground", then we're gonna set
// the alpha to .3 manually here.
// (ThemeColor::UnfocusedTabOpacity will do this for us). If the
// user sets both unfocused and focused tab.background to
// terminalBackground, this will allow for some differentiation
// (and is generally just sensible).
deselectedTabColor = til::color{ ThemeColor::ColorFromBrush(themeBrush) }.with_alpha(_unfocusedThemeColor.UnfocusedTabOpacity());
}
}

// currently if a tab has a custom color, a deselected state is
// signified by using the same color with a bit of transparency
deselectedTabBrush.Color(deselectedTabColor.with_alpha(255));
deselectedTabBrush.Opacity(deselectedTabColor.a / 255.f);

hoverTabBrush.Color(color);
hoverTabBrush.Opacity(0.6);

// Account for the color of the tab row when setting the color of text
// on inactive tabs. Consider:
// * black active tabs
// * on a white tab row
// * with a transparent inactive tab color
//
// We don't want that to result in white text on a white tab row for
// inactive tabs.
auto deselectedActualColor = deselectedTabColor.blend_with(_tabRowColor);
if (TerminalApp::ColorHelper::IsBrightColor(deselectedActualColor))
{
deselectedFontBrush.Color(winrt::Windows::UI::Colors::Black());
}
else
{
deselectedFontBrush.Color(winrt::Windows::UI::Colors::White());
}

// Prior to MUX 2.7, we set TabViewItemHeaderBackground, but now we can
// use TabViewItem().Background() for that. HOWEVER,
// TabViewItem().Background() only sets the color of the tab background
// when the TabViewItem is unselected. So we still need to set the other
// properties ourselves.
//
// In GH#11294 we thought we'd still need to set
// TabViewItemHeaderBackground manually, but GH#11382 discovered that
// Background() was actually okay after all.
TabViewItem().Background(deselectedTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), hoverTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush);

// Similarly, TabViewItem().Foreground() sets the color for the text
// when the TabViewItem isn't selected, but not when it is hovered,
// pressed, dragged, or selected, so we'll need to just set them all
// anyways.
TabViewItem().Foreground(deselectedFontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForeground"), deselectedFontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundSelected"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundPointerOver"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForegroundPressed"), fontBrush);

TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonForeground"), deselectedFontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonForegroundPressed"), secondaryFontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonForegroundPointerOver"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderPressedCloseButtonForeground"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderPointerOverCloseButtonForeground"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderSelectedCloseButtonForeground"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonBackgroundPressed"), subtleFillColorTertiaryBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderCloseButtonBackgroundPointerOver"), subtleFillColorSecondaryBrush);

TabViewItem().Resources().Insert(winrt::box_value(L"TabViewButtonForegroundActiveTab"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewButtonForegroundPressed"), fontBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewButtonForegroundPointerOver"), fontBrush);

_RefreshVisualState();
}

// Method Description:
// - Clear out any color we've set for the TabViewItem.
// - This method should only be called on the UI thread.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_ClearTabBackgroundColor()
{
winrt::hstring keys[] = {
L"TabViewItemHeaderBackground",
L"TabViewItemHeaderBackgroundSelected",
L"TabViewItemHeaderBackgroundPointerOver",
L"TabViewItemHeaderBackgroundPressed",
L"TabViewItemHeaderForeground",
L"TabViewItemHeaderForegroundSelected",
L"TabViewItemHeaderForegroundPointerOver",
L"TabViewItemHeaderForegroundPressed",
L"TabViewItemHeaderCloseButtonForeground",
L"TabViewItemHeaderCloseButtonForegroundPressed",
L"TabViewItemHeaderCloseButtonForegroundPointerOver",
L"TabViewItemHeaderPressedCloseButtonForeground",
L"TabViewItemHeaderPointerOverCloseButtonForeground",
L"TabViewItemHeaderSelectedCloseButtonForeground",
L"TabViewItemHeaderCloseButtonBackgroundPressed",
L"TabViewItemHeaderCloseButtonBackgroundPointerOver",
L"TabViewButtonForegroundActiveTab",
L"TabViewButtonForegroundPressed",
L"TabViewButtonForegroundPointerOver"
};

// simply clear any of the colors in the tab's dict
for (auto keyString : keys)
{
auto key = winrt::box_value(keyString);
if (TabViewItem().Resources().HasKey(key))
{
TabViewItem().Resources().Remove(key);
}
}

// GH#11382 DON'T set the background to null. If you do that, then the
// tab won't be hit testable at all. Transparent, however, is a totally
// valid hit test target. That makes sense.
TabViewItem().Background(WUX::Media::SolidColorBrush{ Windows::UI::Colors::Transparent() });

_RefreshVisualState();
}

// Method Description:
// Toggles the visual state of the tab view item,
// so that changes to the tab color are reflected immediately
// Arguments:
// - <none>
// Return Value:
// - <none>
void TabBase::_RefreshVisualState()
{
if (TabViewItem().IsSelected())
{
VisualStateManager::GoToState(TabViewItem(), L"Normal", true);
VisualStateManager::GoToState(TabViewItem(), L"Selected", true);
}
else
{
VisualStateManager::GoToState(TabViewItem(), L"Selected", true);
VisualStateManager::GoToState(TabViewItem(), L"Normal", true);
}
}

}
Loading

0 comments on commit c1df08e

Please sign in to comment.