FTXUI  5.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
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 {
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.
77/// @ingroup screen
78Color::Color() = default;
79
80/// @brief Build a transparent color.
81/// @ingroup screen
82Color::Color(Palette1 /*value*/) : Color() {}
83
84/// @brief Build a color using the Palette16 colors.
85/// @ingroup screen
87 : type_(ColorType::Palette16), red_(index), alpha_(255) {}
88
89/// @brief Build a color using Palette256 colors.
90/// @ingroup screen
92 : type_(ColorType::Palette256), red_(index), alpha_(255) {
94 return;
95 }
96 type_ = ColorType::Palette16;
98}
99
100/// @brief Build a Color from its RGB representation.
101/// https://en.wikipedia.org/wiki/RGB_color_model
102///
103/// @param red The quantity of red [0,255]
104/// @param green The quantity of green [0,255]
105/// @param blue The quantity of blue [0,255]
106/// @param alpha The quantity of alpha [0,255]
107/// @ingroup screen
109 : type_(ColorType::TrueColor),
110 red_(red),
111 green_(green),
112 blue_(blue),
113 alpha_(alpha) {
115 return;
116 }
117
118 // Find the closest Color from the database:
119 const int max_distance = 256 * 256 * 3;
120 int closest = max_distance;
121 int best = 0;
122 const int database_begin = 16;
123 const int database_end = 256;
124 for (int i = database_begin; i < database_end; ++i) {
126 const int dr = color_info.red - red;
127 const int dg = color_info.green - green;
128 const int db = color_info.blue - blue;
129 const int dist = dr * dr + dg * dg + db * db;
130 if (closest > dist) {
131 closest = dist;
132 best = i;
133 }
134 }
135
137 type_ = ColorType::Palette256;
138 red_ = best;
139 } else {
140 type_ = ColorType::Palette16;
142 }
143}
144
145/// @brief Build a Color from its RGB representation.
146/// https://en.wikipedia.org/wiki/RGB_color_model
147///
148/// @param red The quantity of red [0,255]
149/// @param green The quantity of green [0,255]
150/// @param blue The quantity of blue [0,255]
151/// @ingroup screen
152// static
154 return RGBA(red, green, blue, 255);
155}
156
157/// @brief Build a Color from its RGBA representation.
158/// https://en.wikipedia.org/wiki/RGB_color_model
159/// @param red The quantity of red [0,255]
160/// @param green The quantity of green [0,255]
161/// @param blue The quantity of blue [0,255]
162/// @param alpha The quantity of alpha [0,255]
163/// @ingroup screen
164/// @see Color::RGB
165// static
167 return {red, green, blue, alpha};
168}
169
170/// @brief Build a Color from its HSV representation.
171/// https://en.wikipedia.org/wiki/HSL_and_HSV
172///
173/// @param h The hue of the color [0,255]
174/// @param s The "colorfulness" [0,255].
175/// @param v The "Lightness" [0,255]
176/// @param alpha The quantity of alpha [0,255]
177/// @ingroup screen
178// static
180 uint8_t region = h / 43; // NOLINT
181 uint8_t remainder = (h - (region * 43)) * 6; // NOLINT
182 uint8_t p = (v * (255 - s)) >> 8; // NOLINT
183 uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8; // NOLINT
184 uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; // NOLINT
185
186 // clang-format off
187 switch (region) { // NOLINT
188 case 0: return Color(v,t,p, alpha); // NOLINT
189 case 1: return Color(q,v,p, alpha); // NOLINT
190 case 2: return Color(p,v,t, alpha); // NOLINT
191 case 3: return Color(p,q,v, alpha); // NOLINT
192 case 4: return Color(t,p,v, alpha); // NOLINT
193 case 5: return Color(v,p,q, alpha); // NOLINT
194 } // NOLINT
195 // clang-format on
196 return {0, 0, 0, alpha};
197}
198
199/// @brief Build a Color from its HSV representation.
200/// https://en.wikipedia.org/wiki/HSL_and_HSV
201///
202/// @param h The hue of the color [0,255]
203/// @param s The "colorfulness" [0,255].
204/// @param v The "Lightness" [0,255]
205/// @ingroup screen
206// static
208 return HSVA(h, s, v, 255);
209}
210
211// static
212Color Color::Interpolate(float t, const Color& a, const Color& b) {
213 if (a.type_ == ColorType::Palette1 || //
214 b.type_ == ColorType::Palette1) {
215 if (t < 0.5F) { // NOLINT
216 return a;
217 } else {
218 return b;
219 }
220 }
221
222 auto get_color = [](const Color& color, //
223 uint8_t* red, uint8_t* green, uint8_t* blue) {
224 switch (color.type_) {
225 case ColorType::Palette1: {
226 return;
227 }
228
229 case ColorType::Palette16: {
231 *red = info.red;
232 *green = info.green;
233 *blue = info.blue;
234 return;
235 }
236
237 case ColorType::Palette256: {
239 *red = info.red;
240 *green = info.green;
241 *blue = info.blue;
242 return;
243 }
244
245 case ColorType::TrueColor:
246 default: {
247 *red = color.red_;
248 *green = color.green_;
249 *blue = color.blue_;
250 return;
251 }
252 }
253 };
254
255 uint8_t a_r = 0;
256 uint8_t a_g = 0;
257 uint8_t a_b = 0;
258 uint8_t b_r = 0;
259 uint8_t b_g = 0;
260 uint8_t b_b = 0;
261 get_color(a, &a_r, &a_g, &a_b);
262 get_color(b, &b_r, &b_g, &b_b);
263
264 // Gamma correction:
265 // https://en.wikipedia.org/wiki/Gamma_correction
266 auto interp = [t](uint8_t a_u, uint8_t b_u) {
267 constexpr float gamma = 2.2F;
268 const float a_f = powf(a_u, gamma);
269 const float b_f = powf(b_u, gamma);
270 const float c_f = a_f * (1.0F - t) + //
271 b_f * t;
272 return static_cast<uint8_t>(powf(c_f, 1.F / gamma));
273 };
274 return Color::RGB(interp(a_r, b_r), //
275 interp(a_g, b_g), //
276 interp(a_b, b_b)); //
277}
278
279/// @brief Blend two colors together using the alpha channel.
280// static
282 Color out = Interpolate(float(rhs.alpha_) / 255.F, lhs, rhs);
283 out.alpha_ = lhs.alpha_ + rhs.alpha_ - lhs.alpha_ * rhs.alpha_ / 255;
284 return out;
285}
286
287inline namespace literals {
288
289Color operator""_rgb(unsigned long long int combined) {
290 // assert(combined <= 0xffffffU);
291 auto const red = static_cast<uint8_t>(combined >> 16U);
292 auto const green = static_cast<uint8_t>(combined >> 8U);
293 auto const blue = static_cast<uint8_t>(combined);
294 return {red, green, blue};
295}
296
297} // namespace literals
298
299} // namespace ftxui
A class representing terminal colors.
Definition color.hpp:20
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.
Definition color.cpp:207
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.
Definition color.cpp:166
static Color Blend(const Color &lhs, const Color &rhs)
Blend two colors together using the alpha channel.
Definition color.cpp:281
bool operator!=(const Color &rhs) const
Definition color.cpp:42
bool operator==(const Color &rhs) const
Definition color.cpp:37
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.
Definition color.cpp:153
std::string Print(bool is_background_color) const
Definition color.cpp:46
static Color Interpolate(float t, const Color &a, const Color &b)
Definition color.cpp:212
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.
Definition color.cpp:179
Color ColorSupport()
Get the color support of the terminal.
Definition terminal.cpp:130
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
ColorInfo GetColorInfo(Color::Palette256 index)
Decorator color(Color)
Decorate using a foreground color.
Definition color.cpp:110