/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * 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 . * * 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((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 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; }