Skip to content

Commit

Permalink
Add support for a profile to specify an "unfocused" appearance (#8392)
Browse files Browse the repository at this point in the history
This pull request adds an appearance configuration object to our
settings model and app lib, allowing the control to be rendered
differently depending on its state, and then uses it to add support for
an "unfocused" appearance that the terminal will use when it's not in
focus.

To accomplish this, we isolated the appearance-related settings from
Profile (into AppearanceConfig) and TerminalSettings (into the
IControlAppearance and ICoreAppearance interfaces). A bunch of work was
done to make inheritance work.

The unfocused appearance inherits from the focused one _for that
profile_. This is important: If you define a
defaults.unfocusedAppearance, it will apply all of defaults' settings to
any leaf profile when a terminal in that profile is out of focus.

Specified in #8345 
Closes #3062
Closes #2316
  • Loading branch information
PankajBhojwani authored Apr 8, 2021
1 parent 7f5a19b commit 9e83655
Show file tree
Hide file tree
Showing 44 changed files with 1,095 additions and 497 deletions.
116 changes: 116 additions & 0 deletions doc/cascadia/profiles.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,117 @@
}
]
},
"AppearanceConfig": {
"properties": {
"colorScheme": {
"description": "The name of a color scheme to use when unfocused.",
"type": "string"
},
"foreground": {
"$ref": "#/definitions/Color",
"default": "#cccccc",
"description": "Sets the text color when unfocused. Overrides \"foreground\" from the color scheme. Uses hex color format: \"#rrggbb\".",
"type": ["string", "null"]
},
"background": {
"$ref": "#/definitions/Color",
"default": "#0c0c0c",
"description": "Sets the background color of the text when unfocused. Overrides \"background\" from the color scheme. Uses hex color format: \"#rrggbb\".",
"type": ["string", "null"]
},
"selectionBackground": {
"oneOf": [
{"$ref": "#/definitions/Color"},
{ "type": "null" }
],
"description": "Sets the background color of selected text when unfocused. Overrides selectionBackground set in the color scheme. Uses hex color format: \"#rrggbb\"."
},
"cursorColor": {
"oneOf": [
{ "$ref": "#/definitions/Color" },
{"type": "null"}
],
"description": "Sets the color of the cursor when unfocused. Overrides the cursor color from the color scheme. Uses hex color format: \"#rrggbb\"."
},
"cursorShape": {
"default": "bar",
"description": "Sets the shape of the cursor when unfocused. Possible values:\n -\"bar\" ( ┃, default )\n -\"doubleUnderscore\" ( ‗ )\n -\"emptyBox\" ( ▯ )\n -\"filledBox\" ( █ )\n -\"underscore\" ( ▁ )\n -\"vintage\" ( ▃ )",
"enum": [
"bar",
"doubleUnderscore",
"emptyBox",
"filledBox",
"underscore",
"vintage"
],
"type": "string"
},
"cursorHeight": {
"description": "Sets the percentage height of the cursor (when unfocused) starting from the bottom. Only works when cursorShape is set to \"vintage\". Accepts values from 1-100.",
"maximum": 100,
"minimum": 1,
"type": ["integer","null"],
"default": 25
},
"backgroundImage": {
"description": "Sets the file location of the image to draw over the window background when unfocused.",
"oneOf": [
{
"type": ["string", null]
},
{
"enum": [
"desktopWallpaper"
]
}
],
"type": [ "string", "null" ]
},
"backgroundImageOpacity": {
"default": 1.0,
"description": "Sets the transparency of the background image when unfocused. Accepts floating point values from 0-1.",
"maximum": 1.0,
"minimum": 0.0,
"type": "number"
},
"backgroundImageStretchMode": {
"default": "uniformToFill",
"description": "Sets how the background image is resized to fill the window when unfocused.",
"enum": [
"fill",
"none",
"uniform",
"uniformToFill"
],
"type": "string"
},
"backgroundImageAlignment": {
"default": "center",
"enum": [
"bottom",
"bottomLeft",
"bottomRight",
"center",
"left",
"right",
"top",
"topLeft",
"topRight"
],
"description": "Sets how the background image aligns to the boundaries of the window when unfocused. Possible values: \"center\", \"left\", \"top\", \"right\", \"bottom\", \"topLeft\", \"topRight\", \"bottomLeft\", \"bottomRight\"",
"type": "string"
},
"experimental.retroTerminalEffect": {
"description": "When set to true, enable retro terminal effects when unfocused. This is an experimental feature, and its continued existence is not guaranteed.",
"type": "boolean"
},
"experimental.pixelShaderPath": {
"description": "Use to set a path to a pixel shader to use with the Terminal when unfocused. Overrides `experimental.retroTerminalEffect`. This is an experimental feature, and its continued existence is not guaranteed.",
"type": "string"
}
},
"type": "object"
},
"ProfileGuid": {
"default": "{}",
"pattern": "^\\{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\}$",
Expand Down Expand Up @@ -1000,6 +1111,11 @@
"description": "Sets the background color of the text. Overrides \"background\" from the color scheme. Uses hex color format: \"#rrggbb\".",
"type": ["string", "null"]
},
"unfocusedAppearance": {
"$ref": "#/definitions/AppearanceConfig",
"description": "Sets the appearance of the terminal when it is unfocused.",
"type": ["object", "null"]
},
"backgroundImage": {
"description": "Sets the file location of the image to draw over the window background.",
"oneOf": [
Expand Down
20 changes: 10 additions & 10 deletions src/cascadia/LocalTests_SettingsModel/ColorSchemeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,34 +338,34 @@ namespace SettingsModelLocalTests

// verify profile defaults
Log::Comment(L"Profile Defaults");
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().ColorSchemeName());
VERIFY_IS_TRUE(settings->ProfileDefaults().HasColorSchemeName());
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasColorSchemeName());

