FTXUI  5.0.0
C++ functional terminal UI.
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.
4 #include "ftxui/screen/color.hpp"
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 
14 namespace ftxui {
15 namespace {
16 const 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 
37 bool Color::operator==(const Color& rhs) const {
38  return red_ == rhs.red_ && green_ == rhs.green_ && blue_ == rhs.blue_ &&
39  type_ == rhs.type_;
40 }
41 
42 bool Color::operator!=(const Color& rhs) const {
43  return !operator==(rhs);
44 }
45 
46 std::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.
77 /// @ingroup screen
78 Color::Color() = default;
79 
80 /// @brief Build a transparent color.
81 /// @ingroup screen
82 Color::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
108 Color::Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
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) {
125  const ColorInfo color_info = GetColorInfo(Color::Palette256(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
153 Color Color::RGB(uint8_t red, uint8_t green, uint8_t blue) {
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
166 Color Color::RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) {
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
179 Color Color::HSVA(uint8_t h, uint8_t s, uint8_t v, uint8_t alpha) {
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
207 Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
208  return HSVA(h, s, v, 255);
209 }
210 
211 // static
212 Color 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: {
230  const ColorInfo info = GetColorInfo(Color::Palette16(color.red_));
231  *red = info.red;
232  *green = info.green;
233  *blue = info.blue;
234  return;
235  }
236 
237  case ColorType::Palette256: {
238  const ColorInfo info = GetColorInfo(Color::Palette256(color.red_));
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
281 Color Color::Blend(const Color& lhs, const Color& rhs) {
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 
287 inline namespace literals {
288 
289 Color 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
enum Palette1 uint8_t enum Palette16 uint8_t enum Palette256 uint8_t 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::string to_string(const std::wstring &s)
Convert a UTF8 std::string into a std::wstring.
Definition: string.cpp:1565
ColorInfo GetColorInfo(Color::Palette256 index)
Definition: color_info.cpp:272
Decorator color(Color)
Decorate using a foreground color.
Definition: color.cpp:110