FTXUI 6.1.9
C++ functional terminal UI.
Loading...
Searching...
No Matches
screen/color.cpp
Go to the documentation of this file.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// Use of this source code is governed by the MIT license that can be found in
3// the LICENSE file.
5
6#include <array> // for array
7#include <cmath>
8#include <cstdint>
9#include <string>
10
11#include "ftxui/screen/color_info.hpp" // for GetColorInfo, ColorInfo
12#include "ftxui/screen/terminal.hpp" // for ColorSupport, Color, Palette256, TrueColor
13
14namespace ftxui {
15namespace {
16const std::array<const char*, 33> palette16code = {
17 "30", "40", //
18 "31", "41", //
19 "32", "42", //
20 "33", "43", //
21 "34", "44", //
22 "35", "45", //
23 "36", "46", //
24 "37", "47", //
25 "90", "100", //
26 "91", "101", //
27 "92", "102", //
28 "93", "103", //
29 "94", "104", //
30 "95", "105", //
31 "96", "106", //
32 "97", "107", //
33};
34
35} // namespace
36
37bool Color::operator==(const Color& rhs) const {
38 return red_ == rhs.red_ && green_ == rhs.green_ && blue_ == rhs.blue_ &&
39 type_ == rhs.type_;
40}
41
42bool Color::operator!=(const Color& rhs) const {
43 return !operator==(rhs);
44}
45
46std::string Color::Print(bool is_background_color) const {
47 if (is_background_color) {
48 switch (type_) {
49 case ColorType::Palette1:
50 return "49";
51 case ColorType::Palette16:
52 return palette16code[2 * red_ + 1]; // NOLINT
53 case ColorType::Palette256:
54 return "48;5;" + std::to_string(red_);
55 case ColorType::TrueColor:
56 return "48;2;" + std::to_string(red_) + ";" + std::to_string(green_) +
57 ";" + std::to_string(blue_);
58 }
59 } else {
60 switch (type_) {
61 case ColorType::Palette1:
62 return "39";
63 case ColorType::Palette16:
64 return palette16code[2 * red_]; // NOLINT
65 case ColorType::Palette256:
66 return "38;5;" + std::to_string(red_);
67 case ColorType::TrueColor:
68 return "38;2;" + std::to_string(red_) + ";" + std::to_string(green_) +
69 ";" + std::to_string(blue_);
70 }
71 }
72 // NOTREACHED();
73 return "";
74}
75
76/// @brief Build a transparent color.
77Color::Color() = default;
78
79/// @brief Build a transparent color.
80Color::Color(Palette1 /*value*/) : Color() {}
81
82/// @brief Build a color using the Palette16 colors.
84 : type_(ColorType::Palette16), red_(index), alpha_(255) {}
85
86/// @brief Build a color using Palette256 colors.
88 : type_(ColorType::Palette256), red_(index), alpha_(255) {
89 if (Terminal::ColorSupport() >= Terminal::Color::Palette256) {
90 return;
91 }
92 type_ = ColorType::Palette16;
94}
95
96/// @brief Build a Color from its RGB representation.
97/// https://en.wikipedia.org/wiki/RGB_color_model
98///
99/// @param red The quantity of red [0,255]
100/// @param green The quantity of green [0,255]
101/// @param blue The quantity of blue [0,255]
102/// @param alpha The quantity of alpha [0,255]
103Color::Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
104 : type_(ColorType::TrueColor),
105 red_(red),
106 green_(green),
107 blue_(blue),
108 alpha_(alpha) {
109 if (Terminal::ColorSupport() == Terminal::Color::TrueColor) {
110 return;
111 }
112
113 // Find the closest Color from the database:
114 const int max_distance = 256 * 256 * 3;
115 int closest = max_distance;
116 int best = 0;
117 const int database_begin = 16;
118 const int database_end = 256;
119 for (int i = database_begin; i < database_end; ++i) {
120 const ColorInfo color_info = GetColorInfo(Color::Palette256(i));
121 const int dr = color_info.red - red;
122 const int dg = color_info.green - green;
123 const int db = color_info.blue - blue;
124 const int dist = dr * dr + dg * dg + db * db;
125 if (closest > dist) {
126 closest = dist;
127 best = i;
128 }
129 }
130
131 if (Terminal::ColorSupport() == Terminal::Color::Palette256) {
132 type_ = ColorType::Palette256;
133 red_ = best;
134 } else {
135 type_ = ColorType::Palette16;
137 }
138}
139
140/// @brief Build a Color from its RGB representation.
141/// https://en.wikipedia.org/wiki/RGB_color_model
142///
143/// @param red The quantity of red [0,255]
144/// @param green The quantity of green [0,255]
145/// @param blue The quantity of blue [0,255]
146// static
147Color Color::RGB(uint8_t red, uint8_t green, uint8_t blue) {
148 return RGBA(red, green, blue, 255);
149}
150
151/// @brief Build a Color from its RGBA representation.
152/// https://en.wikipedia.org/wiki/RGB_color_model
153/// @param red The quantity of red [0,255]
154/// @param green The quantity of green [0,255]
155/// @param blue The quantity of blue [0,255]
156/// @param alpha The quantity of alpha [0,255]
157/// @see Color::RGB
158// static
159Color Color::RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
160 return {red, green, blue, alpha};
161}
162
163/// @brief Build a Color from its HSV representation.
164/// https://en.wikipedia.org/wiki/HSL_and_HSV
165///
166/// @param h The hue of the color [0,255]
167/// @param s The "colorfulness" [0,255].
168/// @param v The "Lightness" [0,255]
169/// @param alpha The quantity of alpha [0,255]
170// static
171Color Color::HSVA(uint8_t h, uint8_t s, uint8_t v, uint8_t alpha) {
172 uint8_t region = h / 43; // NOLINT
173 uint8_t remainder = (h - (region * 43)) * 6; // NOLINT
174 uint8_t p = (v * (255 - s)) >> 8; // NOLINT
175 uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8; // NOLINT
176 uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; // NOLINT
177
178 // clang-format off
179 switch (region) { // NOLINT
180 case 0: return Color(v,t,p, alpha); // NOLINT
181 case 1: return Color(q,v,p, alpha); // NOLINT
182 case 2: return Color(p,v,t, alpha); // NOLINT
183 case 3: return Color(p,q,v, alpha); // NOLINT
184 case 4: return Color(t,p,v, alpha); // NOLINT
185 case 5: return Color(v,p,q, alpha); // NOLINT
186 } // NOLINT
187 // clang-format on
188 return {0, 0, 0, alpha};
189}
190
191/// @brief Build a Color from its HSV representation.
192/// https://en.wikipedia.org/wiki/HSL_and_HSV
193///
194/// @param h The hue of the color [0,255]
195/// @param s The "colorfulness" [0,255].
196/// @param v The "Lightness" [0,255]
197// static
198Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
199 return HSVA(h, s, v, 255);
200}
201
202// static
203Color Color::Interpolate(float t, const Color& a, const Color& b) {
204 if (a.type_ == ColorType::Palette1 || //
205 b.type_ == ColorType::Palette1) {
206 if (t < 0.5F) { // NOLINT
207 return a;
208 } else {
209 return b;
210 }
211 }
212
213 auto get_color = [](const Color& color, //
214 uint8_t* red, uint8_t* green, uint8_t* blue) {
215 switch (color.type_) {
216 case ColorType::Palette1: {
217 return;
218 }
219
220 case ColorType::Palette16: {
221 const ColorInfo info = GetColorInfo(Color::Palette16(color.red_));
222 *red = info.red;
223 *green = info.green;
224 *blue = info.blue;
225 return;
226 }
227
228 case ColorType::Palette256: {
229 const ColorInfo info = GetColorInfo(Color::Palette256(color.red_));
230 *red = info.red;
231 *green = info.green;
232 *blue = info.blue;
233 return;
234 }
235
236 case ColorType::TrueColor:
237 default: {
238 *red = color.red_;
239 *green = color.green_;
240 *blue = color.blue_;
241 return;
242 }
243 }
244 };
245
246 uint8_t a_r = 0;
247 uint8_t a_g = 0;
248 uint8_t a_b = 0;
249 uint8_t b_r = 0;
250 uint8_t b_g = 0;
251 uint8_t b_b = 0;
252 get_color(a, &a_r, &a_g, &a_b);
253 get_color(b, &b_r, &b_g, &b_b);
254
255 // Gamma correction:
256 // https://en.wikipedia.org/wiki/Gamma_correction
257 auto interp = [t](uint8_t a_u, uint8_t b_u) {
258 constexpr float gamma = 2.2F;
259 const float a_f = powf(a_u, gamma);
260 const float b_f = powf(b_u, gamma);
261 const float c_f = a_f * (1.0F - t) + //
262 b_f * t;
263 return static_cast<uint8_t>(powf(c_f, 1.F / gamma));
264 };
265 return Color::RGB(interp(a_r, b_r), //
266 interp(a_g, b_g), //
267 interp(a_b, b_b)); //
268}
269
270/// @brief Blend two colors together using the alpha channel.
271// static
272Color Color::Blend(const Color& lhs, const Color& rhs) {
273 Color out = Interpolate(float(rhs.alpha_) / 255.F, lhs, rhs);
274 out.alpha_ = lhs.alpha_ + rhs.alpha_ - lhs.alpha_ * rhs.alpha_ / 255;
275 return out;
276}
277
278inline namespace literals {
279
280Color operator""_rgb(unsigned long long int combined) {
281 // assert(combined <= 0xffffffU);
282 auto const red = static_cast<uint8_t>(combined >> 16U);
283 auto const green = static_cast<uint8_t>(combined >> 8U);
284 auto const blue = static_cast<uint8_t>(combined);
285 return {red, green, blue};
286}
287
288} // namespace literals
289
290} // namespace ftxui
Decorator color(Color)
Decorate using a foreground color.
Color()
Build a transparent color.
static Color HSV(uint8_t hue, uint8_t saturation, uint8_t value)
Build a Color from its HSV representation. https://en.wikipedia.org/wiki/HSL_and_HSV.
static Color RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
Build a Color from its RGBA representation. https://en.wikipedia.org/wiki/RGB_color_model.
static Color Blend(const Color &lhs, const Color &rhs)
Blend two colors together using the alpha channel.
bool operator!=(const Color &rhs) const
bool operator==(const Color &rhs) const
static Color RGB(uint8_t red, uint8_t green, uint8_t blue)
Build a Color from its RGB representation. https://en.wikipedia.org/wiki/RGB_color_model.
std::string Print(bool is_background_color) const
static Color Interpolate(float t, const Color &a, const Color &b)
static Color HSVA(uint8_t hue, uint8_t saturation, uint8_t value, uint8_t alpha)
Build a Color from its HSV representation. https://en.wikipedia.org/wiki/HSL_and_HSV.
Color is a class that represents a color in the terminal user interface.
Definition color.hpp:22
ColorInfo is a structure that contains information about the terminal color palette.
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
ColorInfo GetColorInfo(Color::Palette256 index)