diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 8a7f933..2ab1203 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -1124,9 +1124,10 @@ void BlocksTreeWidget::alignProgressBar() if (m_progress != nullptr) { - const auto pos = center;//mapToGlobal(center); + const auto& pos = center; m_progress->move(pos.x() - (m_progress->width() >> 1), std::max(pos.y() - (m_progress->height() >> 1), header()->height())); + m_progress->update(); } m_hintLabel->move(center.x() - (m_hintLabel->width() >> 1), diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index f5fb889..46582ff 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -150,7 +150,7 @@ inline void clear_stream(std::stringstream& _stream) #endif } -static void convertPointSizes(QString& style) +static void convertPointSizes(QString& style, QString from, QString to) { // Find font family const auto fontMatch = QRegularExpression("font-family:\\s*\\\"(.*)\\\"\\s*;").match(style); @@ -162,7 +162,7 @@ static void convertPointSizes(QString& style) //QMessageBox::information(nullptr, "Point size", QString("100pt = %1\n1pt = %2").arg(pointSizeF * 1e2).arg(pointSizeF)); // Find and convert all sizes from points to pixels - QRegularExpression re("(\\d+\\.?\\d*)ex"); + QRegularExpression re(QString("(\\d+\\.?\\d*)%1").arg(from)); auto it = re.globalMatch(style); std::vector matches; @@ -183,8 +183,9 @@ static void convertPointSizes(QString& style) { const auto pt = capturedTexts.back().toDouble(); const int pixels = static_cast(lround(pointSizeF * pt)); - style.replace(QString(" %1").arg(capturedTexts.front()), QString(" %1px").arg(pixels)); - style.replace(QString(":%1").arg(capturedTexts.front()), QString(":%1px").arg(pixels)); + auto converted = QString("%1%2").arg(pixels).arg(to); + style.replace(QString(" %1").arg(capturedTexts.front()), QString(" %1").arg(converted)); + style.replace(QString(":%1").arg(capturedTexts.front()), QString(":%1").arg(converted)); } } @@ -196,7 +197,7 @@ static void replaceOsDependentSettings(QString& style) #if defined(_WIN32) QRegularExpression re("/\\*\\{win\\}(.*)\\*/"); #elif defined(__APPLE__) - QRegularExpression re("/\\*\\{mac\\}(.*)\\*/"); + QRegularExpression re("/\\*\\{osx\\}(.*)\\*/"); #else QRegularExpression re("/\\*\\{lin\\}(.*)\\*/"); #endif @@ -232,7 +233,8 @@ static void loadTheme(const QString& _theme) QString style = in.readAll(); if (!style.isEmpty()) { - convertPointSizes(style); + convertPointSizes(style, "ex", "px"); + convertPointSizes(style, "qex", ""); replaceOsDependentSettings(style); qApp->setStyleSheet(style); } @@ -1566,10 +1568,27 @@ void MainWindow::showEvent(QShowEvent* show_event) void MainWindow::resizeEvent(QResizeEvent* event) { Parent::resizeEvent(event); + centerDialogs(); +} + +void MainWindow::moveEvent(QMoveEvent* _event) +{ + Parent::moveEvent(_event); + centerDialogs(); +} + +void MainWindow::centerDialogs() +{ + const auto center = rect().center(); + if (m_progress != nullptr) { - const auto pos = rect().center(); - m_progress->move(pos.x() - (m_progress->width() >> 1), pos.y() - (m_progress->height() >> 1)); + m_progress->move(center.x() - (m_progress->width() >> 1), center.y() - (m_progress->height() >> 1)); + } + + if (m_listenerDialog != nullptr) + { + m_listenerDialog->move(center.x() - (m_listenerDialog->width() >> 1), center.y() - (m_listenerDialog->height() >> 1)); } } @@ -1882,8 +1901,8 @@ void MainWindow::createProgressDialog(const QString& text) destroyProgressDialog(); m_progress = new RoundProgressDialog(text, this); - m_progress->setCancelButtonEnabled(true); - connect(m_progress, &RoundProgressDialog::canceled, this, &This::onFileReaderCancel); + m_progress->setObjectName(QStringLiteral("LoadProgress")); + connect(m_progress, &RoundProgressDialog::rejected, this, &This::onFileReaderCancel); m_progress->setModal(true); m_progress->setValue(0); @@ -1999,10 +2018,16 @@ void MainWindow::onListenerDialogClose(int _result) { case ListenerRegime::Capture: { - m_listenerDialog = new Dialog(this, QMessageBox::Information, "Receiving data...", - "This process may take some time.", QMessageBox::Cancel); + m_listenerDialog = new RoundProgressDialog( + QStringLiteral("Receiving data..."), + RoundProgressIndicator::Cross, + QDialog::Rejected, + this + ); + m_listenerDialog->setObjectName("ReceiveProgress"); m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true); m_listenerDialog->show(); + centerDialogs(); m_listener.stopCapture(); @@ -2026,11 +2051,17 @@ void MainWindow::onListenerDialogClose(int _result) { if (_result == QDialog::Accepted) { - m_listenerDialog = new Dialog(this, QMessageBox::Information, "Receiving data...", - "This process may take some time.", QMessageBox::Cancel); + m_listenerDialog = new RoundProgressDialog( + QStringLiteral("Receiving data..."), + RoundProgressIndicator::Cross, + QDialog::Rejected, + this + ); + m_listenerDialog->setObjectName("ReceiveProgress"); connect(m_listenerDialog, &QDialog::finished, this, &This::onListenerDialogClose); m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true); m_listenerDialog->show(); + centerDialogs(); } else { @@ -2703,20 +2734,18 @@ void MainWindow::onCaptureClicked(bool) m_listenerTimer.start(250); - m_listenerDialog = new Dialog(this, QMessageBox::Information, "Capturing frames..." - , "Close this dialog to stop capturing.", QMessageBox::NoButton); - - auto button = new QToolButton(m_listenerDialog); - button->setAutoRaise(true); - button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - button->setIconSize(applicationIconsSize()); - button->setIcon(QIcon(imagePath("stop"))); - button->setText("Stop"); - m_listenerDialog->addButton(button, QMessageBox::AcceptRole); + m_listenerDialog = new RoundProgressDialog( + QStringLiteral("Capturing frames..."), + RoundProgressIndicator::Stop, + QDialog::Accepted, + this + ); + m_listenerDialog->setObjectName("CaptureProgress"); m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true); connect(m_listenerDialog, &QDialog::finished, this, &This::onListenerDialogClose); m_listenerDialog->show(); + centerDialogs(); } void MainWindow::onGetBlockDescriptionsClicked(bool) @@ -2743,10 +2772,11 @@ void MainWindow::onGetBlockDescriptionsClicked(bool) return; } - m_listenerDialog = new Dialog(this, QMessageBox::Information, "Waiting for blocks...", - "This may take some time.", QMessageBox::NoButton); + m_listenerDialog = new RoundProgressDialog(QStringLiteral("Waiting for blocks..."), this); + m_listenerDialog->setObjectName("GetDescriptorsProgress"); m_listenerDialog->setAttribute(Qt::WA_DeleteOnClose, true); m_listenerDialog->show(); + centerDialogs(); m_listener.requestBlocksDescription(); diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index cd553bd..ccfc626 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -276,7 +276,7 @@ protected: class RoundProgressDialog* m_progress = nullptr; class BlockDescriptorsWidget* m_dialogDescTree = nullptr; - class Dialog* m_listenerDialog = nullptr; + class RoundProgressDialog* m_listenerDialog = nullptr; QTimer m_readerTimer; QTimer m_listenerTimer; QTimer m_fpsRequestTimer; @@ -314,6 +314,7 @@ public: void showEvent(QShowEvent* event) override; void resizeEvent(QResizeEvent* event) override; + void moveEvent(QMoveEvent* _event) override; void closeEvent(QCloseEvent* close_event) override; void changeEvent(QEvent* event) override; void dragEnterEvent(QDragEnterEvent* drag_event) override; @@ -380,6 +381,8 @@ private: // Private non-virtual methods + void centerDialogs(); + void closeProgressDialogAndClearReader(); void onLoadingFinish(profiler::block_index_t& _nblocks); void onSavingFinish(); diff --git a/profiler_gui/round_progress_widget.cpp b/profiler_gui/round_progress_widget.cpp index 089178f..1ad0838 100644 --- a/profiler_gui/round_progress_widget.cpp +++ b/profiler_gui/round_progress_widget.cpp @@ -69,19 +69,37 @@ # undef max #endif +namespace +{ + +// According to the Qt documentation on QPainter::drawArc: an angle must be specified in 1/16th of a degree +EASY_CONSTEXPR int Deg90 = 90 * 16; +EASY_CONSTEXPR int FullCircle = 360 * 16; + +} // end of namespace . + RoundProgressIndicator::RoundProgressIndicator(QWidget* parent) : Parent(parent) , m_text("0%") , m_background(Qt::transparent) , m_color(Qt::green) + , m_buttonColor(QColor::fromRgb(profiler::colors::Red500)) + , m_buttonSize(0.33) + , m_style(Percent) + , m_buttonStyle(NoButton) + , m_buttonRole(QDialog::Rejected) + , m_angle(Deg90) + , m_indicatorWidth(px(2)) + , m_crossWidth(px(1)) , m_value(0) , m_pressed(false) - , m_cancelButtonEnabled(false) { setWindowFlags(windowFlags() | Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground); setAutoFillBackground(false); setProperty("hover", false); + setProperty("pressed", false); + m_animationTimer.setInterval(16); } RoundProgressIndicator::~RoundProgressIndicator() @@ -89,15 +107,176 @@ RoundProgressIndicator::~RoundProgressIndicator() } -bool RoundProgressIndicator::cancelButtonEnabled() const +RoundProgressIndicator::ButtonStyle RoundProgressIndicator::buttonStyle() const { - return m_cancelButtonEnabled; + return m_buttonStyle; } -void RoundProgressIndicator::setCancelButtonEnabled(bool enabled) +void RoundProgressIndicator::setButtonStyle(ButtonStyle style) { - m_cancelButtonEnabled = enabled; - update(); + const auto prev = m_buttonStyle; + m_buttonStyle = style; + + if (prev == m_buttonStyle) + { + return; + } + + const bool hover = property("hover").toBool(); + if (hover) + { + update(); + } +} + +QString RoundProgressIndicator::buttonStyleStr() const +{ + switch (m_buttonStyle) + { + case NoButton: + { + return QStringLiteral("none"); + } + + case Cross: + { + return QStringLiteral("cross"); + } + + case Stop: + { + return QStringLiteral("stop"); + } + + default: + { + return QStringLiteral("unknown"); + } + } +} + +void RoundProgressIndicator::setButtonStyle(QString style) +{ + style = style.toLower(); + if (style == QStringLiteral("cross")) + { + setButtonStyle(Cross); + } + else if (style == QStringLiteral("stop")) + { + setButtonStyle(Stop); + } + else if (style == QStringLiteral("none") || style.isEmpty()) + { + setButtonStyle(NoButton); + } +} + +RoundProgressIndicator::Style RoundProgressIndicator::style() const +{ + return m_style; +} + +void RoundProgressIndicator::setStyle(Style style) +{ + const auto prev = m_style; + m_style = style; + + if (prev != m_style) + { + if (m_animationTimer.isActive()) + { + m_animationTimer.stop(); + disconnect(&m_animationTimer, &QTimer::timeout, this, &RoundProgressIndicator::onTimeout); + } + + if (m_style == Infinite) + { + m_angle = Deg90; + connect(&m_animationTimer, &QTimer::timeout, this, &RoundProgressIndicator::onTimeout); + m_animationTimer.start(); + } + + update(); + } +} + +QString RoundProgressIndicator::styleStr() const +{ + switch (m_style) + { + case Percent: + { + return QStringLiteral("percent"); + } + + case Infinite: + { + return QStringLiteral("infinite"); + } + + default: + { + return QStringLiteral("unknown"); + } + } +} + +void RoundProgressIndicator::setStyle(QString style) +{ + style = style.toLower(); + if (style == QStringLiteral("percent")) + { + setStyle(Percent); + } + else if (style == QStringLiteral("inf") || style == QStringLiteral("infinite")) + { + setStyle(Infinite); + } +} + +QDialog::DialogCode RoundProgressIndicator::buttonRole() const +{ + return m_buttonRole; +} + +void RoundProgressIndicator::setButtonRole(QDialog::DialogCode role) +{ + m_buttonRole = role; +} + +QString RoundProgressIndicator::buttonRoleStr() const +{ + switch (m_buttonRole) + { + case QDialog::Accepted: + { + return QStringLiteral("accept"); + } + + case QDialog::Rejected: + { + return QStringLiteral("reject"); + } + + default: + { + return QStringLiteral("unknown"); + } + } +} + +void RoundProgressIndicator::setButtonRole(QString style) +{ + style = style.toLower(); + if (style == QStringLiteral("accept")) + { + setButtonRole(QDialog::Accepted); + } + else if (style == QStringLiteral("reject")) + { + setButtonRole(QDialog::Rejected); + } } int RoundProgressIndicator::value() const @@ -114,6 +293,7 @@ void RoundProgressIndicator::setValue(int value) void RoundProgressIndicator::reset() { + m_angle = Deg90; m_value = 0; m_text = "0%"; update(); @@ -153,15 +333,129 @@ void RoundProgressIndicator::setColor(QString color) update(); } +QColor RoundProgressIndicator::buttonColor() const +{ + return m_buttonColor; +} + +void RoundProgressIndicator::setButtonColor(QColor color) +{ + m_buttonColor = std::move(color); + + if (m_buttonStyle == NoButton) + { + return; + } + + const bool hover = property("hover").toBool(); + if (hover) + { + update(); + } +} + +void RoundProgressIndicator::setButtonColor(QString color) +{ + m_buttonColor.setNamedColor(color); + + if (m_buttonStyle == NoButton) + { + return; + } + + const bool hover = property("hover").toBool(); + if (hover) + { + update(); + } +} + +qreal RoundProgressIndicator::buttonSize() const +{ + return m_buttonSize; +} + +void RoundProgressIndicator::setButtonSize(qreal size) +{ + m_buttonSize = size; + + if (m_buttonStyle == NoButton) + { + return; + } + + const bool hover = property("hover").toBool(); + if (hover) + { + update(); + } +} + +int RoundProgressIndicator::crossWidth() const +{ + return m_crossWidth; +} + +void RoundProgressIndicator::setCrossWidth(int width) +{ + m_crossWidth = width; + + if (m_buttonStyle != Cross) + { + return; + } + + const bool hover = property("hover").toBool(); + if (hover) + { + update(); + } +} + +int RoundProgressIndicator::indicatorWidth() const +{ + return m_indicatorWidth; +} + +void RoundProgressIndicator::setIndicatorWidth(int width) +{ + m_indicatorWidth = width; + update(); +} + void RoundProgressIndicator::showEvent(QShowEvent* event) { Parent::showEvent(event); + updateSize(); +} +void RoundProgressIndicator::updateSize() +{ const QFontMetrics fm(font()); const QString text = QStringLiteral("100%"); - const int size = std::max(fm.width(text), fm.height()) + px(4 * 4); + const int margins = m_indicatorWidth * 4 + px(2); + const int size = static_cast(std::max(fm.width(text), fm.height()) * profiler_gui::FONT_METRICS_FACTOR) + margins; setFixedSize(size, size); + + emit sizeChanged(); +} + +void RoundProgressIndicator::onTimeout() +{ + EASY_CONSTEXPR int Step = -8 * 16; + + m_angle += Step; + if (m_angle > FullCircle) + { + m_angle -= FullCircle; + } + else if (m_angle < 0) + { + m_angle += FullCircle; + } + + update(); } void RoundProgressIndicator::paintEvent(QPaintEvent* /*event*/) @@ -170,49 +464,97 @@ void RoundProgressIndicator::paintEvent(QPaintEvent* /*event*/) painter.setRenderHint(QPainter::Antialiasing); painter.setBrush(Qt::NoBrush); - const auto px4 = px(4); - auto r = rect().adjusted(px4, px4, -px4, -px4); + auto r = rect().adjusted(m_indicatorWidth, m_indicatorWidth, -m_indicatorWidth, -m_indicatorWidth); auto p = painter.pen(); - // Draw circle - p.setWidth(px4); + // Draw background circle + p.setWidth(m_indicatorWidth); p.setColor(m_background); painter.setPen(p); - painter.drawArc(r, 0, 360 * 16); + painter.drawEllipse(r); + // Draw current progress arc p.setColor(m_color); painter.setPen(p); - painter.drawArc(r, 90 * 16, -1 * static_cast(m_value) * 16 * 360 / 100); + + if (m_style == Percent) + { + painter.drawArc(r, Deg90, -1 * static_cast(m_value) * FullCircle / 100); + } + else + { + painter.drawArc(r, m_angle, -1 * FullCircle / 5); + } const bool hover = property("hover").toBool(); - if (hover && m_cancelButtonEnabled) + if (hover && m_buttonStyle != NoButton) { - // Draw cancel button (red cross) + switch (m_buttonStyle) + { + case Cross: + { + paintCrossButton(painter, r); + break; + } - const auto hquarter = px4 + (r.width() >> 2); - const auto vquarter = px4 + (r.height() >> 2); - r.adjust(hquarter, vquarter, -hquarter, -vquarter); + case Stop: + { + paintStopButton(painter, r); + break; + } - p.setWidth(px(2)); - p.setColor(QColor::fromRgb(m_pressed ? profiler::colors::Red900 : profiler::colors::Red500)); - p.setCapStyle(Qt::SquareCap); - - painter.setPen(p); - painter.setBrush(Qt::NoBrush); - painter.drawLine(r.topLeft(), r.bottomRight()); - painter.drawLine(r.bottomLeft(), r.topRight()); + default: + { + break; + } + } } - else + else if (m_style == Percent) { // Draw text p.setWidth(px(1)); p.setColor(palette().foreground().color()); painter.setPen(p); + painter.setFont(font()); painter.drawText(r, Qt::AlignCenter, m_text); } } +void RoundProgressIndicator::paintCrossButton(QPainter& painter, QRect& r) +{ + // Draw cancel button (red cross) + + const auto margin = (1. - m_buttonSize) * 0.5; + const auto dh = m_indicatorWidth + static_cast(r.width() * margin); + const auto dv = m_indicatorWidth + static_cast(r.height() * margin); + r.adjust(dh, dv, -dh, -dv); + + auto p = painter.pen(); + p.setWidth(m_crossWidth); + p.setColor(m_buttonColor); + p.setCapStyle(Qt::SquareCap); + + painter.setPen(p); + painter.setBrush(Qt::NoBrush); + painter.drawLine(r.topLeft(), r.bottomRight()); + painter.drawLine(r.bottomLeft(), r.topRight()); +} + +void RoundProgressIndicator::paintStopButton(QPainter& painter, QRect& r) +{ + // Draw cancel button (red cross) + + const auto margin = (1. - m_buttonSize) * 0.5; + const auto dh = m_indicatorWidth + static_cast(r.width() * margin); + const auto dv = m_indicatorWidth + static_cast(r.height() * margin); + r.adjust(dh, dv, -dh, -dv); + + painter.setPen(Qt::NoPen); + painter.setBrush(m_buttonColor); + painter.drawRect(r); +} + void RoundProgressIndicator::enterEvent(QEvent* event) { Parent::enterEvent(event); profiler_gui::updateProperty(this, "hover", true); @@ -227,7 +569,7 @@ void RoundProgressIndicator::mousePressEvent(QMouseEvent* event) { Parent::mousePressEvent(event); m_pressed = true; - update(); + profiler_gui::updateProperty(this, "pressed", true); } void RoundProgressIndicator::mouseReleaseEvent(QMouseEvent* event) @@ -238,11 +580,11 @@ void RoundProgressIndicator::mouseReleaseEvent(QMouseEvent* event) const bool pressed = m_pressed; m_pressed = false; - update(); + profiler_gui::updateProperty(this, "pressed", false); - if (pressed && hover && m_cancelButtonEnabled) + if (pressed && hover && m_buttonStyle != NoButton) { - emit cancelButtonClicked(); + emit buttonClicked(m_buttonRole); } } @@ -291,7 +633,10 @@ RoundProgressWidget::RoundProgressWidget(const QString& title, QWidget* parent) lay->addWidget(m_title); lay->addWidget(m_indicatorWrapper); - connect(m_indicator, &RoundProgressIndicator::cancelButtonClicked, this, &RoundProgressWidget::canceled); + connect(m_indicator, &RoundProgressIndicator::buttonClicked, this, &RoundProgressWidget::finished); + connect(m_indicator, &RoundProgressIndicator::sizeChanged, [this] { + adjustSize(); + }); } RoundProgressWidget::~RoundProgressWidget() @@ -322,7 +667,9 @@ void RoundProgressWidget::setValue(int value) emit valueChanged(v); if (v == 100) - emit finished(); + { + emit finished(QDialog::Accepted); + } } void RoundProgressWidget::reset() @@ -376,23 +723,57 @@ void RoundProgressWidget::setTopTitlePosition(bool isTop) setTitlePosition(isTop ? RoundProgressWidget::Top : RoundProgressWidget::Bottom); } -bool RoundProgressWidget::cancelButtonEnabled() const +RoundProgressButtonStyle RoundProgressWidget::buttonStyle() const { - return m_indicator->cancelButtonEnabled(); + return m_indicator->buttonStyle(); } -void RoundProgressWidget::setCancelButtonEnabled(bool enabled) +void RoundProgressWidget::setButtonStyle(RoundProgressButtonStyle style) { - m_indicator->setCancelButtonEnabled(enabled); + m_indicator->setButtonStyle(style); } +QDialog::DialogCode RoundProgressWidget::buttonRole() const +{ + return m_indicator->buttonRole(); +} + +void RoundProgressWidget::setButtonRole(QDialog::DialogCode role) +{ + m_indicator->setButtonRole(role); +} + +RoundProgressStyle RoundProgressWidget::style() const +{ + return m_indicator->style(); +} + +void RoundProgressWidget::setStyle(RoundProgressStyle style) +{ + m_indicator->setStyle(style); +} + + RoundProgressDialog::RoundProgressDialog(const QString& title, QWidget* parent) + : RoundProgressDialog(title, RoundProgressIndicator::NoButton, QDialog::Rejected, parent) +{ +} + +RoundProgressDialog::RoundProgressDialog( + const QString& title, + RoundProgressButtonStyle button, + QDialog::DialogCode buttonRole, + QWidget* parent +) : Parent(parent) , m_progress(new RoundProgressWidget(title, this)) , m_background(Qt::transparent) + , m_borderRadius(px(15)) { setWindowTitle(profiler_gui::DEFAULT_WINDOW_TITLE); - setWindowFlags(windowFlags() | Qt::FramelessWindowHint); + + // do not merge with existing windowFlags() to let the dialog be always binded to it's parent + setWindowFlags(Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground); setAutoFillBackground(false); @@ -400,8 +781,10 @@ RoundProgressDialog::RoundProgressDialog(const QString& title, QWidget* parent) lay->addWidget(m_progress); connect(m_progress, &RoundProgressWidget::valueChanged, this, &RoundProgressDialog::valueChanged); - connect(m_progress, &RoundProgressWidget::finished, this, &RoundProgressDialog::finished); - connect(m_progress, &RoundProgressWidget::canceled, this, &RoundProgressDialog::canceled); + connect(m_progress, &RoundProgressWidget::finished, this, &RoundProgressDialog::onFinished); + + m_progress->setButtonStyle(button); + m_progress->setButtonRole(buttonRole); } RoundProgressDialog::~RoundProgressDialog() @@ -409,6 +792,18 @@ RoundProgressDialog::~RoundProgressDialog() } +void RoundProgressDialog::onFinished(int role) +{ + if (role == QDialog::Accepted) + { + accept(); + } + else + { + reject(); + } +} + QColor RoundProgressDialog::background() const { return m_background; @@ -420,20 +815,51 @@ void RoundProgressDialog::setBackground(QColor color) update(); } +int RoundProgressDialog::borderRadius() const +{ + return m_borderRadius; +} + +void RoundProgressDialog::setBorderRadius(int radius) +{ + m_borderRadius = radius; + update(); +} + void RoundProgressDialog::setBackground(QString color) { m_background.setNamedColor(color); update(); } -bool RoundProgressDialog::cancelButtonEnabled() const +RoundProgressButtonStyle RoundProgressDialog::buttonStyle() const { - return m_progress->cancelButtonEnabled(); + return m_progress->buttonStyle(); } -void RoundProgressDialog::setCancelButtonEnabled(bool enabled) +void RoundProgressDialog::setButtonStyle(RoundProgressButtonStyle style) { - m_progress->setCancelButtonEnabled(enabled); + m_progress->setButtonStyle(style); +} + +RoundProgressStyle RoundProgressDialog::style() const +{ + return m_progress->style(); +} + +void RoundProgressDialog::setStyle(RoundProgressStyle style) +{ + m_progress->setStyle(style); +} + +QDialog::DialogCode RoundProgressDialog::buttonRole() const +{ + return m_progress->buttonRole(); +} + +void RoundProgressDialog::setButtonRole(QDialog::DialogCode role) +{ + m_progress->setButtonRole(role); } void RoundProgressDialog::showEvent(QShowEvent* event) @@ -455,5 +881,5 @@ void RoundProgressDialog::paintEvent(QPaintEvent*) painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); painter.setBrush(m_background); - painter.drawRect(0, 0, width(), height()); + painter.drawRoundedRect(rect(), m_borderRadius, m_borderRadius); } diff --git a/profiler_gui/round_progress_widget.h b/profiler_gui/round_progress_widget.h index 0ed75fe..4762e08 100644 --- a/profiler_gui/round_progress_widget.h +++ b/profiler_gui/round_progress_widget.h @@ -54,26 +54,49 @@ #include #include #include +#include #include class RoundProgressIndicator : public QWidget { -Q_OBJECT + Q_OBJECT + +public: + + enum ButtonStyle { NoButton = 0, Cross, Stop }; + enum Style { Percent = 0, Infinite }; + +private: using Parent = QWidget; using This = RoundProgressIndicator; - QString m_text; - QColor m_background; - QColor m_color; - int8_t m_value; - bool m_pressed; - bool m_cancelButtonEnabled; + QTimer m_animationTimer; + QString m_text; + QColor m_background; + QColor m_color; + QColor m_buttonColor; + qreal m_buttonSize; + Style m_style; + ButtonStyle m_buttonStyle; + QDialog::DialogCode m_buttonRole; + int m_angle; + int m_indicatorWidth; + int m_crossWidth; + int8_t m_value; + bool m_pressed; public: Q_PROPERTY(QColor color READ color WRITE setColor); Q_PROPERTY(QColor background READ background WRITE setBackground); + Q_PROPERTY(QColor buttonColor READ buttonColor WRITE setButtonColor); + Q_PROPERTY(qreal buttonSize READ buttonSize WRITE setButtonSize); + Q_PROPERTY(int indicatorWidth READ indicatorWidth WRITE setIndicatorWidth); + Q_PROPERTY(int crossWidth READ crossWidth WRITE setCrossWidth); + Q_PROPERTY(QString buttonStyle READ buttonStyleStr WRITE setButtonStyle); + Q_PROPERTY(QString buttonRole READ buttonRoleStr WRITE setButtonRole); + Q_PROPERTY(QString style READ styleStr WRITE setStyle); explicit RoundProgressIndicator(QWidget* parent = nullptr); ~RoundProgressIndicator() override; @@ -84,13 +107,31 @@ public: QColor background() const; QColor color() const; + QColor buttonColor() const; - bool cancelButtonEnabled() const; - void setCancelButtonEnabled(bool enabled); + qreal buttonSize() const; + int indicatorWidth() const; + int crossWidth() const; + + ButtonStyle buttonStyle() const; + QString buttonStyleStr() const; + void setButtonStyle(ButtonStyle style); + void setButtonStyle(QString style); + + QDialog::DialogCode buttonRole() const; + QString buttonRoleStr() const; + void setButtonRole(QDialog::DialogCode role); + void setButtonRole(QString role); + + Style style() const; + QString styleStr() const; + void setStyle(Style style); + void setStyle(QString style); signals: - void cancelButtonClicked(); + void buttonClicked(int role); + void sizeChanged(); public slots: @@ -98,6 +139,15 @@ public slots: void setBackground(QString color); void setColor(QColor color); void setColor(QString color); + void setButtonColor(QColor color); + void setButtonColor(QString color); + void setButtonSize(qreal size); + void setIndicatorWidth(int width); + void setCrossWidth(int width); + +private slots: + + void onTimeout(); protected: @@ -109,8 +159,17 @@ protected: void mouseReleaseEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; +private: + + void updateSize(); + void paintCrossButton(QPainter& painter, QRect& r); + void paintStopButton(QPainter& painter, QRect& r); + }; // end of class RoundProgressIndicator. +using RoundProgressButtonStyle = RoundProgressIndicator::ButtonStyle; +using RoundProgressStyle = RoundProgressIndicator::Style; + class RoundProgressWidget : public QWidget { Q_OBJECT @@ -146,8 +205,14 @@ public: TitlePosition titlePosition() const; bool isTopTitlePosition() const; - bool cancelButtonEnabled() const; - void setCancelButtonEnabled(bool enabled); + RoundProgressButtonStyle buttonStyle() const; + void setButtonStyle(RoundProgressButtonStyle style); + + QDialog::DialogCode buttonRole() const; + void setButtonRole(QDialog::DialogCode role); + + RoundProgressStyle style() const; + void setStyle(RoundProgressStyle style); public slots: @@ -159,9 +224,8 @@ public slots: signals: void valueChanged(int value); - void finished(); + void finished(int role); void titlePositionChanged(); - void canceled(); }; // end of class RoundProgressWidget. @@ -174,18 +238,33 @@ class RoundProgressDialog : public QDialog RoundProgressWidget* m_progress; QColor m_background; + int m_borderRadius; public: Q_PROPERTY(QColor background READ background WRITE setBackground); + Q_PROPERTY(int borderRadius READ borderRadius WRITE setBorderRadius); explicit RoundProgressDialog(const QString& title, QWidget* parent = nullptr); + RoundProgressDialog( + const QString& title, + RoundProgressIndicator::ButtonStyle button, + QDialog::DialogCode buttonRole, + QWidget* parent = nullptr + ); ~RoundProgressDialog() override; QColor background() const; + int borderRadius() const; - bool cancelButtonEnabled() const; - void setCancelButtonEnabled(bool enabled); + RoundProgressButtonStyle buttonStyle() const; + void setButtonStyle(RoundProgressButtonStyle style); + + QDialog::DialogCode buttonRole() const; + void setButtonRole(QDialog::DialogCode role); + + RoundProgressStyle style() const; + void setStyle(RoundProgressStyle style); protected: @@ -196,13 +275,16 @@ public slots: void setBackground(QColor color); void setBackground(QString color); + void setBorderRadius(int radius); void setValue(int value); signals: void valueChanged(int value); - void finished(); - void canceled(); + +private slots: + + void onFinished(int role); }; // end of RoundProgressDialog. diff --git a/profiler_gui/themes/default.css b/profiler_gui/themes/default.css index d9effc8..f46e92b 100644 --- a/profiler_gui/themes/default.css +++ b/profiler_gui/themes/default.css @@ -6,6 +6,25 @@ * default.scss by pysassc tool * * * ***********************************/ +/************************************************************************** +* Legend * +* * +* ex - 'pt' analog for widgets. It is converted to 'px' on program start. * +* Example: '10ex' will be converted to '21px'. * +* * +* qex - same as 'ex' but with removed 'px' in resulting text. * +* It is used for 'qproperty' properties. * +* Example: '10qex' will be converted to '21'. * +* * +* OS dependent properties: * +* * +* {lin}font-weight: bold; * +* {win}height: 12ex; * +* {osx}backgound: transparent; * +* * +* Such properties will be uncommented on program start for specified OS * +* * +***************************************************************************/ * { font-family: "DejaVu Sans"; font-size: 10pt; @@ -17,11 +36,51 @@ RoundProgressIndicator { qproperty-color: #3297FD; qproperty-background: #c4c4c4; + qproperty-indicatorWidth: 2qex; background: transparent; } - + RoundProgressDialog { - qproperty-background: rgba(255, 255, 255, 70%); } - + qproperty-background: rgba(255, 255, 255, 0.7); + qproperty-borderRadius: 10qex; } + +RoundProgressDialog#LoadProgress { + qproperty-background: rgba(0, 0, 0, 0.5); } + RoundProgressDialog#LoadProgress RoundProgressWidget RoundProgressIndicator { + qproperty-buttonColor: white; + qproperty-buttonStyle: cross; + qproperty-buttonRole: reject; + qproperty-buttonSize: 0.4; + qproperty-crossWidth: 1; + color: white; } + RoundProgressDialog#LoadProgress RoundProgressWidget RoundProgressIndicator[pressed=true] { + qproperty-buttonColor: red; } + RoundProgressDialog#LoadProgress RoundProgressWidget QLabel { + color: white; } + +RoundProgressDialog#CaptureProgress, RoundProgressDialog#ReceiveProgress { + qproperty-background: rgba(0, 0, 0, 0.5); } + RoundProgressDialog#CaptureProgress RoundProgressWidget RoundProgressIndicator, RoundProgressDialog#ReceiveProgress RoundProgressWidget RoundProgressIndicator { + qproperty-style: infinite; + qproperty-buttonColor: red; + qproperty-buttonStyle: stop; + qproperty-buttonRole: accept; + qproperty-buttonSize: 0.35; + color: white; } + RoundProgressDialog#CaptureProgress RoundProgressWidget RoundProgressIndicator[pressed=true], RoundProgressDialog#ReceiveProgress RoundProgressWidget RoundProgressIndicator[pressed=true] { + qproperty-buttonColor: darkRed; } + RoundProgressDialog#CaptureProgress RoundProgressWidget QLabel, RoundProgressDialog#ReceiveProgress RoundProgressWidget QLabel { + color: white; } + +RoundProgressDialog#ReceiveProgress RoundProgressWidget RoundProgressIndicator { + qproperty-buttonColor: white; + qproperty-buttonStyle: cross; + qproperty-buttonRole: reject; + qproperty-buttonSize: 0.4; + qproperty-crossWidth: 1; } + +RoundProgressDialog#ReceiveProgress RoundProgressWidget RoundProgressIndicator[pressed=true] { + qproperty-buttonColor: red; } + MainWindow, QToolBar, QDialog { background-color: white; } diff --git a/profiler_gui/themes/default.scss b/profiler_gui/themes/default.scss index 608a5d7..5e3f9bb 100644 --- a/profiler_gui/themes/default.scss +++ b/profiler_gui/themes/default.scss @@ -11,6 +11,26 @@ @return fade_out($color, 1.0 - $opacity); } +/************************************************************************** +* Legend * +* * +* ex - 'pt' analog for widgets. It is converted to 'px' on program start. * +* Example: '10ex' will be converted to '21px'. * +* * +* qex - same as 'ex' but with removed 'px' in resulting text. * +* It is used for 'qproperty' properties. * +* Example: '10qex' will be converted to '21'. * +* * +* OS dependent properties: * +* * +* {lin}font-weight: bold; * +* {win}height: 12ex; * +* {osx}backgound: transparent; * +* * +* Such properties will be uncommented on program start for specified OS * +* * +***************************************************************************/ + // CONSTANTS ---------------------------------------------- $FontSize: 10pt; @@ -61,11 +81,67 @@ $WindowHeaderHoverColor: lighten($BorderColor, 14%); // #e8e8e8 RoundProgressIndicator { qproperty-color: $DarkSelectionColor; qproperty-background: $BorderColor; + qproperty-indicatorWidth: 2qex; background: transparent; } RoundProgressDialog { - qproperty-background: rgba(255, 255, 255, 70%); + qproperty-background: rgb_a(#ffffff, 0.7); + qproperty-borderRadius: 10qex; +} + +RoundProgressDialog#LoadProgress { + qproperty-background: rgb_a(#000000, 0.5); + + RoundProgressWidget { + RoundProgressIndicator { + qproperty-buttonColor: white; + qproperty-buttonStyle: cross; + qproperty-buttonRole: reject; + qproperty-buttonSize: 0.4; + qproperty-crossWidth: 1; + color: white; + } + RoundProgressIndicator[pressed=true] { + qproperty-buttonColor: red; + } + QLabel { + color: white; + } + } +} + +RoundProgressDialog#CaptureProgress, RoundProgressDialog#ReceiveProgress { + qproperty-background: rgb_a(#000000, 0.5); + + RoundProgressWidget { + RoundProgressIndicator { + qproperty-style: infinite; + qproperty-buttonColor: red; + qproperty-buttonStyle: stop; + qproperty-buttonRole: accept; + qproperty-buttonSize: 0.35; + color: white; + } + RoundProgressIndicator[pressed=true] { + qproperty-buttonColor: darkRed; + } + QLabel { + color: white; + } + } +} + +RoundProgressDialog#ReceiveProgress RoundProgressWidget RoundProgressIndicator { + qproperty-buttonColor: white; + qproperty-buttonStyle: cross; + qproperty-buttonRole: reject; + qproperty-buttonSize: 0.4; + qproperty-crossWidth: 1; +} + +RoundProgressDialog#ReceiveProgress RoundProgressWidget RoundProgressIndicator[pressed=true] { + qproperty-buttonColor: red; } MainWindow, QToolBar, QDialog {