44 Commits
v1.0 ... v1.2

Author SHA1 Message Date
Pranav
74674154f5 Update README.md 2019-12-17 10:01:41 -06:00
Pranav
c42ae6862e Merge pull request #10 from p-ranav/feature/time
Feature/time
2019-12-17 10:00:23 -06:00
Pranav Srinivas Kumar
1e45ef3530 Updated README 2019-12-17 09:59:15 -06:00
Pranav Srinivas Kumar
d5a1c9a440 Update README 2019-12-17 09:48:36 -06:00
Pranav Srinivas Kumar
8c37f2f1dc Update README 2019-12-17 09:44:50 -06:00
Pranav Srinivas Kumar
aa5dffa4e2 Time elapsed/remaining is hidden by default 2019-12-17 09:43:53 -06:00
Pranav
78b7abcfbd Update README.md 2019-12-17 09:37:11 -06:00
Pranav Srinivas Kumar
fdad265e99 Update README 2019-12-17 09:35:52 -06:00
Pranav Srinivas Kumar
f28ab68c60 Updated README 2019-12-17 09:33:08 -06:00
Pranav Srinivas Kumar
6224a46371 Updated samples/demos to show usage of hide/show time elapsed/remaining 2019-12-17 09:31:43 -06:00
Pranav Srinivas Kumar
8198d8a802 Added time elapsed/remaining meter for progress spinner 2019-12-17 09:20:10 -06:00
Pranav Srinivas Kumar
5360fec641 Added time elapsed/remaining meter for block progress bar 2019-12-17 09:13:48 -06:00
Pranav Srinivas Kumar
c770704697 Draft implementation of time elapsed/remaining meter 2019-12-17 09:06:46 -06:00
Pranav Srinivas Kumar
97c89284a9 Clang format 2019-12-17 09:06:36 -06:00
Pranav
24d92beaca Merge pull request #9 from offa/cmake_samples
CMake support for Demo and Samples
2019-12-16 11:58:08 -06:00
offa
fe38859715 CMake support for building the demo added. 2019-12-16 18:49:06 +01:00
offa
ab63e2c45b CMake support for building the samples added. 2019-12-16 18:45:19 +01:00
Pranav
9d951f5e82 Update README.md 2019-12-16 11:07:16 -06:00
Pranav Srinivas Kumar
36ec8bb4d2 Merge branch 'master' of github.com:p-ranav/indicators 2019-12-16 11:03:36 -06:00
Pranav Srinivas Kumar
094f25e012 Added progress bar samples 2019-12-16 11:03:31 -06:00
Pranav
e9feed8aa1 Update README.md 2019-12-16 11:00:38 -06:00
Pranav
2b67c02ba6 Update README.md 2019-12-16 10:53:53 -06:00
Pranav
4c9ed35080 Update README.md 2019-12-16 10:22:14 -06:00
Pranav Srinivas Kumar
5f35000071 Merge branch 'master' of github.com:p-ranav/indicators 2019-12-16 10:19:55 -06:00
Pranav Srinivas Kumar
fb2d9bddbe Added progress spinner sample 2019-12-16 10:19:47 -06:00
Pranav
e7d0135316 Update README.md 2019-12-16 09:48:23 -06:00
Pranav Srinivas Kumar
2edbccce9c Updated README 2019-12-16 09:31:10 -06:00
Pranav
e6ae6c5513 Update README.md 2019-12-16 09:29:19 -06:00
Pranav Srinivas Kumar
1c2e7d5bd1 Updated README 2019-12-16 09:28:55 -06:00
Pranav Srinivas Kumar
b6d0ec0ee0 Updated README 2019-12-16 09:26:49 -06:00
Pranav Srinivas Kumar
cb879b5eb1 Added block progress bar GIF 2019-12-16 09:24:22 -06:00
Pranav
25001ceb1f Merge pull request #8 from p-ranav/feature/block_progress_bar
Feature/block progress bar
2019-12-16 09:12:37 -06:00
Pranav Srinivas Kumar
21391f3ca0 Added sample for smooth block progress bar 2019-12-16 09:11:25 -06:00
Pranav Srinivas Kumar
55f9eb7c67 Updated smooth block progress bar update logic 2019-12-16 09:07:57 -06:00
Pranav Srinivas Kumar
a516957135 Draft implementation of smooth block progress bar 2019-12-16 08:48:42 -06:00
Pranav
56489bf37a Merge pull request #6 from myd7349/fix-headers-installation
Improve CMakeLists.txt
2019-12-14 07:00:42 -06:00
myd7349
8f903b9741 Improve CMakeLists.txt
- Fix headers installation;
- Handle Threads dependency automatically;
2019-12-14 18:21:40 +08:00
Pranav
a938eb8f4c Update progress_spinner.hpp 2019-12-12 15:15:01 -06:00
Pranav
9e088af612 Update progress_bar.hpp 2019-12-12 15:14:38 -06:00
Pranav Srinivas KumaR
a41c7c118e Closes #2 2019-12-05 19:55:28 -06:00
Pranav Srinivas KumaR
cde4dbd83c Added termcolor LICENSE 2019-12-05 19:49:32 -06:00
Pranav
6f69ca5246 Update README.md 2019-12-05 15:56:17 -06:00
Pranav
d3ef0b0209 Update README.md 2019-12-05 15:55:55 -06:00
Pranav
3012fa78cf Update README.md 2019-12-05 12:59:23 -06:00
19 changed files with 817 additions and 54 deletions

