#include "ProgressBar.h" #include #include #include #include #include Progress_Bar::Progress_Bar(const std::vector& tick_list, QWidget *parent) : QWidget(parent), tick_list(tick_list) { setAttribute(Qt::WA_OpaquePaintEvent, true); timer = startTimer(30); } double Progress_Bar::get_draw_width(double value) { int n = tick_list.size(); if (n < 2 || QWidget::width() <= 0) return 0.0; if (!std::isfinite(value)) value = tick_list.front().value; int i = 1; for(; i < n - 1; ++i) { double cur = tick_list[i].value; if(value < cur || qFuzzyCompare(value, cur)) { break; } } int lower_offset = i - 1; int upper_offset = i; double lower = tick_list[lower_offset].value; double upper = tick_list[upper_offset].value; double w_step = (double)QWidget::width()/(double)(n-1); double last_rate = upper == lower ? 0.0 : (value - lower)/(upper - lower); last_rate = std::clamp(last_rate, 0.0, 1.0); double draw_width = w_step * (last_rate + lower_offset); return std::clamp(draw_width, 0.0, (double)QWidget::width()); } void Progress_Bar::setValue(double value) { if (thread() != QThread::currentThread()) { QMetaObject::invokeMethod(this, [this, value]() { setValue(value); }, Qt::QueuedConnection); return; } this->value = value; update(); } void Progress_Bar::paintEvent(QPaintEvent *event) { Q_UNUSED(event) QPainter painter(this); painter.setPen(Qt::NoPen); painter.fillRect(rect(), QApplication::style()->standardPalette().brush(QPalette::Window)); painter.setPen(QPen(Qt::black)); auto w = (double)QWidget::width(); auto hh = (double)height()/2; int n = tick_list.size(); int tick_w = 1; double draw_width = get_draw_width(value); int fill_width = std::max(0, static_cast(draw_width) - tick_w - 4); if (fill_width > 0) painter.fillRect(0, 0, fill_width, height()/2, Qt::black); int cur_x = 0; int tick_step = std::max(1, tick_w + (int)tick_space_w); while(cur_x + tick_w + 4 < draw_width){ painter.fillRect(cur_x, 0, tick_w, height()/2, Qt::gray); cur_x += tick_step; } int line_y = (int)hh + 2; int marker_x = std::clamp(cur_x - (int)tick_space_w, 0, std::max(0, QWidget::width() - 4)); painter.fillRect(marker_x, 0, 4, line_y, Qt::yellow); painter.drawLine(0, line_y , (int)w, line_y); QFont font; font.setBold(true); QFontMetrics fm(font); for(int i = 0; i < n; ++i){ int tick_x = (int)((double)(QWidget::width() * i)/(double)(n - 1)); int text_w = fm.horizontalAdvance( tick_list[i].text); int text_x; if(i == n - 1) { text_x = tick_x - text_w; tick_x -=1; } else if( i == 0) { text_x = tick_x; } else { text_x = tick_x - text_w/2; } painter.setPen(Qt::black); painter.drawLine(tick_x, line_y, tick_x, (line_y + 5)); painter.setPen(tick_list[i].color); painter.setFont(font); painter.drawText(QRectF(text_x, line_y, text_w, line_y), Qt::AlignCenter, tick_list[i].text); } } void Progress_Bar::timerEvent(QTimerEvent *event) { if(event->timerId() == timer) { if(set_value) set_value(); update(); } QObject::timerEvent(event); }