Indicators
Activity Indicators for Modern C++
Install / Use
/learn @p-ranav/IndicatorsREADME
Highlights
- Thread-safe progress bars and spinners
- Header-only library. Grab a copy of
include/indicators. - Single-header version in
single_include/indicators. - Source for the above GIF can be found here
- MIT License
Table of Contents
- Supported Indicators
- Additional Samples
- Building Samples
- Generating Single Header
- Contributing
- License
Basic 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 size_t 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%.
#include <indicators/progress_bar.hpp>
#include <thread>
#include <chrono>
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},
option::ShowPercentage{true},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// 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:
#include <chrono>
#include <indicators/cursor_control.hpp>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
using namespace indicators;
// Hide cursor
show_console_cursor(false);
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},
option::ShowPercentage{true},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}} };
// 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
// Show cursor
show_console_cursor(true);
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 module, the format of this meter is [{elapsed}<{remaining}]:
#include <chrono>
#include <indicators/cursor_control.hpp>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
using namespace indicators;
// Hide cursor
show_console_cursor(false);
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::ShowPercentage{true},
option::ShowElapsedTime{true},
option::ShowRemainingTime{true},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// Update bar state
while (true) {
bar.tick();
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
// Show cursor
show_console_cursor(true);
return 0;
}
Indeterminate Progress Bar
You might have a use-case for a progress bar where the maximum amount of progress is unknown, e.g., you're downloading from a remote server that isn't advertising the total bytes.
Use an indicators::IndeterminateProgressBar for such cases. An IndeterminateProgressBar is similar to a regular progress bar except the total amount to progress towards is unknown. Ticking on this progress bar will happily run forever.
When you know progress is complete, simply call bar.mark_as_completed().
#include <chrono>
#include <indicators/indeterminate_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <indicators/termcolor.hpp>
#include <thread>
int main() {
indicators::IndeterminateProgressBar bar{
indicators::option::BarWidth{40},
indicators::option::Start{"["},
indicators::option::Fill{"·"},
indicators::option::Lead{"<==>"},
indicators::option::End{"]"},
indicators::option::PostfixText{"Checking for Updates"},
indicators::option::ForegroundColor{indicators::Color::yellow},
indicators::option::FontStyles{
std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
};
indicators::show_console_cursor(false);
auto job = [&bar]() {
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
bar.mark_as_completed();
std::cout << termcolor::bold << termcolor::green
<< "System is up to date!\n" << termcolor::reset;
};
std::thread job_completion_thread(job);
// Update bar state
while (!bar.is_completed()) {
bar.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
job_completion_thread.join();
indicators::show_console_cursor(true);
return 0;
}
Block Progress Bar
Are you in need of a smooth block progress bar using unicode block elements? Use BlockProgressBar instead of ProgressBar. Thanks to this blog post for making BlockProgressBar an easy addition to the library.
#include <indicators/block_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>
#include <chrono>
int main() {
using namespace indicators;
// Hide cursor
show_console_cursor(false);
BlockProgressBar bar{
option::BarWidth{80},
option::Start{"["},
option::End{"]"},
option::ForegroundColor{Color::white} ,
option::ShowPercentage{true},
option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
};
// 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
show_console_cursor(true);
return 0;
}
MultiProgress
indicators supports management of multiple progress bars with the MultiProgress class template.
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.
Use this class if you know the number of progress bars to manage at compile time.
Below is an example MultiProgress object that manages three ProgressBar objects.
#include <indicators/multi_progress.hpp>
#include <indicators/progress_bar.hpp>
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::yel
