commits
tags
#include "torlinkc/ui/progress_bar.hpp"
#include <algorithm>
#include <cmath>
#include "torlinkc/ui/theme.hpp"
using namespace ftxui;
namespace torlinkc::ui {
namespace {
constexpr float kSheenRadius = 4.5f; // bell half-width, in bar cells
constexpr float kSheenGap = 8.0f; // dark cells between sweeps
constexpr float kSheenSpeed = 11.25f; // cells per second
constexpr float kSheenMax = 0.9f; // peak blend toward the highlight
const Color kSheenPeak = Color::RGB(244, 239, 255); // #f4efff
const Color kAnimatedDeep = Color::RGB(124, 92, 214); // #7c5cd6, ProgressBar.tsx's DEEP
float sheenPeriod(int width) { return static_cast<float>(width) + kSheenRadius * 2.0f + kSheenGap; }
float sheenIntensity(float cell, float center) {
const float d = std::fabs(cell - center);
if (d >= kSheenRadius) return 0.0f;
return 0.5f * (1.0f + std::cos(static_cast<float>(M_PI) * d / kSheenRadius)) * kSheenMax;
}
Color ramp(float t, Color deep, Color mid, Color bright) {
return t <= 0.5f ? Color::Interpolate(t / 0.5f, deep, mid) : Color::Interpolate((t - 0.5f) / 0.5f, mid, bright);
}
} // namespace
float progressSheenCenter(float clockSeconds, int width) {
return std::fmod(clockSeconds * kSheenSpeed, sheenPeriod(width)) - kSheenRadius;
}
Element renderProgressBar(int pct, int width, Color base, std::optional<float> sweepCenter) {
const int clamped = std::clamp(pct, 0, 100);
const int filled = static_cast<int>(std::lround((clamped / 100.0) * width));
const int empty = std::max(0, width - filled);
const int denom = std::max(1, width - 1);
Color deep;
Color mid;
Color bright;
if (sweepCenter) {
deep = kAnimatedDeep;
mid = palette::accent;
bright = palette::bright;
} else {
deep = Color::Interpolate(0.3f, base, Color::RGB(0, 0, 0));
mid = base;
bright = Color::Interpolate(0.35f, base, palette::text);
}
Elements cells;
cells.reserve(static_cast<std::size_t>(width));
for (int i = 0; i < filled; ++i) {
const float t = static_cast<float>(i) / static_cast<float>(denom);
Color c = ramp(t, deep, mid, bright);
if (sweepCenter) {
const float intensity = sheenIntensity(static_cast<float>(i), *sweepCenter);
if (intensity > 0.0f) c = Color::Interpolate(intensity, c, kSheenPeak);
}
cells.push_back(text("█") | color(c));
}
for (int i = 0; i < empty; ++i) cells.push_back(text("░") | color(palette::rule));
return hbox(std::move(cells));
}
} // namespace torlinkc::ui