Activity Indicators for Modern C++

Overview

ci status codacy license version

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

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::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::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::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 <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::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::yellow},
    option::ShowElapsedTime{true},
    option::ShowRemainingTime{true},
    option::PrefixText{"Progress Bar #1 "},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };

  // 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 "},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };
  
  // 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 "},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };

  // Construct MultiProgress object
  indicators::MultiProgress<indicators::ProgressBar, 3> 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;
}

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.

To add new progress bars, call bars.push_back(new_bar). This call will return the index of the appended bar. You can then refer to this bar with the indexing operator, e.g., bars[4].set_progress(55).

Use this class if you don't know the number of progress bars at compile time.

Below is an example DynamicProgress object that manages six ProgressBar objects. Three of these bars are added dynamically.

#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:

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).

#include <indicators/progress_spinner.hpp>

int main() {
  using namespace indicators;
  indicators::ProgressSpinner spinner{
    option::PostfixText{"Checking credentials"},
    option::ForegroundColor{Color::yellow},
    option::SpinnerStates{std::vector<std::string>{"", "", "", "", "", "", "", ""}},
    option::FontStyles{std::vector<FontStyle>{FontStyle::bold}}
  };
 
  // 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;
}

Decremental Progress

indicators allows you to easily control the progress direction, i.e., incremental or decremental progress by using option::ProgressType. To program a countdown progress bar, use option::ProgressType::decremental

#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
using namespace indicators;

int main() {

  ProgressBar bar{option::BarWidth{50},
                  option::ProgressType{ProgressType::decremental},
                  option::Start{"["},
                  option::Fill{""},
                  option::Lead{""},
                  option::Remainder{"-"},
                  option::End{"]"},
                  option::PostfixText{"Reverting System Restore"},
                  option::ForegroundColor{Color::yellow},
                  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));
  }

  std::cout << termcolor::bold << termcolor::white
            << "Task Failed Successfully\n" << termcolor::reset;

  return 0;
}

Working with Iterables

If you'd like to use progress bars to indicate progress while iterating over iterables, e.g., a list of numbers, this can be achieved by using the option::MaxProgress:

#include <chrono>
#include <indicators/block_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>

int main() {

  // Hide cursor
  indicators::show_console_cursor(false);

  // Random list of numbers
  std::vector<size_t> numbers;
  for (size_t i = 0; i < 1259438; ++i) {
      numbers.push_back(i);
  }

  using namespace indicators;
  BlockProgressBar bar{
    option::BarWidth{80},
    option::ForegroundColor{Color::white},
    option::FontStyles{
          std::vector<FontStyle>{FontStyle::bold}},
    option::MaxProgress{numbers.size()}
  };

  std::cout << "Iterating over a list of numbers (size = "
            << numbers.size() << ")\n";

  std::vector<size_t> result;
  for (size_t i = 0; i < numbers.size(); ++i) {

    // Perform some computation
    result.push_back(numbers[i] * numbers[i]);

    // Show iteration as postfix text
    bar.set_option(option::PostfixText{
      std::to_string(i) + "/" + std::to_string(numbers.size())
    });

    // update progress bar
    bar.tick();
  }

  bar.mark_as_completed();

  // Show cursor
  indicators::show_console_cursor(true);

  return 0;
}

Unicode Support

indicators supports multi-byte unicode characters in progress bars.

If the option::BarWidth is set, the library aims to respect this setting. When filling the bar, if the next Fill string has a display width that would exceed the bar width, then the library will fill the remainder of the bar with ' ' space characters instead.

See below an example of some progress bars, each with a bar width of 50, displaying different unicode characters:

#include <chrono>
#include <indicators/progress_bar.hpp>
#include <indicators/indeterminate_progress_bar.hpp>
#include <indicators/cursor_control.hpp>
#include <thread>

