Skip to content

Commit

Permalink
Update ColorScheme with Json Serializer and color table API (#7609)
Browse files Browse the repository at this point in the history
Add `ToJson()` to the `ConversionTrait`s in JsonUtils. This can be used
to serialize settings objects into JSON.

As a proof of concept, `ToJson` and `UpdateJson` were added to
`ColorScheme`.

Getters and setters for members and colors in the color table were added
and polished.

## References
#1564 - Settings UI

`ColorScheme` is a particularly easy example of serialization because it
has _no fallback_.

Added a few tests for JSON serializers.
  • Loading branch information
carlos-zamora authored Sep 17, 2020
1 parent c033594 commit b70ffdf
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 99 deletions.
1 change: 1 addition & 0 deletions .github/actions/spell-check/dictionary/apis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ACCESSDENIED
alignof
bitfield
bitfields
COLORPROPERTY
CLASSNOTAVAILABLE
environstrings
EXPCMDFLAGS
Expand Down
58 changes: 29 additions & 29 deletions src/cascadia/LocalTests_TerminalApp/ColorSchemeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,11 @@ namespace TerminalAppLocalTests
const auto scheme2Json = VerifyParseSucceeded(scheme2String);

auto scheme0 = ColorScheme::FromJson(scheme0Json);
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_schemeName);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_selectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_cursorColor);
VERIFY_ARE_EQUAL(L"scheme0", scheme0->_Name);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 1), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 1, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 1), scheme0->_table[XTERM_BLUE_ATTR]);
Expand All @@ -144,10 +144,10 @@ namespace TerminalAppLocalTests
L"Layering scheme1 on top of scheme0"));
scheme0->LayerJson(scheme1Json);

VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_selectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_cursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 0, 4), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 2, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 1, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
Expand All @@ -156,10 +156,10 @@ namespace TerminalAppLocalTests
L"Layering scheme2Json on top of (scheme0+scheme1)"));
scheme0->LayerJson(scheme2Json);

VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_selectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_cursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 0), scheme0->_SelectionBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 0, 6), scheme0->_CursorColor);
VERIFY_ARE_EQUAL(ARGB(0, 3, 0, 0), scheme0->_table[XTERM_RED_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 3, 0), scheme0->_table[XTERM_GREEN_ATTR]);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 2), scheme0->_table[XTERM_BLUE_ATTR]);
Expand Down Expand Up @@ -218,8 +218,8 @@ namespace TerminalAppLocalTests
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
}

settings->_LayerOrCreateColorScheme(scheme1Json);
Expand All @@ -238,10 +238,10 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 0, 0, 0), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 1, 1, 1), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme2Json);

Expand All @@ -259,10 +259,10 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
}
settings->_LayerOrCreateColorScheme(scheme3Json);

Expand All @@ -283,12 +283,12 @@ namespace TerminalAppLocalTests
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme1Json));
VERIFY_IS_NOT_NULL(settings->_FindMatchingColorScheme(scheme2Json));
VERIFY_IS_NULL(settings->_FindMatchingColorScheme(scheme3Json));
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_defaultForeground);
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_defaultBackground);
VERIFY_ARE_EQUAL(ARGB(0, 4, 4, 4), scheme0->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 5, 5, 5), scheme0->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 2, 2, 2), scheme1->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 3, 3, 3), scheme1->_Background);
VERIFY_ARE_EQUAL(ARGB(0, 6, 6, 6), scheme2->_Foreground);
VERIFY_ARE_EQUAL(ARGB(0, 7, 7, 7), scheme2->_Background);
}
}
}
98 changes: 51 additions & 47 deletions src/cascadia/TerminalApp/ColorScheme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ static constexpr std::string_view ForegroundKey{ "foreground" };
static constexpr std::string_view BackgroundKey{ "background" };
static constexpr std::string_view SelectionBackgroundKey{ "selectionBackground" };
static constexpr std::string_view CursorColorKey{ "cursorColor" };

static constexpr std::array<std::string_view, 16> TableColors = {
"black",
"red",
Expand All @@ -40,26 +41,19 @@ static constexpr std::array<std::string_view, 16> TableColors = {
};

ColorScheme::ColorScheme() :
_schemeName{ L"" },
_table{},
_defaultForeground{ DEFAULT_FOREGROUND_WITH_ALPHA },
_defaultBackground{ DEFAULT_BACKGROUND_WITH_ALPHA },
_selectionBackground{ DEFAULT_FOREGROUND },
_cursorColor{ DEFAULT_CURSOR_COLOR }
_Foreground{ DEFAULT_FOREGROUND_WITH_ALPHA },
_Background{ DEFAULT_BACKGROUND_WITH_ALPHA },
_SelectionBackground{ DEFAULT_FOREGROUND },
_CursorColor{ DEFAULT_CURSOR_COLOR }
{
}

ColorScheme::ColorScheme(winrt::hstring name, Color defaultFg, Color defaultBg, Color cursorColor) :
_schemeName{ name },
_table{},
_defaultForeground{ defaultFg },
_defaultBackground{ defaultBg },
_selectionBackground{ DEFAULT_FOREGROUND },
_cursorColor{ cursorColor }
{
}

ColorScheme::~ColorScheme()
_Name{ name },
_Foreground{ defaultFg },
_Background{ defaultBg },
_SelectionBackground{ DEFAULT_FOREGROUND },
_CursorColor{ cursorColor }
{
}

Expand Down Expand Up @@ -89,7 +83,7 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
std::wstring nameFromJson{};
if (JsonUtils::GetValueForKey(json, NameKey, nameFromJson))
{
return nameFromJson == _schemeName;
return nameFromJson == _Name;
}
return false;
}
Expand All @@ -106,50 +100,60 @@ bool ColorScheme::ShouldBeLayered(const Json::Value& json) const
// <none>
void ColorScheme::LayerJson(const Json::Value& json)
{
JsonUtils::GetValueForKey(json, NameKey, _schemeName);
JsonUtils::GetValueForKey(json, ForegroundKey, _defaultForeground);
JsonUtils::GetValueForKey(json, BackgroundKey, _defaultBackground);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _selectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _cursorColor);

