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) {
103 if (i >= gradient.positions.size()) {
104 const float half = 0.5F;
105 return Color::Interpolate(half, gradient.colors.back(),
106 gradient.colors.back());
108 if (t <= gradient.positions[i]) {
114 const float t0 = gradient.positions[i - 1];
115 const float t1 = gradient.positions[i - 0];
116 const float tt = (t - t0) / (t1 - t0);
118 const Color& c0 = gradient.colors[i - 1];
119 const Color& c1 = gradient.colors[i - 0];
120 const Color& cc = Color::Interpolate(tt, c0, c1);
125class LinearGradientColor :
public NodeDecorator {
127 explicit LinearGradientColor(
Element child,
128 const LinearGradient& gradient,
129 bool background_color)
130 : NodeDecorator(std::move(child)),
131 gradient_(Normalize(gradient)),
132 background_color_{background_color} {}
135 void Render(Screen& screen)
override {
136 const float degtorad = 0.01745329251F;
137 const float dx = std::cos(gradient_.angle * degtorad);
138 const float dy = std::sin(gradient_.angle * degtorad);
141 const float p1 = float(box_.x_min) * dx + float(box_.y_min) * dy;
142 const float p2 = float(box_.x_min) * dx + float(box_.y_max) * dy;
143 const float p3 = float(box_.x_max) * dx + float(box_.y_min) * dy;
144 const float p4 = float(box_.x_max) * dx + float(box_.y_max) * dy;
145 const float min = std::min({p1, p2, p3, p4});
146 const float max = std::max({p1, p2, p3, p4});
149 const float dX = dx / (max - min);
150 const float dY = dy / (max - min);
151 const float dZ = -min / (max - min);
154 if (background_color_) {
155 for (
int y = box_.y_min;
y <= box_.y_max; ++
y) {
156 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
157 const float t = float(x) * dX + float(
y) * dY + dZ;
158 screen.CellAt(x,
y).background_color = Interpolate(gradient_, t);
162 for (
int y = box_.y_min;
y <= box_.y_max; ++
y) {
163 for (
int x = box_.x_min; x <= box_.x_max; ++x) {
164 const float t = float(x) * dX + float(
y) * dY + dZ;
165 screen.CellAt(x,
y).foreground_color = Interpolate(gradient_, t);
170 NodeDecorator::Render(screen);
173 LinearGradientNormalized gradient_;
174 bool background_color_;
190LinearGradient::LinearGradient() =
default;
195LinearGradient::LinearGradient(Color begin, Color end)
196 : LinearGradient(0, begin, end) {}
202LinearGradient::LinearGradient(
float a, Color begin, Color end) :
angle(a) {
203 stops.push_back({begin, {}});
204 stops.push_back({end, {}});
210LinearGradient& LinearGradient::Angle(
float a) {
218LinearGradient& LinearGradient::Stop(Color c,
float p) {
219 stops.push_back({c, p});
227LinearGradient& LinearGradient::Stop(Color c) {
228 stops.push_back({c, {}});
244 return std::make_shared<LinearGradientColor>(std::move(child), gradient,
260 return std::make_shared<LinearGradientColor>(std::move(child), gradient,
276 [gradient](
Element child) {
return color(gradient, std::move(child)); };
291 [gradient](
Element child) {
return bgcolor(gradient, std::move(child)); };
Element bgcolor(Color color, Element child)
Définit la couleur d'arrière-plan d'un élément.
Element color(Color color, Element child)
Définit la couleur de premier plan d'un élément.
L'espace de noms FTXUI 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