# indicators
**Repository Path**: three_c/indicators
## Basic Information
- **Project Name**: indicators
- **Description**: Activity Indicators for Modern C++
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2020-03-07
- **Last Updated**: 2024-05-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Highlights
* Thread-safe progress bars and spinners
* Header-only library. Grab a copy of `include/indicators`
* Source for the above GIF can be found [here](demo/demo.cpp)
* MIT License
# Table of Contents
* [Progress Bar](#progress-bar)
* [Block Progress Bar](#block-progress-bar)
* [Multi Progress](#multiprogress)
* [Progress Spinner](#progress-spinner)
* [Contributing](#contributing)
* [License](#license)
# Progress bar
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:
```
{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.
From application-level code, there are two ways in which you can update this progress:
## Update progress using `bar.tick()`
You can update the progress bar using `bar.tick()` which increments progress by exactly `1%`.
```cpp
#include
#include
#include
int main() {
using namespace indicators;
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
option::Fill{"="},
option::Lead{">"},
option::Remainder{" "},
option::End{"]"},
option::PostfixText{"Extracting Archive"},
option::ForegroundColor{Color::green}
};
// 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.
## Updating progress using `bar.set_progress(value)`
If you'd rather control progress of the bar in discrete steps, consider using `bar.set_progress(value)`. Example:
```cpp
#include
#include
#include
int main() {
// Hide cursor
std::cout << "\e[?25l";
using namespace indicators;
ProgressBar bar{
option::BarWidth{50},
option::Start{"["},
option::Fill{"■"},
option::Lead{"■"},
option::Remainder{"-"},
option::End{" ]"},
option::PostfixText{"Loading dependency 1/4"},
option::ForegroundColor{Color::cyan}
};
// Update bar state
bar.set_progress(10); // 10% done
// do some work
std::this_thread::sleep_for(std::chrono::milliseconds(800));
bar.set_option(option::PostfixText{"Loading dependency 2/4"});
bar.set_progress(30); // 30% done
// do some more work
std::this_thread::sleep_for(std::chrono::milliseconds(700));
bar.set_option(option::PostfixText{"Loading dependency 3/4"});
bar.set_progress(65); // 65% done
// do final bit of work
std::this_thread::sleep_for(std::chrono::milliseconds(900));
bar.set_option(option::PostfixText{"Loaded dependencies!"});
bar.set_progress(100); // all done
bar.mark_as_completed();
// Show cursor
std::cout << "\e[?25h";
return 0;
}
```
## 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 `[{elapsed}<{remaining}]`:
```cpp
#include
#include
#include
int main() {
using namespace indicators;
indicators::ProgressBar bar{
option::BarWidth{50},
option::Start{" ["},
option::Fill{"█"},
option::Lead{"█"},
option::Remainder{"-"},
option::End{"]"},
option::PrefixText{"Training Gaze Network 👀"},
option::ForegroundColor{Color::yellow},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true}
};
// 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
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.
```cpp
#include
#include
#include
int main() {
// Hide cursor
std::cout << "\e[?25l";
using namespace indicators;
BlockProgressBar bar{
option::BarWidth{80},
option::Start{"["},
option::End{"]"},
option::ForegroundColor{Color::white}
};
// 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));
}
// Show cursor
std::cout << "\e[?25h";
return 0;
}
```
# MultiProgress
`indicators` supports management of multiple progress bars with the `MultiProgress` class template.
`template 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.
```cpp
#include
#include
int main() {
using namespace indicators;
// Configure first progress bar
ProgressBar bar1{
option::BarWidth{50},
option::Start{"["},
option::Fill{"■"},
option::Lead{"■"},
option::Remainder{" "},
option::End{" ]"},
option::ForegroundColor{Color::yellow},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #1 "}
};
// Configure second progress bar
ProgressBar bar2{
option::BarWidth{50},
option::Start{"["},
option::Fill{"="},
option::Lead{">"},
option::Remainder{" "},
option::End{" ]"},
option::ForegroundColor{Color::cyan},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #2 "}
};
// Configure third progress bar
indicators::ProgressBar bar3{
option::BarWidth{50},
option::Start{"["},
option::Fill{"#"},
option::Lead{"#"},
option::Remainder{" "},
option::End{" ]"},
option::ForegroundColor{Color::red},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::PrefixText{"Progress Bar #3 "}
};
// Construct MultiProgress object
indicators::MultiProgress bars(bar1, bar2, bar3);
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;
}
```
# 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:
```
{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)`.
```cpp
#include
int main() {
using namespace indicators;
indicators::ProgressSpinner spinner{
option::PostfixText{"Checking credentials"},
option::ForegroundColor{Color::yellow},
option::SpinnerStates{std::vector{"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"}}
};
// Update spinner state
auto job = [&spinner]() {
while (true) {
if (spinner.is_completed()) {
spinner.set_option(option::ForegroundColor{Color::green});
spinner.set_option(option::PrefixText{"✔"});
spinner.set_option(option::ShowSpinner{false});
spinner.set_option(option::ShowPercentage{false});
spinner.set_option(option::PostfixText{"Authenticated!"});
spinner.mark_as_completed();
break;
} else
spinner.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
};
std::thread thread(job);
thread.join();
return 0;
}
```
## 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.