// verify all other profiles
const auto& profiles{ settings->AllProfiles() };
{
const auto& prof{ profiles.GetAt(0) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
VERIFY_IS_TRUE(prof.HasColorSchemeName());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(1) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
VERIFY_IS_TRUE(prof.HasColorSchemeName());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(2) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(newName, prof.ColorSchemeName());
VERIFY_IS_FALSE(prof.HasColorSchemeName());
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_FALSE(prof.DefaultAppearance().HasColorSchemeName());
}
{
const auto& prof{ profiles.GetAt(3) };
Log::Comment(prof.Name().c_str());
VERIFY_ARE_EQUAL(L"Scheme 2", prof.ColorSchemeName());
VERIFY_IS_TRUE(prof.HasColorSchemeName());
VERIFY_ARE_EQUAL(L"Scheme 2", prof.DefaultAppearance().ColorSchemeName());
VERIFY_IS_TRUE(prof.DefaultAppearance().HasColorSchemeName());
}
}
}
18 changes: 9 additions & 9 deletions src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1311,9 +1311,9 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());

VERIFY_ARE_EQUAL(L"schemeOne", settings->_allProfiles.GetAt(0).ColorSchemeName());
VERIFY_ARE_EQUAL(L"InvalidSchemeName", settings->_allProfiles.GetAt(1).ColorSchemeName());
VERIFY_ARE_EQUAL(L"Campbell", settings->_allProfiles.GetAt(2).ColorSchemeName());
VERIFY_ARE_EQUAL(L"schemeOne", settings->_allProfiles.GetAt(0).DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"InvalidSchemeName", settings->_allProfiles.GetAt(1).DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"Campbell", settings->_allProfiles.GetAt(2).DefaultAppearance().ColorSchemeName());

settings->_ValidateAllSchemesExist();

Expand All @@ -1323,9 +1323,9 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(3u, settings->_allProfiles.Size());
VERIFY_ARE_EQUAL(2u, settings->_globals->ColorSchemes().Size());

VERIFY_ARE_EQUAL(L"schemeOne", settings->_allProfiles.GetAt(0).ColorSchemeName());
VERIFY_ARE_EQUAL(L"Campbell", settings->_allProfiles.GetAt(1).ColorSchemeName());
VERIFY_ARE_EQUAL(L"Campbell", settings->_allProfiles.GetAt(2).ColorSchemeName());
VERIFY_ARE_EQUAL(L"schemeOne", settings->_allProfiles.GetAt(0).DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"Campbell", settings->_allProfiles.GetAt(1).DefaultAppearance().ColorSchemeName());
VERIFY_ARE_EQUAL(L"Campbell", settings->_allProfiles.GetAt(2).DefaultAppearance().ColorSchemeName());
}

