diff --git a/src/cascadia/TerminalApp/App.xaml b/src/cascadia/TerminalApp/App.xaml
index 2f025073f97..7dabb689a3c 100644
--- a/src/cascadia/TerminalApp/App.xaml
+++ b/src/cascadia/TerminalApp/App.xaml
@@ -153,6 +153,9 @@
+
+
@@ -166,6 +169,9 @@
+
+
@@ -183,6 +189,9 @@
-->
+
+
diff --git a/src/cascadia/TerminalApp/SettingsTab.cpp b/src/cascadia/TerminalApp/SettingsTab.cpp
index 54e48ed1e0d..6ac9bb5e79e 100644
--- a/src/cascadia/TerminalApp/SettingsTab.cpp
+++ b/src/cascadia/TerminalApp/SettingsTab.cpp
@@ -23,9 +23,11 @@ namespace winrt
namespace winrt::TerminalApp::implementation
{
- SettingsTab::SettingsTab(MainPage settingsUI)
+ SettingsTab::SettingsTab(MainPage settingsUI,
+ winrt::Windows::UI::Xaml::ElementTheme requestedTheme)
{
Content(settingsUI);
+ _requestedTheme = requestedTheme;
_MakeTabViewItem();
_CreateContextMenu();
@@ -36,6 +38,10 @@ namespace winrt::TerminalApp::implementation
{
auto settingsUI{ Content().as() };
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:
@@ -105,4 +111,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();
+ }
}
diff --git a/src/cascadia/TerminalApp/SettingsTab.h b/src/cascadia/TerminalApp/SettingsTab.h
index 803ed8cb03e..e9cfc9c8376 100644
--- a/src/cascadia/TerminalApp/SettingsTab.h
+++ b/src/cascadia/TerminalApp/SettingsTab.h
@@ -24,7 +24,8 @@ namespace winrt::TerminalApp::implementation
struct SettingsTab : SettingsTabT
{
public:
- SettingsTab(winrt::Microsoft::Terminal::Settings::Editor::MainPage settingsUI);
+ SettingsTab(winrt::Microsoft::Terminal::Settings::Editor::MainPage settingsUI,
+ winrt::Windows::UI::Xaml::ElementTheme requestedTheme);
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
@@ -32,7 +33,11 @@ namespace winrt::TerminalApp::implementation
std::vector 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;
};
}
diff --git a/src/cascadia/TerminalApp/TabBase.cpp b/src/cascadia/TerminalApp/TabBase.cpp
index 167b5008066..dda15f10bc8 100644
--- a/src/cascadia/TerminalApp/TabBase.cpp
+++ b/src/cascadia/TerminalApp/TabBase.cpp
@@ -5,6 +5,8 @@
#include
#include "TabBase.h"
#include "TabBase.g.cpp"
+#include "Utils.h"
+#include "ColorHelper.h"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
@@ -252,4 +254,291 @@ namespace winrt::TerminalApp::implementation
});
}
+ std::optional 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:
+ // -
+ // Return Value:
+ // -
+ 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.
+ const auto currentColor = tab->GetTabColor();
+ if (currentColor.has_value())
+ {
+ tab->_ApplyTabColorOnUIThread(currentColor.value());
+ }
+ else if (tab->_themeColor != nullptr)
+ {
+ // Safely get the active control's brush.
+ const 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->_ApplyTabColorOnUIThread(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:
+ // -
+ void TabBase::_ApplyTabColorOnUIThread(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 DON'T have a color set from the color picker, or the profile's
+ // tabColor, but we do have a unfocused color in the theme, use the
+ // unfocused theme color here instead.
+ if (!GetTabColor().has_value() &&
+ _unfocusedThemeColor != nullptr)
+ {
+ // Safely get the active control's brush.
+ const 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.
+ const auto deselectedActualColor = deselectedTabColor.layer_over(_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:
+ // -
+ // Return Value:
+ // -
+ void TabBase::_ClearTabBackgroundColor()
+ {
+ static const 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 (const 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:
+ // -
+ // Return Value:
+ // -
+ 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);
+ }
+ }
+
}
diff --git a/src/cascadia/TerminalApp/TabBase.h b/src/cascadia/TerminalApp/TabBase.h
index a04873f8905..fb32fe0e377 100644
--- a/src/cascadia/TerminalApp/TabBase.h
+++ b/src/cascadia/TerminalApp/TabBase.h
@@ -25,6 +25,11 @@ namespace winrt::TerminalApp::implementation
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
virtual std::vector BuildStartupActions() const = 0;
+ virtual std::optional GetTabColor();
+ void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& focused,
+ const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& unfocused,
+ const til::color& tabRowColor);
+
WINRT_CALLBACK(RequestFocusActiveControl, winrt::delegate);
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler);
@@ -51,6 +56,10 @@ namespace winrt::TerminalApp::implementation
Microsoft::Terminal::Settings::Model::IActionMapView _actionMap{ nullptr };
winrt::hstring _keyChord{};
+ winrt::Microsoft::Terminal::Settings::Model::ThemeColor _themeColor{ nullptr };
+ winrt::Microsoft::Terminal::Settings::Model::ThemeColor _unfocusedThemeColor{ nullptr };
+ til::color _tabRowColor;
+
virtual void _CreateContextMenu();
virtual winrt::hstring _CreateToolTipTitle();
@@ -63,6 +72,12 @@ namespace winrt::TerminalApp::implementation
winrt::fire_and_forget _UpdateSwitchToTabKeyChord();
void _UpdateToolTip();
+ void _RecalculateAndApplyTabColor();
+ void _ApplyTabColorOnUIThread(const winrt::Windows::UI::Color& color);
+ void _ClearTabBackgroundColor();
+ void _RefreshVisualState();
+ virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() = 0;
+
friend class ::TerminalAppLocalTests::TabTests;
};
}
diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
index 36937f4481d..37436c48cc3 100644
--- a/src/cascadia/TerminalApp/TerminalPage.cpp
+++ b/src/cascadia/TerminalApp/TerminalPage.cpp
@@ -19,6 +19,7 @@
#include "DebugTapConnection.h"
#include "SettingsTab.h"
#include "TabRowControl.h"
+#include "Utils.h"
using namespace winrt;
using namespace winrt::Microsoft::Terminal::Control;
@@ -3321,7 +3322,7 @@ namespace winrt::TerminalApp::implementation
}
});
- auto newTabImpl = winrt::make_self(sui);
+ auto newTabImpl = winrt::make_self(sui, _settings.GlobalSettings().CurrentTheme().RequestedTheme());
// Add the new tab to the list of our tabs.
_tabs.Append(*newTabImpl);
@@ -4101,79 +4102,11 @@ namespace winrt::TerminalApp::implementation
const auto theme = _settings.GlobalSettings().CurrentTheme();
auto requestedTheme{ theme.RequestedTheme() };
- // First: Update the colors of our individual TabViewItems. This applies tab.background to the tabs via TerminalTab::ThemeColor
- {
- auto tabBackground = theme.Tab() ? theme.Tab().Background() : nullptr;
- for (const auto& tab : _tabs)
- {
- if (const auto& terminalTabImpl{ _GetTerminalTabImpl(tab) })
- {
- terminalTabImpl->ThemeColor(tabBackground);
- }
- }
- }
-
const auto res = Application::Current().Resources();
- // XAML Hacks:
- //
- // the App is always in the OS theme, so the
- // App::Current().Resources() lookup will always get the value for the
- // OS theme, not the requested theme.
- //
- // This helper allows us to instead lookup the value of a resource
- // specified by `key` for the given `requestedTheme`, from the
- // dictionaries in App.xaml. Make sure the value is actually there!
- // Otherwise this'll throw like any other Lookup for a resource that
- // isn't there.
- static const auto lookup = [](auto& res, auto& requestedTheme, auto& key) {
- // You want the Default version of the resource? Great, the App is
- // always in the OS theme. Just look it up and be done.
- if (requestedTheme == ElementTheme::Default)
- {
- return res.Lookup(key);
- }
- static const auto lightKey = winrt::box_value(L"Light");
- static const auto darkKey = winrt::box_value(L"Dark");
- // There isn't an ElementTheme::HighContrast.
-
- auto requestedThemeKey = requestedTheme == ElementTheme::Dark ? darkKey : lightKey;
- for (const auto& dictionary : res.MergedDictionaries())
- {
- // Don't look in the MUX resources. They come first. A person
- // with more patience than me may find a way to look through our
- // dictionaries first, then the MUX ones, but that's not needed
- // currently
- if (dictionary.Source())
- {
- continue;
- }
- // Look through the theme dictionaries we defined:
- for (const auto& [dictionaryKey, dict] : dictionary.ThemeDictionaries())
- {
- // Does the key for this dict match the theme we're looking for?
- if (winrt::unbox_value(dictionaryKey) !=
- winrt::unbox_value(requestedThemeKey))
- {
- // No? skip it.
- continue;
- }
- // Look for the requested resource in this dict.
- const auto themeDictionary = dict.as();
- if (themeDictionary.HasKey(key))
- {
- return themeDictionary.Lookup(key);
- }
- }
- }
-
- // We didn't find it in the requested dict, fall back to the default dictionary.
- return res.Lookup(key);
- };
-
// Use our helper to lookup the theme-aware version of the resource.
const auto tabViewBackgroundKey = winrt::box_value(L"TabViewBackground");
- const auto backgroundSolidBrush = lookup(res, requestedTheme, tabViewBackgroundKey).as();
+ const auto backgroundSolidBrush = ThemeLookup(res, requestedTheme, tabViewBackgroundKey).as();
til::color bgColor = backgroundSolidBrush.Color();
@@ -4218,6 +4151,21 @@ namespace winrt::TerminalApp::implementation
_tabRow.Background(TitlebarBrush());
}
+ // Second: Update the colors of our individual TabViewItems. This
+ // applies tab.background to the tabs via TerminalTab::ThemeColor.
+ //
+ // Do this second, so that we already know the bgColor of the titlebar.
+ {
+ const auto tabBackground = theme.Tab() ? theme.Tab().Background() : nullptr;
+ const auto tabUnfocusedBackground = theme.Tab() ? theme.Tab().UnfocusedBackground() : nullptr;
+ for (const auto& tab : _tabs)
+ {
+ winrt::com_ptr tabImpl;
+ tabImpl.copy_from(winrt::get_self(tab));
+ tabImpl->ThemeColor(tabBackground, tabUnfocusedBackground, bgColor);
+ }
+ }
+
// Update the new tab button to have better contrast with the new color.
// In theory, it would be convenient to also change these for the
// inactive tabs as well, but we're leaving that as a follow up.
diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp
index 6ef8c735853..4bac51928bf 100644
--- a/src/cascadia/TerminalApp/TerminalTab.cpp
+++ b/src/cascadia/TerminalApp/TerminalTab.cpp
@@ -1394,169 +1394,6 @@ namespace winrt::TerminalApp::implementation
_RecalculateAndApplyTabColor();
}
- void TerminalTab::ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& color)
- {
- _themeColor = color;
- _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:
- // -
- // Return Value:
- // -
- void TerminalTab::_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)
- {
- // One-liner to safely get the active control's brush.
- Media::Brush terminalBrush{ nullptr };
- if (const auto& c{ tab->GetActiveTerminalControl() })
- {
- terminalBrush = c.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:
- // -
- void TerminalTab::_ApplyTabColor(const winrt::Windows::UI::Color& color)
- {
- Media::SolidColorBrush selectedTabBrush{};
- Media::SolidColorBrush deselectedTabBrush{};
- Media::SolidColorBrush fontBrush{};
- 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);
-
- // 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(color);
- deselectedTabBrush.Opacity(0.3);
-
- hoverTabBrush.Color(color);
- hoverTabBrush.Opacity(0.6);
-
- // 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);
-
- // TabViewItem().Foreground() unfortunately does not work for us. It
- // 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().Resources().Insert(winrt::box_value(L"TabViewItemHeaderForeground"), fontBrush);
- 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"), fontBrush);
- 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();
-
- _ColorSelectedHandlers(color);
- }
-
// Method Description:
// - Clear the custom runtime color of the tab, if any color is set. This
// will re-apply whatever the tab's base color should be (either the color
@@ -1571,54 +1408,14 @@ namespace winrt::TerminalApp::implementation
_RecalculateAndApplyTabColor();
}
- // Method Description:
- // - Clear out any color we've set for the TabViewItem.
- // - This method should only be called on the UI thread.
- // Arguments:
- // -
- // Return Value:
- // -
- void TerminalTab::_ClearTabBackgroundColor()
+ winrt::Windows::UI::Xaml::Media::Brush TerminalTab::_BackgroundBrush()
{
- 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)
+ Media::Brush terminalBrush{ nullptr };
+ if (const auto& c{ GetActiveTerminalControl() })
{
- auto key = winrt::box_value(keyString);
- if (TabViewItem().Resources().HasKey(key))
- {
- TabViewItem().Resources().Remove(key);
- }
+ terminalBrush = c.BackgroundBrush();
}
-
- // 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();
- _ColorClearedHandlers();
+ return terminalBrush;
}
// Method Description:
@@ -1633,27 +1430,6 @@ namespace winrt::TerminalApp::implementation
_ColorPickerRequestedHandlers();
}
- // Method Description:
- // Toggles the visual state of the tab view item,
- // so that changes to the tab color are reflected immediately
- // Arguments:
- // -
- // Return Value:
- // -
- void TerminalTab::_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);
- }
- }
-
// - Get the total number of leaf panes in this tab. This will be the number
// of actual controls hosted by this tab.
// Arguments:
diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h
index 5f7a4c8ed82..53492095db1 100644
--- a/src/cascadia/TerminalApp/TerminalTab.h
+++ b/src/cascadia/TerminalApp/TerminalTab.h
@@ -71,9 +71,7 @@ namespace winrt::TerminalApp::implementation
void ResetTabText();
void ActivateTabRenamer();
- std::optional GetTabColor();
-
- void ThemeColor(const winrt::Microsoft::Terminal::Settings::Model::ThemeColor& color);
+ virtual std::optional GetTabColor() override;
void SetRuntimeTabColor(const winrt::Windows::UI::Color& color);
void ResetRuntimeTabColor();
void RequestColorPicker();
@@ -100,8 +98,6 @@ namespace winrt::TerminalApp::implementation
}
WINRT_CALLBACK(ActivePaneChanged, winrt::delegate<>);
- WINRT_CALLBACK(ColorSelected, winrt::delegate);
- WINRT_CALLBACK(ColorCleared, winrt::delegate<>);
WINRT_CALLBACK(TabRaiseVisualBell, winrt::delegate<>);
WINRT_CALLBACK(DuplicateRequested, winrt::delegate<>);
WINRT_CALLBACK(SplitTabRequested, winrt::delegate<>);
@@ -119,7 +115,6 @@ namespace winrt::TerminalApp::implementation
std::optional _runtimeTabColor{};
winrt::TerminalApp::TabHeaderControl _headerControl{};
winrt::TerminalApp::TerminalTabStatus _tabStatus{};
- winrt::Microsoft::Terminal::Settings::Model::ThemeColor _themeColor{ nullptr };
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{ nullptr };
winrt::event_token _colorSelectedToken;
@@ -163,8 +158,6 @@ namespace winrt::TerminalApp::implementation
void _CreateContextMenu() override;
virtual winrt::hstring _CreateToolTipTitle() override;
- void _RefreshVisualState();
-
void _DetachEventHandlersFromControl(const uint32_t paneId, const winrt::Microsoft::Terminal::Control::TermControl& control);
void _AttachEventHandlersToControl(const uint32_t paneId, const winrt::Microsoft::Terminal::Control::TermControl& control);
void _AttachEventHandlersToPane(std::shared_ptr pane);
@@ -173,16 +166,14 @@ namespace winrt::TerminalApp::implementation
winrt::hstring _GetActiveTitle() const;
- void _RecalculateAndApplyTabColor();
- void _ApplyTabColor(const winrt::Windows::UI::Color& color);
- void _ClearTabBackgroundColor();
-
void _RecalculateAndApplyReadOnly();
void _UpdateProgressState();
void _DuplicateTab();
+ virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;
+
friend class ::TerminalAppLocalTests::TabTests;
};
}
diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
index 4ebc362ddd6..502b4adb404 100644
--- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h
+++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
@@ -129,6 +129,7 @@ Author(s):
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr) \
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedBackground, "unfocusedBackground", nullptr)
-#define MTSM_THEME_TAB_SETTINGS(X) \
- X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr) \
+#define MTSM_THEME_TAB_SETTINGS(X) \
+ X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr) \
+ X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedBackground, "unfocusedBackground", nullptr) \
X(winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility, ShowCloseButton, "showCloseButton", winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility::Always)
diff --git a/src/cascadia/TerminalSettingsModel/Theme.cpp b/src/cascadia/TerminalSettingsModel/Theme.cpp
index dfb108634ac..c7236a8463f 100644
--- a/src/cascadia/TerminalSettingsModel/Theme.cpp
+++ b/src/cascadia/TerminalSettingsModel/Theme.cpp
@@ -199,6 +199,30 @@ winrt::WUX::Media::Brush ThemeColor::Evaluate(const winrt::WUX::ResourceDictiona
return nullptr;
}
+// Method Description:
+// - This is not an actual property on a theme color setting, but rather
+// something derived from the value itself. This is "the opacity we should use
+// for this ThemeColor should it be used as a unfocusedTab color". Basically,
+// terminalBackground and accent use 30% opacity when set, to match the how
+// inactive tabs were colored before themes existed.
+// Arguments:
+// -
+// Return Value:
+// - the opacity that should be used if this color is being applied to a
+// tab.unfocusedBackground property.
+uint8_t ThemeColor::UnfocusedTabOpacity() const noexcept
+{
+ switch (ColorType())
+ {
+ case ThemeColorType::Accent:
+ case ThemeColorType::TerminalBackground:
+ return 77; // 77 = .3 * 256
+ case ThemeColorType::Color:
+ return _Color.a;
+ }
+ return 0;
+}
+
#define THEME_SETTINGS_FROM_JSON(type, name, jsonKey, ...) \
{ \
std::optional _val; \
diff --git a/src/cascadia/TerminalSettingsModel/Theme.h b/src/cascadia/TerminalSettingsModel/Theme.h
index 96a496b908c..e39d42b8f20 100644
--- a/src/cascadia/TerminalSettingsModel/Theme.h
+++ b/src/cascadia/TerminalSettingsModel/Theme.h
@@ -39,6 +39,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
winrt::Windows::UI::Xaml::Media::Brush Evaluate(const winrt::Windows::UI::Xaml::ResourceDictionary& res,
const winrt::Windows::UI::Xaml::Media::Brush& terminalBackground,
const bool forTitlebar);
+ uint8_t UnfocusedTabOpacity() const noexcept;
WINRT_PROPERTY(til::color, Color);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::ThemeColorType, ColorType);
diff --git a/src/cascadia/TerminalSettingsModel/Theme.idl b/src/cascadia/TerminalSettingsModel/Theme.idl
index 32127abf2ce..39260bb0cf4 100644
--- a/src/cascadia/TerminalSettingsModel/Theme.idl
+++ b/src/cascadia/TerminalSettingsModel/Theme.idl
@@ -32,6 +32,7 @@ namespace Microsoft.Terminal.Settings.Model
Windows.UI.Xaml.Media.Brush Evaluate(Windows.UI.Xaml.ResourceDictionary res,
Windows.UI.Xaml.Media.Brush terminalBackground,
Boolean forTitlebar);
+ UInt8 UnfocusedTabOpacity { get; };
}
runtimeclass WindowTheme {
@@ -45,6 +46,7 @@ namespace Microsoft.Terminal.Settings.Model
runtimeclass TabTheme {
ThemeColor Background { get; };
+ ThemeColor UnfocusedBackground { get; };
TabCloseButtonVisibility ShowCloseButton { get; };
}
diff --git a/src/cascadia/WinRTUtils/inc/Utils.h b/src/cascadia/WinRTUtils/inc/Utils.h
index 82824c5bfaa..ec8233fcb3c 100644
--- a/src/cascadia/WinRTUtils/inc/Utils.h
+++ b/src/cascadia/WinRTUtils/inc/Utils.h
@@ -53,3 +53,66 @@ winrt::Windows::Foundation::IAsyncOperation SaveFilePicker(HWND
}
winrt::Windows::Foundation::IAsyncOperation OpenImagePicker(HWND parentHwnd);
+
+#ifdef WINRT_Windows_UI_Xaml_H
+// Only compile me if Windows.UI.Xaml is already included.
+//
+// XAML Hacks:
+//
+// the App is always in the OS theme, so the
+// App::Current().Resources() lookup will always get the value for the
+// OS theme, not the requested theme.
+//
+// This helper allows us to instead lookup the value of a resource
+// specified by `key` for the given `requestedTheme`, from the
+// dictionaries in App.xaml. Make sure the value is actually there!
+// Otherwise this'll throw like any other Lookup for a resource that
+// isn't there.
+winrt::Windows::Foundation::IInspectable ThemeLookup(const auto& res,
+ const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme,
+ const winrt::Windows::Foundation::IInspectable& key)
+{
+ // You want the Default version of the resource? Great, the App is
+ // always in the OS theme. Just look it up and be done.
+ if (requestedTheme == winrt::Windows::UI::Xaml::ElementTheme::Default)
+ {
+ return res.Lookup(key);
+ }
+ static const auto lightKey = winrt::box_value(L"Light");
+ static const auto darkKey = winrt::box_value(L"Dark");
+ // There isn't an ElementTheme::HighContrast.
+
+ const auto requestedThemeKey = requestedTheme == winrt::Windows::UI::Xaml::ElementTheme::Dark ? darkKey : lightKey;
+ for (const auto& dictionary : res.MergedDictionaries())
+ {
+ // Don't look in the MUX resources. They come first. A person
+ // with more patience than me may find a way to look through our
+ // dictionaries first, then the MUX ones, but that's not needed
+ // currently
+ if (dictionary.Source())
+ {
+ continue;
+ }
+ // Look through the theme dictionaries we defined:
+ for (const auto& [dictionaryKey, dict] : dictionary.ThemeDictionaries())
+ {
+ // Does the key for this dict match the theme we're looking for?
+ if (winrt::unbox_value(dictionaryKey) !=
+ winrt::unbox_value(requestedThemeKey))
+ {
+ // No? skip it.
+ continue;
+ }
+ // Look for the requested resource in this dict.
+ const auto themeDictionary = dict.as();
+ if (themeDictionary.HasKey(key))
+ {
+ return themeDictionary.Lookup(key);
+ }
+ }
+ }
+
+ // We didn't find it in the requested dict, fall back to the default dictionary.
+ return res.Lookup(key);
+};
+#endif
diff --git a/src/inc/til/color.h b/src/inc/til/color.h
index 5054be53318..ca07522b35b 100644
--- a/src/inc/til/color.h
+++ b/src/inc/til/color.h
@@ -134,6 +134,29 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
};
}
+ // source-over alpha blending/composition.
+ // `this` (source/top) will be blended "over" `destination` (bottom).
+ // `this` and `destination` are expected to be in straight alpha.
+ // See https://en.wikipedia.org/wiki/Alpha_compositing#Description
+ constexpr color layer_over(const color& destination) const
+ {
+ const auto sourceAlpha = a / 255.0f;
+ const auto destinationAlpha = destination.a / 255.0f;
+ const auto aInverse = 1.0f - sourceAlpha;
+
+ const auto resultA = a + destination.a * aInverse;
+ const auto resultR = (r * sourceAlpha + destination.r * destinationAlpha * aInverse) / resultA;
+ const auto resultG = (g * sourceAlpha + destination.g * destinationAlpha * aInverse) / resultA;
+ const auto resultB = (b * sourceAlpha + destination.b * destinationAlpha * aInverse) / resultA;
+
+ return {
+ static_cast(resultR + 0.5f),
+ static_cast(resultG + 0.5f),
+ static_cast(resultB + 0.5f),
+ static_cast(resultA + 0.5f),
+ };
+ }
+
#ifdef D3DCOLORVALUE_DEFINED
constexpr operator D3DCOLORVALUE() const
{