From 6d737952189c05e0b4d0fff50d5bc60d54560746 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Fri, 8 May 2020 17:13:28 -0500 Subject: [PATCH] Implemented indeterminate progress bar w/ sample --- include/indicators/details/stream_helper.hpp | 11 +- .../indicators/indeterminate_progress_bar.hpp | 112 +++++++----------- samples/CMakeLists.txt | 3 + samples/indeterminate_progress_bar.cpp | 38 ++++++ 4 files changed, 87 insertions(+), 77 deletions(-) create mode 100644 samples/indeterminate_progress_bar.cpp diff --git a/include/indicators/details/stream_helper.hpp b/include/indicators/details/stream_helper.hpp index 935599e..5c499a9 100644 --- a/include/indicators/details/stream_helper.hpp +++ b/include/indicators/details/stream_helper.hpp @@ -161,15 +161,14 @@ public: const std::string &lead) : os(os), bar_width(bar_width), fill(fill), lead(lead) {} - std::ostream &write(float progress) { - auto pos = static_cast(progress * bar_width / 100.0); + std::ostream &write(size_t progress) { for (size_t i = 0; i < bar_width; ++i) { - if (i < pos) + if (i < progress) os << fill; - else if (i == pos) + else if (i == progress) os << lead; - else - os << remainder; + else + os << fill; } return os; } diff --git a/include/indicators/indeterminate_progress_bar.hpp b/include/indicators/indeterminate_progress_bar.hpp index 8054220..4e7bc94 100644 --- a/include/indicators/indeterminate_progress_bar.hpp +++ b/include/indicators/indeterminate_progress_bar.hpp @@ -49,9 +49,15 @@ class IndeterminateProgressBar { std::tuple; + enum class Direction { + forward, + backward + }; + + Direction direction_{Direction::forward}; + public: template (args)...), details::get(option::End{"]"}, std::forward(args)...), - details::get(option::Fill{"="}, + details::get(option::Fill{"."}, std::forward(args)...), - details::get(option::Lead{">"}, + details::get(option::Lead{"<==>"}, std::forward(args)...), details::get( option::MaxPostfixTextLen{0}, std::forward(args)...), details::get(option::Completed{false}, std::forward(args)...), - details::get( - option::ShowElapsedTime{false}, std::forward(args)...), - details::get( - option::ShowRemainingTime{false}, std::forward(args)...), - details::get( - option::SavedStartTime{false}, std::forward(args)...), details::get( option::ForegroundColor{Color::unspecified}, std::forward(args)...), details::get( - option::FontStyles{std::vector{}}, std::forward(args)...), - details::get( - option::MaxProgress{100}, std::forward(args)...)) {} + option::FontStyles{std::vector{}}, std::forward(args)...)) { + // starts with [<==>...........] + // progress_ = 0 + + // ends with [...........<==>] + // ^^^^^^^^^^^^^^^^^ bar_width + // ^^^^^^^^^^^^ (bar_width - len(lead)) + // progress_ = bar_width - len(lead) + progress_ = 0; + max_progress_ = get_value() + - get_value().size() + + get_value().size() + + get_value().size(); + } template void set_option(details::Setting &&setting) { @@ -129,12 +140,24 @@ public: void tick() { { std::lock_guard lock{mutex_}; - progress_ += 1; + if (get_value()) + return; + + progress_ += (direction_ == Direction::forward) ? 1 : -1; + if (direction_ == Direction::forward && progress_ == max_progress_) { + // time to go back + direction_ = Direction::backward; + } else if (direction_ == Direction::backward && progress_ == 0) { + direction_ = Direction::forward; + } } - save_start_time(); print_progress(); } + bool is_completed() { + return get_value(); + } + void mark_as_completed() { get_value() = true; print_progress(); @@ -153,35 +176,21 @@ private: } size_t progress_{0}; + size_t max_progress_; Settings settings_; std::chrono::nanoseconds elapsed_; - std::chrono::time_point start_time_point_; std::mutex mutex_; template friend class MultiProgress; template friend class DynamicProgress; std::atomic multi_progress_mode_{false}; - void save_start_time() { - auto &show_elapsed_time = get_value(); - auto &saved_start_time = get_value(); - auto &show_remaining_time = get_value(); - if ((show_elapsed_time || show_remaining_time) && !saved_start_time) { - start_time_point_ = std::chrono::high_resolution_clock::now(); - saved_start_time = true; - } - } - public: void print_progress(bool from_multi_progress = false) { std::lock_guard lock{mutex_}; if (multi_progress_mode_ && !from_multi_progress) { return; } - auto now = std::chrono::high_resolution_clock::now(); - if (!get_value()) - elapsed_ = std::chrono::duration_cast(now - start_time_point_); - if (get_value() != Color::unspecified) details::set_stream_color(std::cout, get_value()); @@ -192,59 +201,20 @@ public: std::cout << get_value(); - details::ProgressScaleWriter writer{std::cout, + details::IndeterminateProgressScaleWriter writer{std::cout, get_value(), get_value(), - get_value(), - get_value()}; - writer.write(double(progress_) / double(max_progress) * 100.0f); + get_value()}; + writer.write(progress_); std::cout << get_value(); - if (get_value()) { - std::cout << " " << std::min(static_cast(static_cast(progress_) / max_progress * 100), size_t(100)) << "%"; - } - - auto &saved_start_time = get_value(); - - if (get_value()) { - std::cout << " ["; - if (saved_start_time) - details::write_duration(std::cout, elapsed_); - else - std::cout << "00:00s"; - } - - if (get_value()) { - if (get_value()) - std::cout << "<"; - else - std::cout << " ["; - - if (saved_start_time) { - auto eta = std::chrono::nanoseconds( - progress_ > 0 ? static_cast(elapsed_.count() * max_progress / progress_) : 0); - auto remaining = eta > elapsed_ ? (eta - elapsed_) : (elapsed_ - eta); - details::write_duration(std::cout, remaining); - } else { - std::cout << "00:00s"; - } - - std::cout << "]"; - } else { - if (get_value()) - std::cout << "]"; - } - if (get_value() == 0) get_value() = 10; std::cout << " " << get_value() << std::string(get_value(), ' ') << "\r"; std::cout.flush(); - if (progress_ >= max_progress) { - get_value() = true; - } if (get_value() && !from_multi_progress) // Don't std::endl if calling from MultiProgress std::cout << termcolor::reset << std::endl; diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 5cdb763..de33bee 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -29,3 +29,6 @@ target_link_libraries(dynamic_progress PRIVATE indicators::indicators) add_executable(max_progress max_progress.cpp) target_link_libraries(max_progress PRIVATE indicators::indicators) +add_executable(indeterminate_progress_bar indeterminate_progress_bar.cpp) +target_link_libraries(indeterminate_progress_bar PRIVATE indicators::indicators) + diff --git a/samples/indeterminate_progress_bar.cpp b/samples/indeterminate_progress_bar.cpp new file mode 100644 index 0000000..02c2297 --- /dev/null +++ b/samples/indeterminate_progress_bar.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +int main() { + indicators::IndeterminateProgressBar bar{ + indicators::option::BarWidth{40}, + indicators::option::Start{"["}, + indicators::option::Fill{"ยท"}, + indicators::option::Lead{"<==>"}, + indicators::option::End{"]"}, + indicators::option::PostfixText{"Checking for Updates"}, + indicators::option::ForegroundColor{indicators::Color::yellow}, + indicators::option::FontStyles{ + std::vector{indicators::FontStyle::bold}} + }; + + indicators::show_console_cursor(false); + + auto job = [&bar]() { + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); + bar.mark_as_completed(); + std::cout << termcolor::bold << termcolor::green + << "System is up to date!\n" << termcolor::reset; + }; + std::thread job_completion_thread(job); + + // Update bar state + while (!bar.is_completed()) { + bar.tick(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + + job_completion_thread.join(); + return 0; +}