2019-12-04 18:32:10 -06:00
< p align = "center" >
2019-12-04 21:12:12 -06:00
< img height = "70" src = "img/logo.png" / >
2019-12-04 18:33:06 -06:00
< / p >
2019-12-04 19:34:03 -06:00
< p align = "center" >
2019-12-17 18:25:02 +01:00
< a href = "https://travis-ci.com/p-ranav/indicators" >
< img src = "https://travis-ci.com/p-ranav/indicators.svg?branch=master" alt = "ci status" / >
< / a >
2019-12-27 15:22:19 -06:00
< a href = "https://www.codacy.com/manual/p-ranav/indicators?utm_source=github.com&utm_medium=referral&utm_content=p-ranav/indicators&utm_campaign=Badge_Grade" >
< img src = "https://api.codacy.com/project/badge/Grade/93401e73f250407cb32445afec4e3e99" alt = "codacy" / >
< / a >
2019-12-04 21:10:58 -06:00
< a href = "https://github.com/p-ranav/indicators/blob/master/LICENSE" >
2019-12-04 19:34:03 -06:00
< img src = "https://img.shields.io/badge/License-MIT-yellow.svg" alt = "license" / >
< / a >
2020-02-11 17:29:41 +05:30
< img src = "https://img.shields.io/badge/version-1.7-blue.svg?cacheSeconds=2592000" alt = "version" / >
2019-12-04 19:34:03 -06:00
< / p >
2019-12-04 18:33:06 -06:00
< p align = "center" >
< img src = "img/demo.gif" / >
2019-12-04 18:32:10 -06:00
< / p >
2019-12-04 19:21:34 -06:00
2019-12-04 20:01:47 -06:00
# Highlights
2019-12-16 09:48:23 -06:00
* Thread-safe progress bars and spinners
2019-12-04 21:10:58 -06:00
* Header-only library. Grab a copy of `include/indicators`
2019-12-04 20:13:44 -06:00
* Source for the above GIF can be found [here ](demo/demo.cpp )
2019-12-04 21:00:44 -06:00
* MIT License
2019-12-04 20:01:47 -06:00
2020-02-21 16:01:20 +05:30
```bash
git clone https://github.com/p-ranav/indicators
cd indicators
mkdir build & & cd build
cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..
make
```
2019-12-17 21:15:47 -06:00
# Table of Contents
* [Progress Bar ](#progress-bar )
* [Block Progress Bar ](#block-progress-bar )
* [Multi Progress ](#multiprogress )
* [Progress Spinner ](#progress-spinner )
* [Contributing ](#contributing )
* [License ](#license )
2019-12-04 19:32:32 -06:00
# Progress bar
2019-12-04 19:21:34 -06:00
2019-12-17 21:41:44 -06:00
To introduce a progress bar in your application, include `indicators/progress_bar.hpp` and create a `ProgressBar` object. Here's the general structure of a progress bar:
2019-12-16 11:07:16 -06:00
```
2019-12-17 10:05:44 -06:00
{prefix} {start} {fill} {lead} {remaining} {end} {percentage} [{elapsed}< {remaining}] {postfix}
2019-12-17 09:37:11 -06:00
^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^
2019-12-16 11:07:16 -06:00
```
The amount of progress in ProgressBar is maintained as a float in range `[0, 100]` . When progress reaches 100, the progression is complete.
2019-12-04 19:21:34 -06:00
From application-level code, there are two ways in which you can update this progress:
2019-12-04 20:42:30 -06:00
## Update progress using `bar.tick()`
2019-12-04 19:21:34 -06:00
You can update the progress bar using `bar.tick()` which increments progress by exactly `1%` .
2019-12-17 21:41:44 -06:00
< p align = "center" >
< img src = "img/progress_bar_tick.gif" / >
< / p >
2019-12-04 19:21:34 -06:00
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_bar.hpp>
2019-12-04 19:21:34 -06:00
#include <thread>
#include <chrono>
int main() {
2020-02-10 21:25:54 +01:00
using namespace indicators;
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
option::Fill{"="},
option::Lead{">"},
option::Remainder{" "},
option::End{"]"},
2020-02-13 14:20:40 +05:30
option::PostfixText{"Extracting Archive"},
option::ForegroundColor{Color::green}
2020-02-10 21:25:54 +01:00
};
2019-12-04 19:21:34 -06:00
// Update bar state
while (true) {
bar.tick();
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}
```
The above code will print a progress bar that goes from 0 to 100% at the rate of 1% every 100 ms.
2019-12-04 19:32:32 -06:00
## Updating progress using `bar.set_progress(value)`
2019-12-04 19:21:34 -06:00
If you'd rather control progress of the bar in discrete steps, consider using `bar.set_progress(value)` . Example:
2019-12-17 22:03:28 -06:00
2019-12-17 21:59:29 -06:00
< p align = "center" >
< img src = "img/progress_bar_set_progress.gif" / >
< / p >
2019-12-04 19:21:34 -06:00
```cpp
2019-12-17 22:02:40 -06:00
#include <chrono>
2019-12-04 21:10:58 -06:00
#include <indicators/progress_bar.hpp>
2019-12-04 19:21:34 -06:00
#include <thread>
int main() {
2019-12-17 22:02:40 -06:00
// Hide cursor
std::cout << "\e[?25l";
2020-02-10 21:25:54 +01:00
using namespace indicators;
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
option::Fill{"■"},
option::Lead{"■"},
option::Remainder{"-"},
option::End{" ]"},
option::PostfixText{"Loading dependency 1/4"},
2020-02-11 17:29:41 +05:30
option::ForegroundColor{Color::cyan}
2020-02-10 21:25:54 +01:00
};
2019-12-17 22:02:40 -06:00
2019-12-04 19:21:34 -06:00
// Update bar state
2019-12-05 15:55:55 -06:00
bar.set_progress(10); // 10% done
2019-12-17 22:02:40 -06:00
2019-12-05 15:55:55 -06:00
// do some work
2019-12-17 22:02:40 -06:00
std::this_thread::sleep_for(std::chrono::milliseconds(800));
2020-02-10 21:25:54 +01:00
bar.set_option(option::PostfixText{"Loading dependency 2/4"});
2019-12-17 22:02:40 -06:00
2019-12-05 15:55:55 -06:00
bar.set_progress(30); // 30% done
2019-12-17 22:02:40 -06:00
// do some more work
std::this_thread::sleep_for(std::chrono::milliseconds(700));
2020-02-10 21:25:54 +01:00
bar.set_option(option::PostfixText{"Loading dependency 3/4"});
2019-12-17 22:02:40 -06:00
2019-12-05 15:55:55 -06:00
bar.set_progress(65); // 65% done
2019-12-17 22:02:40 -06:00
2019-12-05 15:55:55 -06:00
// do final bit of work
2019-12-17 22:02:40 -06:00
std::this_thread::sleep_for(std::chrono::milliseconds(900));
2020-02-10 21:25:54 +01:00
bar.set_option(option::PostfixText{"Loaded dependencies!"});
2019-12-17 22:02:40 -06:00
2019-12-05 15:55:55 -06:00
bar.set_progress(100); // all done
2019-12-17 22:02:40 -06:00
bar.mark_as_completed();
// Show cursor
std::cout << "\e[?25h";
2019-12-04 19:21:34 -06:00
return 0;
}
```
2019-12-17 09:48:36 -06:00
## Showing Time Elapsed/Remaining
2019-12-17 10:01:41 -06:00
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 `[{elapsed}<{remaining}]` :
2019-12-17 09:48:36 -06:00
2019-12-17 09:59:15 -06:00
< p align = "center" >
< img src = "img/time_meter.gif" / >
< / p >
2019-12-17 09:48:36 -06:00
```cpp
2019-12-17 09:59:15 -06:00
#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
2020-02-10 21:25:54 +01:00
using namespace indicators;
indicators::ProgressBar bar{
option::BarWidth{50},
option::Start{" ["},
option::Fill{"█"},
option::Lead{"█"},
option::Remainder{"-"},
option::End{"]"},
2020-02-11 17:29:41 +05:30
option::PrefixText{"Training Gaze Network 👀"},
2020-02-13 14:20:40 +05:30
option::ForegroundColor{Color::yellow},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true}
2020-02-10 21:25:54 +01:00
};
2019-12-17 09:59:15 -06:00
// 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;
}
2019-12-17 09:48:36 -06:00
```
2019-12-16 10:53:53 -06:00
# Block Progress Bar
2019-12-16 09:26:49 -06:00
2019-12-16 09:29:19 -06:00
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.
2019-12-16 09:26:49 -06:00
< p align = "center" >
2019-12-16 10:22:14 -06:00
< img src = "img/block_progress_bar.gif" / >
2019-12-16 09:26:49 -06:00
< / p >
```cpp
2019-12-16 09:31:10 -06:00
#include <indicators/block_progress_bar.hpp>
#include <thread>
#include <chrono>
int main() {
// Hide cursor
std::cout << "\e[?25l";
2020-02-10 21:25:54 +01:00
using namespace indicators;
BlockProgressBar bar{
option::BarWidth{80},
option::Start{"["},
option::End{"]"},
2020-02-11 17:29:41 +05:30
option::ForegroundColor{Color::white}
2020-02-10 21:25:54 +01:00
};
2019-12-16 09:26:49 -06:00
// Update bar state
auto progress = 0.0f;
while (true) {
bar.set_progress(progress);
progress += 0.25f;
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
2019-12-16 09:31:10 -06:00
// Show cursor
std::cout << "\e[?25h";
return 0;
}
2019-12-16 09:26:49 -06:00
```
2019-12-17 20:28:18 -06:00
# MultiProgress
2019-12-18 12:46:08 -06:00
`indicators` supports management of multiple progress bars with the `MultiProgress` class template.
2019-12-17 20:36:39 -06:00
`template <typename Indicator, size_t count> class MultiProgress` is a class template that holds references to multiple progress bars and provides a safe interface to update the state of each bar. `MultiProgress` works with both `ProgressBar` and `BlockProgressBar` classes.
Below is an example `MultiProgress` object that manages three `ProgressBar` objects.
2019-12-17 20:28:18 -06:00
< p align = "center" >
< img src = "img/multi_progress.gif" / >
< / p >
```cpp
#include <indicators/multi_progress.hpp>
#include <indicators/progress_bar.hpp>
int main() {
2020-02-10 21:25:54 +01:00
using namespace indicators;
2019-12-17 20:36:39 -06:00
// Configure first progress bar
2020-02-10 21:25:54 +01:00
ProgressBar bar1{
option::BarWidth{50},
option::Start{"["},
option::Fill{"■"},
option::Lead{"■"},
option::Remainder{" "},
option::End{" ]"},
2020-02-11 17:29:41 +05:30
option::ForegroundColor{Color::yellow},
2020-02-10 21:25:54 +01:00
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #1 "}
};
2019-12-17 20:28:18 -06:00
2019-12-17 20:36:39 -06:00
// Configure second progress bar
2019-12-17 20:28:18 -06:00
2020-02-13 14:20:40 +05:30
ProgressBar bar2{
2020-02-10 21:25:54 +01:00
option::BarWidth{50},
option::Start{"["},
option::Fill{"="},
option::Lead{">"},
option::Remainder{" "},
option::End{" ]"},
2020-02-11 17:29:41 +05:30
option::ForegroundColor{Color::cyan},
2020-02-10 21:25:54 +01:00
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #2 "}
};
2019-12-17 20:36:39 -06:00
// Configure third progress bar
2020-02-10 21:25:54 +01:00
indicators::ProgressBar bar3{
option::BarWidth{50},
option::Start{"["},
option::Fill{"#"},
option::Lead{"#"},
option::Remainder{" "},
option::End{" ]"},
2020-02-11 17:29:41 +05:30
option::ForegroundColor{Color::red},
2020-02-10 21:25:54 +01:00
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #3 "}
};
2019-12-17 20:28:18 -06:00
2019-12-17 20:36:39 -06:00
// Construct MultiProgress object
2019-12-18 11:57:50 -06:00
indicators::MultiProgress< indicators::ProgressBar , 3 > bars(bar1, bar2, bar3);
2019-12-17 20:28:18 -06:00
std::cout << "Multiple Progress Bars:\n";
auto job1 = [& bars]() {
while (true) {
bars.tick< 0 > ();
if (bars.is_completed< 0 > ())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
};
auto job2 = [& bars]() {
while (true) {
bars.tick< 1 > ();
if (bars.is_completed< 1 > ())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
};
auto job3 = [& bars]() {
while (true) {
bars.tick< 2 > ();
if (bars.is_completed< 2 > ())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(60));
}
};
std::thread first_job(job1);
std::thread second_job(job2);
std::thread third_job(job3);
first_job.join();
second_job.join();
third_job.join();
return 0;
}
```
2019-12-04 19:51:29 -06:00
# Progress Spinner
2019-12-17 21:33:22 -06:00
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:
2019-12-16 11:07:16 -06:00
```
2019-12-17 09:37:11 -06:00
{prefix} {spinner} {percentage} [{elapsed}< {remaining}] {postfix}
2019-12-16 11:07:16 -06:00
```
2019-12-04 19:52:33 -06:00
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)` .
2019-12-04 19:51:29 -06:00
2019-12-17 21:33:22 -06:00
< p align = "center" >
< img src = "img/progress_spinner.gif" / >
< / p >
2019-12-04 19:51:29 -06:00
```cpp
2019-12-04 21:10:58 -06:00
#include <indicators/progress_spinner.hpp>
2019-12-04 19:51:29 -06:00
int main() {
2020-02-10 21:25:54 +01:00
using namespace indicators;
indicators::ProgressSpinner spinner{
option::PostfixText{"Checking credentials"},
2020-02-11 17:29:41 +05:30
option::ForegroundColor{Color::yellow},
2020-02-11 08:57:38 +01:00
option::SpinnerStates{std::vector< std::string > {"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}}
2020-02-10 21:25:54 +01:00
};
2019-12-04 19:51:29 -06:00
// Update spinner state
auto job = [& spinner]() {
while (true) {
if (spinner.is_completed()) {
2020-02-11 17:29:41 +05:30
spinner.set_option(option::ForegroundColor{Color::green});
2020-02-10 21:25:54 +01:00
spinner.set_option(option::PrefixText{"✔"});
2020-02-11 08:57:38 +01:00
spinner.set_option(option::ShowSpinner{false});
2020-02-10 21:25:54 +01:00
spinner.set_option(option::ShowPercentage{false});
spinner.set_option(option::PostfixText{"Authenticated!"});
2019-12-17 09:33:08 -06:00
spinner.mark_as_completed();
2019-12-04 19:51:29 -06:00
break;
} else
spinner.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
};
std::thread thread(job);
thread.join();
return 0;
}
```
2019-12-04 19:58:25 -06:00
## Contributing
Contributions are welcome, have a look at the [CONTRIBUTING.md ](CONTRIBUTING.md ) document for more information.
## License
The project is available under the [MIT ](https://opensource.org/licenses/MIT ) license.