gctl/lib/utility/progress_bar.cpp
2024-09-10 15:45:07 +08:00

183 lines
5.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* Geophysical Computational Tools & Library (GCTL)
*
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
*
* GCTL is distributed under a dual licensing scheme. You can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version. You should have
* received a copy of the GNU Lesser General Public License along with this
* program. If not, see <http://www.gnu.org/licenses/>.
*
* If the terms and conditions of the LGPL v.2. would prevent you from using
* the GCTL, please consider the option to obtain a commercial license for a
* fee. These licenses are offered by the GCTL's original author. As a rule,
* licenses are provided "as-is", unlimited in time for a one time fee. Please
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
* to include some description of your company and the realm of its activities.
* Also add information on how to contact you by electronic and paper mail.
******************************************************/
#include "progress_bar.h"
gctl::progress_bar::progress_bar(){}
gctl::progress_bar::progress_bar(unsigned long n_, const char* description_,
std::ostream& out_)
{
reset(n_, description_, out_);
}
void gctl::progress_bar::reset(unsigned long n_, const char *description_,
std::ostream& out_)
{
n = n_;
frequency_update = n_;
description = description_;
out = &out_;
unit_bar = "\u2588";
unit_space = "-";
desc_width = std::strlen(description); // character width of description field
return;
}
void gctl::progress_bar::set_frequency_update(unsigned long frequency_update_)
{
if(frequency_update_ > n)
{
frequency_update = n; // prevents crash if freq_updates_ > n_
}
else
{
frequency_update = frequency_update_;
}
return;
}
void gctl::progress_bar::set_style(const char* unit_bar_, const char* unit_space_)
{
unit_bar = unit_bar_;
unit_space = unit_space_;
return;
}
int gctl::progress_bar::get_console_width()
{
int width;
#ifdef _WINDOWS
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
width = csbi.srWindow.Right - csbi.srWindow.Left;
#else
struct winsize win;
//注意当我们使用pipe here-doc等通道获取程序参数时无法正确的获取窗口大小 此时我们将使用预定值
if (ioctl(0, TIOCGWINSZ, &win) != -1)
width = win.ws_col;
else width = 100;
#endif
return width;
}
int gctl::progress_bar::get_bar_length()
{
// get console width and according adjust the length of the progress bar
int bar_length = static_cast<int>((get_console_width() - desc_width - CHARACTER_WIDTH_PERCENTAGE) / 2.);
return bar_length;
}
void gctl::progress_bar::clear_bar_field()
{
for(int i = 0; i < get_console_width(); ++i)
{
*out << " ";
}
*out << "\r" << std::flush;
return;
}
void gctl::progress_bar::progressed(unsigned long idx_)
{
try
{
if(idx_ > n) throw idx_;
// determines whether to update the progress bar from frequency_update
if ((idx_ != n-1) && ((idx_+1) % (n/frequency_update) != 0)) return;
// calculate the size of the progress bar
int bar_size = get_bar_length();
// calculate percentage of progress
double progress_percent;
if (n == 1)
progress_percent = 100.0;
else progress_percent = idx_* TOTAL_PERCENTAGE/(n-1);
// calculate the percentage value of a unit bar
double percent_per_unit_bar = TOTAL_PERCENTAGE/bar_size;
// display progress bar
*out << " " << description << " |";
for(int bar_length=0;bar_length<=bar_size-1;++bar_length){
if(bar_length*percent_per_unit_bar<progress_percent){
*out << unit_bar;
}
else{
*out << unit_space;
}
}
if(idx_ == n-1)
*out << "|" << std::setw(CHARACTER_WIDTH_PERCENTAGE + 1) << std::setprecision(1) << std::fixed << progress_percent << "%\r" << std::flush << std::endl;
else *out << "|" << std::setw(CHARACTER_WIDTH_PERCENTAGE + 1) << std::setprecision(1) << std::fixed << progress_percent << "%\r" << std::flush;
}
catch(unsigned long e)
{
clear_bar_field();
throw runtime_error("Index went out of bounds. From progress_bar::progressed(...)");
}
return;
}
void gctl::progress_bar::progressed_simple(unsigned long idx_)
{
try
{
if(idx_ > n) throw idx_;
// determines whether to update the progress bar from frequency_update
if ((idx_ != n-1) && ((idx_+1) % (n/frequency_update) != 0)) return;
// calculate percentage of progress
double progress_percent;
if (n == 1)
progress_percent = 100.0;
else progress_percent = idx_* TOTAL_PERCENTAGE/(n-1);
// display progress bar
*out << " " << description << ":";
if(idx_ == n-1)
*out << std::setw(CHARACTER_WIDTH_PERCENTAGE + 1) << std::setprecision(1) << std::fixed << progress_percent << "%\r" << std::flush << std::endl;
else *out << std::setw(CHARACTER_WIDTH_PERCENTAGE + 1) << std::setprecision(1) << std::fixed << progress_percent << "%\r" << std::flush;
}
catch(unsigned long e)
{
clear_bar_field();
throw runtime_error("Index went out of bounds. From progress_bar::progressed(...)");
}
return;
}