mirror of
https://github.com/p-ranav/indicators.git
synced 2025-12-12 01:18:52 +08:00
Merge pull request #32 from p-ranav/feature/dynamic-progress
Feature/dynamic progress
This commit is contained in:
154
README.md
154
README.md
@@ -39,6 +39,7 @@ make
|
|||||||
* [Progress Bar](#progress-bar)
|
* [Progress Bar](#progress-bar)
|
||||||
* [Block Progress Bar](#block-progress-bar)
|
* [Block Progress Bar](#block-progress-bar)
|
||||||
* [Multi Progress](#multiprogress)
|
* [Multi Progress](#multiprogress)
|
||||||
|
* [Dynamic Progress](#dynamicprogress)
|
||||||
* [Progress Spinner](#progress-spinner)
|
* [Progress Spinner](#progress-spinner)
|
||||||
* [Contributing](#contributing)
|
* [Contributing](#contributing)
|
||||||
* [License](#license)
|
* [License](#license)
|
||||||
@@ -350,6 +351,159 @@ int main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# DynamicProgress
|
||||||
|
|
||||||
|
`DynamicProgress` is a container class, similar to `MultiProgress`, for managing multiple progress bars. As the name suggests, with `DynamicProgress`, you can dynamically add new progress bars. Simply call `bars.push_back`.
|
||||||
|
|
||||||
|
Below is an example `DynamicProgress` object that manages six `ProgressBar` objects. Three of these bars are added dynamically.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="img/dynamic_progress_bar.gif"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <indicators/dynamic_progress.hpp>
|
||||||
|
#include <indicators/progress_bar.hpp>
|
||||||
|
using namespace indicators;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
ProgressBar bar1{option::BarWidth{50}, option::ForegroundColor{Color::red},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"5c90d4a2d1a8: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar2{option::BarWidth{50}, option::ForegroundColor{Color::yellow},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"22337bfd13a9: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar3{option::BarWidth{50}, option::ForegroundColor{Color::green},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"10f26c680a34: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar4{option::BarWidth{50}, option::ForegroundColor{Color::white},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"6364e0d7a283: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar5{option::BarWidth{50}, option::ForegroundColor{Color::blue},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"ff1356ba118b: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar6{option::BarWidth{50}, option::ForegroundColor{Color::cyan},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"5a17453338b4: Downloading "}};
|
||||||
|
|
||||||
|
std::cout << termcolor::bold << termcolor::white << "Pulling image foo:bar/baz\n";
|
||||||
|
|
||||||
|
// Construct with 3 progress bars. We'll add 3 more at a later point
|
||||||
|
DynamicProgress<ProgressBar> bars(bar1, bar2, bar3);
|
||||||
|
|
||||||
|
// Do not hide bars when completed
|
||||||
|
bars.set_option(option::HideBarWhenComplete{false});
|
||||||
|
|
||||||
|
std::thread fourth_job, fifth_job, sixth_job;
|
||||||
|
|
||||||
|
auto job4 = [&bars](size_t i) {
|
||||||
|
while (true) {
|
||||||
|
bars[i].tick();
|
||||||
|
if (bars[i].is_completed()) {
|
||||||
|
bars[i].set_option(option::PrefixText{"6364e0d7a283: Pull complete "});
|
||||||
|
bars[i].mark_as_completed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job5 = [&bars](size_t i) {
|
||||||
|
while (true) {
|
||||||
|
bars[i].tick();
|
||||||
|
if (bars[i].is_completed()) {
|
||||||
|
bars[i].set_option(option::PrefixText{"ff1356ba118b: Pull complete "});
|
||||||
|
bars[i].mark_as_completed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job6 = [&bars](size_t i) {
|
||||||
|
while (true) {
|
||||||
|
bars[i].tick();
|
||||||
|
if (bars[i].is_completed()) {
|
||||||
|
bars[i].set_option(option::PrefixText{"5a17453338b4: Pull complete "});
|
||||||
|
bars[i].mark_as_completed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job1 = [&bars, &bar6, &sixth_job, &job6]() {
|
||||||
|
while (true) {
|
||||||
|
bars[0].tick();
|
||||||
|
if (bars[0].is_completed()) {
|
||||||
|
bars[0].set_option(option::PrefixText{"5c90d4a2d1a8: Pull complete "});
|
||||||
|
// bar1 is completed, adding bar6
|
||||||
|
auto i = bars.push_back(bar6);
|
||||||
|
sixth_job = std::thread(job6, i);
|
||||||
|
sixth_job.join();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(140));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job2 = [&bars, &bar5, &fifth_job, &job5]() {
|
||||||
|
while (true) {
|
||||||
|
bars[1].tick();
|
||||||
|
if (bars[1].is_completed()) {
|
||||||
|
bars[1].set_option(option::PrefixText{"22337bfd13a9: Pull complete "});
|
||||||
|
// bar2 is completed, adding bar5
|
||||||
|
auto i = bars.push_back(bar5);
|
||||||
|
fifth_job = std::thread(job5, i);
|
||||||
|
fifth_job.join();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(25));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job3 = [&bars, &bar4, &fourth_job, &job4]() {
|
||||||
|
while (true) {
|
||||||
|
bars[2].tick();
|
||||||
|
if (bars[2].is_completed()) {
|
||||||
|
bars[2].set_option(option::PrefixText{"10f26c680a34: Pull complete "});
|
||||||
|
// bar3 is completed, adding bar4
|
||||||
|
auto i = bars.push_back(bar4);
|
||||||
|
fourth_job = std::thread(job4, i);
|
||||||
|
fourth_job.join();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread first_job(job1);
|
||||||
|
std::thread second_job(job2);
|
||||||
|
std::thread third_job(job3);
|
||||||
|
|
||||||
|
third_job.join();
|
||||||
|
second_job.join();
|
||||||
|
first_job.join();
|
||||||
|
|
||||||
|
std::cout << termcolor::bold << termcolor::green << "✔ Downloaded image foo/bar:baz" << std::endl;
|
||||||
|
std::cout << termcolor::reset;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above code, notice the option `bars.set_option(option::HideBarWhenComplete{true});`. Yes, you can hide progress bars as and when they complete by setting this option to `true`. If you do so, the above example will look like this:
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="img/dynamic_progress_bar_hide_completed.gif"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
# Progress Spinner
|
# Progress Spinner
|
||||||
|
|
||||||
To introduce a progress spinner in your application, include `indicators/progress_spinner.hpp` and create a `ProgressSpinner` object. Here's the general structure of a progress spinner:
|
To introduce a progress spinner in your application, include `indicators/progress_spinner.hpp` and create a `ProgressSpinner` object. Here's the general structure of a progress spinner:
|
||||||
|
|||||||
BIN
img/dynamic_progress_bar.gif
Normal file
BIN
img/dynamic_progress_bar.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 MiB |
BIN
img/dynamic_progress_bar_hide_completed.gif
Normal file
BIN
img/dynamic_progress_bar_hide_completed.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 MiB |
@@ -164,6 +164,7 @@ private:
|
|||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
|
||||||
template <typename Indicator, size_t count> friend class MultiProgress;
|
template <typename Indicator, size_t count> friend class MultiProgress;
|
||||||
|
template <typename Indicator> friend class DynamicProgress;
|
||||||
std::atomic<bool> multi_progress_mode_{false};
|
std::atomic<bool> multi_progress_mode_{false};
|
||||||
|
|
||||||
void save_start_time() {
|
void save_start_time() {
|
||||||
|
|||||||
138
include/indicators/dynamic_progress.hpp
Normal file
138
include/indicators/dynamic_progress.hpp
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
Activity Indicators for Modern C++
|
||||||
|
https://github.com/p-ranav/indicators
|
||||||
|
|
||||||
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <indicators/color.hpp>
|
||||||
|
#include <indicators/setting.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace indicators {
|
||||||
|
|
||||||
|
template <typename Indicator> class DynamicProgress {
|
||||||
|
using Settings = std::tuple<option::HideBarWhenComplete>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename... Indicators> explicit DynamicProgress(Indicators &... bars) {
|
||||||
|
bars_ = {bars...};
|
||||||
|
for (auto &bar : bars_) {
|
||||||
|
bar.get().multi_progress_mode_ = true;
|
||||||
|
++total_count_;
|
||||||
|
++incomplete_count_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Indicator &operator[](size_t index) {
|
||||||
|
print_progress();
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
return bars_[index].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t push_back(Indicator &bar) {
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
bar.multi_progress_mode_ = true;
|
||||||
|
bars_.push_back(bar);
|
||||||
|
return bars_.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, details::ProgressBarOption id>
|
||||||
|
void set_option(details::Setting<T, id> &&setting) {
|
||||||
|
static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
|
||||||
|
std::declval<Settings>()))>::type>::value,
|
||||||
|
"Setting has wrong type!");
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
get_value<id>() = std::move(setting).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, details::ProgressBarOption id>
|
||||||
|
void set_option(const details::Setting<T, id> &setting) {
|
||||||
|
static_assert(!std::is_same<T, typename std::decay<decltype(details::get_value<id>(
|
||||||
|
std::declval<Settings>()))>::type>::value,
|
||||||
|
"Setting has wrong type!");
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
get_value<id>() = setting.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Settings settings_;
|
||||||
|
std::atomic<bool> started_{false};
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::vector<std::reference_wrapper<Indicator>> bars_;
|
||||||
|
std::atomic<size_t> total_count_{0};
|
||||||
|
std::atomic<size_t> incomplete_count_{0};
|
||||||
|
|
||||||
|
template <details::ProgressBarOption id>
|
||||||
|
auto get_value() -> decltype((details::get_value<id>(std::declval<Settings &>()).value)) {
|
||||||
|
return details::get_value<id>(settings_).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <details::ProgressBarOption id>
|
||||||
|
auto get_value() const
|
||||||
|
-> decltype((details::get_value<id>(std::declval<const Settings &>()).value)) {
|
||||||
|
return details::get_value<id>(settings_).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_progress() {
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
auto &hide_bar_when_complete = get_value<details::ProgressBarOption::hide_bar_when_complete>();
|
||||||
|
if (hide_bar_when_complete) {
|
||||||
|
// Hide completed bars
|
||||||
|
if (started_) {
|
||||||
|
for (size_t i = 0; i < incomplete_count_; ++i)
|
||||||
|
std::cout << "\033[A\r\033[K" << std::flush;
|
||||||
|
}
|
||||||
|
incomplete_count_ = 0;
|
||||||
|
for (auto &bar : bars_) {
|
||||||
|
if (!bar.get().is_completed()) {
|
||||||
|
bar.get().print_progress(true);
|
||||||
|
std::cout << "\n";
|
||||||
|
++incomplete_count_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!started_)
|
||||||
|
started_ = true;
|
||||||
|
} else {
|
||||||
|
// Don't hide any bars
|
||||||
|
if (started_) {
|
||||||
|
for (size_t i = 0; i < total_count_; ++i)
|
||||||
|
std::cout << "\x1b[A";
|
||||||
|
}
|
||||||
|
for (auto &bar: bars_) {
|
||||||
|
bar.get().print_progress(true);
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
if (!started_)
|
||||||
|
started_ = true;
|
||||||
|
}
|
||||||
|
total_count_ = bars_.size();
|
||||||
|
std::cout << termcolor::reset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace indicators
|
||||||
@@ -176,6 +176,7 @@ private:
|
|||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
|
||||||
template <typename Indicator, size_t count> friend class MultiProgress;
|
template <typename Indicator, size_t count> friend class MultiProgress;
|
||||||
|
template <typename Indicator> friend class DynamicProgress;
|
||||||
std::atomic<bool> multi_progress_mode_{false};
|
std::atomic<bool> multi_progress_mode_{false};
|
||||||
|
|
||||||
void save_start_time() {
|
void save_start_time() {
|
||||||
@@ -189,13 +190,13 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void print_progress(bool from_multi_progress = false) {
|
void print_progress(bool from_multi_progress = false) {
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
if (multi_progress_mode_ && !from_multi_progress) {
|
if (multi_progress_mode_ && !from_multi_progress) {
|
||||||
if (progress_ > 100.0) {
|
if (progress_ > 100.0) {
|
||||||
get_value<details::ProgressBarOption::completed>() = true;
|
get_value<details::ProgressBarOption::completed>() = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::lock_guard<std::mutex> lock{mutex_};
|
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
if (!get_value<details::ProgressBarOption::completed>())
|
if (!get_value<details::ProgressBarOption::completed>())
|
||||||
elapsed_ = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_point_);
|
elapsed_ = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time_point_);
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ enum class ProgressBarOption {
|
|||||||
saved_start_time,
|
saved_start_time,
|
||||||
foreground_color,
|
foreground_color,
|
||||||
spinner_show,
|
spinner_show,
|
||||||
spinner_states
|
spinner_states,
|
||||||
|
hide_bar_when_complete
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, ProgressBarOption Id> struct Setting {
|
template <typename T, ProgressBarOption Id> struct Setting {
|
||||||
@@ -196,5 +197,7 @@ using ForegroundColor = details::Setting<Color, details::ProgressBarOption::fore
|
|||||||
using ShowSpinner = details::BooleanSetting<details::ProgressBarOption::spinner_show>;
|
using ShowSpinner = details::BooleanSetting<details::ProgressBarOption::spinner_show>;
|
||||||
using SpinnerStates =
|
using SpinnerStates =
|
||||||
details::Setting<std::vector<std::string>, details::ProgressBarOption::spinner_states>;
|
details::Setting<std::vector<std::string>, details::ProgressBarOption::spinner_states>;
|
||||||
|
using HideBarWhenComplete =
|
||||||
|
details::BooleanSetting<details::ProgressBarOption::hide_bar_when_complete>;
|
||||||
} // namespace option
|
} // namespace option
|
||||||
} // namespace indicators
|
} // namespace indicators
|
||||||
@@ -22,3 +22,6 @@ target_link_libraries(multi_progress_bar PRIVATE indicators::indicators)
|
|||||||
|
|
||||||
add_executable(multi_block_progress_bar multi_block_progress_bar.cpp)
|
add_executable(multi_block_progress_bar multi_block_progress_bar.cpp)
|
||||||
target_link_libraries(multi_block_progress_bar PRIVATE indicators::indicators)
|
target_link_libraries(multi_block_progress_bar PRIVATE indicators::indicators)
|
||||||
|
|
||||||
|
add_executable(dynamic_progress dynamic_progress.cpp)
|
||||||
|
target_link_libraries(dynamic_progress PRIVATE indicators::indicators)
|
||||||
|
|||||||
131
samples/dynamic_progress.cpp
Normal file
131
samples/dynamic_progress.cpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#include <indicators/dynamic_progress.hpp>
|
||||||
|
#include <indicators/progress_bar.hpp>
|
||||||
|
using namespace indicators;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
ProgressBar bar1{option::BarWidth{50}, option::ForegroundColor{Color::red},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"5c90d4a2d1a8: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar2{option::BarWidth{50}, option::ForegroundColor{Color::yellow},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"22337bfd13a9: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar3{option::BarWidth{50}, option::ForegroundColor{Color::green},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"10f26c680a34: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar4{option::BarWidth{50}, option::ForegroundColor{Color::white},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"6364e0d7a283: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar5{option::BarWidth{50}, option::ForegroundColor{Color::blue},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"ff1356ba118b: Downloading "}};
|
||||||
|
|
||||||
|
ProgressBar bar6{option::BarWidth{50}, option::ForegroundColor{Color::cyan},
|
||||||
|
option::ShowElapsedTime{true}, option::ShowRemainingTime{true},
|
||||||
|
option::PrefixText{"5a17453338b4: Downloading "}};
|
||||||
|
|
||||||
|
std::cout << termcolor::bold << termcolor::white << "Pulling image foo:bar/baz\n";
|
||||||
|
|
||||||
|
DynamicProgress<ProgressBar> bars(bar1, bar2, bar3);
|
||||||
|
bars.set_option(option::HideBarWhenComplete{false});
|
||||||
|
|
||||||
|
std::thread fourth_job, fifth_job, sixth_job;
|
||||||
|
|
||||||
|
auto job4 = [&bars](size_t i) {
|
||||||
|
while (true) {
|
||||||
|
bars[i].tick();
|
||||||
|
if (bars[i].is_completed()) {
|
||||||
|
bars[i].set_option(option::PrefixText{"6364e0d7a283: Pull complete "});
|
||||||
|
bars[i].mark_as_completed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job5 = [&bars](size_t i) {
|
||||||
|
while (true) {
|
||||||
|
bars[i].tick();
|
||||||
|
if (bars[i].is_completed()) {
|
||||||
|
bars[i].set_option(option::PrefixText{"ff1356ba118b: Pull complete "});
|
||||||
|
bars[i].mark_as_completed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job6 = [&bars](size_t i) {
|
||||||
|
while (true) {
|
||||||
|
bars[i].tick();
|
||||||
|
if (bars[i].is_completed()) {
|
||||||
|
bars[i].set_option(option::PrefixText{"5a17453338b4: Pull complete "});
|
||||||
|
bars[i].mark_as_completed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(40));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job1 = [&bars, &bar6, &sixth_job, &job6]() {
|
||||||
|
while (true) {
|
||||||
|
bars[0].tick();
|
||||||
|
if (bars[0].is_completed()) {
|
||||||
|
bars[0].set_option(option::PrefixText{"5c90d4a2d1a8: Pull complete "});
|
||||||
|
// bar1 is completed, adding bar6
|
||||||
|
auto i = bars.push_back(bar6);
|
||||||
|
sixth_job = std::thread(job6, i);
|
||||||
|
sixth_job.join();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(140));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job2 = [&bars, &bar5, &fifth_job, &job5]() {
|
||||||
|
while (true) {
|
||||||
|
bars[1].tick();
|
||||||
|
if (bars[1].is_completed()) {
|
||||||
|
bars[1].set_option(option::PrefixText{"22337bfd13a9: Pull complete "});
|
||||||
|
// bar2 is completed, adding bar5
|
||||||
|
auto i = bars.push_back(bar5);
|
||||||
|
fifth_job = std::thread(job5, i);
|
||||||
|
fifth_job.join();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(25));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto job3 = [&bars, &bar4, &fourth_job, &job4]() {
|
||||||
|
while (true) {
|
||||||
|
bars[2].tick();
|
||||||
|
if (bars[2].is_completed()) {
|
||||||
|
bars[2].set_option(option::PrefixText{"10f26c680a34: Pull complete "});
|
||||||
|
// bar3 is completed, adding bar4
|
||||||
|
auto i = bars.push_back(bar4);
|
||||||
|
fourth_job = std::thread(job4, i);
|
||||||
|
fourth_job.join();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread first_job(job1);
|
||||||
|
std::thread second_job(job2);
|
||||||
|
std::thread third_job(job3);
|
||||||
|
|
||||||
|
third_job.join();
|
||||||
|
second_job.join();
|
||||||
|
first_job.join();
|
||||||
|
|
||||||
|
std::cout << termcolor::bold << termcolor::green << "✔ Downloaded image foo/bar:baz" << std::endl;
|
||||||
|
std::cout << termcolor::reset;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user