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_view> // for literals
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 
16 using namespace std::literals;
17 
18 namespace {
19 const std::array<const char*, 33> palette16code = {
20  "30", "40", //
21  "31", "41", //
22  "32", "42", //
23  "33", "43", //
24  "34", "44", //
25  "35", "45", //
26  "36", "46", //
27  "37", "47", //
28  "90", "100", //
29  "91", "101", //
30  "92", "102", //
31  "93", "103", //
32  "94", "104", //
33  "95", "105", //
34  "96", "106", //
35  "97", "107", //
36 };
37 
38 } // namespace
39 
40 bool Color::operator==(const Color& rhs) const {
41  return red_ == rhs.red_ && green_ == rhs.green_ && blue_ == rhs.blue_ &&
42  type_ == rhs.type_;
43 }
44 
45 bool Color::operator!=(const Color& rhs) const {
46  return !operator==(rhs);
47 }
48 
49 std::string Color::Print(bool is_background_color) const {
50  switch (type_) {
52  return is_background_color ? "49"s : "39"s;
53 
55  return palette16code[2 * red_ + is_background_color]; // NOLINT;
56 
58  return (is_background_color ? "48;5;"s : "38;5;"s) + std::to_string(red_);
59 
61  default:
62  return (is_background_color ? "48;2;"s : "38;2;"s) //
63  + std::to_string(red_) + ";" //
64  + std::to_string(green_) + ";" //
65  + std::to_string(blue_); //
66  }
67 }
68 
69 /// @brief Build a transparent color.
70 /// @ingroup screen
71 Color::Color() = default;
72 
73 /// @brief Build a transparent color.
74 /// @ingroup screen
75 Color::Color(Palette1 /*value*/) : Color() {}
76 
77 /// @brief Build a transparent using Palette16 colors.
78 /// @ingroup screen
79 Color::Color(Palette16 index) : type_(ColorType::Palette16), red_(index) {}
80 
81 /// @brief Build a transparent using Palette256 colors.
82 /// @ingroup screen
83 Color::Color(Palette256 index) : type_(ColorType::Palette256), red_(index) {
85  return;
86  }
87  type_ = ColorType::Palette16;
89 }
90 
91 /// @brief Build a Color from its RGB representation.
92 /// https://en.wikipedia.org/wiki/RGB_color_model
93 ///
94 /// @param red The quantity of red [0,255]
95 /// @param green The quantity of green [0,255]
96 /// @param blue The quantity of blue [0,255]
97 /// @ingroup screen
98 Color::Color(uint8_t red, uint8_t green, uint8_t blue)
99  : type_(ColorType::TrueColor), red_(red), green_(green), blue_(blue) {
101  return;
102  }
103 
104  // Find the closest Color from the database:
105  const int max_distance = 256 * 256 * 3;
106  int closest = max_distance;
107  int best = 0;
108  const int database_begin = 16;
109  const int database_end = 256;
110  for (int i = database_begin; i < database_end; ++i) {
111  const ColorInfo color_info = GetColorInfo(Color::Palette256(i));
112  const int dr = color_info.red - red;
113  const int dg = color_info.green - green;
114  const int db = color_info.blue - blue;
115  const int dist = dr * dr + dg * dg + db * db;
116  if (closest > dist) {
117  closest = dist;
118  best = i;
119  }
120  }
121 
123  type_ = ColorType::Palette256;
124  red_ = best;
125  } else {
126  type_ = ColorType::Palette16;
128  }
129 }
130 
131 /// @brief Build a Color from its RGB representation.
132 /// https://en.wikipedia.org/wiki/RGB_color_model
133 ///
134 /// @param red The quantity of red [0,255]
135 /// @param green The quantity of green [0,255]
136 /// @param blue The quantity of blue [0,255]
137 /// @ingroup screen
138 // static
139 Color Color::RGB(uint8_t red, uint8_t green, uint8_t blue) {
140  return {red, green, blue};
141 }
142 
143 /// @brief Build a Color from its HSV representation.
144 /// https://en.wikipedia.org/wiki/HSL_and_HSV
145 ///
146 /// @param h The hue of the color [0,255]
147 /// @param s The "colorfulness" [0,255].
148 /// @param v The "Lightness" [0,255]
149 /// @ingroup screen
150 // static
151 Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
152  if (s == 0) {
153  return {0, 0, 0};
154  }
155 
156  uint8_t region = h / 43; // NOLINT
157  uint8_t remainder = (h - (region * 43)) * 6; // NOLINT
158  uint8_t p = (v * (255 - s)) >> 8; // NOLINT
159  uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8; // NOLINT
160  uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; // NOLINT
161 
162  // clang-format off
163  switch (region) { // NOLINT
164  case 0: return Color(v,t,p); // NOLINT
165  case 1: return Color(q,v,p); // NOLINT
166  case 2: return Color(p,v,t); // NOLINT
167  case 3: return Color(p,q,v); // NOLINT
168  case 4: return Color(t,p,v); // NOLINT
169  case 5: return Color(v,p,q); // NOLINT
170  } // NOLINT
171  // clang-format on
172  return {0, 0, 0};
173 }
174 
175 // static
176 Color Color::Interpolate(float t, const Color& a, const Color& b) {
177  if (a.type_ == ColorType::Palette1 || //
178  b.type_ == ColorType::Palette1) {
179  if (t < 0.5F) { // NOLINT
180  return a;
181  } else {
182  return b;
183  }
184  }
185 
186  auto get_color = [](const Color& color, //
187  uint8_t* red, uint8_t* green, uint8_t* blue) {
188  switch (color.type_) {
189  case ColorType::Palette1: {
190  return;
191  }
192 
193  case ColorType::Palette16: {
194  const ColorInfo info = GetColorInfo(Color::Palette16(color.red_));
195  *red = info.red;
196  *green = info.green;
197  *blue = info.blue;
198  return;
199  }
200 
201  case ColorType::Palette256: {
202  const ColorInfo info = GetColorInfo(Color::Palette256(color.red_));
203  *red = info.red;
204  *green = info.green;
205  *blue = info.blue;
206  return;
207  }
208 
209  case ColorType::TrueColor:
210  default: {
211  *red = color.red_;
212  *green = color.green_;
213  *blue = color.blue_;
214  return;
215  }
216  }
217  };
218 
219  uint8_t a_r = 0;
220  uint8_t a_g = 0;
221  uint8_t a_b = 0;
222  uint8_t b_r = 0;
223  uint8_t b_g = 0;
224  uint8_t b_b = 0;
225  get_color(a, &a_r, &a_g, &a_b);
226  get_color(b, &b_r, &b_g, &b_b);
227 
228  // Gamma correction:
229  // https://en.wikipedia.org/wiki/Gamma_correction
230  auto interp = [t](uint8_t a_u, uint8_t b_u) {
231  constexpr float gamma = 2.2F;
232  const float a_f = powf(a_u, gamma);
233  const float b_f = powf(b_u, gamma);
234  const float c_f = a_f * (1.0F - t) + //
235  b_f * t;
236  return static_cast<uint8_t>(powf(c_f, 1.F / gamma));
237  };
238  return Color::RGB(interp(a_r, b_r), //
239  interp(a_g, b_g), //
240  interp(a_b, b_b)); //
241 }
242 
243 inline namespace literals {
244 
245 Color operator""_rgb(unsigned long long int combined) {
246  // assert(combined <= 0xffffffU);
247  auto const red = static_cast<uint8_t>(combined >> 16U);
248  auto const green = static_cast<uint8_t>(combined >> 8U);
249  auto const blue = static_cast<uint8_t>(combined);
250  return {red, green, blue};
251 }
252 
253 } // namespace literals
254 
255 } // namespace ftxui
A class representing terminal colors.
Definition: color.hpp:21
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:151
bool operator!=(const Color &rhs) const
Definition: color.cpp:45
bool operator==(const Color &rhs) const
Definition: color.cpp:40
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:139
std::string Print(bool is_background_color) const
Definition: color.cpp:49
static Color Interpolate(float t, const Color &a, const Color &b)
Definition: color.cpp:176
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:91