From fd71fc323751769093eb9523485fa5ecac4eeab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Br=C3=A6strup=20Sayoc?= Date: Wed, 6 Nov 2024 16:11:30 +0100 Subject: [PATCH] [Gui] Fix 100% CPU usage due to StartView (#17565) * [Gui] Fix 100% CPU usage due to StartView * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/Mod/Start/Gui/StartView.cpp | 231 ++++++++++++++++++-------------- src/Mod/Start/Gui/StartView.h | 2 - 2 files changed, 127 insertions(+), 106 deletions(-) diff --git a/src/Mod/Start/Gui/StartView.cpp b/src/Mod/Start/Gui/StartView.cpp index 56df595f80..c0859dafde 100644 --- a/src/Mod/Start/Gui/StartView.cpp +++ b/src/Mod/Start/Gui/StartView.cpp @@ -68,43 +68,117 @@ struct NewButton QString iconPath; }; -gsl::owner createNewButton(const NewButton& newButton) +class NewFileButton: public QPushButton { - auto hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Start"); - const auto cardSpacing = static_cast(hGrp->GetInt("FileCardSpacing", 25)); // NOLINT - const auto newFileIconSize = static_cast(hGrp->GetInt("NewFileIconSize", 48)); // NOLINT - const auto cardLabelWith = static_cast(hGrp->GetInt("FileCardLabelWith", 180)); // NOLINT - auto button = gsl::owner(new QPushButton()); - auto mainLayout = gsl::owner(new QHBoxLayout(button)); - auto iconLabel = gsl::owner(new QLabel(button)); - mainLayout->addWidget(iconLabel); - QIcon baseIcon(newButton.iconPath); - iconLabel->setPixmap(baseIcon.pixmap(newFileIconSize, newFileIconSize)); - iconLabel->setPixmap(baseIcon.pixmap(newFileIconSize, newFileIconSize)); +public: + NewFileButton(const NewButton& newButton) + { + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); + const auto cardSpacing = static_cast(hGrp->GetInt("FileCardSpacing", 25)); // NOLINT + const auto newFileIconSize = + static_cast(hGrp->GetInt("NewFileIconSize", 48)); // NOLINT + const auto cardLabelWith = + static_cast(hGrp->GetInt("FileCardLabelWith", 180)); // NOLINT - auto textLayout = gsl::owner(new QVBoxLayout); - auto textLabelLine1 = gsl::owner(new QLabel(button)); - textLabelLine1->setText(newButton.heading); - textLabelLine1->setStyleSheet(QLatin1String("font-weight: bold;")); - auto textLabelLine2 = gsl::owner(new QLabel(button)); - textLabelLine2->setText(newButton.description); - textLabelLine2->setWordWrap(true); - textLayout->addWidget(textLabelLine1); - textLayout->addWidget(textLabelLine2); - textLayout->setSpacing(0); - mainLayout->addItem(textLayout); + auto mainLayout = gsl::owner(new QHBoxLayout(this)); + auto iconLabel = gsl::owner(new QLabel(this)); + mainLayout->addWidget(iconLabel); + QIcon baseIcon(newButton.iconPath); + iconLabel->setPixmap(baseIcon.pixmap(newFileIconSize, newFileIconSize)); + iconLabel->setPixmap(baseIcon.pixmap(newFileIconSize, newFileIconSize)); - mainLayout->addStretch(); + auto textLayout = gsl::owner(new QVBoxLayout); + auto textLabelLine1 = gsl::owner(new QLabel(this)); + textLabelLine1->setText(newButton.heading); + textLabelLine1->setStyleSheet(QLatin1String("font-weight: bold;")); + auto textLabelLine2 = gsl::owner(new QLabel(this)); + textLabelLine2->setText(newButton.description); + textLabelLine2->setWordWrap(true); + textLayout->addWidget(textLabelLine1); + textLayout->addWidget(textLabelLine2); + textLayout->setSpacing(0); + mainLayout->addItem(textLayout); - button->setMinimumHeight(newFileIconSize + cardSpacing); - button->setMinimumWidth(newFileIconSize + cardLabelWith); - return button; -} + mainLayout->addStretch(); + + this->setMinimumHeight(newFileIconSize + cardSpacing); + this->setMinimumWidth(newFileIconSize + cardLabelWith); + + updateStyle(); + } + + void updateStyle() + { + QString style = QStringLiteral(""); + if (qApp->styleSheet().isEmpty()) { + style = fileCardStyle(); + } + setStyleSheet(style); // This will trigger a changeEvent + } + + void changeEvent(QEvent* event) override + { + if (!changeInProgress && event->type() == QEvent::StyleChange) { + changeInProgress = true; // Block recursive calls. + updateStyle(); + changeInProgress = false; + } + + QPushButton::changeEvent(event); + } + + + QString fileCardStyle() const + { + auto hGrp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Start"); + + auto getUserColor = [&hGrp](QColor color, const char* parameter) { + uint32_t packed = App::Color::asPackedRGB(color); + packed = hGrp->GetUnsigned(parameter, packed); + color = App::Color::fromPackedRGB(packed); + return color; + }; + + QColor background(221, 221, 221); // NOLINT + background = getUserColor(background, "FileCardBackgroundColor"); + + QColor hovered(98, 160, 234); // NOLINT + hovered = getUserColor(hovered, "FileCardBorderColor"); + + QColor pressed(38, 162, 105); // NOLINT + pressed = getUserColor(pressed, "FileCardSelectionColor"); + + return QString::fromLatin1("QPushButton {" + " background-color: rgb(%1, %2, %3);" + " border-radius: 8px;" + "}" + "QPushButton:hover {" + " border: 2px solid rgb(%4, %5, %6);" + "}" + "QPushButton:pressed {" + " border: 2px solid rgb(%7, %8, %9);" + "}") + .arg(background.red()) + .arg(background.green()) + .arg(background.blue()) + .arg(hovered.red()) + .arg(hovered.green()) + .arg(hovered.blue()) + .arg(pressed.red()) + .arg(pressed.green()) + .arg(pressed.blue()); + } + +private: + bool changeInProgress = false; +}; } // namespace + StartView::StartView(QWidget* parent) : Gui::MDIView(nullptr, parent) , _contents(new QStackedWidget(parent)) @@ -211,24 +285,30 @@ StartView::StartView(QWidget* parent) void StartView::configureNewFileButtons(QLayout* layout) const { - auto newEmptyFile = createNewButton({tr("Empty file"), - tr("Create a new empty FreeCAD file"), - QLatin1String(":/icons/document-new.svg")}); - auto openFile = createNewButton({tr("Open File"), - tr("Open an existing CAD file or 3D model"), - QLatin1String(":/icons/document-open.svg")}); - auto partDesign = createNewButton({tr("Parametric Part"), - tr("Create a part with the Part Design workbench"), - QLatin1String(":/icons/PartDesignWorkbench.svg")}); - auto assembly = createNewButton({tr("Assembly"), - tr("Create an assembly project"), - QLatin1String(":/icons/AssemblyWorkbench.svg")}); - auto draft = createNewButton({tr("2D Draft"), - tr("Create a 2D Draft with the Draft workbench"), - QLatin1String(":/icons/DraftWorkbench.svg")}); - auto arch = createNewButton({tr("BIM/Architecture"), - tr("Create an architectural project"), - QLatin1String(":/icons/BIMWorkbench.svg")}); + auto newEmptyFile = + gsl::owner(new NewFileButton({tr("Empty file"), + tr("Create a new empty FreeCAD file"), + QLatin1String(":/icons/document-new.svg")})); + auto openFile = + gsl::owner(new NewFileButton({tr("Open File"), + tr("Open an existing CAD file or 3D model"), + QLatin1String(":/icons/document-open.svg")})); + auto partDesign = gsl::owner( + new NewFileButton({tr("Parametric Part"), + tr("Create a part with the Part Design workbench"), + QLatin1String(":/icons/PartDesignWorkbench.svg")})); + auto assembly = gsl::owner( + new NewFileButton({tr("Assembly"), + tr("Create an assembly project"), + QLatin1String(":/icons/AssemblyWorkbench.svg")})); + auto draft = gsl::owner( + new NewFileButton({tr("2D Draft"), + tr("Create a 2D Draft with the Draft workbench"), + QLatin1String(":/icons/DraftWorkbench.svg")})); + auto arch = + gsl::owner(new NewFileButton({tr("BIM/Architecture"), + tr("Create an architectural project"), + QLatin1String(":/icons/BIMWorkbench.svg")})); // TODO: Ensure all of the required WBs are actually available layout->addWidget(partDesign); @@ -246,63 +326,6 @@ void StartView::configureNewFileButtons(QLayout* layout) const connect(arch, &QPushButton::clicked, this, &StartView::newArchFile); } -void StartView::paintEvent(QPaintEvent* event) -{ - QString style = QStringLiteral(""); - if (qApp->styleSheet().isEmpty()) { - style = fileCardStyle(); - } - setStyleSheet(style); - - Gui::MDIView::paintEvent(event); -} - -QString StartView::fileCardStyle() const -{ - if (!qApp->styleSheet().isEmpty()) { - return {}; - } - - auto hGrp = App::GetApplication().GetParameterGroupByPath( - "User parameter:BaseApp/Preferences/Mod/Start"); - - auto getUserColor = [&hGrp](QColor color, const char* parameter) { - uint32_t packed = App::Color::asPackedRGB(color); - packed = hGrp->GetUnsigned(parameter, packed); - color = App::Color::fromPackedRGB(packed); - return color; - }; - - QColor background(221, 221, 221); // NOLINT - background = getUserColor(background, "FileCardBackgroundColor"); - - QColor hovered(98, 160, 234); // NOLINT - hovered = getUserColor(hovered, "FileCardBorderColor"); - - QColor pressed(38, 162, 105); // NOLINT - pressed = getUserColor(pressed, "FileCardSelectionColor"); - - return QString::fromLatin1("QPushButton {" - " background-color: rgb(%1, %2, %3);" - " border-radius: 8px;" - "}" - "QPushButton:hover {" - " border: 2px solid rgb(%4, %5, %6);" - "}" - "QPushButton:pressed {" - " border: 2px solid rgb(%7, %8, %9);" - "}") - .arg(background.red()) - .arg(background.green()) - .arg(background.blue()) - .arg(hovered.red()) - .arg(hovered.green()) - .arg(hovered.blue()) - .arg(pressed.red()) - .arg(pressed.green()) - .arg(pressed.blue()); -} - void StartView::configureFileCardWidget(QListView* fileCardWidget) { auto delegate = gsl::owner(new FileCardDelegate(fileCardWidget)); diff --git a/src/Mod/Start/Gui/StartView.h b/src/Mod/Start/Gui/StartView.h index 9a0df584a2..b9199018d5 100644 --- a/src/Mod/Start/Gui/StartView.h +++ b/src/Mod/Start/Gui/StartView.h @@ -96,8 +96,6 @@ protected: QString fileCardStyle() const; - void paintEvent(QPaintEvent* event) override; - private: void retranslateUi();