#ifndef INDICATORS_DYNAMIC_PROGRESS #define INDICATORS_DYNAMIC_PROGRESS #include #include #include #include #include #include #include #include #include #include #include namespace indicators { template class DynamicProgress { using Settings = std::tuple; public: template explicit DynamicProgress(Indicators &&... bars) { (bars_.emplace_back(std::move(bars)), ...); for (auto &bar : bars_) { bar->multi_progress_mode_ = true; ++total_count_; ++incomplete_count_; } } Indicator &operator[](size_t index) { print_progress(); std::lock_guard lock{mutex_}; return *bars_[index]; } size_t push_back(std::unique_ptr bar) { std::lock_guard lock{mutex_}; bar->multi_progress_mode_ = true; bars_.push_back(std::move(bar)); return bars_.size() - 1; } template void set_option(details::Setting &&setting) { static_assert(!std::is_same( std::declval()))>::type>::value, "Setting has wrong type!"); std::lock_guard lock(mutex_); get_value() = std::move(setting).value; } template void set_option(const details::Setting &setting) { static_assert(!std::is_same( std::declval()))>::type>::value, "Setting has wrong type!"); std::lock_guard lock(mutex_); get_value() = setting.value; } private: Settings settings_; std::atomic started_{false}; std::mutex mutex_; std::vector> bars_; std::atomic total_count_{0}; std::atomic incomplete_count_{0}; template auto get_value() -> decltype((details::get_value(std::declval()).value)) { return details::get_value(settings_).value; } template auto get_value() const -> decltype((details::get_value(std::declval()).value)) { return details::get_value(settings_).value; } public: void print_progress() { std::lock_guard lock{mutex_}; auto &hide_bar_when_complete = get_value(); if (hide_bar_when_complete) { // Hide completed bars if (started_) { for (size_t i = 0; i < incomplete_count_; ++i) { move_up(1); erase_line(); std::cout << std::flush; } } incomplete_count_ = 0; for (auto &bar : bars_) { if (!bar->is_completed()) { bar->print_progress(true); std::cout << "\n"; ++incomplete_count_; } } if (!started_) started_ = true; } else { // Don't hide any bars if (started_) move_up(static_cast(total_count_)); for (auto &bar : bars_) { bar->print_progress(true); std::cout << "\n"; } if (!started_) started_ = true; } total_count_ = bars_.size(); std::cout << termcolor::reset; } }; } // namespace indicators #endif