Move most color_util functions into rgba class
The intent is for every color to be stored in a rgba instance The rgba class now stores the color in a 32 bit integer to save space This also removes the unused class rgb and moves everything else into a cpp file. Many functions also had weird template parameters. For example alpha_channel<unsigned short int> would give a 2 byte number with the alpha channel byte in both bytes. color_util::hex would return a hex string with alpha channel if unsigned short int was given and without if unsigned char was given. Even more curiously those parameters were passed to *_channel and the result nevertheless truncated to 8bits.
This commit is contained in:
parent
75eb41f5ad
commit
b238ec3403
@ -7,159 +7,47 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
static cache<string, unsigned int> g_cache_hex;
|
static cache<string, uint32_t> g_cache_hex;
|
||||||
static cache<unsigned int, string> g_cache_colors;
|
|
||||||
|
|
||||||
struct rgba;
|
|
||||||
|
|
||||||
namespace color_util {
|
|
||||||
template <typename T = unsigned char>
|
|
||||||
T alpha_channel(const unsigned int value) {
|
|
||||||
unsigned char a = value >> 24;
|
|
||||||
if (std::is_same<T, unsigned char>::value)
|
|
||||||
return a << 8 / 0xff;
|
|
||||||
else if (std::is_same<T, unsigned short int>::value)
|
|
||||||
return a << 8 | a << 8 / 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T = unsigned char>
|
|
||||||
T red_channel(const unsigned int value) {
|
|
||||||
unsigned char r = value >> 16;
|
|
||||||
if (std::is_same<T, unsigned char>::value)
|
|
||||||
return r << 8 / 0xff;
|
|
||||||
else if (std::is_same<T, unsigned short int>::value)
|
|
||||||
return r << 8 | r << 8 / 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T = unsigned char>
|
|
||||||
T green_channel(const unsigned int value) {
|
|
||||||
unsigned char g = value >> 8;
|
|
||||||
if (std::is_same<T, unsigned char>::value)
|
|
||||||
return g << 8 / 0xff;
|
|
||||||
else if (std::is_same<T, unsigned short int>::value)
|
|
||||||
return g << 8 | g << 8 / 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T = unsigned char>
|
|
||||||
T blue_channel(const unsigned int value) {
|
|
||||||
unsigned char b = value;
|
|
||||||
if (std::is_same<T, unsigned char>::value)
|
|
||||||
return b << 8 / 0xff;
|
|
||||||
else if (std::is_same<T, unsigned short int>::value)
|
|
||||||
return b << 8 | b << 8 / 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T = unsigned int>
|
|
||||||
unsigned int premultiply_alpha(const T value) {
|
|
||||||
auto a = color_util::alpha_channel(value);
|
|
||||||
auto r = color_util::red_channel(value) * a / 255;
|
|
||||||
auto g = color_util::green_channel(value) * a / 255;
|
|
||||||
auto b = color_util::blue_channel(value) * a / 255;
|
|
||||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
string hex(unsigned int color) {
|
|
||||||
return *g_cache_hex.object(color, [&] {
|
|
||||||
char s[12];
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
unsigned char a = alpha_channel<T>(color);
|
|
||||||
unsigned char r = red_channel<T>(color);
|
|
||||||
unsigned char g = green_channel<T>(color);
|
|
||||||
unsigned char b = blue_channel<T>(color);
|
|
||||||
|
|
||||||
if (std::is_same<T, unsigned short int>::value) {
|
|
||||||
len = snprintf(s, sizeof(s), "#%02x%02x%02x%02x", a, r, g, b);
|
|
||||||
} else if (std::is_same<T, unsigned char>::value) {
|
|
||||||
len = snprintf(s, sizeof(s), "#%02x%02x%02x", r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(s, len);
|
|
||||||
}());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline string parse_hex(string hex) {
|
|
||||||
if (hex[0] != '#')
|
|
||||||
hex.insert(0, 1, '#');
|
|
||||||
if (hex.length() == 4)
|
|
||||||
hex = {'#', hex[1], hex[1], hex[2], hex[2], hex[3], hex[3]};
|
|
||||||
if (hex.length() == 7)
|
|
||||||
hex = "#ff" + hex.substr(1);
|
|
||||||
if (hex.length() != 9)
|
|
||||||
return "";
|
|
||||||
return hex;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int parse(string hex, unsigned int fallback = 0) {
|
|
||||||
if ((hex = parse_hex(hex)).empty())
|
|
||||||
return fallback;
|
|
||||||
return std::strtoul(&hex[1], nullptr, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline string simplify_hex(string hex) {
|
|
||||||
// convert #ffrrggbb to #rrggbb
|
|
||||||
if (hex.length() == 9 && std::toupper(hex[1]) == 'F' && std::toupper(hex[2]) == 'F') {
|
|
||||||
hex.erase(1, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert #rrggbb to #rgb
|
|
||||||
if (hex.length() == 7) {
|
|
||||||
if (hex[1] == hex[2] && hex[3] == hex[4] && hex[5] == hex[6]) {
|
|
||||||
hex = {'#', hex[1], hex[3], hex[5]};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct rgb {
|
|
||||||
double r;
|
|
||||||
double g;
|
|
||||||
double b;
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
explicit rgb(double r, double g, double b) : r(r), g(g), b(b) {}
|
|
||||||
explicit rgb(unsigned int color) : rgb(
|
|
||||||
color_util::red_channel<unsigned char>(color_util::premultiply_alpha(color)) / 255.0,
|
|
||||||
color_util::green_channel<unsigned char>(color_util::premultiply_alpha(color)) / 255.0,
|
|
||||||
color_util::blue_channel<unsigned char>(color_util::premultiply_alpha(color)) / 255.0) {}
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
operator unsigned int() {
|
|
||||||
// clang-format off
|
|
||||||
return 0xFF << 24
|
|
||||||
| static_cast<int>(r * 255) << 16
|
|
||||||
| static_cast<int>(g * 255) << 8
|
|
||||||
| static_cast<int>(b * 255);
|
|
||||||
// clang-format on
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rgba {
|
struct rgba {
|
||||||
double r;
|
/**
|
||||||
double g;
|
* Color value in the form ARGB or A000 depending on the type
|
||||||
double b;
|
*/
|
||||||
double a;
|
uint32_t m_value;
|
||||||
|
|
||||||
// clang-format off
|
enum color_type { NONE, ARGB, ALPHA_ONLY } m_type{NONE};
|
||||||
explicit rgba(double r, double g, double b, double a) : r(r), g(g), b(b), a(a) {}
|
|
||||||
explicit rgba(unsigned int color) : rgba(
|
|
||||||
color_util::red_channel<unsigned char>(color) / 255.0,
|
|
||||||
color_util::green_channel<unsigned char>(color) / 255.0,
|
|
||||||
color_util::blue_channel<unsigned char>(color) / 255.0,
|
|
||||||
color_util::alpha_channel<unsigned char>(color) / 255.0) {}
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
operator unsigned int() {
|
explicit rgba();
|
||||||
// clang-format off
|
explicit rgba(uint32_t value, color_type type = ARGB);
|
||||||
return static_cast<int>(a * 255) << 24
|
explicit rgba(string hex);
|
||||||
| static_cast<int>(r * 255) << 16
|
|
||||||
| static_cast<int>(g * 255) << 8
|
operator string() const;
|
||||||
| static_cast<int>(b * 255);
|
operator uint32_t() const;
|
||||||
// clang-format on
|
bool operator==(const rgba& other) const;
|
||||||
}
|
|
||||||
|
double a() const;
|
||||||
|
double r() const;
|
||||||
|
double g() const;
|
||||||
|
double b() const;
|
||||||
|
|
||||||
|
uint8_t a_int() const;
|
||||||
|
uint8_t r_int() const;
|
||||||
|
uint8_t g_int() const;
|
||||||
|
uint8_t b_int() const;
|
||||||
|
|
||||||
|
bool has_color() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace color_util {
|
||||||
|
|
||||||
|
uint8_t alpha_channel(const uint32_t value);
|
||||||
|
uint8_t red_channel(const uint32_t value);
|
||||||
|
uint8_t green_channel(const uint32_t value);
|
||||||
|
uint8_t blue_channel(const uint32_t value);
|
||||||
|
|
||||||
|
string hex(uint32_t color);
|
||||||
|
|
||||||
|
string simplify_hex(string hex);
|
||||||
|
} // namespace color_util
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
174
src/utils/color.cpp
Normal file
174
src/utils/color.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#include "utils/color.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a hex string as input and brings it into a normalized form
|
||||||
|
*
|
||||||
|
* The input can either be only an alpha channel #AA
|
||||||
|
* or any of these forms: #RGB, #ARGB, #RRGGBB, #AARRGGBB
|
||||||
|
*
|
||||||
|
* Colors without alpha channel will get an alpha channel of FF
|
||||||
|
* The input does not have to start with '#'
|
||||||
|
*
|
||||||
|
* \returns Empty string for malformed input, either AA for the alpha only
|
||||||
|
* input or an 8 character string of the expanded form AARRGGBB
|
||||||
|
*/
|
||||||
|
static string normalize_hex(string hex) {
|
||||||
|
if (hex.length() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// We remove the hash because it makes processing easier
|
||||||
|
if (hex[0] == '#') {
|
||||||
|
hex.erase(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.length() == 2) {
|
||||||
|
// We only have an alpha channel
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.length() == 3) {
|
||||||
|
// RGB -> ARGB
|
||||||
|
hex.insert(0, 1, 'f');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.length() == 4) {
|
||||||
|
// ARGB -> AARRGGBB
|
||||||
|
hex = {hex[0], hex[0], hex[1], hex[1], hex[2], hex[2], hex[3], hex[3]};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.length() == 6) {
|
||||||
|
// RRGGBB -> FFRRGGBB
|
||||||
|
hex.insert(0, 2, 'f');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.length() != 8) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rgba::rgba() : m_value(0), m_type(NONE) {}
|
||||||
|
rgba::rgba(uint32_t value, color_type type) : m_value(value), m_type(type) {}
|
||||||
|
rgba::rgba(string hex) {
|
||||||
|
hex = normalize_hex(hex);
|
||||||
|
|
||||||
|
if (hex.length() == 0) {
|
||||||
|
// TODO we need a way to inform the user that their color was malformed
|
||||||
|
m_value = 0;
|
||||||
|
m_type = NONE;
|
||||||
|
} else if (hex.length() == 2) {
|
||||||
|
m_value = std::strtoul(hex.c_str(), nullptr, 16) << 24;
|
||||||
|
m_type = ALPHA_ONLY;
|
||||||
|
} else {
|
||||||
|
m_value = std::strtoul(hex.c_str(), nullptr, 16);
|
||||||
|
m_type = ARGB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rgba::operator string() const {
|
||||||
|
char s[10];
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
len = snprintf(s, 10, "#%08x", m_value);
|
||||||
|
return string(s, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rgba::operator==(const rgba& other) const {
|
||||||
|
if (m_type != other.m_type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_type) {
|
||||||
|
case NONE:
|
||||||
|
return true;
|
||||||
|
case ARGB:
|
||||||
|
return m_value == other.m_value;
|
||||||
|
case ALPHA_ONLY:
|
||||||
|
return a_int() == other.a_int();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rgba::operator uint32_t() const {
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rgba::a() const {
|
||||||
|
return a_int() / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rgba::r() const {
|
||||||
|
return r_int() / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rgba::g() const {
|
||||||
|
return g_int() / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rgba::b() const {
|
||||||
|
return b_int() / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rgba::a_int() const {
|
||||||
|
return color_util::alpha_channel(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rgba::r_int() const {
|
||||||
|
return color_util::red_channel(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rgba::g_int() const {
|
||||||
|
return color_util::green_channel(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rgba::b_int() const {
|
||||||
|
return color_util::blue_channel(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t color_util::alpha_channel(const uint32_t value) {
|
||||||
|
return (value >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t color_util::red_channel(const uint32_t value) {
|
||||||
|
return (value >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t color_util::green_channel(const uint32_t value) {
|
||||||
|
return (value >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t color_util::blue_channel(const uint32_t value) {
|
||||||
|
return value & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
string color_util::hex(uint32_t color) {
|
||||||
|
return *g_cache_hex.object(color, [&] { return static_cast<string>(rgba{color}); }());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rgba::has_color() const {
|
||||||
|
return m_type != NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
string color_util::simplify_hex(string hex) {
|
||||||
|
// convert #ffrrggbb to #rrggbb
|
||||||
|
if (hex.length() == 9 && std::toupper(hex[1]) == 'F' && std::toupper(hex[2]) == 'F') {
|
||||||
|
hex.erase(1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert #rrggbb to #rgb
|
||||||
|
if (hex.length() == 7) {
|
||||||
|
if (hex[1] == hex[2] && hex[3] == hex[4] && hex[5] == hex[6]) {
|
||||||
|
hex = {'#', hex[1], hex[3], hex[5]};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -1,68 +1,129 @@
|
|||||||
#include "common/test.hpp"
|
|
||||||
#include "utils/color.hpp"
|
#include "utils/color.hpp"
|
||||||
|
|
||||||
|
#include "common/test.hpp"
|
||||||
|
|
||||||
using namespace polybar;
|
using namespace polybar;
|
||||||
|
|
||||||
TEST(String, rgb) {
|
TEST(Rgba, constructor) {
|
||||||
unsigned int color{0x123456};
|
rgba v{"invalid"};
|
||||||
EXPECT_EQ(0, color_util::alpha_channel<unsigned char>(color));
|
EXPECT_FALSE(v.has_color());
|
||||||
EXPECT_EQ(0x12, color_util::red_channel<unsigned char>(color));
|
|
||||||
EXPECT_EQ(0x34, color_util::green_channel<unsigned char>(color));
|
|
||||||
EXPECT_EQ(0x3434, color_util::green_channel<unsigned short int>(color));
|
|
||||||
EXPECT_EQ(0x56, color_util::blue_channel<unsigned char>(color));
|
|
||||||
|
|
||||||
EXPECT_TRUE(0x33 / 255.0 == rgb{0xFF112233}.b);
|
v = rgba{"#f"};
|
||||||
EXPECT_TRUE(0x51 / 255.0 == rgb{0x88449933}.g);
|
EXPECT_FALSE(v.has_color());
|
||||||
EXPECT_TRUE(0xff0f0f0f == rgb{0xee111111});
|
|
||||||
EXPECT_TRUE(0xff0a141e == rgb{0x99112233});
|
v = rgba{"#12"};
|
||||||
|
EXPECT_EQ(rgba::ALPHA_ONLY, v.m_type);
|
||||||
|
|
||||||
|
v = rgba{"#ff"};
|
||||||
|
EXPECT_EQ(0xff000000, v.m_value);
|
||||||
|
|
||||||
|
v = rgba{"#fff"};
|
||||||
|
EXPECT_EQ(0xffffffff, v.m_value);
|
||||||
|
|
||||||
|
v = rgba{"#890"};
|
||||||
|
EXPECT_EQ(0xFF889900, v.m_value);
|
||||||
|
|
||||||
|
v = rgba{"#a890"};
|
||||||
|
EXPECT_EQ(0xaa889900, v.m_value);
|
||||||
|
|
||||||
|
v = rgba{"#55888777"};
|
||||||
|
EXPECT_EQ(0x55888777, v.m_value);
|
||||||
|
|
||||||
|
v = rgba{"#88aaaaaa"};
|
||||||
|
EXPECT_EQ(0x88aaaaaa, v.m_value);
|
||||||
|
|
||||||
|
v = rgba{"#00aaaaaa"};
|
||||||
|
EXPECT_EQ(0x00aaaaaa, v.m_value);
|
||||||
|
|
||||||
|
v = rgba{"#00FFFFFF"};
|
||||||
|
EXPECT_EQ(0x00FFFFFF, v.m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(String, rgba) {
|
TEST(Rgba, parse) {
|
||||||
unsigned int color{0xCC123456};
|
EXPECT_EQ(0xffffffff, rgba{"#fff"}.m_value);
|
||||||
EXPECT_EQ(0xCCCC, color_util::alpha_channel<unsigned short int>(color));
|
EXPECT_EQ(0xffffffff, rgba{"fff"}.m_value);
|
||||||
EXPECT_EQ(0x1212, color_util::red_channel<unsigned short int>(color));
|
EXPECT_EQ(0xff112233, rgba{"#123"}.m_value);
|
||||||
EXPECT_EQ(0x12, color_util::red_channel<unsigned char>(color));
|
EXPECT_EQ(0xff112233, rgba{"123"}.m_value);
|
||||||
EXPECT_EQ(0x3434, color_util::green_channel<unsigned short int>(color));
|
EXPECT_EQ(0xff888888, rgba{"#888888"}.m_value);
|
||||||
EXPECT_EQ(0x5656, color_util::blue_channel<unsigned short int>(color));
|
EXPECT_EQ(0xff888888, rgba{"888888"}.m_value);
|
||||||
|
EXPECT_EQ(0x00aa00aa, rgba{"#00aa00aa"}.m_value);
|
||||||
EXPECT_EQ(0xCC / 255.0, rgba{0xCC112233}.a);
|
EXPECT_EQ(0x00aa00aa, rgba{"00aa00aa"}.m_value);
|
||||||
EXPECT_EQ(0x99 / 255.0, rgba{0x88449933}.g);
|
EXPECT_EQ(0x11223344, rgba{"#1234"}.m_value);
|
||||||
EXPECT_EQ(0xFF111111, static_cast<unsigned int>(rgba{0xFF111111}));
|
EXPECT_EQ(0x11223344, rgba{"1234"}.m_value);
|
||||||
EXPECT_EQ(0x00FFFFFF, static_cast<unsigned int>(rgba{0x00FFFFFF}));
|
EXPECT_EQ(0xaa000000, rgba{"#aa"}.m_value);
|
||||||
|
EXPECT_EQ(0xaa000000, rgba{"aa"}.m_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(String, hex) {
|
TEST(Rgba, string) {
|
||||||
unsigned int colorA{0x123456};
|
rgba v{"#1234"};
|
||||||
EXPECT_EQ("#123456"s, color_util::hex<unsigned char>(colorA));
|
|
||||||
unsigned int colorB{0xCC123456};
|
EXPECT_EQ("#11223344", static_cast<string>(v));
|
||||||
EXPECT_EQ("#cc123456"s, color_util::hex<unsigned short int>(colorB));
|
|
||||||
unsigned int colorC{0x00ffffff};
|
v = rgba{"#12"};
|
||||||
EXPECT_EQ("#00ffffff"s, color_util::hex<unsigned short int>(colorC));
|
|
||||||
|
EXPECT_EQ("#12000000", static_cast<string>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(String, parseHex) {
|
TEST(Rgba, eq) {
|
||||||
EXPECT_EQ("#ffffffff", color_util::parse_hex("#fff"));
|
rgba v(0x12, rgba::NONE);
|
||||||
EXPECT_EQ("#ff112233", color_util::parse_hex("#123"));
|
|
||||||
EXPECT_EQ("#ff888888", color_util::parse_hex("#888888"));
|
EXPECT_TRUE(v == rgba(0, rgba::NONE));
|
||||||
EXPECT_EQ("#00aa00aa", color_util::parse_hex("#00aa00aa"));
|
EXPECT_TRUE(v == rgba(0x11, rgba::NONE));
|
||||||
|
EXPECT_FALSE(v == rgba{0x1234});
|
||||||
|
|
||||||
|
v = rgba{0xCC123456};
|
||||||
|
|
||||||
|
EXPECT_TRUE(v == rgba{0xCC123456});
|
||||||
|
EXPECT_FALSE(v == rgba(0xCC123456, rgba::NONE));
|
||||||
|
|
||||||
|
v = rgba{"#aa"};
|
||||||
|
|
||||||
|
EXPECT_TRUE(v == rgba(0xaa000000, rgba::ALPHA_ONLY));
|
||||||
|
EXPECT_FALSE(v == rgba(0xaa000000, rgba::ARGB));
|
||||||
|
EXPECT_FALSE(v == rgba(0xab000000, rgba::ALPHA_ONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(String, parse) {
|
TEST(Rgba, hasColor) {
|
||||||
EXPECT_EQ(0, color_util::parse("invalid"));
|
rgba v{"#"};
|
||||||
EXPECT_EQ(0, color_util::parse("#f"));
|
|
||||||
EXPECT_EQ(0, color_util::parse("#ff"));
|
EXPECT_FALSE(v.has_color());
|
||||||
EXPECT_EQ(0xFF999999, color_util::parse("invalid", 0xFF999999));
|
|
||||||
EXPECT_EQ(0x00111111, color_util::parse("invalid", 0x00111111));
|
v = rgba{"#ff"};
|
||||||
EXPECT_EQ(0xFF000000, color_util::parse("invalid", 0xFF000000));
|
|
||||||
EXPECT_EQ(0xffffffff, color_util::parse("#fff"));
|
EXPECT_TRUE(v.has_color());
|
||||||
EXPECT_EQ(0xFF889900, color_util::parse("#890"));
|
|
||||||
EXPECT_EQ(0x55888777, color_util::parse("#55888777"));
|
v = rgba{"#cc123456"};
|
||||||
EXPECT_EQ(0x88aaaaaa, color_util::parse("#88aaaaaa"));
|
|
||||||
EXPECT_EQ(0x00aaaaaa, color_util::parse("#00aaaaaa"));
|
EXPECT_TRUE(v.has_color());
|
||||||
EXPECT_EQ(0x00FFFFFF, color_util::parse("#00FFFFFF"));
|
|
||||||
|
v = rgba(0x1243, rgba::NONE);
|
||||||
|
|
||||||
|
EXPECT_FALSE(v.has_color());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(String, simplify) {
|
TEST(ColorUtil, rgba) {
|
||||||
|
uint32_t color{0xCC123456};
|
||||||
|
EXPECT_EQ(0xCC, color_util::alpha_channel(color));
|
||||||
|
EXPECT_EQ(0x12, color_util::red_channel(color));
|
||||||
|
EXPECT_EQ(0x34, color_util::green_channel(color));
|
||||||
|
EXPECT_EQ(0x56, color_util::blue_channel(color));
|
||||||
|
|
||||||
|
EXPECT_EQ(0xCC / 255.0, rgba{0xCC112233}.a());
|
||||||
|
EXPECT_EQ(0x99 / 255.0, rgba{0x88449933}.g());
|
||||||
|
EXPECT_EQ(0xFF111111, static_cast<uint32_t>(rgba{"#FF111111"}));
|
||||||
|
EXPECT_EQ(0x00FFFFFF, static_cast<uint32_t>(rgba{"#00FFFFFF"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ColorUtil, hex) {
|
||||||
|
uint32_t colorA{0x123456};
|
||||||
|
EXPECT_EQ("#00123456"s, color_util::hex(colorA));
|
||||||
|
uint32_t colorB{0xCC123456};
|
||||||
|
EXPECT_EQ("#cc123456"s, color_util::hex(colorB));
|
||||||
|
uint32_t colorC{0x00ffffff};
|
||||||
|
EXPECT_EQ("#00ffffff"s, color_util::hex(colorC));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ColorUtil, simplify) {
|
||||||
EXPECT_EQ("#111", color_util::simplify_hex("#FF111111"));
|
EXPECT_EQ("#111", color_util::simplify_hex("#FF111111"));
|
||||||
EXPECT_EQ("#234", color_util::simplify_hex("#ff223344"));
|
EXPECT_EQ("#234", color_util::simplify_hex("#ff223344"));
|
||||||
EXPECT_EQ("#ee223344", color_util::simplify_hex("#ee223344"));
|
EXPECT_EQ("#ee223344", color_util::simplify_hex("#ee223344"));
|
||||||
|
Loading…
Reference in New Issue
Block a user