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