19struct LinearGradientNormalized {
21 std::vector<Color> colors;
22 std::vector<float> positions;
26LinearGradientNormalized Normalize(LinearGradient gradient) {
28 if (gradient.stops.size() == 0) {
29 return LinearGradientNormalized{
34 if (!gradient.stops.front().position) {
35 gradient.stops.front().position = 0.f;
37 if (!gradient.stops.back().position) {
38 gradient.stops.back().position = 1.f;
42 size_t last_checkpoint = 0;
43 for (
size_t i = 1; i < gradient.stops.size(); ++i) {
44 if (!gradient.stops[i].position) {
48 if (i - last_checkpoint >= 2) {
49 const float min = gradient.stops[i].position.value();
50 const float max = gradient.stops[last_checkpoint].position.value();
51 for (
size_t j = last_checkpoint + 1; j < i; ++j) {
52 gradient.stops[j].position =
53 min + (max - min) * (j - last_checkpoint) / (i - last_checkpoint);
62 gradient.stops.begin(), gradient.stops.end(),
63 [](
const auto& a,
const auto& b) { return a.position < b.position; });
66 if (gradient.stops.front().position != 0) {
67 gradient.stops.insert(gradient.stops.begin(),
68 {gradient.stops.front().color, 0.f});
71 if (gradient.stops.back().position != 1) {
72 gradient.stops.push_back({gradient.stops.back().color, 1.f});
76 LinearGradientNormalized normalized;
77 normalized.angle = std::fmod(std::fmod(gradient.angle, 360.f) + 360.f, 360.f);
78 for (
auto& stop : gradient.stops) {
79 normalized.colors.push_back(stop.color);
80 normalized.positions.push_back(stop.position.value());
85Color Interpolate(
const LinearGradientNormalized& gradient,
float t) {
89 if (i > gradient.positions.size()) {
91 gradient.colors.back());
93 if (t <= gradient.positions[i]) {
99 const float t0 = gradient.positions[i - 1];
100 const float t1 = gradient.positions[i - 0];
101 const float tt = (t - t0) / (t1 - t0);
103 const Color& c0 = gradient.colors[i - 1];
104 const Color& c1 = gradient.colors[i - 0];
110class LinearGradientColor :
public NodeDecorator {
112 explicit LinearGradientColor(
Element child,
113 const LinearGradient& gradient,
114 bool background_color)
115 : NodeDecorator(std::move(child)),
116 gradient_(Normalize(gradient)),
117 background_color_{background_color} {}
120 void Render(Screen& screen)
override {
121 const float degtorad = 0.01745329251f;
122 const float dx = std::cos(gradient_.angle * degtorad);
123 const float dy = std::sin(gradient_.angle * degtorad);
126 const float p1 = box_.x_min * dx + box_.y_min * dy;
127 const float p2 = box_.x_min * dx + box_.y_max * dy;
128 const float p3 = box_.x_max * dx + box_.y_min * dy;
129 const float p4 = box_.x_max * dx + box_.y_max * dy;
130 const float min = std::min({p1, p2, p3, p4});
131 const float max = std::max({p1, p2, p3, p4});
135 const float dX = dx / (max - min);
136 const float dY = dy / (max - min);
137 const float dZ = -min / (max - min);
140 if (background_color_) {
141 for (
int y = box_.y_min; y <= box_.y_max; ++y) {
142 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
143 const float t = x * dX + y * dY + dZ;
144 screen.PixelAt(x, y).background_color = Interpolate(gradient_, t);
148 for (
int y = box_.y_min; y <= box_.y_max; ++y) {
149 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
150 const float t = x * dX + y * dY + dZ;
151 screen.PixelAt(x, y).foreground_color = Interpolate(gradient_, t);
159 LinearGradientNormalized gradient_;
160 bool background_color_;
184 stops.push_back({begin, {}});
185 stops.push_back({end, {}});
195 stops.push_back({begin, {}});
196 stops.push_back({end, {}});
213 stops.push_back({c, p});
223 stops.push_back({c, {}});
239 return std::make_shared<LinearGradientColor>(std::move(child), gradient,
255 return std::make_shared<LinearGradientColor>(std::move(child), gradient,
271 [gradient](
Element child) {
return color(gradient, std::move(child)); };
286 [gradient](
Element child) {
return bgcolor(gradient, std::move(child)); };
A class representing terminal colors.
static Color Interpolate(float t, const Color &a, const Color &b)
virtual void Render(Screen &screen)
Display an element on a ftxui::Screen.
Decorator bgcolor(Color)
Decorate using a background color.
std::function< Element(Element)> Decorator
std::shared_ptr< Node > Element
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Decorator color(Color)
Decorate using a foreground color.
A class representing the settings for linear-gradient color effect.
LinearGradient & Stop(Color color, float position)
Add a color stop to the gradient.
LinearGradient & Angle(float angle)
Set the angle of the gradient.
LinearGradient()
Build the "empty" gradient. This is often followed by calls to LinearGradient::Angle() and LinearGrad...
std::vector< Stop > stops