View File

@@ -1,9 +1,14 @@
cmake_minimum_required(VERSION 3.8)
project(indica VERSION 1.0.0 LANGUAGES CXX)
option(INDICA_BUILD_TESTS OFF)
option(SAMPLES "Build Samples" OFF)
option(DEMO "Build Demo" OFF)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
find_package(Threads REQUIRED)
add_library(indica INTERFACE)
add_library(indica::indica ALIAS indica)
@@ -11,10 +16,29 @@ target_compile_features(indica INTERFACE cxx_std_11)
target_include_directories(indica INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
target_link_libraries(indica INTERFACE Threads::Threads)
install(TARGETS indica EXPORT indicaConfig)
install(EXPORT indicaConfig
if( DEMO )
add_subdirectory(demo)
endif()
if( SAMPLES )
add_subdirectory(samples)
endif()
configure_package_config_file(indicaConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/indicaConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/indica)
install(TARGETS indica EXPORT indicaTargets)
install(EXPORT indicaTargets
FILE indicaTargets.cmake
NAMESPACE indica::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/indica)
install(FILES ${CMAKE_CURRENT_LIST_DIR}/include/indica.hpp
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/indica)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/indicaConfig.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/indica)
install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/indicators
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
USE_SOURCE_PERMISSIONS
PATTERN "*.hpp")

31
LICENSE.termcolor Normal file
View File

@@ -0,0 +1,31 @@
Copyright (c) 2013, Ihor Kalnytskyi.
All rights reserved.
Redistribution and use in source and binary forms of the software as well
as documentation, with or without modification, are permitted provided
that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

155
README.md
View File

