From 6f057a51a11b3f401c02ddb213dae3e97b77164a Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Sat, 9 May 2020 20:33:15 -0500 Subject: [PATCH] Closes #22 --- include/indicators/block_progress_bar.hpp | 50 +++++++++++-------- .../indicators/indeterminate_progress_bar.hpp | 27 ++++++---- include/indicators/progress_bar.hpp | 47 +++++++++-------- include/indicators/progress_spinner.hpp | 39 ++++++++------- include/indicators/setting.hpp | 4 +- samples/CMakeLists.txt | 3 ++ samples/progress_bar_sstream.cpp | 37 ++++++++++++++ 7 files changed, 135 insertions(+), 72 deletions(-) create mode 100644 samples/progress_bar_sstream.cpp diff --git a/include/indicators/block_progress_bar.hpp b/include/indicators/block_progress_bar.hpp index decea9a..1329387 100644 --- a/include/indicators/block_progress_bar.hpp +++ b/include/indicators/block_progress_bar.hpp @@ -47,7 +47,7 @@ class BlockProgressBar { option::PrefixText, option::PostfixText, option::ShowPercentage, option::ShowElapsedTime, option::ShowRemainingTime, option::Completed, option::SavedStartTime, option::MaxPostfixTextLen, option::FontStyles, - option::MaxProgress>; + option::MaxProgress, option::Stream>; public: template ( option::FontStyles{std::vector{}}, std::forward(args)...), details::get(option::MaxProgress{100}, - std::forward(args)...) + std::forward(args)...), + details::get( + option::Stream{std::cout}, std::forward(args)...) ) {} template @@ -185,6 +187,10 @@ private: public: void print_progress(bool from_multi_progress = false) { + std::lock_guard lock{mutex_}; + + auto& os = get_value(); + const auto max_progress = get_value(); if (multi_progress_mode_ && !from_multi_progress) { if (progress_ > max_progress) { @@ -192,71 +198,71 @@ public: } return; } - std::lock_guard lock{mutex_}; + auto now = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration_cast(now - start_time_point_); if (get_value() != Color::unspecified) - details::set_stream_color(std::cout, get_value()); + details::set_stream_color(os, get_value()); for (auto &style : get_value()) - details::set_font_style(std::cout, style); + details::set_font_style(os, style); - std::cout << get_value(); - std::cout << get_value(); + os << get_value(); + os << get_value(); - details::BlockProgressScaleWriter writer{std::cout, + details::BlockProgressScaleWriter writer{os, get_value()}; writer.write(progress_ / max_progress * 100); - std::cout << get_value(); + os << get_value(); if (get_value()) { - std::cout << " " << std::min(static_cast(progress_ / max_progress * 100.0), size_t(100)) << "%"; + os << " " << std::min(static_cast(progress_ / max_progress * 100.0), size_t(100)) << "%"; } auto &saved_start_time = get_value(); if (get_value()) { - std::cout << " ["; + os << " ["; if (saved_start_time) - details::write_duration(std::cout, elapsed); + details::write_duration(os, elapsed); else - std::cout << "00:00s"; + os << "00:00s"; } if (get_value()) { if (get_value()) - std::cout << "<"; + os << "<"; else - std::cout << " ["; + os << " ["; 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); + details::write_duration(os, remaining); } else { - std::cout << "00:00s"; + os << "00:00s"; } - std::cout << "]"; + os << "]"; } else { if (get_value()) - std::cout << "]"; + os << "]"; } if (get_value() == 0) get_value() = 10; - std::cout << " " << get_value() + os << " " << get_value() << std::string(get_value(), ' ') << "\r"; - std::cout.flush(); + os.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; + os << termcolor::reset << std::endl; } }; diff --git a/include/indicators/indeterminate_progress_bar.hpp b/include/indicators/indeterminate_progress_bar.hpp index 4e7bc94..b331e1c 100644 --- a/include/indicators/indeterminate_progress_bar.hpp +++ b/include/indicators/indeterminate_progress_bar.hpp @@ -49,7 +49,7 @@ class IndeterminateProgressBar { std::tuple; + option::ForegroundColor, option::FontStyles, option::Stream>; enum class Direction { forward, @@ -85,7 +85,9 @@ public: details::get( option::ForegroundColor{Color::unspecified}, std::forward(args)...), details::get( - option::FontStyles{std::vector{}}, std::forward(args)...)) { + option::FontStyles{std::vector{}}, std::forward(args)...), + details::get( + option::Stream{std::cout}, std::forward(args)...)) { // starts with [<==>...........] // progress_ = 0 @@ -188,36 +190,39 @@ private: public: void print_progress(bool from_multi_progress = false) { std::lock_guard lock{mutex_}; + + auto& os = get_value(); + if (multi_progress_mode_ && !from_multi_progress) { return; } if (get_value() != Color::unspecified) - details::set_stream_color(std::cout, get_value()); + details::set_stream_color(os, get_value()); for (auto &style : get_value()) - details::set_font_style(std::cout, style); + details::set_font_style(os, style); - std::cout << get_value(); + os << get_value(); - std::cout << get_value(); + os << get_value(); - details::IndeterminateProgressScaleWriter writer{std::cout, + details::IndeterminateProgressScaleWriter writer{os, get_value(), get_value(), get_value()}; writer.write(progress_); - std::cout << get_value(); + os << get_value(); if (get_value() == 0) get_value() = 10; - std::cout << " " << get_value() + os << " " << get_value() << std::string(get_value(), ' ') << "\r"; - std::cout.flush(); + os.flush(); if (get_value() && !from_multi_progress) // Don't std::endl if calling from MultiProgress - std::cout << termcolor::reset << std::endl; + os << termcolor::reset << std::endl; } }; diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index 1d0d0fd..05de489 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -50,7 +50,7 @@ class ProgressBar { option::End, option::Fill, option::Lead, option::Remainder, option::MaxPostfixTextLen, option::Completed, option::ShowPercentage, option::ShowElapsedTime, option::ShowRemainingTime, option::SavedStartTime, - option::ForegroundColor, option::FontStyles, option::MaxProgress>; + option::ForegroundColor, option::FontStyles, option::MaxProgress, option::Stream>; public: template ( option::FontStyles{std::vector{}}, std::forward(args)...), details::get( - option::MaxProgress{100}, std::forward(args)...)) {} + option::MaxProgress{100}, std::forward(args)...), + details::get( + option::Stream{std::cout}, std::forward(args)...)) {} template void set_option(details::Setting &&setting) { @@ -196,6 +198,9 @@ private: public: void print_progress(bool from_multi_progress = false) { std::lock_guard lock{mutex_}; + + auto& os = get_value(); + const auto max_progress = get_value(); if (multi_progress_mode_ && !from_multi_progress) { if (progress_ >= max_progress) { @@ -208,71 +213,71 @@ public: elapsed_ = std::chrono::duration_cast(now - start_time_point_); if (get_value() != Color::unspecified) - details::set_stream_color(std::cout, get_value()); + details::set_stream_color(os, get_value()); for (auto &style : get_value()) - details::set_font_style(std::cout, style); + details::set_font_style(os, style); - std::cout << get_value(); + os << get_value(); - std::cout << get_value(); + os << get_value(); - details::ProgressScaleWriter writer{std::cout, + details::ProgressScaleWriter writer{os, get_value(), get_value(), get_value(), get_value()}; writer.write(double(progress_) / double(max_progress) * 100.0f); - std::cout << get_value(); + os << get_value(); if (get_value()) { - std::cout << " " << std::min(static_cast(static_cast(progress_) / max_progress * 100), size_t(100)) << "%"; + os << " " << std::min(static_cast(static_cast(progress_) / max_progress * 100), size_t(100)) << "%"; } auto &saved_start_time = get_value(); if (get_value()) { - std::cout << " ["; + os << " ["; if (saved_start_time) - details::write_duration(std::cout, elapsed_); + details::write_duration(os, elapsed_); else - std::cout << "00:00s"; + os << "00:00s"; } if (get_value()) { if (get_value()) - std::cout << "<"; + os << "<"; else - std::cout << " ["; + os << " ["; 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); + details::write_duration(os, remaining); } else { - std::cout << "00:00s"; + os << "00:00s"; } - std::cout << "]"; + os << "]"; } else { if (get_value()) - std::cout << "]"; + os << "]"; } if (get_value() == 0) get_value() = 10; - std::cout << " " << get_value() + os << " " << get_value() << std::string(get_value(), ' ') << "\r"; - std::cout.flush(); + os.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; + os << termcolor::reset << std::endl; } }; diff --git a/include/indicators/progress_spinner.hpp b/include/indicators/progress_spinner.hpp index 1a95803..9ad8a7c 100644 --- a/include/indicators/progress_spinner.hpp +++ b/include/indicators/progress_spinner.hpp @@ -50,7 +50,7 @@ class ProgressSpinner { option::ShowPercentage, option::ShowElapsedTime, option::ShowRemainingTime, option::ShowSpinner, option::SavedStartTime, option::Completed, option::MaxPostfixTextLen, option::SpinnerStates, option::FontStyles, - option::MaxProgress>; + option::MaxProgress, option::Stream>; public: template ( option::FontStyles{std::vector{}}, std::forward(args)...), details::get( - option::MaxProgress{100}, std::forward(args)...)) {} + option::MaxProgress{100}, std::forward(args)...), + details::get( + option::Stream{std::cout}, std::forward(args)...)) {} template void set_option(details::Setting &&setting) { @@ -185,56 +187,59 @@ private: public: void print_progress() { std::lock_guard lock{mutex_}; + + auto& os = get_value(); + const auto max_progress = get_value(); auto now = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration_cast(now - start_time_point_); if (get_value() != Color::unspecified) - details::set_stream_color(std::cout, get_value()); + details::set_stream_color(os, get_value()); for (auto &style : get_value()) - details::set_font_style(std::cout, style); + details::set_font_style(os, style); - std::cout << get_value(); + os << get_value(); if (get_value()) - std::cout << get_value() + os << get_value() [index_ % get_value().size()]; if (get_value()) { - std::cout << " " << std::min(progress_, size_t(max_progress)) << "%"; + os << " " << std::min(progress_, size_t(max_progress)) << "%"; } if (get_value()) { - std::cout << " ["; - details::write_duration(std::cout, elapsed); + os << " ["; + details::write_duration(os, elapsed); } if (get_value()) { if (get_value()) - std::cout << "<"; + os << "<"; else - std::cout << " ["; + os << " ["; 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); - std::cout << "]"; + details::write_duration(os, remaining); + os << "]"; } else { if (get_value()) - std::cout << "]"; + os << "]"; } if (get_value() == 0) get_value() = 10; - std::cout << " " << get_value() + os << " " << get_value() << std::string(get_value(), ' ') << "\r"; - std::cout.flush(); + os.flush(); index_ += 1; if (progress_ > max_progress) { get_value() = true; } if (get_value()) - std::cout << termcolor::reset << std::endl; + os << termcolor::reset << std::endl; } }; diff --git a/include/indicators/setting.hpp b/include/indicators/setting.hpp index 26686b6..292d9bd 100644 --- a/include/indicators/setting.hpp +++ b/include/indicators/setting.hpp @@ -90,7 +90,8 @@ enum class ProgressBarOption { spinner_states, font_styles, hide_bar_when_complete, - max_progress + max_progress, + stream }; template struct Setting { @@ -206,5 +207,6 @@ using HideBarWhenComplete = using FontStyles = details::Setting, details::ProgressBarOption::font_styles>; using MaxProgress = details::IntegerSetting; +using Stream = details::Setting; } // namespace option } // namespace indicators diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index de33bee..674086d 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -11,6 +11,9 @@ target_link_libraries(progress_bar_set_progress PRIVATE indicators::indicators) add_executable(progress_bar_tick progress_bar_tick.cpp) target_link_libraries(progress_bar_tick PRIVATE indicators::indicators) +add_executable(progress_bar_sstream progress_bar_sstream.cpp) +target_link_libraries(progress_bar_sstream PRIVATE indicators::indicators) + add_executable(progress_spinner progress_spinner.cpp) target_link_libraries(progress_spinner PRIVATE indicators::indicators) diff --git a/samples/progress_bar_sstream.cpp b/samples/progress_bar_sstream.cpp new file mode 100644 index 0000000..8f338e3 --- /dev/null +++ b/samples/progress_bar_sstream.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +int main() { + using namespace indicators; + + std::stringstream os; + + ProgressBar bar{ + option::BarWidth{50}, + option::Start{"["}, + option::Fill{"="}, + option::Lead{">"}, + option::Remainder{" "}, + option::End{"]"}, + option::PostfixText{"Getting started"}, + option::ForegroundColor{indicators::Color::green}, + option::FontStyles{ + std::vector{indicators::FontStyle::bold}}, + option::Stream{os} + }; + + // Update bar state + while (true) { + bar.tick(); + if (bar.is_completed()) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + std::cout << "Stream contents:\n"; + std::cout << os.str() << "\n"; + + return 0; +}