From a51695713574758dbfc28833a2e7e22293334a5e Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Mon, 16 Dec 2019 08:48:42 -0600 Subject: [PATCH] Draft implementation of smooth block progress bar --- include/indicators/block_progress_bar.hpp | 179 ++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 include/indicators/block_progress_bar.hpp diff --git a/include/indicators/block_progress_bar.hpp b/include/indicators/block_progress_bar.hpp new file mode 100644 index 0000000..e68b992 --- /dev/null +++ b/include/indicators/block_progress_bar.hpp @@ -0,0 +1,179 @@ +/* +Activity Indicators for Modern C++ +https://github.com/p-ranav/indicators + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2019 Pranav Srinivas Kumar . + +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 +#include +#include +#include +#include +#include +#include +#include + +namespace indicators { + +class BlockProgressBar { +public: + void set_foreground_color(Color color) { + std::unique_lock lock{_mutex}; + _foreground_color = color; + } + + void set_bar_width(size_t bar_width) { + std::unique_lock lock{_mutex}; + _bar_width = bar_width; + } + + void start_bar_with(const std::string &start) { + std::unique_lock lock{_mutex}; + _start = start; + } + + void end_bar_with(const std::string &end) { + std::unique_lock lock{_mutex}; + _end = end; + } + + void set_prefix_text(const std::string &text) { + std::unique_lock lock{_mutex}; + _prefix_text = text; + } + + void set_postfix_text(const std::string &text) { + std::unique_lock 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 set_progress(float value) { + { + std::unique_lock lock{_mutex}; + _progress = value; + } + _print_progress(); + } + + void tick() { + { + std::unique_lock lock{_mutex}; + _progress += 1; + } + _print_progress(); + } + + size_t current() { + return std::min(static_cast(_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 _max_postfix_text_length{0}; + std::atomic _completed{false}; + std::atomic _show_percentage{true}; + std::mutex _mutex; + Color _foreground_color; + + void _print_progress() { + std::unique_lock lock{_mutex}; + 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; + auto pos = static_cast(_progress * static_cast(_bar_width) / 100.0); + auto remainder = _bar_width - pos; + std::vector lead_characters{" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"}; + _lead = lead_characters[remainder % lead_characters.size()]; + for (size_t i = 0; i < _bar_width; ++i) { + if (i < pos) + std::cout << _fill; + else if (i == pos) + std::cout << _lead; + else + std::cout << _remainder; + } + std::cout << _end; + if (_show_percentage) { + std::cout << " " << std::min(static_cast(_progress), size_t(100)) << "%"; + } + 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