@@ -6,7 +6,7 @@
<a href="https://github.com/p-ranav/indicators/blob/master/LICENSE">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="license"/>
</a>
<img src="https://img.shields.io/badge/version-1.0-blue.svg?cacheSeconds=2592000" alt="version"/>
<img src="https://img.shields.io/badge/version-1.1-blue.svg?cacheSeconds=2592000" alt="version"/>
</p>
<p align="center">
@@ -15,7 +15,7 @@
# Highlights
* Thread-safe `ProgressBar` and `ProgressSpinner` classes
* 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
@@ -27,24 +27,6 @@ To introduce a progress bar in your application, include `indicators/progress_ba
```cpp
#include <indicators/progress_bar.hpp>
int main() {
indicators::ProgressBar bar;
return 0;
}
```
Here's the general structure of a progress bar:
```
<prefix_text> <bar_start> <fill> <lead> <remaining> <bar_end> <progress_percentage>? <postfix_text>
^^^^^^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^^^^ ^^^^^ Show/Hide ^^^^^
```
Each of these elements (and more) can be configured using the ProgressBar API. Here's an example configuration:
```cpp
#include <indicators/progress_bar.hpp>
int main() {
indicators::ProgressBar bar;
@@ -56,7 +38,7 @@ int main() {
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
bar.set_foreground_color(indicators::Color::GREEN);
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
@@ -64,7 +46,14 @@ int main() {
}
```
Now that the bar is configured, let's update the state of the bar. The amount of progress in ProgressBar is maintained as a float in range `[0, 100]`. When progress reaches 100, the progression is complete.
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:
@@ -127,19 +116,28 @@ int main() {
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
size_t i = 0;
while (i < 101) {
bar.set_progress(i);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
i += 10;
}
bar.set_progress(10); // 10% done
// do some work
std::this_thread::sleep_for(std::chrono::milliseconds(100));
bar.set_progress(30); // 30% done
// do some more work
std::this_thread::sleep_for(std::chrono::milliseconds(600));
bar.set_progress(65); // 65% done
// do final bit of work
std::this_thread::sleep_for(std::chrono::milliseconds(300));
bar.set_progress(100); // all done
return 0;
}
```
The above code will print a progress bar that goes from 0 to 100% at the rate of 10% every 100 ms.
## Multi-threaded Example
```cpp
@@ -208,28 +206,97 @@ int main() {
}
```
For more examples, checkout the examples in the `samples/` directory.
## Showing Time Elapsed/Remaining
# Progress Spinner
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}]`:
To introduce a progress spinner in your application, include `indicators/progress_spinner.hpp` and create a `ProgressSpinner` object.
<p align="center">
<img src="img/time_meter.gif"/>
</p>
```cpp
#include <indicators/progress_spinner.hpp>
#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
indicators::ProgressSpinner spinner;
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with(" [");
bar.fill_bar_progress_with("");
bar.lead_bar_progress_with("");
bar.fill_bar_remainder_with("-");
bar.end_bar_with("]");
bar.set_prefix_text("Training Gaze Network 👀");
bar.set_foreground_color(indicators::Color::YELLOW);
// Show time elapsed and remaining
bar.show_elapsed_time();
bar.show_remaining_time();
// 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;
}
```
Here's the general structure of a progress spinner:
# Block Progress Bar
```
<prefix_text> <spinner> <progress_percentage>? <postfix_text>
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.
<p align="center">
<img src="img/block_progress_bar.gif"/>
</p>
```cpp
#include <indicators/block_progress_bar.hpp>
#include <thread>
#include <chrono>
int main() {
// Hide cursor
std::cout << "\e[?25l";
indicators::BlockProgressBar bar;
// Configure the bar
bar.set_bar_width(80);
bar.start_bar_with("[");
bar.end_bar_with("]");
bar.set_foreground_color(indicators::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;
}
```
Each of these elements (and more) can be configured using the ProgressSpinner API. Here's an example configuration:
# Progress Spinner
To introduce a progress spinner in your application, include `indicators/progress_spinner.hpp` and create a `ProgressSpinner` object.
```cpp
#include <indicators/progress_spinner.hpp>
@@ -249,6 +316,12 @@ int main() {
}
```
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
@@ -271,7 +344,7 @@ int main() {
spinner.hide_spinner();
spinner.hide_percentage();
spinner.set_postfix_text("Authenticated!");
spinner.mark_as_completed();
spinner.mark_as_completed();
break;
} else
spinner.tick();

View File

@@ -1,2 +1,2 @@
#!/usr/bin/env bash
find ./include ./demo/ -type f \( -iname \*.cpp -o -iname \*.hpp \) | xargs clang-format -style="{ColumnLimit : 100}" -i
find ./include ./demo/ ./samples/ -type f \( -iname \*.cpp -o -iname \*.hpp \) | xargs clang-format -style="{ColumnLimit : 100}" -i

2
demo/CMakeLists.txt Normal file
View File

@@ -0,0 +1,2 @@
add_executable(demo demo.cpp)
target_link_libraries(demo PRIVATE indica::indica)

