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_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
14namespace ftxui {
15
16using namespace std::literals;
17
18namespace {
19const 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
40bool Color::operator==(const Color& rhs) const {
41 return red_ == rhs.red_ && green_ == rhs.green_ && blue_ == rhs.blue_ &&
42 type_ == rhs.type_;
43}
44
45bool Color::operator!=(const Color& rhs) const {
46 return !operator==(rhs);
47}
48
49std::string Color::Print(bool is_background_color) const {
50 switch (type_) {
51 case ColorType::Palette1:
52 return is_background_color ? "49"s : "39"s;
53
54 case ColorType::Palette16:
55 return palette16code[2 * red_ + is_background_color]; // NOLINT;
56
57 case ColorType::Palette256:
58 return (is_background_color ? "48;5;"s : "38;5;"s) + std::to_string(red_);
59
60 case ColorType::TrueColor:
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
71Color::Color() = default;
72
73/// @brief Build a transparent color.
74/// @ingroup screen
75Color::Color(Palette1 /*value*/) : Color() {}
76
77/// @brief Build a transparent using Palette16 colors.
78/// @ingroup screen
79Color::Color(Palette16 index) : type_(ColorType::Palette16), red_(index) {}
80
81/// @brief Build a transparent using Palette256 colors.
82/// @ingroup screen
83Color::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
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) {
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
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
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
176Color 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: {
195 *red = info.red;
196 *green = info.green;
197 *blue = info.blue;
198 return;
199 }
200
201 case ColorType::Palette256: {
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
243inline namespace literals {
244
245Color 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
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
ColorInfo GetColorInfo(Color::Palette256 index)
Component Slider(SliderOption< T > options)
A slider in any direction.
Definition slider.cpp:339
Decorator color(Color)
Decorate using a foreground color.
Definition color.cpp:91