diff --git a/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp index 721e426761b..fb84a1db5df 100644 --- a/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp @@ -217,6 +217,14 @@ namespace SettingsModelLocalTests { "name": "Different reference", "colorScheme": "One Half Dark" + }, + { + "name": "Different reference / Light and Dark", + "colorScheme": + { + "dark": "One Half Dark", + "light": "One Half Light" + } } ] }, @@ -322,5 +330,14 @@ namespace SettingsModelLocalTests VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().ColorSchemeName()); VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); } + { + const auto& prof{ profiles.GetAt(4) }; + VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().DarkColorSchemeName()); + VERIFY_ARE_EQUAL(L"One Half Light", prof.DefaultAppearance().LightColorSchemeName()); + VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().ColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName()); + VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName()); + } } } diff --git a/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp b/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp index 8680e7f9cd2..0ae0bcc164e 100644 --- a/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp @@ -779,21 +779,22 @@ namespace SettingsModelLocalTests VERIFY_ARE_EQUAL(6u, settings->ActiveProfiles().Size()); VERIFY_ARE_EQUAL(2u, settings->GlobalSettings().ColorSchemes().Size()); - auto createTerminalSettings = [&](const auto& profile, const auto& schemes) { + auto createTerminalSettings = [&](const auto& profile, const auto& schemes, const auto& Theme) { auto terminalSettings{ winrt::make_self() }; terminalSettings->_ApplyProfileSettings(profile); - terminalSettings->_ApplyAppearanceSettings(profile.DefaultAppearance(), schemes); + terminalSettings->_ApplyAppearanceSettings(profile.DefaultAppearance(), schemes, Theme); return terminalSettings; }; const auto activeProfiles = settings->ActiveProfiles(); const auto colorSchemes = settings->GlobalSettings().ColorSchemes(); - const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes); - const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes); - const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), colorSchemes); - const auto terminalSettings3 = createTerminalSettings(activeProfiles.GetAt(3), colorSchemes); - const auto terminalSettings4 = createTerminalSettings(activeProfiles.GetAt(4), colorSchemes); - const auto terminalSettings5 = createTerminalSettings(activeProfiles.GetAt(5), colorSchemes); + const auto currentTheme = settings->GlobalSettings().CurrentTheme(); + const auto terminalSettings0 = createTerminalSettings(activeProfiles.GetAt(0), colorSchemes, currentTheme); + const auto terminalSettings1 = createTerminalSettings(activeProfiles.GetAt(1), colorSchemes, currentTheme); + const auto terminalSettings2 = createTerminalSettings(activeProfiles.GetAt(2), colorSchemes, currentTheme); + const auto terminalSettings3 = createTerminalSettings(activeProfiles.GetAt(3), colorSchemes, currentTheme); + const auto terminalSettings4 = createTerminalSettings(activeProfiles.GetAt(4), colorSchemes, currentTheme); + const auto terminalSettings5 = createTerminalSettings(activeProfiles.GetAt(5), colorSchemes, currentTheme); VERIFY_ARE_EQUAL(til::color(0x12, 0x34, 0x56), terminalSettings0->CursorColor()); // from color scheme VERIFY_ARE_EQUAL(DEFAULT_CURSOR_COLOR, terminalSettings1->CursorColor()); // default diff --git a/src/cascadia/TerminalControl/IControlAppearance.idl b/src/cascadia/TerminalControl/IControlAppearance.idl index 96c3db75a11..8cd18b2513e 100644 --- a/src/cascadia/TerminalControl/IControlAppearance.idl +++ b/src/cascadia/TerminalControl/IControlAppearance.idl @@ -14,6 +14,7 @@ namespace Microsoft.Terminal.Control // IntenseIsBold and IntenseIsBright are in Core Appearance Double Opacity { get; }; + String ColorSchemeName { get; }; // Experimental settings Boolean RetroTerminalEffect { get; }; String PixelShaderPath { get; }; diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp index d48763eca1c..e9f4fcd2b6b 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.cpp @@ -18,6 +18,7 @@ static constexpr std::string_view SelectionBackgroundKey{ "selectionBackground" static constexpr std::string_view CursorColorKey{ "cursorColor" }; static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" }; static constexpr std::string_view OpacityKey{ "opacity" }; +static constexpr std::string_view ColorSchemeKey{ "colorScheme" }; AppearanceConfig::AppearanceConfig(winrt::weak_ref sourceProfile) : _sourceProfile(std::move(sourceProfile)) @@ -32,6 +33,9 @@ winrt::com_ptr AppearanceConfig::CopyAppearance(const Appearan appearance->_SelectionBackground = source->_SelectionBackground; appearance->_CursorColor = source->_CursorColor; appearance->_Opacity = source->_Opacity; + appearance->_ColorSchemeName = source->_ColorSchemeName; + appearance->_DarkColorSchemeName = source->_DarkColorSchemeName; + appearance->_LightColorSchemeName = source->_LightColorSchemeName; #define APPEARANCE_SETTINGS_COPY(type, name, jsonKey, ...) \ appearance->_##name = source->_##name; @@ -50,6 +54,25 @@ Json::Value AppearanceConfig::ToJson() const JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground); JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor); JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); + if (HasDarkColorSchemeName() && HasLightColorSchemeName()) + { + // check if the setting is coming from the UI, if so grab the ColorSchemeName until the settings UI is fixed.. + if (_ColorSchemeName != _DarkColorSchemeName) + { + JsonUtils::SetValueForKey(json["colorScheme"], "dark", _ColorSchemeName); + JsonUtils::SetValueForKey(json["colorScheme"], "light", _ColorSchemeName); + } + else + { + JsonUtils::SetValueForKey(json["colorScheme"], "dark", _DarkColorSchemeName); + JsonUtils::SetValueForKey(json["colorScheme"], "light", _LightColorSchemeName); + } + } + else if (HasColorSchemeName()) + { + JsonUtils::SetValueForKey(json["colorScheme"], "dark", _ColorSchemeName); + JsonUtils::SetValueForKey(json["colorScheme"], "light", _ColorSchemeName); + } #define APPEARANCE_SETTINGS_TO_JSON(type, name, jsonKey, ...) \ JsonUtils::SetValueForKey(json, jsonKey, _##name); @@ -79,6 +102,20 @@ void AppearanceConfig::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity); JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter{}); + if (json["colorScheme"].isString()) + { + // to make the UI happy, set ColorSchemeName. + JsonUtils::GetValueForKey(json, ColorSchemeKey, _ColorSchemeName); + JsonUtils::GetValueForKey(json, ColorSchemeKey, _DarkColorSchemeName); + JsonUtils::GetValueForKey(json, ColorSchemeKey, _LightColorSchemeName); + } + else if (json["colorScheme"].isObject()) + { + // to make the UI happy, set ColorSchemeName to whatever the dark value is. + JsonUtils::GetValueForKey(json["colorScheme"], "dark", _ColorSchemeName); + JsonUtils::GetValueForKey(json["colorScheme"], "dark", _DarkColorSchemeName); + JsonUtils::GetValueForKey(json["colorScheme"], "light", _LightColorSchemeName); + } #define APPEARANCE_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \ JsonUtils::GetValueForKey(json, jsonKey, _##name); diff --git a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h index bbc30927eb7..9fd8d96231f 100644 --- a/src/cascadia/TerminalSettingsModel/AppearanceConfig.h +++ b/src/cascadia/TerminalSettingsModel/AppearanceConfig.h @@ -41,6 +41,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, SelectionBackground, nullptr); INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, CursorColor, nullptr); INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0); + INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, ColorSchemeName, L"Campbell"); + INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, DarkColorSchemeName, L"Campbell"); + INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, LightColorSchemeName, L"Campbell"); #define APPEARANCE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \ INHERITABLE_SETTING(Model::IAppearanceConfig, type, name, ##__VA_ARGS__) diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index 9712c6e51cf..9c1e4a473a8 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -326,6 +326,9 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source) DUPLICATE_SETTING_MACRO_SUB(appearance, target, SelectionBackground); DUPLICATE_SETTING_MACRO_SUB(appearance, target, CursorColor); DUPLICATE_SETTING_MACRO_SUB(appearance, target, Opacity); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, DarkColorSchemeName); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, LightColorSchemeName); + DUPLICATE_SETTING_MACRO_SUB(appearance, target, ColorSchemeName); } // UnfocusedAppearance is treated as a single setting, @@ -430,22 +433,29 @@ void CascadiaSettings::_validateSettings() void CascadiaSettings::_validateAllSchemesExist() { const auto colorSchemes = _globals->ColorSchemes(); - auto foundInvalidScheme = false; + auto foundInvalidDarkScheme = false; + auto foundInvalidLightScheme = false; for (const auto& profile : _allProfiles) { for (const auto& appearance : std::array{ profile.DefaultAppearance(), profile.UnfocusedAppearance() }) { - if (appearance && !colorSchemes.HasKey(appearance.ColorSchemeName())) + if (appearance && !colorSchemes.HasKey(appearance.DarkColorSchemeName())) { - // Clear the user set color scheme. We'll just fallback instead. - appearance.ClearColorSchemeName(); - foundInvalidScheme = true; + // Clear the user set dark color scheme. We'll just fallback instead. + appearance.ClearDarkColorSchemeName(); + foundInvalidDarkScheme = true; + } + if (appearance && !colorSchemes.HasKey(appearance.LightColorSchemeName())) + { + // Clear the user set light color scheme. We'll just fallback instead. + appearance.ClearLightColorSchemeName(); + foundInvalidLightScheme = true; } } } - if (foundInvalidScheme) + if (foundInvalidDarkScheme || foundInvalidLightScheme) { _warnings.Append(SettingsLoadWarnings::UnknownColorScheme); } diff --git a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl index 2cfa305dec4..94fa06da0da 100644 --- a/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl +++ b/src/cascadia/TerminalSettingsModel/IAppearanceConfig.idl @@ -5,7 +5,7 @@ import "Profile.idl"; #include "IInheritable.idl.h" #define INHERITABLE_APPEARANCE_SETTING(Type, Name) \ - _BASE_INHERITABLE_SETTING(Type, Name); \ + _BASE_INHERITABLE_SETTING(Type, Name); \ Microsoft.Terminal.Settings.Model.IAppearanceConfig Name##OverrideSource { get; } namespace Microsoft.Terminal.Settings.Model @@ -22,9 +22,7 @@ namespace Microsoft.Terminal.Settings.Model Vertical_Bottom = 0x20 }; - [flags] - enum IntenseStyle - { + [flags] enum IntenseStyle { Bold = 0x1, Bright = 0x2, All = 0xffffffff @@ -34,6 +32,8 @@ namespace Microsoft.Terminal.Settings.Model { Microsoft.Terminal.Settings.Model.Profile SourceProfile { get; }; INHERITABLE_APPEARANCE_SETTING(String, ColorSchemeName); + INHERITABLE_APPEARANCE_SETTING(String, DarkColorSchemeName); + INHERITABLE_APPEARANCE_SETTING(String, LightColorSchemeName); INHERITABLE_APPEARANCE_SETTING(Windows.Foundation.IReference, Foreground); INHERITABLE_APPEARANCE_SETTING(Windows.Foundation.IReference, Background); INHERITABLE_APPEARANCE_SETTING(Windows.Foundation.IReference, SelectionBackground); diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h index 3ac59361ff9..a3b957aa307 100644 --- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h +++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h @@ -110,7 +110,6 @@ Author(s): X(bool, RetroTerminalEffect, "experimental.retroTerminalEffect", false) \ X(hstring, PixelShaderPath, "experimental.pixelShaderPath") \ X(ConvergedAlignment, BackgroundImageAlignment, "backgroundImageAlignment", ConvergedAlignment::Horizontal_Center | ConvergedAlignment::Vertical_Center) \ - X(hstring, ColorSchemeName, "colorScheme", L"Campbell") \ X(hstring, BackgroundImagePath, "backgroundImage") \ X(Model::IntenseStyle, IntenseTextStyle, "intenseTextStyle", Model::IntenseStyle::Bright) \ X(Core::AdjustTextMode, AdjustIndistinguishableColors, "adjustIndistinguishableColors", Core::AdjustTextMode::Never) diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index 0ba57857303..016097c501d 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -57,7 +57,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation const auto globals = appSettings.GlobalSettings(); settings->_ApplyProfileSettings(profile); settings->_ApplyGlobalSettings(globals); - settings->_ApplyAppearanceSettings(profile.DefaultAppearance(), globals.ColorSchemes()); + settings->_ApplyAppearanceSettings(profile.DefaultAppearance(), globals.ColorSchemes(), globals.CurrentTheme()); return settings; } @@ -91,7 +91,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { const auto globals = appSettings.GlobalSettings(); auto childImpl = settings->CreateChild(); - childImpl->_ApplyAppearanceSettings(unfocusedAppearance, globals.ColorSchemes()); + childImpl->_ApplyAppearanceSettings(unfocusedAppearance, globals.ColorSchemes(), globals.CurrentTheme()); child = *childImpl; } @@ -183,17 +183,58 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return settingsPair; } - void TerminalSettings::_ApplyAppearanceSettings(const IAppearanceConfig& appearance, const Windows::Foundation::Collections::IMapView& schemes) + void TerminalSettings::_ApplyAppearanceSettings(const IAppearanceConfig& appearance, const Windows::Foundation::Collections::IMapView& schemes, const winrt::Microsoft::Terminal::Settings::Model::Theme currentTheme) { _CursorShape = appearance.CursorShape(); _CursorHeight = appearance.CursorHeight(); - if (!appearance.ColorSchemeName().empty()) + // check if this setting update is coming from the UI. DarkColorSchemeName doesn't update till the save button is hit. This means if they differ, it is just the control preview that needs the update. + if (appearance.DarkColorSchemeName() != appearance.ColorSchemeName()) { if (const auto scheme = schemes.TryLookup(appearance.ColorSchemeName())) { ApplyColorScheme(scheme); } } + else if (currentTheme.Name() == L"dark") + { + if (!appearance.DarkColorSchemeName().empty()) + { + if (const auto scheme = schemes.TryLookup(appearance.DarkColorSchemeName())) + { + ApplyColorScheme(scheme); + } + } + } + else if (currentTheme.Name() == L"light") + { + if (!appearance.LightColorSchemeName().empty()) + { + if (const auto scheme = schemes.TryLookup(appearance.LightColorSchemeName())) + { + ApplyColorScheme(scheme); + } + } + } + else if (currentTheme.Name() == L"system" && Windows::UI::Xaml::Application::Current().RequestedTheme() == Windows::UI::Xaml::ApplicationTheme::Dark) + { + if (!appearance.DarkColorSchemeName().empty()) + { + if (const auto scheme = schemes.TryLookup(appearance.DarkColorSchemeName())) + { + ApplyColorScheme(scheme); + } + } + } + else if (currentTheme.Name() == L"system" && Windows::UI::Xaml::Application::Current().RequestedTheme() == Windows::UI::Xaml::ApplicationTheme::Light) + { + if (!appearance.LightColorSchemeName().empty()) + { + if (const auto scheme = schemes.TryLookup(appearance.LightColorSchemeName())) + { + ApplyColorScheme(scheme); + } + } + } if (appearance.Foreground()) { _DefaultForeground = til::color{ appearance.Foreground().Value() }; @@ -330,6 +371,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation else { AppliedColorScheme(scheme); + ColorSchemeName(scheme.Name()); _DefaultForeground = til::color{ scheme.Foreground() }; _DefaultBackground = til::color{ scheme.Background() }; _SelectionBackground = til::color{ scheme.SelectionBackground() }; diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 0dd65cdfbb7..84b62177935 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -128,6 +128,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::TerminalSettings, IFontFeatureMap, FontFeatures); INHERITABLE_SETTING(Model::TerminalSettings, Model::ColorScheme, AppliedColorScheme); + INHERITABLE_SETTING(Model::TerminalSettings, hstring, ColorSchemeName); INHERITABLE_SETTING(Model::TerminalSettings, hstring, BackgroundImage); INHERITABLE_SETTING(Model::TerminalSettings, double, BackgroundImageOpacity, 1.0); @@ -170,7 +171,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation void _ApplyGlobalSettings(const Model::GlobalAppSettings& globalSettings) noexcept; void _ApplyAppearanceSettings(const Microsoft::Terminal::Settings::Model::IAppearanceConfig& appearance, - const Windows::Foundation::Collections::IMapView& schemes); + const Windows::Foundation::Collections::IMapView& schemes, + const winrt::Microsoft::Terminal::Settings::Model::Theme currentTheme); friend class SettingsModelLocalTests::TerminalSettingsTests; }; diff --git a/src/cascadia/inc/ControlProperties.h b/src/cascadia/inc/ControlProperties.h index 5911fa26183..1a5efc0e1bf 100644 --- a/src/cascadia/inc/ControlProperties.h +++ b/src/cascadia/inc/ControlProperties.h @@ -16,10 +16,11 @@ X(winrt::Microsoft::Terminal::Core::AdjustTextMode, AdjustIndistinguishableColors, winrt::Microsoft::Terminal::Core::AdjustTextMode::Never) // --------------------------- Control Appearance --------------------------- -// All of these settings are defined in IControlSettings. +// All of these settings are defined in IControlAppearance. #define CONTROL_APPEARANCE_SETTINGS(X) \ X(til::color, SelectionBackground, DEFAULT_FOREGROUND) \ X(double, Opacity, 1.0) \ + X(winrt::hstring, ColorSchemeName, L"Campbell") \ X(winrt::hstring, BackgroundImage) \ X(double, BackgroundImageOpacity, 1.0) \ X(winrt::Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill) \