2016-10-30 20:21:24 -04:00
|
|
|
#pragma once
|
|
|
|
|
2017-01-24 06:37:19 -05:00
|
|
|
#include <cstdlib>
|
|
|
|
|
2016-10-30 20:21:24 -04:00
|
|
|
#include "common.hpp"
|
2017-01-18 23:38:42 -05:00
|
|
|
#include "utils/cache.hpp"
|
2016-10-30 20:21:24 -04:00
|
|
|
|
2016-11-19 00:22:44 -05:00
|
|
|
POLYBAR_NS
|
2016-10-30 20:21:24 -04:00
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
static cache<string, unsigned int> g_cache_hex;
|
|
|
|
static cache<unsigned int, string> g_cache_colors;
|
2017-01-18 23:38:42 -05:00
|
|
|
|
|
|
|
struct rgba;
|
|
|
|
|
2016-10-30 20:21:24 -04:00
|
|
|
namespace color_util {
|
2017-01-19 05:11:28 -05:00
|
|
|
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)
|
2016-11-02 15:22:45 -04:00
|
|
|
return a << 8 / 0xff;
|
2017-01-19 05:11:28 -05:00
|
|
|
else if (std::is_same<T, unsigned short int>::value)
|
2016-11-02 15:22:45 -04:00
|
|
|
return a << 8 | a << 8 / 0xff;
|
2016-10-30 20:21:24 -04:00
|
|
|
}
|
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
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)
|
2016-11-02 15:22:45 -04:00
|
|
|
return r << 8 / 0xff;
|
2017-01-19 05:11:28 -05:00
|
|
|
else if (std::is_same<T, unsigned short int>::value)
|
2016-11-02 15:22:45 -04:00
|
|
|
return r << 8 | r << 8 / 0xff;
|
2016-10-30 20:21:24 -04:00
|
|
|
}
|
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
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)
|
2016-11-02 15:22:45 -04:00
|
|
|
return g << 8 / 0xff;
|
2017-01-19 05:11:28 -05:00
|
|
|
else if (std::is_same<T, unsigned short int>::value)
|
2016-11-02 15:22:45 -04:00
|
|
|
return g << 8 | g << 8 / 0xff;
|
2016-10-30 20:21:24 -04:00
|
|
|
}
|
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
template <typename T = unsigned char>
|
|
|
|
T blue_channel(const unsigned int value) {
|
|
|
|
unsigned char b = value;
|
|
|
|
if (std::is_same<T, unsigned char>::value)
|
2016-11-02 15:22:45 -04:00
|
|
|
return b << 8 / 0xff;
|
2017-01-19 05:11:28 -05:00
|
|
|
else if (std::is_same<T, unsigned short int>::value)
|
2016-11-02 15:22:45 -04:00
|
|
|
return b << 8 | b << 8 / 0xff;
|
2016-10-30 20:21:24 -04:00
|
|
|
}
|
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
template <typename T = unsigned int>
|
|
|
|
unsigned int premultiply_alpha(const T value) {
|
2016-11-04 13:54:33 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-11-21 09:07:00 -05:00
|
|
|
template <typename T>
|
2017-01-19 05:11:28 -05:00
|
|
|
string hex(unsigned int color) {
|
2017-01-23 17:54:09 -05:00
|
|
|
return *g_cache_hex.object(color, [&] {
|
2017-01-18 23:38:42 -05:00
|
|
|
char s[12];
|
|
|
|
size_t len = 0;
|
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
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);
|
2017-01-18 23:38:42 -05:00
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
if (std::is_same<T, unsigned short int>::value) {
|
2017-01-18 23:38:42 -05:00
|
|
|
len = snprintf(s, sizeof(s), "#%02x%02x%02x%02x", a, r, g, b);
|
2017-01-19 05:11:28 -05:00
|
|
|
} else if (std::is_same<T, unsigned char>::value) {
|
2017-01-18 23:38:42 -05:00
|
|
|
len = snprintf(s, sizeof(s), "#%02x%02x%02x", r, g, b);
|
|
|
|
}
|
|
|
|
|
2017-01-23 17:54:09 -05:00
|
|
|
return string(s, len);
|
|
|
|
}());
|
2016-10-30 20:21:24 -04:00
|
|
|
}
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
inline string parse_hex(string hex) {
|
2016-12-26 22:58:41 -05:00
|
|
|
if (hex[0] != '#')
|
|
|
|
hex.insert(0, 1, '#');
|
2016-11-02 15:22:45 -04:00
|
|
|
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;
|
2016-10-30 20:21:24 -04:00
|
|
|
}
|
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
inline unsigned int parse(string hex, unsigned int fallback = 0) {
|
2016-11-02 15:22:45 -04:00
|
|
|
if ((hex = parse_hex(hex)).empty())
|
2016-11-21 09:07:00 -05:00
|
|
|
return fallback;
|
2017-01-24 06:37:19 -05:00
|
|
|
return std::strtoul(&hex[1], nullptr, 16);
|
2016-11-24 13:24:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
inline string simplify_hex(string hex) {
|
|
|
|
// convert #ffrrggbb to #rrggbb
|
2017-01-27 07:46:27 -05:00
|
|
|
if (hex.length() == 9 && std::toupper(hex[1]) == 'F' && std::toupper(hex[2]) == 'F') {
|
2016-11-24 13:24:47 -05:00
|
|
|
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;
|
2016-10-30 20:21:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-18 23:38:42 -05:00
|
|
|
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) {}
|
2017-01-19 05:11:28 -05:00
|
|
|
explicit rgb(unsigned int color) : rgb(
|
2017-01-27 07:46:27 -05:00
|
|
|
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) {}
|
2017-01-18 23:38:42 -05:00
|
|
|
// clang-format on
|
2017-01-27 07:46:27 -05:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2017-01-18 23:38:42 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct rgba {
|
|
|
|
double r;
|
|
|
|
double g;
|
|
|
|
double b;
|
|
|
|
double a;
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
explicit rgba(double r, double g, double b, double a) : r(r), g(g), b(b), a(a) {}
|
2017-01-19 05:11:28 -05:00
|
|
|
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) {}
|
2017-01-18 23:38:42 -05:00
|
|
|
// clang-format on
|
|
|
|
|
2017-01-19 05:11:28 -05:00
|
|
|
operator unsigned int() {
|
2017-01-18 23:38:42 -05:00
|
|
|
// clang-format off
|
|
|
|
return static_cast<int>(a * 255) << 24
|
|
|
|
| static_cast<int>(r * 255) << 16
|
|
|
|
| static_cast<int>(g * 255) << 8
|
|
|
|
| static_cast<int>(b * 255);
|
|
|
|
// clang-format on
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-11-19 00:22:44 -05:00
|
|
|
POLYBAR_NS_END
|