Skip to content

Commit

Permalink
Incorporate PR feedback and paint the non-client area microsoft#2994
Browse files Browse the repository at this point in the history
- add color helper class for converting colors, calculating luminance,
etc.
- paint the tab row when a tab's color changes
- paint the title bar when a tab's color changes
- remove spurious orig files
  • Loading branch information
gbaychev committed Feb 7, 2020
1 parent 8a21d91 commit 63981ef
Show file tree
Hide file tree
Showing 27 changed files with 888 additions and 554 deletions.
63 changes: 0 additions & 63 deletions src/cascadia/LocalTests_TerminalApp/pch.h.orig

This file was deleted.

2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(TitleChanged, winrt::Windows::Foundation::IInspectable, winrt::hstring, _root, TitleChanged);
FORWARDED_TYPED_EVENT(LastTabClosed, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::LastTabClosedEventArgs, _root, LastTabClosed);
FORWARDED_TYPED_EVENT(ToggleFullscreen, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::ToggleFullscreenEventArgs, _root, ToggleFullscreen);
FORWARDED_TYPED_EVENT(SetTitleBarColor, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::TabColorChangedEventArgs, _root, SetTitleBarColor);
FORWARDED_TYPED_EVENT(ClearTitleBarColor, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Color, _root, ClearTitleBarColor);
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.idl
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.ElementTheme> RequestedThemeChanged;
event Windows.Foundation.TypedEventHandler<Object, ToggleFullscreenEventArgs> ToggleFullscreen;
event Windows.Foundation.TypedEventHandler<Object, TabColorChangedEventArgs> SetTitleBarColor;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Color> ClearTitleBarColor;
}
}
273 changes: 273 additions & 0 deletions src/cascadia/TerminalApp/ColorHelper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
#include "pch.h"
#include "ColorHelper.h"
#include <limits>

using namespace winrt::TerminalApp;

// Method Description:
// Determines whether or not a given color is light
// Arguments:
// - color: this color is going to be examined whether it
// is light or not
// Return Value:
// - true of light, false if dark
bool ColorHelper::IsBrightColor(const winrt::Windows::UI::Color& color)
{
//http://www.w3.org/TR/AERT#color-contrast
auto brightness = (color.R * 299 + color.G * 587 + color.B * 114) / 1000.f;
return brightness > 128.f;
}

// Method Description:
// Converts a rgb color to hsl one
// Arguments:
// - color: the rgb color, which is going to be converted
// Return Value:
// - a hsl color with the following ranges
// - H: [0.f -360.f]
// - L: [0.f - 1.f] (rounded to the third decimal place)
// - S: [0.f - 1.f] (rounded to the third decimal place)
HSL ColorHelper::RgbToHsl(const winrt::Windows::UI::Color& color)
{
// https://www.rapidtables.com/convert/color/rgb-to-hsl.html
auto epsilon = std::numeric_limits<float>::epsilon();
auto r = color.R / 255.f;
auto g = color.G / 255.f;
auto b = color.B / 255.f;

auto max = std::max(r, std::max(g, b));
auto min = std::min(r, std::min(g, b));

auto delta = max - min;

auto h = 0.f;
auto s = 0.f;
auto l = (max + min) / 2;

if (delta < epsilon || max < epsilon) /* delta == 0 || max == 0*/
{
l = std::roundf(l * 1000) / 1000;
return HSL{ h, s, l };
}

s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);

if (max - r < epsilon) // max == r
{
h = (g - b) / delta + (g < b ? 6 : 0);
}
else if (max - g < epsilon) // max == g
{
h = (b - r) / delta + 2;
}
else if (max - b < epsilon) // max == b
{
h = (r - g) / delta + 4;
}

// three decimal places after the comma ought
// to be enough for everybody - Bill Gates, 1981
float finalH = std::roundf(h * 60);
float finalS = std::roundf(s * 1000) / 1000;
float finalL = std::roundf(l * 1000) / 1000;

return HSL{ finalH, finalS, finalL };
}

// Method Description:
// Converts a hsl color to rgb one
// Arguments:
// - color: the hsl color, which is going to be converted
// Return Value:
// - the rgb color (r,g,b - [0, 255] range)
winrt::Windows::UI::Color ColorHelper::HslToRgb(const HSL& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();

auto h = (color.H - 1.f > epsilon) ? color.H / 360.f : color.H;
auto s = (color.S - 1.f > epsilon) ? color.S / 100.f : color.S;
auto l = (color.L - 1.f > epsilon) ? color.L / 100.f : color.L;

auto r = l;
auto g = l;
auto b = l;

if (s > epsilon)
{
auto q = l < 0.5 ? l * (1 + s) : l + s - l * s;
auto p = 2 * l - q;
r = HueToRgb(p, q, h + 1.f / 3.f);
g = HueToRgb(p, q, h);
b = HueToRgb(p, q, h - 1.f / 3.f);
}

auto finalR = static_cast<uint8_t>(std::roundf(r * 255));
auto finalG = static_cast<uint8_t>(std::roundf(g * 255));
auto finalB = static_cast<uint8_t>(std::roundf(b * 255));
uint8_t finalA = 255; //opaque

return winrt::Windows::UI::ColorHelper::FromArgb(finalA, finalR, finalG, finalB);
}