int i = 0;
for (const auto& current : TableColors)
JsonUtils::GetValueForKey(json, NameKey, _Name);
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);

for (unsigned int i = 0; i < TableColors.size(); ++i)
{
JsonUtils::GetValueForKey(json, current, _table.at(i));
i++;
JsonUtils::GetValueForKey(json, til::at(TableColors, i), _table.at(i));
}
}

winrt::hstring ColorScheme::Name() const noexcept
// Method Description:
// - Create a new serialized JsonObject from an instance of this class
// Arguments:
// - <none>
// Return Value:
// <none>
Json::Value ColorScheme::ToJson()
{
return _schemeName;
}
Json::Value json{ Json::ValueType::objectValue };

winrt::com_array<Color> ColorScheme::Table() const noexcept
{
winrt::com_array<Color> result{ COLOR_TABLE_SIZE };
std::transform(_table.begin(), _table.end(), result.begin(), [](til::color c) -> Color { return c; });
return result;
}
JsonUtils::SetValueForKey(json, NameKey, _Name);
JsonUtils::SetValueForKey(json, ForegroundKey, _Foreground);
JsonUtils::SetValueForKey(json, BackgroundKey, _Background);
JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor);

Color ColorScheme::Foreground() const noexcept
{
return _defaultForeground;
}
for (unsigned int i = 0; i < TableColors.size(); ++i)
{
JsonUtils::SetValueForKey(json, til::at(TableColors, i), _table.at(i));
}

Color ColorScheme::Background() const noexcept
{
return _defaultBackground;
return json;
}

Color ColorScheme::SelectionBackground() const noexcept
winrt::com_array<Color> ColorScheme::Table() const noexcept
{
return _selectionBackground;
winrt::com_array<Color> result{ base::checked_cast<uint32_t>(_table.size()) };
std::transform(_table.begin(), _table.end(), result.begin(), [](til::color c) -> Color { return c; });
return result;
}

Color ColorScheme::CursorColor() const noexcept
// Method Description:
// - Set a color in the color table
// Arguments:
// - index: the index of the desired color within the table
// - value: the color value we are setting the color table color to
// Return Value:
// - none
void ColorScheme::SetColorTableEntry(uint8_t index, const winrt::Windows::UI::Color& value) noexcept
{
return _cursorColor;
THROW_HR_IF(E_INVALIDARG, index > _table.size() - 1);
_table[index] = value;
}

// Method Description:
Expand Down
22 changes: 10 additions & 12 deletions src/cascadia/TerminalApp/ColorScheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,26 @@ namespace winrt::TerminalApp::implementation
public:
ColorScheme();
ColorScheme(hstring name, Windows::UI::Color defaultFg, Windows::UI::Color defaultBg, Windows::UI::Color cursorColor);
~ColorScheme();

static com_ptr<ColorScheme> FromJson(const Json::Value& json);
bool ShouldBeLayered(const Json::Value& json) const;
void LayerJson(const Json::Value& json);

hstring Name() const noexcept;
com_array<Windows::UI::Color> Table() const noexcept;
Windows::UI::Color Foreground() const noexcept;
Windows::UI::Color Background() const noexcept;
Windows::UI::Color SelectionBackground() const noexcept;
Windows::UI::Color CursorColor() const noexcept;
Json::Value ToJson();

static std::optional<std::wstring> GetNameFromJson(const Json::Value& json);

com_array<Windows::UI::Color> Table() const noexcept;
void SetColorTableEntry(uint8_t index, const winrt::Windows::UI::Color& value) noexcept;

GETSET_PROPERTY(winrt::hstring, Name);
GETSET_COLORPROPERTY(Foreground); // defined in constructor
GETSET_COLORPROPERTY(Background); // defined in constructor
GETSET_COLORPROPERTY(SelectionBackground); // defined in constructor
GETSET_COLORPROPERTY(CursorColor); // defined in constructor

private:
hstring _schemeName;
std::array<til::color, COLOR_TABLE_SIZE> _table;
til::color _defaultForeground;
til::color _defaultBackground;
til::color _selectionBackground;
til::color _cursorColor;

friend class TerminalAppLocalTests::SettingsTests;
friend class TerminalAppLocalTests::ColorSchemeTests;
Expand Down
12 changes: 6 additions & 6 deletions src/cascadia/TerminalApp/ColorScheme.idl
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ namespace TerminalApp
{
[default_interface] runtimeclass ColorScheme {
ColorScheme();
ColorScheme(String name, Windows.UI.Color defaultFg, Windows.UI.Color defaultBg, Windows.UI.Color cursorColor);

String Name { get; };
String Name;

Windows.UI.Color Foreground { get; };
Windows.UI.Color Background { get; };
Windows.UI.Color SelectionBackground { get; };
Windows.UI.Color CursorColor { get; };
Windows.UI.Color Foreground;
Windows.UI.Color Background;
Windows.UI.Color SelectionBackground;
Windows.UI.Color CursorColor;

Windows.UI.Color[] Table { get; };
void SetColorTableEntry(UInt8 index, Windows.UI.Color value);
}
}
Loading

0 comments on commit b70ffdf

Please sign in to comment.