int main() {

    indicators::show_console_cursor(false);

    std::this_thread::sleep_for(std::chrono::milliseconds(2000));

    {
        // Plain old ASCII
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"="},
            indicators::option::Lead{">"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Plain-old ASCII"},
            indicators::option::ForegroundColor{indicators::Color::green},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Unicode
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"驚くばかり"},
            indicators::option::Lead{">"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Japanese"},
            indicators::option::ForegroundColor{indicators::Color::yellow},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Russian
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"Потрясающие"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Russian"},
            indicators::option::ForegroundColor{indicators::Color::red},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Greek
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"Φοβερός"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Greek"},
            indicators::option::ForegroundColor{indicators::Color::cyan},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Chinese
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"太棒了"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Chinese"},
            indicators::option::ForegroundColor{indicators::Color::green},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }        
    }

    {
        // Emojis
        indicators::ProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{"🔥"},
            indicators::option::Lead{"🔥"},
            indicators::option::Remainder{" "},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Emojis"},
            indicators::option::ForegroundColor{indicators::Color::white},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        // Update bar state
        while (true) {
            bar.tick();
            if (bar.is_completed())
            break;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    {
        // Indeterminate progress bar
        indicators::IndeterminateProgressBar bar{
            indicators::option::BarWidth{50},
            indicators::option::Start{"["},
            indicators::option::Fill{""},
            indicators::option::Lead{"載入中"},
            indicators::option::End{" ]"},
            indicators::option::PostfixText{"Loading Progress Bar"},
            indicators::option::ForegroundColor{indicators::Color::yellow},
            indicators::option::FontStyles{
                std::vector<indicators::FontStyle>{indicators::FontStyle::bold}}
        };

        auto job = [&bar]() {
            std::this_thread::sleep_for(std::chrono::milliseconds(10000));
            bar.mark_as_completed();
        };
        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;
}

Building Samples

git clone https://github.com/p-ranav/indicators
cd indicators
mkdir build && cd build
cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON ..
make

Generating Single Header

python3 utils/amalgamate/amalgamate.py -c single_include.json -s .

Contributing

Contributions are welcome, have a look at the CONTRIBUTING.md document for more information.

License

The project is available under the MIT license.

Comments
  • Make errors

    Make errors

    Just trying to build the source and examples - but using make - get the following error:

    [email protected]:~/Downloads/indicators-master/build$ make [ 3%] Building CXX object demo/CMakeFiles/demo.dir/demo.cpp.o /home/johughes/Downloads/indicators-master/demo/demo.cpp:1:10: fatal error: indicators.hpp: No such file or directory #include "indicators.hpp" ^~~~~~~~~~~~~~~~ compilation terminated. demo/CMakeFiles/demo.dir/build.make:62: recipe for target 'demo/CMakeFiles/demo.dir/demo.cpp.o' failed make[2]: *** [demo/CMakeFiles/demo.dir/demo.cpp.o] Error 1 CMakeFiles/Makefile2:85: recipe for target 'demo/CMakeFiles/demo.dir/all' failed make[1]: *** [demo/CMakeFiles/demo.dir/all] Error 2 Makefile:151: recipe for target 'all' failed make: *** [all] Error 2

    the previous cmake did not report any errors.

    opened by johughes99 11
  • API change - progress bar can be constructed with proper settings.

    API change - progress bar can be constructed with proper settings.

    Hi there!

    I would like to ask whether you would be open to the following changes.

    The rationale behind them is to make it possible, to create ProgressBar object with options given as constructor parameters, as with current approach it would extremaly difficult to do so.

    opened by dawidpilarski 7
  • Postfix string length grows

    Postfix string length grows

    Hello!

    I use prefix and postfix for my interface I use about 30 characters for postfix, but it prints 70 or more like this: -- Info Checksum is correct·········································

    My limit is 84 characters. Why does string length increase with empty characters?

    opened by dd4e 6
  • ProgressBar::tick() prints progress even if nothing has changed

    ProgressBar::tick() prints progress even if nothing has changed

    From my understanding calling tick() method will trigger the print function which will re-print the progress status regardless. Is this correct? Can I open a PR to update only if something has changed?

    https://github.com/p-ranav/indicators/blob/2291c8c39c031dda6007a68f8e725a0be5ba2ca7/include/indicators/progress_bar.hpp#L112-L119

    opened by amallia 6
  • remove bold output and default color to unspecified

    remove bold output and default color to unspecified

    Hi @p-ranav this is probably a bit controversial but I have modified the code so that a "unspecified" color is available (just the default color from the terminal) and made it the default. I also removed the default of making the font bold.

    Let me know if you don't want me to make these two things the default.

    Maybe we can add a setting for bold, and italic?

    opened by wolfv 5
  • "error: 'mutex' in namespace 'std' does not name a type"

    on windows, when I run the code, it will throw this error : "error: 'mutex' in namespace 'std' does not name a type". I google for it , somebody say "#include" cannt work on windows. I wanna know if there some solutions to solve this problem. thanks a lot.

    opened by qzylalala 5
  • Memoryleak on ProgressSpinner

    Memoryleak on ProgressSpinner

    D (03:00:03.997) HEAP: Iteration: 232000 (diff 304 bytes) V (03:00:04.006) Spinner: Created: 1407943886 V (03:00:04.011) Spinner: Destroyed: 1407943886 D (03:00:04.016) HEAP: Iteration: 231700 (diff 300 bytes) V (03:00:04.025) Spinner: Created: -1271674128 V (03:00:04.030) Spinner: Destroyed: -1271674128 D (03:00:04.035) HEAP: Iteration: 231396 (diff 304 bytes) V (03:00:04.044) Spinner: Created: 72749701 V (03:00:04.049) Spinner: Destroyed: 72749701 D (03:00:04.053) HEAP: Iteration: 231096 (diff 300 bytes) V (03:00:04.063) Spinner: Created: -1957109953 V (03:00:04.067) Spinner: Destroyed: -1957109953 D (03:00:04.073) HEAP: Iteration: 230792 (diff 304 bytes) V (03:00:04.082) Spinner: Created: 569508829 V (03:00:04.086) Spinner: Destroyed: 569508829 D (03:00:04.091) HEAP: Iteration: 230492 (diff 300 bytes)

    every instance 304 or 300 bytes leaked

    opened by drony 4
  • Can i re-use a prior defined bar rather than define two separated bars?

    Can i re-use a prior defined bar rather than define two separated bars?

    Is it possible to re-use a prior defined bar? as follows:

    using namespace indicators;
    indicators::ProgressBar bar {
            option::BarWidth{45},
            option::Start{"["},
            option::Fill{"■"},
            option::Lead{"■"},
            option::Remainder{" "},
            option::End{"]"},
            option::ShowPercentage{true},
            option::ShowElapsedTime{true},
            option::ShowRemainingTime{true},
            option::PrefixText{""}
    };
    
    bar.set_progress(0);
    for(int i = 0; i < 100; i++){
        bar.set_progress(i+1);
    }
    
    #re-use the bar again
    bar.set_progress(0);
    for(int j = 0; j < 100; j++){
        bar.set_progress(j+1);
    }
    

    The first works fine, but the second bar will be printed in a single new line for each update. So i am just wondering if there is a solution for this problem?

    Thanks.

    opened by YinLiLin 3
  • How to let indicator don't cover the print message?

    How to let indicator don't cover the print message?

    indicators is a great tool.

    it show the process dynamically, but when I need to print message in my code.

    the indicators bar will cover my print message will bar. and my message is disappeared.

    Is there any method can let me see the message, and indicators bar process meantime?

    opened by nickhuangxinyu 3
  • ProgressBar broken

    ProgressBar broken

    What could possibly be causing the progress bar to behave this way?

    image

    PS: I only updated the output to cerr instead of cout, but it should still work, right? If I use cout it doesn't print anything at all.

    opened by mirand863 3
  • Windows cursor movements

    Windows cursor movements

    The dynamic progress bar uses ANSI escape codes for moving up and erasing lines.

    This doesn't work on Windows (and I could not make it work using SetConsoleMode( ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_VIRTUAL_TERMINAL_INPUT ) either).

    I found the following library for go which seems great: https://github.com/k0kubun/go-ansi

    The following code works fine on Windows:

    namespace cursor
    {
        void move_up(int lines)
        {
            move(0, -lines);
        }
    
        void move_down(int lines)
        {
            move(0, -lines);
        }
    
        void move_left(int cols)
        {
            move(-cols, 0);
        }
    
        void move_up(int cols)
        {
            move(cols, 0);
        }
    
        void move(int x, int y) {
            auto hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
            if (!hStdout) return;
    
            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
            GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
    
            COORD cursor;
    
            cursor.X = csbiInfo.dwCursorPosition.X + x;
            cursor.Y = csbiInfo.dwCursorPosition.Y + y;
            SetConsoleCursorPosition(hStdout, cursor);
        }
    
    }
    

    It would be nice to have more abstractions (also around finding the terminal windows size). Do you want to integrate these facilities into this library or should we create another one?

    opened by wolfv 3
  • conversion to ‘float’ from ‘double’ may alter its value [-Werror=float-conversion]

    conversion to ‘float’ from ‘double’ may alter its value [-Werror=float-conversion]

    warning while converting double to float

    .../indicators/include/indicators/progress_bar.hpp: In member function ‘void indicators::ProgressBar::print_progress(bool)’: .../indicators/include/indicators/progress_bar.hpp:325:79: error: conversion to ‘float’ from ‘double’ may alter its value [-Werror=float-conversion] writer.write(double(progress_) / double(max_progress) * 100.0f); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ cc1plus: all warnings being treated as errors

    opened by IdoSagiv 0
  • Passing boost::optional ProgressBar handle (from inside DynamicProgress) to function for mutation

    Passing boost::optional ProgressBar handle (from inside DynamicProgress) to function for mutation

    Loving this repo so far, thanks for all your hard work. Any advice would be greatly appreciated. I've got a possible enhancement, but want to make sure I'm not missing anything on how I could do this via a workaround.

    In short, I'd like to have worker functions which can modify an optionally (via boost::optional) passed-in ProgressBar, which is inside a DynamicProgress in the application-level code.

    Say I have a a ProgressBars that I then pass into DynamicProgress dbar, like so:

    indicators::ProgressBar bar1{
          indicators::option::BarWidth{40},
          indicators::option::PrefixText{"progress bar 1"},
          indicators::option::PostfixText{"not mutated by function yet"}
    };
    indicators::ProgressBar bar2{
          indicators::option::BarWidth{40},
          indicators::option::PrefixText{"progress bar 2"},
          indicators::option::PostfixText{"not mutated by function yet"}
      };
    indicators::DynamicProgress<indicators::ProgressBar> dbar;
    dbar.push_back(bar1);
    dbar.push_back(bar2);
    

    I would then like to be able to pass the ProgressBar at dbar[0] to a function which mutates it, e.g. changes the progress or text, without having to pass the parent DynamicProgress. Being forced to pass the parent DynamicProgress is messy: it means that worker functions can't be passed individual progress bars without unnecessary code (e.g. having to first put the single progressbar in a dynamicprogress at the application level), and forces a clunky interface to the worker function because you also have to pass in the index of the bar inside the DynamicProgress.

    Minimum (not) working example of what I'd like to do:

    #include <indicators/progress_bar.hpp>
    #include <indicators/dynamic_progress.hpp>
    #include <boost/optional.hpp>
    
    void pbar_mutation_function(boost::optional<indicators::ProgressBar*> bar=boost::none);
    
    int main() {
        // build progressbars
        indicators::ProgressBar bar1{
            indicators::option::BarWidth{40},
            indicators::option::PrefixText{"progress bar 1"},
            indicators::option::PostfixText{"not mutated by function yet"}
        };
        indicators::ProgressBar bar2{
            indicators::option::BarWidth{40},
            indicators::option::PrefixText{"progress bar 2"},
            indicators::option::PostfixText{"not mutated by function yet"}
        };
        // insert it into a dynamic progress container
        indicators::DynamicProgress<indicators::ProgressBar> dbar;
        dbar.push_back(bar1);
        dbar.push_back(bar2);
        // pass the child progressbar "bar1" into mutation function
        pbar_mutation_function(&(dbar[0])); // this doesn't work :(
        return 0;
    }
    
    void pbar_mutation_function(boost::optional<indicators::ProgressBar*> bar){
        // update bar postfix text to notify you're in the mutation function
        if(bar){
          (*(*bar)).set_option(indicators::option::PostfixText{"inside bar mutation function"});
        }
        // in loop iterate up bar
        for(uint i=0; i<=100; i++){
          if(bar){
            (*(*bar)).set_option(indicators::option::PostfixText{"inside bar mutation function: i="+std::to_string(i)});
            (*(*bar)).tick();
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(5));
        }
        // mark bar as complete
        if(bar){
          (*(*bar)).mark_as_completed();
        }
    }
    

    Desired behavior of above example Two progress bars are initialized on the console, but only bar1 gets iterated up.

    Observed behavior Neither bar gets modified. image

    opened by tmcg0 0
  • [bug] Cannot compile the sample codes with MSVC compiler on Windows.

    [bug] Cannot compile the sample codes with MSVC compiler on Windows.

    Building Commands

    git clone https://github.com/p-ranav/indicators
    cd indicators
    mkdir build && cd build
    vcvarsall x64
    cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON -GNinja ..
    cmake --build .
    

    Platform and Version

    • OS+System: Windows 11
    • CMake Version: 3.21.2
    • Ninja Version: 1.10.2
    • Compiler+Version: MSVC 2019

    Logs

    • Click to expand log
      C:\CPackages\indicators>git clone https://github.com/p-ranav/indicators
      Cloning into 'indicators'...
      remote: Enumerating objects: 1997, done.
      remote: Counting objects: 100% (171/171), done.
      remote: Compressing objects: 100% (41/41), done.
      remote: Total 1997 (delta 83), reused 162 (delta 83), pack-reused 1826
      Receiving objects: 100% (1997/1997), 34.55 MiB | 7.26 MiB/s, done.
      Resolving deltas: 100% (1120/1120), done.
      
      C:\CPackages\indicators>cd indicators
      
      C:\CPackages\indicators\indicators>mkdir build && cd build
      
      C:\CPackages\indicators\indicators\build>vcvarsall x64
      **********************************************************************
      ** Visual Studio 2019 Developer Command Prompt v16.11.11
      ** Copyright (c) 2021 Microsoft Corporation
      **********************************************************************
      [vcvarsall.bat] Environment initialized for: 'x64'
      
      C:\CPackages\indicators\indicators\build>cmake -DINDICATORS_SAMPLES=ON -DINDICATORS_DEMO=ON -GNinja ..
      -- The CXX compiler identification is MSVC 19.29.30141.0
      -- Detecting CXX compiler ABI info
      -- Detecting CXX compiler ABI info - done
      -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
      -- Detecting CXX compile features
      -- Detecting CXX compile features - done
      -- Looking for C++ include pthread.h
      -- Looking for C++ include pthread.h - not found
      -- Found Threads: TRUE
      -- Configuring done
      -- Generating done
      -- Build files have been written to: C:/CPackages/indicators/indicators/build
      
      C:\CPackages\indicators\indicators\build>cmake --build .
      
    • Log of cmake --build . is too long, so I save it into a .txt file and upload it:

      CompileError.txt

    Screenshots

    image

    opened by hwhsu1231 0
  • [question] An `std::range_error` exception in `intermediate_progress_bar.cpp`.

    [question] An `std::range_error` exception in `intermediate_progress_bar.cpp`.

    LINK: https://github.com/p-ranav/indicators/blob/master/samples/indeterminate_progress_bar.cpp

    Source Code (in case of updating)

    Click to expand the Source Code
    #include <chrono>
    #include <indicators/cursor_control.hpp>
    #include <indicators/indeterminate_progress_bar.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;
    }
    

    Screenshots

    image

    opened by hwhsu1231 0
  • Compile error

    Compile error

    Hello I have the following error during compilation : D:\www\QT\untitled35\indicators\include\indicators\setting.hpp:184: erreur : C2955: 'indicators::details::option_idx': use of class template requires template argument list

    I'm just trying to compile the demo.cpp with qt creator (MSVC2019 64bits). I added the demo file and next setup the includepath in the .pro file. Any clue ? Regards

    opened by bzctoons 0
Releases(v2.2)
  • v2.2(May 3, 2021)

    • Fixed the NOMINMAX issue in MinGW build of indicators #76
    • Replaced #pragma once with #ifndef-define pairs to fix the single_include generation and avoid multiple-definition errors
    Source code(tar.gz)
    Source code(zip)
  • v2.1(May 3, 2021)

  • v2.0(Jan 7, 2021)

    • Closed #63 - Use unicode::display_width instead of os.str().size() in helper functions
    • Elevated #includes from being nested in the namespace.
    • Support older compilers with missing header.
    • Closed #67 - typo in terminal_size.hpp
    • Closed #68 - TERMCOLOR_HPP_ defined twice
    • Merged #69 to fix mingw compilation
    • Closed #72 - Using _WIN32 instead of _MSC_VER in macro and defining NOMINMAX correctly
    • Mitigated overflow when calculating ETA
    • Using floating point for remaining time calculation
    • Closed #80
    Source code(tar.gz)
    Source code(zip)
  • v1.9(May 25, 2020)

    • Fixed build issues in g++ caused by missing header #54
    • Auto-detecting terminal width to fill the remainder of the progress bar with empty spaces #56
      • Previously this was hard-coded to 10 spaces
    • Fixed multiple definitions in helper functions, e.g., cursor control #58
    • Implemented option::ProgressType which can be incremental or decremental - Provides an easy interface to implement decremental progress (a regressing bar) #59
    • Updated to latest version of termcolor #60
    • Improved Unicode support in progress bar
    Source code(tar.gz)
    Source code(zip)
  • v1.8(May 16, 2020)

    • IndeterminateProgressBar for modeling bars with unknown totals #43 #51
    • option::MaxProgress to configure the maximum progress for the bar. Default is 100. This enables sweeping over iterables, e.g., a vector of numbers. Example.
    • option::Stream to configure the output stream of progress bars, e.g., using std::stringstream or std::cerr instead of std::cout #22
    • option::FontStyles. The user can specify a vector of font styles, e.g., bold, italic etc. for the progress bar #38
    • New default for progress bar color: Color::unspecified
    • Abstraction for Cursor Movements to work better with Windows #48
    • Show/hide console cursor - Enables hiding the console cursor when progress bar is ticking - Removes the annoying flicker #48
    • Using amalgamate to generate single_include header file.
    Source code(tar.gz)
    Source code(zip)
  • v1.7(Feb 21, 2020)

    • Added DynamicProgress class for managing multiple progress bars dynamically https://github.com/p-ranav/indicators/pull/32
    • Fixed code style - Member names starting with underscore _ https://github.com/p-ranav/indicators/issues/24
    Source code(tar.gz)
    Source code(zip)
  • v1.6(Feb 11, 2020)

    • API Change - Progress bars can be constructed with a Settings object - create ProgressBar object with options given as constructor parameters #21
    • Added pkg-config file to make it easier to consume this package in build systems that support it, such as autotools, Meson, waf, SCons and build2 #27
    • In MultiProgress, elapsed time of each bar is now updated independently, instead of together #18
    • Remove code duplication and refactored for reuse #14 #15 #16 #17
    Source code(tar.gz)
    Source code(zip)
  • v1.5(Dec 18, 2019)

  • v1.4(Dec 18, 2019)

  • v1.3(Dec 17, 2019)

  • v1.2(Dec 17, 2019)

  • v1.1(Dec 16, 2019)

Owner
Pranav
Pranav
KDevelop plugin for automatic time tracking and metrics generated from your programming activity.

Wakatime KDevelop Plugin Installation instructions Make sure the project is configured to install to the directory of your choice: In KDevelop, select

snotr 6 Oct 13, 2021
Pretty Printer for Modern C++

Highlights Single header file Requires C++17 MIT License Quick Start Simply include pprint.hpp and you're good to go. #include <pprint.hpp> To start p

Pranav 879 Dec 22, 2022
Gaming meets modern C++ - a fast and reliable entity component system (ECS) and much more

EnTT is a header-only, tiny and easy to use library for game programming and much more written in modern C++. Among others, it's used in Minecraft by

Michele Caini 7.6k Dec 30, 2022
Nameof operator for modern C++, simply obtain the name of a variable, type, function, macro, and enum

_ _ __ _____ | \ | | / _| / ____|_ _ | \| | __ _ _ __ ___ ___ ___ | |_ | | _| |

Daniil Goncharov 1.5k Jan 8, 2023
Random for modern C++ with convenient API

Random for modern C++ with convenient API Design goals Supported compilers Integration Five-minute tutorial Number range Common type number range Char

Ilya Polishchuk 748 Jan 7, 2023
A Minimal, Header only Modern c++ library for terminal goodies 💄✨

rang Colors for your Terminal. Windows Demo Example usage #include "rang.hpp" using namespace std; using namespace rang; int main() { cout << "P

Abhinav Gauniyal 1.3k Dec 30, 2022
A modern C++ tweening library

Tweeny Tweeny is an inbetweening library designed for the creation of complex animations for games and other beautiful interactive software. It levera

Leonardo Guilherme de Freitas 578 Dec 22, 2022
Table Maker for Modern C++

Source for the above image can be found here Table of Contents Quick Start Formatting Options Style Inheritance Model Word Wrapping Font Alignment Fon

Pranav 1.4k Dec 30, 2022
🏢 A bold, unapologetic, and honest operating system written in modern C

A bold, unapologetic, and honest operating system written in modern C About Striking modernist shapes and bold use of modern C are the hallmarks of BR

Brutal 929 Jan 5, 2023
🏢 An operating system that combine the desire of UNIX utopia from the 1970s with modern technology and engineering

Striking modernist shapes and bold use of modern C are the hallmarks of BRUTAL. BRUTAL combine the desire of UNIX utopia from the 1970s with modern te

Brutal 924 Dec 27, 2022
"Sigma File Manager" is a free, open-source, quickly evolving, modern file manager (explorer / finder) app for Windows, MacOS, and Linux.

"Sigma File Manager" is a free, open-source, quickly evolving, modern file manager (explorer / finder) app for Windows, MacOS, and Linux.

Aleksey Hoffman 1.1k Dec 31, 2022
Ceres is designed to be a modern and minimalistic C like language.

Ceres v0.0.1 Ceres is designed to be a modern and minimalistic C like language. For now, it will be interpreted but later on I do want to write a comp

null 9 May 18, 2022
External CS:GO hack for Arduino written using modern C++ and WinAPI

SQ Project CSGO Arduino Edition External CS:GO hack for Arduino written using C++ and WinAPI. Special thanks to hazedumper for hazedumper. Shock Byte

Klim Markevich 34 Dec 29, 2022
Enoki: structured vectorization and differentiation on modern processor architectures

Enoki: structured vectorization and differentiation on modern processor architectures

Mitsuba Physically Based Renderer 1.2k Dec 25, 2022
Modern C++ 20 compile time OpenAPI parser and code generator implementation

OpenApi++ : openapipp This is a proof of concept, currently under active work to become the best OpenAPI implementation for C++. It allows compile tim

tipi.build 10 Jan 5, 2023
A secure authentication system written in modern javascript and C++ 17

A fully fledged authentication system written in modern JavaScript and C++ 17. Written with the MEVN stack (MySQL, Express.js, Vue.js, Node.js) by a pro leet h4x0r.

vmexit 25 Nov 29, 2022
A modern-day Boss Key software tool. Switch instantly from work to play & play to work with Bosky.

Bosky By: Seanpm2001, Bosky-dev Et; Al. Top README.md Read this article in a different language Sorted by: A-Z Sorting options unavailable ( af Afrika

Sean P. Myrick V19.1.7.2 2 Sep 10, 2022