22struct LinearGradientNormalized {
29LinearGradientNormalized Normalize(LinearGradient gradient) {
31 if (gradient.stops.empty()) {
32 return LinearGradientNormalized{
34 {Color::Default, Color::Default},
40 if (!gradient.stops.front().position) {
41 gradient.stops.front().position = 0.F;
43 if (!gradient.stops.back().position) {
44 gradient.stops.back().position = 1.F;
48 size_t last_checkpoint = 0;
49 for (
size_t i = 1; i < gradient.stops.size(); ++i) {
50 if (!gradient.stops[i].position) {
54 if (i - last_checkpoint >= 2) {
55 const float min = gradient.stops[i].position.value();
57 gradient.stops[last_checkpoint].position.value();
58 for (
size_t j = last_checkpoint + 1; j < i; ++j) {
59 gradient.stops[j].position = min + (max - min) *
60 float(j - last_checkpoint) /
61 float(i - last_checkpoint);
70 gradient.stops.begin(), gradient.stops.end(),
71 [](
const auto& a,
const auto& b) { return a.position < b.position; });
74 if (gradient.stops.front().position != 0) {
75 gradient.stops.insert(gradient.stops.begin(),
76 {gradient.stops.front().color, 0.F});
79 if (gradient.stops.back().position != 1) {
80 gradient.stops.push_back({gradient.stops.back().color, 1.F});
84 LinearGradientNormalized normalized;
85 const float modulo = 360.F;
87 std::fmod(std::fmod(gradient.angle, modulo) + modulo, modulo);
88 for (
auto& stop : gradient.stops) {
89 normalized.colors.push_back(stop.color);
91 normalized.positions.push_back(stop.position.value());
96Color Interpolate(
const LinearGradientNormalized& gradient,
float t) {
104 if (i >= gradient.positions.size()) {
105 const float half = 0.5F;
106 return Color::Interpolate(half, gradient.colors.back(),
107 gradient.colors.back());
109 if (t <= gradient.positions[i]) {
115 const float t0 = gradient.positions[i - 1];
116 const float t1 = gradient.positions[i - 0];
117 const float tt = (t - t0) / (t1 - t0);
119 const Color& c0 = gradient.colors[i - 1];
120 const Color& c1 = gradient.colors[i - 0];
121 const Color& cc = Color::Interpolate(tt, c0, c1);
126class LinearGradientColor :
public NodeDecorator {
128 explicit LinearGradientColor(
Element child,
129 const LinearGradient& gradient,
130 bool background_color)
131 : NodeDecorator(std::move(child)),
132 gradient_(Normalize(gradient)),
133 background_color_{background_color} {}
136 void Render(Screen& screen)
override {
137 const float degtorad = 0.01745329251F;
138 const float dx = std::cos(gradient_.angle * degtorad);
139 const float dy = std::sin(gradient_.angle * degtorad);
142 const float p1 = float(box_.x_min) * dx + float(box_.y_min) * dy;
143 const float p2 = float(box_.x_min) * dx + float(box_.y_max) * dy;
144 const float p3 = float(box_.x_max) * dx + float(box_.y_min) * dy;
145 const float p4 = float(box_.x_max) * dx + float(box_.y_max) * dy;
146 const float min = std::min({p1, p2, p3, p4});
147 const float max = std::max({p1, p2, p3, p4});
151 const float dX = dx / (max - min);
152 const float dY = dy / (max - min);
153 const float dZ = -min / (max - min);
156 if (background_color_) {
157 for (
int y = box_.y_min;
y <= box_.y_max; ++
y) {
158 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
159 const float t = float(x) * dX + float(
y) * dY + dZ;
160 screen.CellAt(x,
y).background_color = Interpolate(gradient_, t);
164 for (
int y = box_.y_min;
y <= box_.y_max; ++
y) {
165 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
166 const float t = float(x) * dX + float(
y) * dY + dZ;
167 screen.CellAt(x,
y).foreground_color = Interpolate(gradient_, t);
172 NodeDecorator::Render(screen);
175 LinearGradientNormalized gradient_;
176 bool background_color_;
192LinearGradient::LinearGradient() =
default;
197LinearGradient::LinearGradient(Color begin, Color end)
198 : LinearGradient(0, begin, end) {}
204LinearGradient::LinearGradient(
float a, Color begin, Color end) :
angle(a) {
205 stops.push_back({begin, {}});
206 stops.push_back({end, {}});
212LinearGradient& LinearGradient::Angle(
float a) {
220LinearGradient& LinearGradient::Stop(Color c,
float p) {
221 stops.push_back({c, p});
229LinearGradient& LinearGradient::Stop(Color c) {
230 stops.push_back({c, {}});
246 return std::make_shared<LinearGradientColor>(std::move(child), gradient,
262 return std::make_shared<LinearGradientColor>(std::move(child), gradient,
278 [gradient](
Element child) {
return color(gradient, std::move(child)); };
293 [gradient](
Element child) {
return bgcolor(gradient, std::move(child)); };
Element bgcolor(Color color, Element child)
Establece el color de fondo de un elemento.
Element color(Color color, Element child)
Establece el color de primer plano de un elemento.
El espacio de nombres ftxui:: de FTXUI.
std::shared_ptr< Node > Element
std::function< Element(Element)> Decorator
void Render(Screen &screen, Node *node, Selection &selection)
std::vector< Color > colors
std::vector< float > positions