diff --git a/demo/demo.cpp b/demo/demo.cpp index dda1a67..5976fb3 100644 --- a/demo/demo.cpp +++ b/demo/demo.cpp @@ -53,7 +53,7 @@ int main() { // PROGRESS BAR 2 // indicators::ProgressBar p; - p.set_option(option::BarWidth{40}); + p.set_option(option::BarWidth{0}); p.set_option(option::PrefixText{"Reading package list... "}); p.set_option(option::Start{""}); p.set_option(option::Fill{""}); @@ -141,6 +141,7 @@ int main() { std::cout << std::endl; p4.set_option(option::ForegroundColor{indicators::Color::red}); p4.set_option(option::PrefixText{"{ ERROR }"}); + p4.set_option(option::BarWidth{0}); p4.set_option(option::Start{}); p4.set_option(option::Fill{}); p4.set_option(option::Lead{}); @@ -158,6 +159,35 @@ int main() { thread4.join(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + { + // + // GOING BACKWARDS + // + indicators::ProgressBar p{option::BarWidth{50}, + option::ProgressType{ProgressType::decremental}, + option::Start{"["}, + option::Fill{"■"}, + option::Lead{"■"}, + option::Remainder{"-"}, + option::End{"]"}, + option::ForegroundColor{indicators::Color::white}, + option::PostfixText{"Reverting system restore"}, + option::FontStyles{ + std::vector{indicators::FontStyle::bold}}}; + auto job = [&p]() { + while (true) { + p.tick(); + if (p.is_completed()) { + p.set_option(option::PostfixText{"Revert complete!"}); + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(60)); + } + }; + std::thread thread(job); + thread.join(); + } } { @@ -285,4 +315,4 @@ int main() { show_console_cursor(true); return 0; -} +} \ No newline at end of file diff --git a/include/indicators/details/stream_helper.hpp b/include/indicators/details/stream_helper.hpp index 5e7e951..2715c0b 100644 --- a/include/indicators/details/stream_helper.hpp +++ b/include/indicators/details/stream_helper.hpp @@ -215,4 +215,4 @@ private: }; } // namespace details -} // namespace indicators +} // namespace indicators \ No newline at end of file diff --git a/include/indicators/progress_bar.hpp b/include/indicators/progress_bar.hpp index 3ce6694..d83817a 100644 --- a/include/indicators/progress_bar.hpp +++ b/include/indicators/progress_bar.hpp @@ -24,7 +24,10 @@ 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::Stream>; + option::ForegroundColor, option::FontStyles, + option::MinProgress, option::MaxProgress, + option::ProgressType, + option::Stream>; public: template (args)...), details::get( option::FontStyles{std::vector{}}, std::forward(args)...), + details::get( + option::MinProgress{0}, std::forward(args)...), details::get( option::MaxProgress{100}, std::forward(args)...), + details::get( + option::ProgressType{ProgressType::incremental}, std::forward(args)...), details::get( - option::Stream{std::cout}, std::forward(args)...)) {} + option::Stream{std::cout}, std::forward(args)...)) { + + // if progress is incremental, start from min_progress + // else start from max_progress + const auto type = get_value(); + if (type == ProgressType::incremental) + progress_ = get_value(); + else + progress_ = get_value(); + } template void set_option(details::Setting &&setting) { @@ -119,7 +135,11 @@ public: void tick() { { std::lock_guard lock{mutex_}; - progress_ += 1; + const auto type = get_value(); + if (type == ProgressType::incremental) + progress_ += 1; + else + progress_ -= 1; } save_start_time(); print_progress(); @@ -175,9 +195,12 @@ public: auto& os = get_value(); + const auto type = get_value(); + const auto min_progress = get_value(); const auto max_progress = get_value(); if (multi_progress_mode_ && !from_multi_progress) { - if (progress_ >= max_progress) { + if ((type == ProgressType::incremental && progress_ >= max_progress) || + (type == ProgressType::decremental && progress_ <= min_progress)) { get_value() = true; } return; @@ -246,9 +269,10 @@ public: << std::string(get_value(), ' ') << "\r"; os.flush(); - if (progress_ >= max_progress) { - get_value() = true; - } + if ((type == ProgressType::incremental && progress_ >= max_progress) || + (type == ProgressType::decremental && progress_ <= min_progress)) { + get_value() = true; + } if (get_value() && !from_multi_progress) // Don't std::endl if calling from MultiProgress os << termcolor::reset << std::endl; diff --git a/include/indicators/progress_type.hpp b/include/indicators/progress_type.hpp new file mode 100644 index 0000000..314f4f0 --- /dev/null +++ b/include/indicators/progress_type.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace indicators { +enum class ProgressType { incremental, decremental }; +} diff --git a/include/indicators/setting.hpp b/include/indicators/setting.hpp index cdc0769..948d71f 100644 --- a/include/indicators/setting.hpp +++ b/include/indicators/setting.hpp @@ -29,6 +29,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -91,7 +92,9 @@ enum class ProgressBarOption { spinner_states, font_styles, hide_bar_when_complete, + min_progress, max_progress, + progress_type, stream }; @@ -207,7 +210,9 @@ using HideBarWhenComplete = details::BooleanSetting; using FontStyles = details::Setting, details::ProgressBarOption::font_styles>; +using MinProgress = details::IntegerSetting; using MaxProgress = details::IntegerSetting; +using ProgressType = details::Setting; using Stream = details::Setting; } // namespace option } // namespace indicators diff --git a/single_include.json b/single_include.json index 103836e..3d868f1 100644 --- a/single_include.json +++ b/single_include.json @@ -4,6 +4,7 @@ "sources": [ "include/indicators/color.hpp", "include/indicators/font_style.hpp", + "include/indicators/progress_type.hpp", "include/indicators/termcolor.hpp", "include/indicators/terminal_size.hpp", "include/indicators/setting.hpp", diff --git a/single_include/indicators/indicators.hpp b/single_include/indicators/indicators.hpp index f08449e..ff0935f 100644 --- a/single_include/indicators/indicators.hpp +++ b/single_include/indicators/indicators.hpp @@ -460,6 +460,11 @@ namespace indicators { enum class FontStyle { bold, dark, italic, underline, blink, reverse, concealed, crossed }; +} +#pragma once + +namespace indicators { +enum class ProgressType { incremental, decremental }; } //! //! termcolor @@ -978,6 +983,7 @@ SOFTWARE. #include // #include // #include +// #include #include #include #include @@ -1040,7 +1046,9 @@ enum class ProgressBarOption { spinner_states, font_styles, hide_bar_when_complete, + min_progress, max_progress, + progress_type, stream }; @@ -1156,7 +1164,9 @@ using HideBarWhenComplete = details::BooleanSetting; using FontStyles = details::Setting, details::ProgressBarOption::font_styles>; +using MinProgress = details::IntegerSetting; using MaxProgress = details::IntegerSetting; +using ProgressType = details::Setting; using Stream = details::Setting; } // namespace option } // namespace indicators @@ -1719,18 +1729,21 @@ public: std::ostream &write(float progress) { auto pos = static_cast(progress * bar_width / 100.0); - for (size_t i = 0, current_display_width = 0; i < bar_width;) { - std::string next; + for (size_t i = 0; i < bar_width;) { + std::string next{""}; + size_t current_display_width = 0; - if (i < pos) { + if (i < pos && !fill.empty()) { next = fill; current_display_width = unicode::display_width(fill); - } else if (i == pos) { + } else if (i == pos && !lead.empty()) { next = lead; current_display_width = unicode::display_width(lead); } else { - next = remainder; - current_display_width = unicode::display_width(remainder); + if (!remainder.empty()) { + next = remainder; + current_display_width = unicode::display_width(remainder); + } } i += current_display_width; @@ -1825,7 +1838,10 @@ 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::Stream>; + option::ForegroundColor, option::FontStyles, + option::MinProgress, option::MaxProgress, + option::ProgressType, + option::Stream>; public: template (args)...), details::get( option::FontStyles{std::vector{}}, std::forward(args)...), + details::get( + option::MinProgress{0}, std::forward(args)...), details::get( option::MaxProgress{100}, std::forward(args)...), + details::get( + option::ProgressType{ProgressType::incremental}, std::forward(args)...), details::get( - option::Stream{std::cout}, std::forward(args)...)) {} + option::Stream{std::cout}, std::forward(args)...)) { + + // if progress is incremental, start from min_progress + // else start from max_progress + const auto type = get_value(); + if (type == ProgressType::incremental) + progress_ = get_value(); + else + progress_ = get_value(); + } template void set_option(details::Setting &&setting) { @@ -1920,7 +1949,11 @@ public: void tick() { { std::lock_guard lock{mutex_}; - progress_ += 1; + const auto type = get_value(); + if (type == ProgressType::incremental) + progress_ += 1; + else + progress_ -= 1; } save_start_time(); print_progress(); @@ -1976,9 +2009,12 @@ public: auto& os = get_value(); + const auto type = get_value(); + const auto min_progress = get_value(); const auto max_progress = get_value(); if (multi_progress_mode_ && !from_multi_progress) { - if (progress_ >= max_progress) { + if ((type == ProgressType::incremental && progress_ >= max_progress) || + (type == ProgressType::decremental && progress_ <= min_progress)) { get_value() = true; } return; @@ -2047,9 +2083,10 @@ public: << std::string(get_value(), ' ') << "\r"; os.flush(); - if (progress_ >= max_progress) { - get_value() = true; - } + if ((type == ProgressType::incremental && progress_ >= max_progress) || + (type == ProgressType::decremental && progress_ <= min_progress)) { + get_value() = true; + } if (get_value() && !from_multi_progress) // Don't std::endl if calling from MultiProgress os << termcolor::reset << std::endl;