Eliya/src/Utils/ProgressBar.cpp

156 lines
4.5 KiB
C++

//
// Created by versustune on 23.02.20.
//
#include <iomanip>
#include <iostream>
#include <cmath>
#include <zconf.h>
#include <thread>
#include "ProgressBar.h"
ProgressBar::ProgressBar(std::string name, int maxTicks, int showAfterTicks) {
ProgressBar::maxTicks = maxTicks + 0;
ProgressBar::ticks = 0 + 0;
ProgressBar::name = "\033[1;32m" + std::move(name) + "\033[0m";
ProgressBar::showAfterTicks = showAfterTicks;
if (maxTicks == -1) {
isUnlimited = true;
}
}
ProgressBar::~ProgressBar() = default;
void ProgressBar::update() {
//only update if ticks reached
if (ticks % showAfterTicks == 0 || (isFinished && !finishedDraw)) {
if (isUnlimited) {
renderUnknown();
} else {
renderNormal();
}
if (isFinished) {
finishedDraw = true;
}
}
}
void ProgressBar::tick() {
++ticks;
if (ticks > maxTicks && maxTicks != -1) {
ticks = maxTicks;
isFinished = true;
}
}
void ProgressBar::setFinished(bool isThread) {
isFinished = true;
if (!isThread) {
this->update();
}
}
void ProgressBar::start() {
start_time = std::chrono::steady_clock::now();
this->update();
}
void ProgressBar::renderUnknown() {
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
double seconds = static_cast<double>(time_elapsed) / 1000.0;
double ticks_per_second = static_cast<double>(ticks) / seconds;
std::stringstream stream;
stream << "\033[2K" << "\r";
stream << "[" << name << "] \033[1;34m[" << unlimitedChars.at(++lastIcon % unlimitedChars.length());
stream << "]\033[1;36m [" << ticks << "]" << " (" << static_cast<std::size_t>(ticks ? ticks_per_second : 0.0)
<< " t/s)\033[0m";
std::cout << stream.str() << std::flush;
}
void ProgressBar::renderNormal() {
int pos = 0;
double progress = 0;
if (ticks > 0) {
progress = double(ticks) / double(maxTicks);
pos = (50 * progress);
}
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count();
double seconds = static_cast<double>(time_elapsed) / 1000.0;
double ticks_per_second = static_cast<double>(ticks) / seconds;
double remaining_ticks = maxTicks - ticks;
double total_seconds_rem = remaining_ticks / ticks_per_second;
std::stringstream stream;
stream << "\033[2K" << "\r";
stream << "[" << name << "]\033[1;34m[";
for (int i = 0; i < 50; ++i) {
if (i < pos) stream << '=';
else if (i == pos) stream << ">";
else stream << ' ';
}
stream << "]\033[1;35m " << std::roundf(progress * 100.0f) << "% ";
stream << ticks << " / " << maxTicks << " [";
convertTime(stream, seconds);
stream << " / ";
if (ticks) {
convertTime(stream, total_seconds_rem);
} else {
stream << "??:??:??";
}
stream << "]";
stream << " (" << static_cast<std::size_t>(ticks ? ticks_per_second : 0.0) << " t/s)\033[0m";
std::cout << stream.str() << std::flush;
}
void ProgressBar::convertTime(std::stringstream &stream, double seconds) {
std::size_t s_in_h(60 * 60), s_in_m(60)/*, m_in_h(60)*/;
int hours_rem = seconds / s_in_h;
int minutes_rem = (seconds - (hours_rem * s_in_h)) / s_in_m;
int seconds_rem = seconds - ((hours_rem * s_in_h) + (minutes_rem * s_in_m));
std::ios init(nullptr), time_fmt(nullptr);
init.copyfmt(stream);
stream << std::setfill('0') << std::setw(2);
time_fmt.copyfmt(stream);
//hours
stream.copyfmt(time_fmt);
stream << hours_rem;
stream.copyfmt(init);
//minutes
stream << ":";
stream.copyfmt(time_fmt);
stream << minutes_rem;
stream.copyfmt(init);
//seconds
stream << ":";
stream.copyfmt(time_fmt);
stream << seconds_rem;
//restore format
stream.copyfmt(init);
}
bool ProgressBar::isDone() const {
return isFinished && finishedDraw;
}
void ProgressBar::runInThread() {
while(!runThread) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
this->start();
while (!isDone()) {
this->update();
}
std::cout << "\n";
delete this;
}
void ProgressBar::setMaxTicks(int newMaxTicks) {
maxTicks = newMaxTicks;
}
void ProgressBar::startThread() {
runThread = true;
}