From 97c89284a970619d514b2d5ffbe7197a33dd6115 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:06:36 -0600 Subject: [PATCH 01/12] Clang format --- include/indicators/block_progress_bar.hpp | 8 +++----- include/indicators/progress_spinner.hpp | 4 +--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/include/indicators/block_progress_bar.hpp b/include/indicators/block_progress_bar.hpp index 62a8e51..0b044d6 100644 --- a/include/indicators/block_progress_bar.hpp +++ b/include/indicators/block_progress_bar.hpp @@ -27,13 +27,13 @@ SOFTWARE. #pragma once #include #include +#include #include #include #include #include #include #include -#include namespace indicators { @@ -91,9 +91,7 @@ public: _print_progress(); } - size_t current() { - return std::min(static_cast(_progress), size_t(100)); - } + size_t current() { return std::min(static_cast(_progress), size_t(100)); } bool is_completed() const { return _completed; } @@ -163,7 +161,7 @@ private: std::cout << _lead; for (size_t i = 0; i < (_bar_width - whole_width - 1); ++i) std::cout << " "; - + std::cout << _end; if (_show_percentage) { std::cout << " " << std::min(static_cast(_progress), size_t(100)) << "%"; diff --git a/include/indicators/progress_spinner.hpp b/include/indicators/progress_spinner.hpp index 5d62344..171cfdf 100644 --- a/include/indicators/progress_spinner.hpp +++ b/include/indicators/progress_spinner.hpp @@ -79,9 +79,7 @@ public: _print_progress(); } - size_t current() { - return std::min(static_cast(_progress), size_t(100)); - } + size_t current() { return std::min(static_cast(_progress), size_t(100)); } bool is_completed() const { return _completed; } From c770704697fc8eae456af6fb1c553ccced5e6c60 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:06:46 -0600 Subject: [PATCH 02/12] Draft implementation of time elapsed/remaining meter --- include/indicators/progress_bar.hpp | 68 +++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index 4fe3f92..7131f4d 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -27,7 +27,10 @@ SOFTWARE. #pragma once #include #include +#include +#include #include +#include #include #include #include @@ -88,11 +91,20 @@ public: void hide_percentage() { _show_percentage = false; } + void show_elapsed_time() { _show_elapsed_time = true; } + + void hide_elapsed_time() { _show_elapsed_time = false; } + + void show_remaining_time() { _show_remaining_time = true; } + + void hide_remaining_time() { _show_remaining_time = false; } + void set_progress(float value) { { std::unique_lock lock{_mutex}; _progress = value; } + _save_start_time(); _print_progress(); } @@ -101,12 +113,11 @@ public: std::unique_lock lock{_mutex}; _progress += 1; } + _save_start_time(); _print_progress(); } - size_t current() { - return std::min(static_cast(_progress), size_t(100)); - } + size_t current() { return std::min(static_cast(_progress), size_t(100)); } bool is_completed() const { return _completed; } @@ -128,11 +139,47 @@ private: std::atomic _max_postfix_text_length{0}; std::atomic _completed{false}; std::atomic _show_percentage{true}; + std::atomic _show_elapsed_time{true}; + std::atomic _show_remaining_time{true}; + std::atomic _saved_start_time{false}; + std::chrono::time_point _start_time_point; std::mutex _mutex; Color _foreground_color; + std::ostream &_print_duration(std::ostream &os, std::chrono::nanoseconds ns) { + using namespace std; + using namespace std::chrono; + typedef duration> days; + char fill = os.fill(); + os.fill('0'); + auto d = duration_cast(ns); + ns -= d; + auto h = duration_cast(ns); + ns -= h; + auto m = duration_cast(ns); + ns -= m; + auto s = duration_cast(ns); + if (d.count() > 0) + os << setw(2) << d.count() << "d:"; + if (h.count() > 0) + os << setw(2) << h.count() << "h:"; + os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's'; + os.fill(fill); + return os; + }; + + void _save_start_time() { + if (_show_elapsed_time && !_saved_start_time) { + _start_time_point = std::chrono::high_resolution_clock::now(); + _saved_start_time = true; + } + } + void _print_progress() { std::unique_lock lock{_mutex}; + auto now = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration_cast(now - _start_time_point); + std::cout << termcolor::bold; switch (_foreground_color) { case Color::GREY: @@ -175,6 +222,21 @@ private: if (_show_percentage) { std::cout << " " << std::min(static_cast(_progress), size_t(100)) << "%"; } + + if (_show_elapsed_time) { + std::cout << " ["; + _print_duration(std::cout, elapsed); + } + + if (_show_remaining_time) { + std::cout << "<"; + auto eta = std::chrono::nanoseconds( + _progress > 0 ? static_cast(elapsed.count() * 100 / _progress) : 0); + auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); + _print_duration(std::cout, remaining); + std::cout << "]"; + } + if (_max_postfix_text_length == 0) _max_postfix_text_length = 10; std::cout << " " << _postfix_text << std::string(_max_postfix_text_length, ' ') << "\r"; From 5360fec6411d2157f96bb940bdd7cd8bee8de77b Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:13:48 -0600 Subject: [PATCH 03/12] Added time elapsed/remaining meter for block progress bar --- include/indicators/block_progress_bar.hpp | 64 +++++++++++++++++++++++ include/indicators/progress_bar.hpp | 3 +- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/include/indicators/block_progress_bar.hpp b/include/indicators/block_progress_bar.hpp index 0b044d6..ab13b04 100644 --- a/include/indicators/block_progress_bar.hpp +++ b/include/indicators/block_progress_bar.hpp @@ -27,8 +27,10 @@ SOFTWARE. #pragma once #include #include +#include #include #include +#include #include #include #include @@ -75,11 +77,20 @@ public: void hide_percentage() { _show_percentage = false; } + void show_elapsed_time() { _show_elapsed_time = true; } + + void hide_elapsed_time() { _show_elapsed_time = false; } + + void show_remaining_time() { _show_remaining_time = true; } + + void hide_remaining_time() { _show_remaining_time = false; } + void set_progress(float value) { { std::unique_lock lock{_mutex}; _progress = value; } + _save_start_time(); _print_progress(); } @@ -88,6 +99,7 @@ public: std::unique_lock lock{_mutex}; _progress += 1; } + _save_start_time(); _print_progress(); } @@ -113,11 +125,47 @@ private: std::atomic _max_postfix_text_length{0}; std::atomic _completed{false}; std::atomic _show_percentage{true}; + std::atomic _show_elapsed_time{true}; + std::atomic _show_remaining_time{true}; + std::atomic _saved_start_time{false}; + std::chrono::time_point _start_time_point; std::mutex _mutex; Color _foreground_color; + std::ostream &_print_duration(std::ostream &os, std::chrono::nanoseconds ns) { + using namespace std; + using namespace std::chrono; + typedef duration> days; + char fill = os.fill(); + os.fill('0'); + auto d = duration_cast(ns); + ns -= d; + auto h = duration_cast(ns); + ns -= h; + auto m = duration_cast(ns); + ns -= m; + auto s = duration_cast(ns); + if (d.count() > 0) + os << setw(2) << d.count() << "d:"; + if (h.count() > 0) + os << setw(2) << h.count() << "h:"; + os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's'; + os.fill(fill); + return os; + }; + + void _save_start_time() { + if (_show_elapsed_time && !_saved_start_time) { + _start_time_point = std::chrono::high_resolution_clock::now(); + _saved_start_time = true; + } + } + void _print_progress() { std::unique_lock lock{_mutex}; + auto now = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration_cast(now - _start_time_point); + std::cout << termcolor::bold; switch (_foreground_color) { case Color::GREY: @@ -166,6 +214,22 @@ private: if (_show_percentage) { std::cout << " " << std::min(static_cast(_progress), size_t(100)) << "%"; } + + if (_show_elapsed_time) { + std::cout << " ["; + _print_duration(std::cout, elapsed); + } + + if (_show_remaining_time) { + if (_show_elapsed_time) + std::cout << "<"; + auto eta = std::chrono::nanoseconds( + _progress > 0 ? static_cast(elapsed.count() * 100 / _progress) : 0); + auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); + _print_duration(std::cout, remaining); + std::cout << "]"; + } + if (_max_postfix_text_length == 0) _max_postfix_text_length = 10; std::cout << " " << _postfix_text << std::string(_max_postfix_text_length, ' ') << "\r"; diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index 7131f4d..370f366 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -229,7 +229,8 @@ private: } if (_show_remaining_time) { - std::cout << "<"; + if (_show_elapsed_time) + std::cout << "<"; auto eta = std::chrono::nanoseconds( _progress > 0 ? static_cast(elapsed.count() * 100 / _progress) : 0); auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); From 8198d8a802b85156940b09ffe3fca5db2d7c986b Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:20:10 -0600 Subject: [PATCH 04/12] Added time elapsed/remaining meter for progress spinner --- include/indicators/progress_spinner.hpp | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/include/indicators/progress_spinner.hpp b/include/indicators/progress_spinner.hpp index 171cfdf..7a9595f 100644 --- a/include/indicators/progress_spinner.hpp +++ b/include/indicators/progress_spinner.hpp @@ -27,7 +27,10 @@ SOFTWARE. #pragma once #include #include +#include +#include #include +#include #include #include #include @@ -59,6 +62,14 @@ public: void hide_percentage() { _show_percentage = false; } + void show_elapsed_time() { _show_elapsed_time = true; } + + void hide_elapsed_time() { _show_elapsed_time = false; } + + void show_remaining_time() { _show_remaining_time = true; } + + void hide_remaining_time() { _show_remaining_time = false; } + void show_spinner() { _show_spinner = true; } void hide_spinner() { _show_spinner = false; } @@ -68,6 +79,7 @@ public: std::unique_lock lock{_mutex}; _progress = value; } + _save_start_time(); _print_progress(); } @@ -76,6 +88,7 @@ public: std::unique_lock lock{_mutex}; _progress += 1; } + _save_start_time(); _print_progress(); } @@ -102,12 +115,48 @@ private: std::atomic _max_postfix_text_length{0}; std::atomic _completed{false}; std::atomic _show_percentage{true}; + std::atomic _show_elapsed_time{true}; + std::atomic _show_remaining_time{true}; + std::atomic _saved_start_time{false}; + std::chrono::time_point _start_time_point; std::atomic _show_spinner{true}; std::mutex _mutex; Color _foreground_color; + std::ostream &_print_duration(std::ostream &os, std::chrono::nanoseconds ns) { + using namespace std; + using namespace std::chrono; + typedef duration> days; + char fill = os.fill(); + os.fill('0'); + auto d = duration_cast(ns); + ns -= d; + auto h = duration_cast(ns); + ns -= h; + auto m = duration_cast(ns); + ns -= m; + auto s = duration_cast(ns); + if (d.count() > 0) + os << setw(2) << d.count() << "d:"; + if (h.count() > 0) + os << setw(2) << h.count() << "h:"; + os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's'; + os.fill(fill); + return os; + }; + + void _save_start_time() { + if (_show_elapsed_time && !_saved_start_time) { + _start_time_point = std::chrono::high_resolution_clock::now(); + _saved_start_time = true; + } + } + void _print_progress() { std::unique_lock lock{_mutex}; + auto now = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration_cast(now - _start_time_point); + std::cout << termcolor::bold; switch (_foreground_color) { case Color::GREY: @@ -141,6 +190,22 @@ private: if (_show_percentage) { std::cout << " " << std::min(static_cast(_progress), size_t(100)) << "%"; } + + if (_show_elapsed_time) { + std::cout << " ["; + _print_duration(std::cout, elapsed); + } + + if (_show_remaining_time) { + if (_show_elapsed_time) + std::cout << "<"; + auto eta = std::chrono::nanoseconds( + _progress > 0 ? static_cast(elapsed.count() * 100 / _progress) : 0); + auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); + _print_duration(std::cout, remaining); + std::cout << "]"; + } + if (_max_postfix_text_length == 0) _max_postfix_text_length = 10; std::cout << " " << _postfix_text << std::string(_max_postfix_text_length, ' ') << "\r"; From 6224a46371aba621ab55d7d3c2c18f0afa8a7841 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:31:43 -0600 Subject: [PATCH 05/12] Updated samples/demos to show usage of hide/show time elapsed/remaining --- clang-format.bash | 2 +- demo/demo.cpp | 16 +++++++++++++ include/indicators/block_progress_bar.hpp | 4 +++- include/indicators/progress_bar.hpp | 4 +++- include/indicators/progress_spinner.hpp | 4 +++- samples/block_progress_bar.cpp | 14 +++++++----- samples/multi_threaded_bar.cpp | 25 ++++++++++---------- samples/progress_bar_set_progress.cpp | 28 ++++++++++++----------- samples/progress_bar_tick.cpp | 10 ++++---- samples/progress_spinner.cpp | 8 ++++--- 10 files changed, 72 insertions(+), 43 deletions(-) diff --git a/clang-format.bash b/clang-format.bash index 897445b..49b6ac6 100755 --- a/clang-format.bash +++ b/clang-format.bash @@ -1,2 +1,2 @@ #!/usr/bin/env bash -find ./include ./demo/ -type f \( -iname \*.cpp -o -iname \*.hpp \) | xargs clang-format -style="{ColumnLimit : 100}" -i +find ./include ./demo/ ./samples/ -type f \( -iname \*.cpp -o -iname \*.hpp \) | xargs clang-format -style="{ColumnLimit : 100}" -i diff --git a/demo/demo.cpp b/demo/demo.cpp index 09da63a..78c9563 100644 --- a/demo/demo.cpp +++ b/demo/demo.cpp @@ -18,6 +18,8 @@ int main() { p.lead_bar_progress_with("■"); p.fill_bar_remainder_with(" "); p.end_bar_with(" ]"); + p.hide_elapsed_time(); + p.hide_remaining_time(); p.set_foreground_color(indicators::Color::YELLOW); std::atomic index{0}; @@ -57,6 +59,8 @@ int main() { p.lead_bar_progress_with(""); p.fill_bar_remainder_with(""); p.end_bar_with(""); + p.hide_elapsed_time(); + p.hide_remaining_time(); p.set_foreground_color(indicators::Color::WHITE); p.hide_percentage(); auto job = [&p]() { @@ -87,6 +91,8 @@ int main() { p.fill_bar_remainder_with(" "); p.end_bar_with("]"); p.set_postfix_text("Getting started"); + p.hide_elapsed_time(); + p.hide_remaining_time(); p.set_foreground_color(indicators::Color::GREEN); auto job = [&p]() { while (true) { @@ -124,6 +130,8 @@ int main() { p4.set_foreground_color(indicators::Color::CYAN); p4.set_postfix_text("Restoring system state"); p4.hide_percentage(); + p4.hide_elapsed_time(); + p4.hide_remaining_time(); std::atomic index4{0}; auto job4 = [&p4, &index4, &lead_spinner]() { while (true) { @@ -167,6 +175,8 @@ int main() { p.set_progress(100); p.set_foreground_color(indicators::Color::WHITE); p.set_postfix_text("Reverting system restore"); + p.hide_elapsed_time(); + p.hide_remaining_time(); std::atomic progress{100}; auto job = [&p, &progress]() { while (true) { @@ -194,6 +204,8 @@ int main() { p.set_postfix_text("Checking credentials"); p.set_foreground_color(indicators::Color::YELLOW); p.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); + p.hide_elapsed_time(); + p.hide_remaining_time(); auto job = [&p]() { while (true) { if (p.is_completed()) { @@ -224,6 +236,8 @@ int main() { p.set_foreground_color(indicators::Color::WHITE); p.set_spinner_states({"▖", "▘", "▝", "▗"}); p.hide_percentage(); + p.hide_elapsed_time(); + p.hide_remaining_time(); auto job = [&p]() { while (true) { auto current = p.current(); @@ -269,6 +283,8 @@ int main() { p2.end_bar_with("🌑"); p2.set_postfix_text("Achieved low-Earth orbit"); p2.set_foreground_color(indicators::Color::WHITE); + p2.hide_elapsed_time(); + p2.hide_remaining_time(); std::vector ship_trail{"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"}; std::atomic ship_trail_index{0}; auto job2 = [&p2, &ship_trail_index, &ship_trail]() { diff --git a/include/indicators/block_progress_bar.hpp b/include/indicators/block_progress_bar.hpp index ab13b04..abd977c 100644 --- a/include/indicators/block_progress_bar.hpp +++ b/include/indicators/block_progress_bar.hpp @@ -155,7 +155,7 @@ private: }; void _save_start_time() { - if (_show_elapsed_time && !_saved_start_time) { + if ((_show_elapsed_time || _show_remaining_time) && !_saved_start_time) { _start_time_point = std::chrono::high_resolution_clock::now(); _saved_start_time = true; } @@ -223,6 +223,8 @@ private: if (_show_remaining_time) { if (_show_elapsed_time) std::cout << "<"; + else + std::cout << " ["; auto eta = std::chrono::nanoseconds( _progress > 0 ? static_cast(elapsed.count() * 100 / _progress) : 0); auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index 370f366..4ecb1a2 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -169,7 +169,7 @@ private: }; void _save_start_time() { - if (_show_elapsed_time && !_saved_start_time) { + if ((_show_elapsed_time || _show_remaining_time) && !_saved_start_time) { _start_time_point = std::chrono::high_resolution_clock::now(); _saved_start_time = true; } @@ -231,6 +231,8 @@ private: if (_show_remaining_time) { if (_show_elapsed_time) std::cout << "<"; + else + std::cout << " ["; auto eta = std::chrono::nanoseconds( _progress > 0 ? static_cast(elapsed.count() * 100 / _progress) : 0); auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); diff --git a/include/indicators/progress_spinner.hpp b/include/indicators/progress_spinner.hpp index 7a9595f..24929b3 100644 --- a/include/indicators/progress_spinner.hpp +++ b/include/indicators/progress_spinner.hpp @@ -146,7 +146,7 @@ private: }; void _save_start_time() { - if (_show_elapsed_time && !_saved_start_time) { + if ((_show_elapsed_time || _show_remaining_time) && !_saved_start_time) { _start_time_point = std::chrono::high_resolution_clock::now(); _saved_start_time = true; } @@ -199,6 +199,8 @@ private: if (_show_remaining_time) { if (_show_elapsed_time) std::cout << "<"; + else + std::cout << " ["; auto eta = std::chrono::nanoseconds( _progress > 0 ? static_cast(elapsed.count() * 100 / _progress) : 0); auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta); diff --git a/samples/block_progress_bar.cpp b/samples/block_progress_bar.cpp index e1ce407..8545dcb 100644 --- a/samples/block_progress_bar.cpp +++ b/samples/block_progress_bar.cpp @@ -1,20 +1,22 @@ +#include #include #include -#include int main() { // Hide cursor std::cout << "\e[?25l"; - + indicators::BlockProgressBar bar; - + // Configure the bar bar.set_bar_width(80); bar.start_bar_with("["); bar.end_bar_with("]"); - bar.set_foreground_color(indicators::Color::WHITE); - + bar.set_foreground_color(indicators::Color::WHITE); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); + // Update bar state auto progress = 0.0f; while (true) { @@ -26,7 +28,7 @@ int main() { } // Show cursor - std::cout << "\e[?25h"; + std::cout << "\e[?25h"; return 0; } diff --git a/samples/multi_threaded_bar.cpp b/samples/multi_threaded_bar.cpp index ec07cf4..a25c132 100644 --- a/samples/multi_threaded_bar.cpp +++ b/samples/multi_threaded_bar.cpp @@ -11,31 +11,30 @@ int main() { bar.fill_bar_remainder_with("-"); bar.end_bar_with("]"); bar.set_foreground_color(indicators::Color::YELLOW); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); // As configured, the bar will look like this: // // [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70% // // - + std::atomic index{0}; - std::vector status_text = - { - "Rocket.exe is not responding", - "Finding a replacement engineer", - "Buying more snacks", - "Assimilating the modding community", - "Crossing fingers", - "Porting KSP to a Nokia 3310" - }; - + std::vector status_text = {"Rocket.exe is not responding", + "Finding a replacement engineer", + "Buying more snacks", + "Assimilating the modding community", + "Crossing fingers", + "Porting KSP to a Nokia 3310"}; + // Let's say you want to append some status text to the right of the progress bar // You can use bar.set_postfix_text(...) to append text to the right // // [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70% Finding a replacement engineer // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // - // + // auto job = [&bar, &index, &status_text]() { while (true) { @@ -58,6 +57,6 @@ int main() { second_job.join(); third_job.join(); last_job.join(); - + return 0; } diff --git a/samples/progress_bar_set_progress.cpp b/samples/progress_bar_set_progress.cpp index 34b5d9f..5a08021 100644 --- a/samples/progress_bar_set_progress.cpp +++ b/samples/progress_bar_set_progress.cpp @@ -1,10 +1,10 @@ +#include #include #include -#include int main() { indicators::ProgressBar bar; - + // Configure the bar bar.set_bar_width(50); bar.start_bar_with("["); @@ -13,26 +13,28 @@ int main() { bar.fill_bar_remainder_with(" "); bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); - bar.set_foreground_color(indicators::Color::GREEN); - + bar.set_foreground_color(indicators::Color::GREEN); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); + // Update bar state - + bar.set_progress(10); // 10% done - + // do some work std::this_thread::sleep_for(std::chrono::milliseconds(100)); - + bar.set_progress(30); // 30% done - - // do some more work + + // do some more work std::this_thread::sleep_for(std::chrono::milliseconds(600)); - + bar.set_progress(65); // 65% done - + // do final bit of work std::this_thread::sleep_for(std::chrono::milliseconds(300)); - + bar.set_progress(100); // all done - + return 0; } diff --git a/samples/progress_bar_tick.cpp b/samples/progress_bar_tick.cpp index 3f0b389..8e741bb 100644 --- a/samples/progress_bar_tick.cpp +++ b/samples/progress_bar_tick.cpp @@ -1,10 +1,10 @@ +#include #include #include -#include int main() { indicators::ProgressBar bar; - + // Configure the bar bar.set_bar_width(50); bar.start_bar_with("["); @@ -13,8 +13,10 @@ int main() { bar.fill_bar_remainder_with(" "); bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); - bar.set_foreground_color(indicators::Color::GREEN); - + bar.set_foreground_color(indicators::Color::GREEN); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); + // Update bar state while (true) { bar.tick(); diff --git a/samples/progress_spinner.cpp b/samples/progress_spinner.cpp index abb918d..bea4074 100644 --- a/samples/progress_spinner.cpp +++ b/samples/progress_spinner.cpp @@ -6,12 +6,14 @@ int main() { std::cout << "\e[?25l"; indicators::ProgressSpinner spinner; - + // Configure the spinner spinner.set_postfix_text("Checking credentials"); spinner.set_foreground_color(indicators::Color::YELLOW); spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); - + spinner.hide_elapsed_time(); + spinner.hide_remaining_time(); + // Update spinner state auto job = [&spinner]() { while (true) { @@ -32,7 +34,7 @@ int main() { thread.join(); // Show cursor - std::cout << "\e[?25h"; + std::cout << "\e[?25h"; return 0; } From f28ab68c6005515b88880f5819f2fddeb7e2fbdf Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:33:08 -0600 Subject: [PATCH 06/12] Updated README --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 717ee33..b85957a 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,9 @@ int main() { bar.fill_bar_remainder_with(" "); bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); - bar.set_foreground_color(indicators::Color::GREEN); + bar.set_foreground_color(indicators::Color::GREEN); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); // Update bar state @@ -78,6 +80,8 @@ int main() { bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); bar.set_foreground_color(indicators::Color::GREEN); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); // Update bar state while (true) { @@ -114,6 +118,8 @@ int main() { bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); bar.set_foreground_color(indicators::Color::GREEN); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); // Update bar state @@ -154,6 +160,8 @@ int main() { bar.fill_bar_remainder_with("-"); bar.end_bar_with("]"); bar.set_foreground_color(indicators::Color::YELLOW); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); // As configured, the bar will look like this: // @@ -231,6 +239,8 @@ int main() { bar.start_bar_with("["); bar.end_bar_with("]"); bar.set_foreground_color(indicators::Color::WHITE); + bar.hide_elapsed_time(); + bar.hide_remaining_time(); // Update bar state auto progress = 0.0f; @@ -264,6 +274,8 @@ int main() { spinner.set_postfix_text("Checking credentials"); spinner.set_foreground_color(indicators::Color::YELLOW); spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); + spinner.hide_elapsed_time(); + spinner.hide_remaining_time(); // Update spinner state @@ -289,6 +301,8 @@ int main() { spinner.set_postfix_text("Checking credentials"); spinner.set_foreground_color(indicators::Color::YELLOW); spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); + spinner.hide_elapsed_time(); + spinner.hide_remaining_time(); // Update spinner state auto job = [&spinner]() { @@ -299,7 +313,7 @@ int main() { spinner.hide_spinner(); spinner.hide_percentage(); spinner.set_postfix_text("Authenticated!"); - spinner.mark_as_completed(); + spinner.mark_as_completed(); break; } else spinner.tick(); From fdad265e99de2ab030dfce5b436bfd658a5eaabe Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:35:52 -0600 Subject: [PATCH 07/12] Update README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b85957a..fdebb98 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ int main() { Here's the general structure of a progress bar: ``` - ? - ^^^^^^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^^^^ ^^^^^ Show/Hide ^^^^^ +{prefix_text} {start} {fill} {lead} {remaining} {end} {percentage} [{elapsed}<{remaining}?] {postfix_text} + ^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^ ``` The amount of progress in ProgressBar is maintained as a float in range `[0, 100]`. When progress reaches 100, the progression is complete. @@ -286,7 +286,7 @@ int main() { Here's the general structure of a progress spinner: ``` - ? +{prefix_text} {spinner} {percentage} [{elapsed}<{remaining}] {postfix_text} ``` ProgressSpinner has a vector of strings: `spinner_states`. At each update, the spinner will pick the next string from this sequence to print to the console. The spinner state can be updated similarly to ProgressBars: Using either `tick()` or `set_progress(value)`. From 78b7abcfbd174c9d91f33572911ffc3827bb3c2d Mon Sep 17 00:00:00 2001 From: Pranav Date: Tue, 17 Dec 2019 09:37:11 -0600 Subject: [PATCH 08/12] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fdebb98..8f278b3 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ int main() { Here's the general structure of a progress bar: ``` -{prefix_text} {start} {fill} {lead} {remaining} {end} {percentage} [{elapsed}<{remaining}?] {postfix_text} - ^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^ +{prefix} {start} {fill} {lead} {remaining} {end} {percentage} [{elapsed}<{remaining}?] {postfix} + ^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^ ``` The amount of progress in ProgressBar is maintained as a float in range `[0, 100]`. When progress reaches 100, the progression is complete. @@ -286,7 +286,7 @@ int main() { Here's the general structure of a progress spinner: ``` -{prefix_text} {spinner} {percentage} [{elapsed}<{remaining}] {postfix_text} +{prefix} {spinner} {percentage} [{elapsed}<{remaining}] {postfix} ``` ProgressSpinner has a vector of strings: `spinner_states`. At each update, the spinner will pick the next string from this sequence to print to the console. The spinner state can be updated similarly to ProgressBars: Using either `tick()` or `set_progress(value)`. From aa5dffa4e2d30d0122cb0cce33cd52a1c8a61c22 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:43:53 -0600 Subject: [PATCH 09/12] Time elapsed/remaining is hidden by default --- demo/demo.cpp | 16 ---------------- include/indicators/block_progress_bar.hpp | 4 ++-- include/indicators/progress_bar.hpp | 4 ++-- include/indicators/progress_spinner.hpp | 4 ++-- samples/block_progress_bar.cpp | 2 -- samples/multi_threaded_bar.cpp | 2 -- samples/progress_bar_set_progress.cpp | 2 -- samples/progress_bar_tick.cpp | 2 -- samples/progress_spinner.cpp | 2 -- 9 files changed, 6 insertions(+), 32 deletions(-) diff --git a/demo/demo.cpp b/demo/demo.cpp index 78c9563..09da63a 100644 --- a/demo/demo.cpp +++ b/demo/demo.cpp @@ -18,8 +18,6 @@ int main() { p.lead_bar_progress_with("■"); p.fill_bar_remainder_with(" "); p.end_bar_with(" ]"); - p.hide_elapsed_time(); - p.hide_remaining_time(); p.set_foreground_color(indicators::Color::YELLOW); std::atomic index{0}; @@ -59,8 +57,6 @@ int main() { p.lead_bar_progress_with(""); p.fill_bar_remainder_with(""); p.end_bar_with(""); - p.hide_elapsed_time(); - p.hide_remaining_time(); p.set_foreground_color(indicators::Color::WHITE); p.hide_percentage(); auto job = [&p]() { @@ -91,8 +87,6 @@ int main() { p.fill_bar_remainder_with(" "); p.end_bar_with("]"); p.set_postfix_text("Getting started"); - p.hide_elapsed_time(); - p.hide_remaining_time(); p.set_foreground_color(indicators::Color::GREEN); auto job = [&p]() { while (true) { @@ -130,8 +124,6 @@ int main() { p4.set_foreground_color(indicators::Color::CYAN); p4.set_postfix_text("Restoring system state"); p4.hide_percentage(); - p4.hide_elapsed_time(); - p4.hide_remaining_time(); std::atomic index4{0}; auto job4 = [&p4, &index4, &lead_spinner]() { while (true) { @@ -175,8 +167,6 @@ int main() { p.set_progress(100); p.set_foreground_color(indicators::Color::WHITE); p.set_postfix_text("Reverting system restore"); - p.hide_elapsed_time(); - p.hide_remaining_time(); std::atomic progress{100}; auto job = [&p, &progress]() { while (true) { @@ -204,8 +194,6 @@ int main() { p.set_postfix_text("Checking credentials"); p.set_foreground_color(indicators::Color::YELLOW); p.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); - p.hide_elapsed_time(); - p.hide_remaining_time(); auto job = [&p]() { while (true) { if (p.is_completed()) { @@ -236,8 +224,6 @@ int main() { p.set_foreground_color(indicators::Color::WHITE); p.set_spinner_states({"▖", "▘", "▝", "▗"}); p.hide_percentage(); - p.hide_elapsed_time(); - p.hide_remaining_time(); auto job = [&p]() { while (true) { auto current = p.current(); @@ -283,8 +269,6 @@ int main() { p2.end_bar_with("🌑"); p2.set_postfix_text("Achieved low-Earth orbit"); p2.set_foreground_color(indicators::Color::WHITE); - p2.hide_elapsed_time(); - p2.hide_remaining_time(); std::vector ship_trail{"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"}; std::atomic ship_trail_index{0}; auto job2 = [&p2, &ship_trail_index, &ship_trail]() { diff --git a/include/indicators/block_progress_bar.hpp b/include/indicators/block_progress_bar.hpp index abd977c..44f01b1 100644 --- a/include/indicators/block_progress_bar.hpp +++ b/include/indicators/block_progress_bar.hpp @@ -125,8 +125,8 @@ private: std::atomic _max_postfix_text_length{0}; std::atomic _completed{false}; std::atomic _show_percentage{true}; - std::atomic _show_elapsed_time{true}; - std::atomic _show_remaining_time{true}; + std::atomic _show_elapsed_time{false}; + std::atomic _show_remaining_time{false}; std::atomic _saved_start_time{false}; std::chrono::time_point _start_time_point; std::mutex _mutex; diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index 4ecb1a2..15ee67a 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -139,8 +139,8 @@ private: std::atomic _max_postfix_text_length{0}; std::atomic _completed{false}; std::atomic _show_percentage{true}; - std::atomic _show_elapsed_time{true}; - std::atomic _show_remaining_time{true}; + std::atomic _show_elapsed_time{false}; + std::atomic _show_remaining_time{false}; std::atomic _saved_start_time{false}; std::chrono::time_point _start_time_point; std::mutex _mutex; diff --git a/include/indicators/progress_spinner.hpp b/include/indicators/progress_spinner.hpp index 24929b3..1481d9b 100644 --- a/include/indicators/progress_spinner.hpp +++ b/include/indicators/progress_spinner.hpp @@ -115,8 +115,8 @@ private: std::atomic _max_postfix_text_length{0}; std::atomic _completed{false}; std::atomic _show_percentage{true}; - std::atomic _show_elapsed_time{true}; - std::atomic _show_remaining_time{true}; + std::atomic _show_elapsed_time{false}; + std::atomic _show_remaining_time{false}; std::atomic _saved_start_time{false}; std::chrono::time_point _start_time_point; std::atomic _show_spinner{true}; diff --git a/samples/block_progress_bar.cpp b/samples/block_progress_bar.cpp index 8545dcb..d0cbcfd 100644 --- a/samples/block_progress_bar.cpp +++ b/samples/block_progress_bar.cpp @@ -14,8 +14,6 @@ int main() { bar.start_bar_with("["); bar.end_bar_with("]"); bar.set_foreground_color(indicators::Color::WHITE); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // Update bar state auto progress = 0.0f; diff --git a/samples/multi_threaded_bar.cpp b/samples/multi_threaded_bar.cpp index a25c132..457c479 100644 --- a/samples/multi_threaded_bar.cpp +++ b/samples/multi_threaded_bar.cpp @@ -11,8 +11,6 @@ int main() { bar.fill_bar_remainder_with("-"); bar.end_bar_with("]"); bar.set_foreground_color(indicators::Color::YELLOW); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // As configured, the bar will look like this: // diff --git a/samples/progress_bar_set_progress.cpp b/samples/progress_bar_set_progress.cpp index 5a08021..ca9bb26 100644 --- a/samples/progress_bar_set_progress.cpp +++ b/samples/progress_bar_set_progress.cpp @@ -14,8 +14,6 @@ int main() { bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); bar.set_foreground_color(indicators::Color::GREEN); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // Update bar state diff --git a/samples/progress_bar_tick.cpp b/samples/progress_bar_tick.cpp index 8e741bb..5d8e594 100644 --- a/samples/progress_bar_tick.cpp +++ b/samples/progress_bar_tick.cpp @@ -14,8 +14,6 @@ int main() { bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); bar.set_foreground_color(indicators::Color::GREEN); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // Update bar state while (true) { diff --git a/samples/progress_spinner.cpp b/samples/progress_spinner.cpp index bea4074..37de709 100644 --- a/samples/progress_spinner.cpp +++ b/samples/progress_spinner.cpp @@ -11,8 +11,6 @@ int main() { spinner.set_postfix_text("Checking credentials"); spinner.set_foreground_color(indicators::Color::YELLOW); spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); - spinner.hide_elapsed_time(); - spinner.hide_remaining_time(); // Update spinner state auto job = [&spinner]() { From 8c37f2f1dc414fa2c4d349da55070fc3e1369805 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:44:50 -0600 Subject: [PATCH 10/12] Update README --- README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/README.md b/README.md index 8f278b3..85d1884 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,6 @@ int main() { bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); bar.set_foreground_color(indicators::Color::GREEN); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // Update bar state @@ -80,8 +78,6 @@ int main() { bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); bar.set_foreground_color(indicators::Color::GREEN); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // Update bar state while (true) { @@ -118,8 +114,6 @@ int main() { bar.end_bar_with("]"); bar.set_postfix_text("Getting started"); bar.set_foreground_color(indicators::Color::GREEN); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // Update bar state @@ -160,8 +154,6 @@ int main() { bar.fill_bar_remainder_with("-"); bar.end_bar_with("]"); bar.set_foreground_color(indicators::Color::YELLOW); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // As configured, the bar will look like this: // @@ -239,8 +231,6 @@ int main() { bar.start_bar_with("["); bar.end_bar_with("]"); bar.set_foreground_color(indicators::Color::WHITE); - bar.hide_elapsed_time(); - bar.hide_remaining_time(); // Update bar state auto progress = 0.0f; @@ -274,8 +264,6 @@ int main() { spinner.set_postfix_text("Checking credentials"); spinner.set_foreground_color(indicators::Color::YELLOW); spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); - spinner.hide_elapsed_time(); - spinner.hide_remaining_time(); // Update spinner state @@ -301,8 +289,6 @@ int main() { spinner.set_postfix_text("Checking credentials"); spinner.set_foreground_color(indicators::Color::YELLOW); spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}); - spinner.hide_elapsed_time(); - spinner.hide_remaining_time(); // Update spinner state auto job = [&spinner]() { From d5a1c9a440564c5665b1ec5f3b6616cbaa7222d0 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:48:36 -0600 Subject: [PATCH 11/12] Update README --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 85d1884..29396e1 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,20 @@ int main() { } ``` +## Showing Time Elapsed/Remaining + +All progress bars and spinners in `indicators` support showing time elapsed and time remaining. Inspired by python's [tqdm](https://github.com/tqdm/tqdm) module, the format of this meter is as follows: + +```bash +[{elapsed}<{remaining}] +``` + +Below is an example for configuring this meter: + +```cpp + +``` + # Block Progress Bar Are you in need of a smooth block progress bar using [unicode block elements](https://en.wikipedia.org/wiki/Block_Elements)? Use `BlockProgressBar` instead of `ProgressBar`. Thanks to [this blog post](https://mike42.me/blog/2018-06-make-better-cli-progress-bars-with-unicode-block-characters) for making `BlockProgressBar` an easy addition to the library. From 1e45ef3530326ebb6672cee97ad7d7d82805e659 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Tue, 17 Dec 2019 09:59:15 -0600 Subject: [PATCH 12/12] Updated README --- README.md | 39 ++++++++++++++++++++++++++++++++++++++- img/time_meter.gif | Bin 0 -> 30162 bytes samples/CMakeLists.txt | 3 +++ samples/time_meter.cpp | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 img/time_meter.gif create mode 100644 samples/time_meter.cpp diff --git a/README.md b/README.md index 29396e1..c933315 100644 --- a/README.md +++ b/README.md @@ -216,8 +216,45 @@ All progress bars and spinners in `indicators` support showing time elapsed and Below is an example for configuring this meter: -```cpp +