void DeserializationTests::ValidateColorSchemeInCommands()
Expand Down Expand Up @@ -1543,7 +1543,7 @@ namespace SettingsModelLocalTests
settings->_ParseJsonString(settingsJson, false);
settings->LayerJson(settings->_userSettings);
VERIFY_ARE_NOT_EQUAL(0u, settings->_allProfiles.Size());
VERIFY_ARE_EQUAL(expectedPath, settings->_allProfiles.GetAt(0).ExpandedBackgroundImagePath());
VERIFY_ARE_EQUAL(expectedPath, settings->_allProfiles.GetAt(0).DefaultAppearance().ExpandedBackgroundImagePath());
}
void DeserializationTests::TestProfileBackgroundImageWithDesktopWallpaper()
{
Expand All @@ -1564,8 +1564,8 @@ namespace SettingsModelLocalTests
auto settings = winrt::make_self<implementation::CascadiaSettings>();
settings->_ParseJsonString(settingsJson, false);
settings->LayerJson(settings->_userSettings);
VERIFY_ARE_EQUAL(expectedBackgroundImagePath, settings->_allProfiles.GetAt(0).BackgroundImagePath());
VERIFY_ARE_NOT_EQUAL(expectedBackgroundImagePath, settings->_allProfiles.GetAt(0).ExpandedBackgroundImagePath());
VERIFY_ARE_EQUAL(expectedBackgroundImagePath, settings->_allProfiles.GetAt(0).DefaultAppearance().BackgroundImagePath());
VERIFY_ARE_NOT_EQUAL(expectedBackgroundImagePath, settings->_allProfiles.GetAt(0).DefaultAppearance().ExpandedBackgroundImagePath());
}
void DeserializationTests::TestCloseOnExitParsing()
{
Expand Down
36 changes: 18 additions & 18 deletions src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ namespace SettingsModelLocalTests
const auto profile2Json = VerifyParseSucceeded(profile2String);

auto profile0 = implementation::Profile::FromJson(profile0Json);
VERIFY_IS_NOT_NULL(profile0->Foreground());
VERIFY_ARE_EQUAL(til::color(0, 0, 0), til::color{ profile0->Foreground().Value() });
VERIFY_IS_NOT_NULL(profile0->DefaultAppearance().Foreground());
VERIFY_ARE_EQUAL(til::color(0, 0, 0), til::color{ profile0->DefaultAppearance().Foreground().Value() });

VERIFY_IS_NOT_NULL(profile0->Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->Background().Value() });
VERIFY_IS_NOT_NULL(profile0->DefaultAppearance().Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->DefaultAppearance().Background().Value() });

VERIFY_IS_NOT_NULL(profile0->SelectionBackground());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->SelectionBackground().Value() });
VERIFY_IS_NOT_NULL(profile0->DefaultAppearance().SelectionBackground());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile0->DefaultAppearance().SelectionBackground().Value() });

VERIFY_ARE_EQUAL(L"profile0", profile0->Name());

Expand All @@ -135,14 +135,14 @@ namespace SettingsModelLocalTests
auto profile1{ profile0->CreateChild() };
profile1->LayerJson(profile1Json);

VERIFY_IS_NOT_NULL(profile1->Foreground());
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile1->Foreground().Value() });
VERIFY_IS_NOT_NULL(profile1->DefaultAppearance().Foreground());
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile1->DefaultAppearance().Foreground().Value() });

VERIFY_IS_NOT_NULL(profile1->Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile1->Background().Value() });
VERIFY_IS_NOT_NULL(profile1->DefaultAppearance().Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile1->DefaultAppearance().Background().Value() });

VERIFY_IS_NOT_NULL(profile1->Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile1->Background().Value() });
VERIFY_IS_NOT_NULL(profile1->DefaultAppearance().Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile1->DefaultAppearance().Background().Value() });

VERIFY_ARE_EQUAL(L"profile1", profile1->Name());

Expand All @@ -154,14 +154,14 @@ namespace SettingsModelLocalTests
auto profile2{ profile1->CreateChild() };
profile2->LayerJson(profile2Json);

VERIFY_IS_NOT_NULL(profile2->Foreground());
VERIFY_ARE_EQUAL(til::color(3, 3, 3), til::color{ profile2->Foreground().Value() });
VERIFY_IS_NOT_NULL(profile2->DefaultAppearance().Foreground());
VERIFY_ARE_EQUAL(til::color(3, 3, 3), til::color{ profile2->DefaultAppearance().Foreground().Value() });

VERIFY_IS_NOT_NULL(profile2->Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile2->Background().Value() });
VERIFY_IS_NOT_NULL(profile2->DefaultAppearance().Background());
VERIFY_ARE_EQUAL(til::color(1, 1, 1), til::color{ profile2->DefaultAppearance().Background().Value() });

VERIFY_IS_NOT_NULL(profile2->SelectionBackground());
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile2->SelectionBackground().Value() });
VERIFY_IS_NOT_NULL(profile2->DefaultAppearance().SelectionBackground());
VERIFY_ARE_EQUAL(til::color(2, 2, 2), til::color{ profile2->DefaultAppearance().SelectionBackground().Value() });

VERIFY_ARE_EQUAL(L"profile2", profile2->Name());

Expand Down
Loading

0 comments on commit 9e83655

Please sign in to comment.