float ColorHelper::HueToRgb(float p, float q, float t)
{
auto epsilon = std::numeric_limits<float>::epsilon();

if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t - (1.f / 6.f) < epsilon)
return p + (q - p) * 6 * t;
if (t - .5f < epsilon)
return q;
if (t - 2.f / 3.f < epsilon)
return p + (q - p) * (2.f / 3.f - t) * 6;
return p;
}

// Method Description:
// Lightens a color by a given amount
// Arguments:
// - color: the color which is going to be lightened
// - amount: the lighten amount (0-100)
// Return Value:
// - the lightened color in RGB format
WUI::Color ColorHelper::Lighten(const WUI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L += amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}

// Method Description:
// Darkens a color by a given amount
// Arguments:
// - color: the color which is going to be darkened
// - amount: the darken amount (0-100)
// Return Value:
// - the darkened color in RGB format
WUI::Color ColorHelper::Darken(const WUI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L -= amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}

// Method Description:
// Gets an accent color to a given color. Basically, generates
// 16 shades of the color and finds the first which has a good
// contrast according to http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Readability ratio of 3.5 seems to look quite nicely
// Arguments:
// - color: the color for which we need an accent
// Return Value:
// - the accemt color in RGB format
WUI::Color ColorHelper::GetAccentColor(const WUI::Color& color)
{
auto accentColor = RgbToHsl(color);

if (accentColor.S == 0.f)
{
accentColor.H = 60 * std::roundf(accentColor.L * 6);
}

if (accentColor.S < 0.15)
{
accentColor.S = 0.5f;
}

constexpr auto shadeCount = 16;
constexpr auto shadeStep = 1.f / shadeCount;
auto shades = std::map<float, HSL>();
for (auto i = 0; i < 15; i++)
{
auto shade = HSL{ accentColor.H, accentColor.S, i * shadeStep };
auto contrast = GetReadability(shade, accentColor);
shades.insert(std::make_pair(contrast, shade));
}

constexpr auto readability = 3.f;
for (auto shade : shades)
{
if (shade.first >= readability)
{
return HslToRgb(shade.second);
}
}
return HslToRgb(shades.end()->second);
}

// Method Description:
// Gets the readability of two colors according to
// http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (hsl)
// - secondColor: the second color for the readability check (hsl)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const HSL& first, const HSL& second)
{
return GetReadability(HslToRgb(first), HslToRgb(second));
}

// Method Description:
// Gets the readability of two colors according to
// http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (rgb)
// - secondColor: the second color for the readability check (rgb)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const WUI::Color& first, const WUI::Color& second)
{
auto l1 = GetLuminance(first);
auto l2 = GetLuminance(second);

return (std::max(l1, l2) + 0.05f) / std::min(l1, l2) + 0.05f;
}

// Method Description:
// Calculates the luminance of a given color according to
// http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
// Arguments:
// - color: its luminance is going to be calculated
// Return Value:
// - the luminance of the color
float ColorHelper::GetLuminance(const WUI::Color& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();
float R, G, B;
auto RsRGB = color.R / 255.f;
auto GsRGB = color.G / 255.f;
auto BsRGB = color.B / 255.f;

if (RsRGB - 0.03928f <= epsilon)
{
R = RsRGB / 12.92f;
}
else
{
R = std::pow(((RsRGB + 0.055f) / 1.055f), 2.4f);
}
if (GsRGB - 0.03928f <= epsilon)
{
G = GsRGB / 12.92f;
}
else
{
G = std::pow(((GsRGB + 0.055f) / 1.055f), 2.4f);
}
if (BsRGB - 0.03928f <= epsilon)
{
B = BsRGB / 12.92f;
}
else
{
B = std::pow(((BsRGB + 0.055f) / 1.055f), 2.4f);
}
float luminance = (0.2126f * R) + (0.7152f * G) + (0.0722f * B);
return std::roundf(luminance * 10000) / 10000.f;
}
34 changes: 34 additions & 0 deletions src/cascadia/TerminalApp/ColorHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once
#include "pch.h"

#include <winrt/windows.ui.core.h>

namespace WUI = winrt::Windows::UI;

namespace winrt::TerminalApp
{
class HSL
{
public:
float H;
float S;
float L;
};

class ColorHelper
{
public:
static bool IsBrightColor(const WUI::Color& color);
static HSL RgbToHsl(const WUI::Color& color);
static WUI::Color HslToRgb(const HSL& color);
static WUI::Color Lighten(const WUI::Color& color, float amount = 10.f);
static WUI::Color Darken(const WUI::Color& color, float amount = 10.f);
static WUI::Color GetAccentColor(const WUI::Color& color);
static float GetLuminance(const WUI::Color& color);
static float GetReadability(const WUI::Color& first, const WUI::Color& second);
static float GetReadability(const HSL& first, const HSL& second);

private:
static float HueToRgb(float p, float q, float t);
};
}
Loading

0 comments on commit 63981ef

Please sign in to comment.