BIN
img/block_progress_bar.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
img/progress_spinner.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
img/time_meter.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,247 @@
/*
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 <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <indicators/color.hpp>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
namespace indicators {
class BlockProgressBar {
public:
void set_foreground_color(Color color) {
std::unique_lock<std::mutex> lock{_mutex};
_foreground_color = color;
}
void set_bar_width(size_t bar_width) {
std::unique_lock<std::mutex> lock{_mutex};
_bar_width = bar_width;
}
void start_bar_with(const std::string &start) {
std::unique_lock<std::mutex> lock{_mutex};
_start = start;
}
void end_bar_with(const std::string &end) {
std::unique_lock<std::mutex> lock{_mutex};
_end = end;
}
void set_prefix_text(const std::string &text) {
std::unique_lock<std::mutex> lock{_mutex};
_prefix_text = text;
}
void set_postfix_text(const std::string &text) {
std::unique_lock<std::mutex> lock{_mutex};
_postfix_text = text;
if (_postfix_text.length() > _max_postfix_text_length)
_max_postfix_text_length = _postfix_text.length();
}
void show_percentage() { _show_percentage = true; }
void hide_percentage() { _show_percentage = false; }
void show_elapsed_time() { _show_elapsed_time = true; }
void hide_elapsed_time() { _show_elapsed_time = false; }
void show_remaining_time() { _show_remaining_time = true; }
void hide_remaining_time() { _show_remaining_time = false; }
void set_progress(float value) {
{
std::unique_lock<std::mutex> lock{_mutex};
_progress = value;
}
_save_start_time();
_print_progress();
}
void tick() {
{
std::unique_lock<std::mutex> lock{_mutex};
_progress += 1;
}
_save_start_time();
_print_progress();
}
size_t current() { return std::min(static_cast<size_t>(_progress), size_t(100)); }
bool is_completed() const { return _completed; }
void mark_as_completed() {
_completed = true;
_print_progress();
}
private:
float _progress{0.0};
size_t _bar_width{100};
std::string _prefix_text{""};
std::string _start{"["};
std::string _fill{""};
std::string _lead{" "};
std::string _remainder{" "};
std::string _end{"]"};
std::string _postfix_text{""};
std::atomic<size_t> _max_postfix_text_length{0};
std::atomic<bool> _completed{false};
std::atomic<bool> _show_percentage{true};
std::atomic<bool> _show_elapsed_time{false};
std::atomic<bool> _show_remaining_time{false};
std::atomic<bool> _saved_start_time{false};
std::chrono::time_point<std::chrono::high_resolution_clock> _start_time_point;
std::mutex _mutex;
Color _foreground_color;
std::ostream &_print_duration(std::ostream &os, std::chrono::nanoseconds ns) {
using namespace std;
using namespace std::chrono;
typedef duration<int, ratio<86400>> days;
char fill = os.fill();
os.fill('0');
auto d = duration_cast<days>(ns);
ns -= d;
auto h = duration_cast<hours>(ns);
ns -= h;
auto m = duration_cast<minutes>(ns);
ns -= m;
auto s = duration_cast<seconds>(ns);
if (d.count() > 0)
os << setw(2) << d.count() << "d:";
if (h.count() > 0)
os << setw(2) << h.count() << "h:";
os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's';
os.fill(fill);
return os;
};
void _save_start_time() {
if ((_show_elapsed_time || _show_remaining_time) && !_saved_start_time) {
_start_time_point = std::chrono::high_resolution_clock::now();
_saved_start_time = true;
}
}
void _print_progress() {
std::unique_lock<std::mutex> lock{_mutex};
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - _start_time_point);
std::cout << termcolor::bold;
switch (_foreground_color) {
case Color::GREY:
std::cout << termcolor::grey;
break;
case Color::RED:
std::cout << termcolor::red;
break;
case Color::GREEN:
std::cout << termcolor::green;
break;
case Color::YELLOW:
std::cout << termcolor::yellow;
break;
case Color::BLUE:
std::cout << termcolor::blue;
break;
case Color::MAGENTA:
std::cout << termcolor::magenta;
break;
case Color::CYAN:
std::cout << termcolor::cyan;
break;
case Color::WHITE:
std::cout << termcolor::white;
break;
}
std::cout << _prefix_text;
std::cout << _start;
std::vector<std::string> lead_characters{" ", "", "", "", "", "", "", ""};
auto progress = std::min(1.0f, std::max(0.0f, _progress / 100.0f));
auto whole_width = std::floor(progress * _bar_width);
auto remainder_width = fmod((progress * _bar_width), 1.0f);
auto part_width = std::floor(remainder_width * lead_characters.size());
_lead = lead_characters[part_width];
if ((_bar_width - whole_width - 1) < 0)
_lead = "";
for (size_t i = 0; i < whole_width; ++i)
std::cout << _fill;
std::cout << _lead;
for (size_t i = 0; i < (_bar_width - whole_width - 1); ++i)
std::cout << " ";
std::cout << _end;
if (_show_percentage) {
std::cout << " " << std::min(static_cast<size_t>(_progress), size_t(100)) << "%";
}
if (_show_elapsed_time) {
std::cout << " [";
_print_duration(std::cout, elapsed);
}
if (_show_remaining_time) {
if (_show_elapsed_time)
std::cout << "<";
else
std::cout << " [";
auto eta = std::chrono::nanoseconds(
_progress > 0 ? static_cast<long long>(elapsed.count() * 100 / _progress) : 0);
auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
_print_duration(std::cout, remaining);
std::cout << "]";
}
if (_max_postfix_text_length == 0)
_max_postfix_text_length = 10;
std::cout << " " << _postfix_text << std::string(_max_postfix_text_length, ' ') << "\r";
std::cout.flush();
if (_progress > 100.0) {
_completed = true;
}
if (_completed)
std::cout << termcolor::reset << std::endl;
}
};
} // namespace indicators

View File

@@ -25,8 +25,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <indicators/color.hpp>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <string>
@@ -87,11 +91,20 @@ public:
void hide_percentage() { _show_percentage = false; }
void show_elapsed_time() { _show_elapsed_time = true; }
void hide_elapsed_time() { _show_elapsed_time = false; }
void show_remaining_time() { _show_remaining_time = true; }
void hide_remaining_time() { _show_remaining_time = false; }
void set_progress(float value) {
{
std::unique_lock<std::mutex> lock{_mutex};
_progress = value;
}
_save_start_time();
_print_progress();
}
@@ -100,13 +113,11 @@ public:
std::unique_lock<std::mutex> lock{_mutex};
_progress += 1;
}
_save_start_time();
_print_progress();
}
size_t current() {
std::unique_lock<std::mutex> lock{_mutex};
return std::min(static_cast<size_t>(_progress), size_t(100));
}
size_t current() { return std::min(static_cast<size_t>(_progress), size_t(100)); }
bool is_completed() const { return _completed; }
@@ -128,11 +139,47 @@ private:
std::atomic<size_t> _max_postfix_text_length{0};
std::atomic<bool> _completed{false};
std::atomic<bool> _show_percentage{true};
std::atomic<bool> _show_elapsed_time{false};
std::atomic<bool> _show_remaining_time{false};
std::atomic<bool> _saved_start_time{false};
std::chrono::time_point<std::chrono::high_resolution_clock> _start_time_point;
std::mutex _mutex;
Color _foreground_color;
std::ostream &_print_duration(std::ostream &os, std::chrono::nanoseconds ns) {
using namespace std;
using namespace std::chrono;
typedef duration<int, ratio<86400>> days;
char fill = os.fill();
os.fill('0');
auto d = duration_cast<days>(ns);
ns -= d;
auto h = duration_cast<hours>(ns);
ns -= h;
auto m = duration_cast<minutes>(ns);
ns -= m;
auto s = duration_cast<seconds>(ns);
if (d.count() > 0)
os << setw(2) << d.count() << "d:";
if (h.count() > 0)
os << setw(2) << h.count() << "h:";
os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's';
os.fill(fill);
return os;
};
void _save_start_time() {
if ((_show_elapsed_time || _show_remaining_time) && !_saved_start_time) {
_start_time_point = std::chrono::high_resolution_clock::now();
_saved_start_time = true;
}
}
void _print_progress() {
std::unique_lock<std::mutex> lock{_mutex};
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - _start_time_point);
std::cout << termcolor::bold;
switch (_foreground_color) {
case Color::GREY:
@@ -175,6 +222,24 @@ private:
if (_show_percentage) {
std::cout << " " << std::min(static_cast<size_t>(_progress), size_t(100)) << "%";
}
if (_show_elapsed_time) {
std::cout << " [";
_print_duration(std::cout, elapsed);
}
if (_show_remaining_time) {
if (_show_elapsed_time)
std::cout << "<";
else
std::cout << " [";
auto eta = std::chrono::nanoseconds(
_progress > 0 ? static_cast<long long>(elapsed.count() * 100 / _progress) : 0);
auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
_print_duration(std::cout, remaining);
std::cout << "]";
}
if (_max_postfix_text_length == 0)
_max_postfix_text_length = 10;
std::cout << " " << _postfix_text << std::string(_max_postfix_text_length, ' ') << "\r";

View File

@@ -25,8 +25,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <indicators/color.hpp>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <string>
@@ -58,6 +62,14 @@ public:
void hide_percentage() { _show_percentage = false; }
void show_elapsed_time() { _show_elapsed_time = true; }
void hide_elapsed_time() { _show_elapsed_time = false; }
void show_remaining_time() { _show_remaining_time = true; }
void hide_remaining_time() { _show_remaining_time = false; }
void show_spinner() { _show_spinner = true; }
void hide_spinner() { _show_spinner = false; }
@@ -67,6 +79,7 @@ public:
std::unique_lock<std::mutex> lock{_mutex};
_progress = value;
}
_save_start_time();
_print_progress();
}
@@ -75,13 +88,11 @@ public:
std::unique_lock<std::mutex> lock{_mutex};
_progress += 1;
}
_save_start_time();
_print_progress();
}
size_t current() {
std::unique_lock<std::mutex> lock{_mutex};
return std::min(static_cast<size_t>(_progress), size_t(100));
}
size_t current() { return std::min(static_cast<size_t>(_progress), size_t(100)); }
bool is_completed() const { return _completed; }
@@ -104,12 +115,48 @@ private:
std::atomic<size_t> _max_postfix_text_length{0};
std::atomic<bool> _completed{false};
std::atomic<bool> _show_percentage{true};
std::atomic<bool> _show_elapsed_time{false};
std::atomic<bool> _show_remaining_time{false};
std::atomic<bool> _saved_start_time{false};
std::chrono::time_point<std::chrono::high_resolution_clock> _start_time_point;
std::atomic<bool> _show_spinner{true};
std::mutex _mutex;
Color _foreground_color;
std::ostream &_print_duration(std::ostream &os, std::chrono::nanoseconds ns) {
using namespace std;
using namespace std::chrono;
typedef duration<int, ratio<86400>> days;
char fill = os.fill();
os.fill('0');
auto d = duration_cast<days>(ns);
ns -= d;
auto h = duration_cast<hours>(ns);
ns -= h;
auto m = duration_cast<minutes>(ns);
ns -= m;
auto s = duration_cast<seconds>(ns);
if (d.count() > 0)
os << setw(2) << d.count() << "d:";
if (h.count() > 0)
os << setw(2) << h.count() << "h:";
os << setw(2) << m.count() << "m:" << setw(2) << s.count() << 's';
os.fill(fill);
return os;
};
void _save_start_time() {
if ((_show_elapsed_time || _show_remaining_time) && !_saved_start_time) {
_start_time_point = std::chrono::high_resolution_clock::now();
_saved_start_time = true;
}
}
void _print_progress() {
std::unique_lock<std::mutex> lock{_mutex};
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - _start_time_point);
std::cout << termcolor::bold;
switch (_foreground_color) {
case Color::GREY:
@@ -143,6 +190,24 @@ private:
if (_show_percentage) {
std::cout << " " << std::min(static_cast<size_t>(_progress), size_t(100)) << "%";
}
if (_show_elapsed_time) {
std::cout << " [";
_print_duration(std::cout, elapsed);
}
if (_show_remaining_time) {
if (_show_elapsed_time)
std::cout << "<";
else
std::cout << " [";
auto eta = std::chrono::nanoseconds(
_progress > 0 ? static_cast<long long>(elapsed.count() * 100 / _progress) : 0);
auto remaining = eta > elapsed ? (eta - elapsed) : (elapsed - eta);
_print_duration(std::cout, remaining);
std::cout << "]";
}
if (_max_postfix_text_length == 0)
_max_postfix_text_length = 10;
std::cout << " " << _postfix_text << std::string(_max_postfix_text_length, ' ') << "\r";

9
indicaConfig.cmake.in Normal file
View File

@@ -0,0 +1,9 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Threads)
if (NOT TARGET indica::indica)
include(${CMAKE_CURRENT_LIST_DIR}/indicaTargets.cmake)
endif ()

18
samples/CMakeLists.txt Normal file
View File

@@ -0,0 +1,18 @@
add_executable(block_progress_bar block_progress_bar.cpp)
target_link_libraries(block_progress_bar PRIVATE indica::indica)
add_executable(multi_threaded_bar multi_threaded_bar.cpp)
target_link_libraries(multi_threaded_bar PRIVATE indica::indica)
add_executable(progress_bar_set_progress progress_bar_set_progress.cpp)
target_link_libraries(progress_bar_set_progress PRIVATE indica::indica)
add_executable(progress_bar_tick progress_bar_tick.cpp)
target_link_libraries(progress_bar_tick PRIVATE indica::indica)
add_executable(progress_spinner progress_spinner.cpp)
target_link_libraries(progress_spinner PRIVATE indica::indica)
add_executable(time_meter time_meter.cpp)
target_link_libraries(time_meter PRIVATE indica::indica)

View File

@@ -0,0 +1,32 @@
#include <chrono>
#include <indicators/block_progress_bar.hpp>
#include <thread>
int main() {
// Hide cursor
std::cout << "\e[?25l";
indicators::BlockProgressBar bar;
// Configure the bar
bar.set_bar_width(80);
bar.start_bar_with("[");
bar.end_bar_with("]");
bar.set_foreground_color(indicators::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;
}

View File

@@ -0,0 +1,60 @@
#include <indicators/progress_bar.hpp>
#include <vector>
int main() {
indicators::ProgressBar bar;
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("");
bar.lead_bar_progress_with("");
bar.fill_bar_remainder_with("-");
bar.end_bar_with("]");
bar.set_foreground_color(indicators::Color::YELLOW);
// As configured, the bar will look like this:
//
// [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70%
//
//
std::atomic<size_t> index{0};
std::vector<std::string> status_text = {"Rocket.exe is not responding",
"Finding a replacement engineer",
"Buying more snacks",
"Assimilating the modding community",
"Crossing fingers",
"Porting KSP to a Nokia 3310"};
// Let's say you want to append some status text to the right of the progress bar
// You can use bar.set_postfix_text(...) to append text to the right
//
// [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70% Finding a replacement engineer
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
//
auto job = [&bar, &index, &status_text]() {
while (true) {
if (bar.is_completed()) {
break;
}
bar.set_postfix_text(status_text[index % status_text.size()]);
bar.tick();
index += 1;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
};
std::thread first_job(job);
std::thread second_job(job);
std::thread third_job(job);
std::thread last_job(job);
first_job.join();
second_job.join();
third_job.join();
last_job.join();
return 0;
}

View File

@@ -0,0 +1,38 @@
#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
bar.set_progress(10); // 10% done
// do some work
std::this_thread::sleep_for(std::chrono::milliseconds(100));
bar.set_progress(30); // 30% done
// do some more work
std::this_thread::sleep_for(std::chrono::milliseconds(600));
bar.set_progress(65); // 65% done
// do final bit of work
std::this_thread::sleep_for(std::chrono::milliseconds(300));
bar.set_progress(100); // all done
return 0;
}

View File

@@ -0,0 +1,27 @@
#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
bar.set_foreground_color(indicators::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;
}

View File

@@ -0,0 +1,38 @@
#include <indicators/progress_spinner.hpp>
int main() {
// Hide cursor
std::cout << "\e[?25l";
indicators::ProgressSpinner spinner;
// Configure the spinner
spinner.set_postfix_text("Checking credentials");
spinner.set_foreground_color(indicators::Color::YELLOW);
spinner.set_spinner_states({"", "", "", "", "", "", "", ""});
// Update spinner state
auto job = [&spinner]() {
while (true) {
if (spinner.is_completed()) {
spinner.set_foreground_color(indicators::Color::GREEN);
spinner.set_prefix_text("");
spinner.hide_spinner();
spinner.hide_percentage();
spinner.set_postfix_text("Authenticated!");
spinner.mark_as_completed();
break;
} else
spinner.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
};
std::thread thread(job);
thread.join();
// Show cursor
std::cout << "\e[?25h";
return 0;
}

34
samples/time_meter.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include <chrono>
#include <indicators/progress_bar.hpp>
#include <thread>
int main() {
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with(" [");
bar.fill_bar_progress_with("");
bar.lead_bar_progress_with("");
bar.fill_bar_remainder_with("-");
bar.end_bar_with("]");
bar.set_prefix_text("Training Gaze Network 👀");
bar.set_foreground_color(indicators::Color::YELLOW);
// Show time elapsed and remaining
bar.show_elapsed_time();
bar.show_remaining_time();
// 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;
}