+ +

+```cpp +#include +#include +#include + +int main() { + indicators::ProgressBar bar; + + // Configure the bar + bar.set_bar_width(50); + bar.start_bar_with(" ["); + bar.fill_bar_progress_with("█"); + bar.lead_bar_progress_with("█"); + bar.fill_bar_remainder_with("-"); + bar.end_bar_with("]"); + bar.set_prefix_text("Training Gaze Network 👀"); + bar.set_foreground_color(indicators::Color::YELLOW); + + // Show time elapsed and remaining + bar.show_elapsed_time(); + bar.show_remaining_time(); + + // Update bar state + while (true) { + bar.tick(); + if (bar.is_completed()) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + + // Show cursor + std::cout << "\e[?25h"; + + return 0; +} ``` # Block Progress Bar diff --git a/img/time_meter.gif b/img/time_meter.gif new file mode 100644 index 0000000000000000000000000000000000000000..c32b79e755542ab2ad4b7f15d2dca95ba58fb1f4 GIT binary patch literal 30162 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 +#include +#include + +int main() { + indicators::ProgressBar bar; + + // Configure the bar + bar.set_bar_width(50); + bar.start_bar_with(" ["); + bar.fill_bar_progress_with("█"); + bar.lead_bar_progress_with("█"); + bar.fill_bar_remainder_with("-"); + bar.end_bar_with("]"); + bar.set_prefix_text("Training Gaze Network 👀"); + bar.set_foreground_color(indicators::Color::YELLOW); + + // Show time elapsed and remaining + bar.show_elapsed_time(); + bar.show_remaining_time(); + + // Update bar state + while (true) { + bar.tick(); + if (bar.is_completed()) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + + // Show cursor + std::cout << "\e[?25h"; + + return 0; +}