diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index bfc8e943ce..51e724cd17 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -141,6 +142,7 @@ #include "Inventor/SoFCPlacementIndicatorKit.h" #include "QtWidgets.h" +#include #include #include #include @@ -2768,6 +2770,38 @@ QString Application::replaceVariablesInQss(const QString& qssText) return QString::fromStdString(d->styleParameterManager->replacePlaceholders(qssText.toStdString())); } +void Application::setStyle(const QString& name) +{ + const auto createStyleFromName = [](const QString& name) -> QStyle* { + if (name == "FreeCAD") { + return new FreeCADStyle(); + } + + if (name.compare("System", Qt::CaseInsensitive) == 0) { + return nullptr; + } + + return QStyleFactory::create(name); + }; + + const auto requiresEventFilter = [](QStyle* style) { + // for now only FreeCAD style requires additional event processing + return qobject_cast(style) != nullptr; + }; + + if (auto* current = qApp->style(); current != nullptr && requiresEventFilter(current)) { + qApp->removeEventFilter(current); + } + + if (auto* style = createStyleFromName(name)) { + qApp->setStyle(style); + + if (requiresEventFilter(style)) { + qApp->installEventFilter(style); + } + } +} + void Application::checkForDeprecatedSettings() { // From 0.21, `FCBak` will be the intended default backup format diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 8a2c634f84..61f15225df 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -236,6 +236,9 @@ public: void setStyleSheet(const QString& qssFile, bool tiledBackground); void reloadStyleSheet(); QString replaceVariablesInQss(const QString& qssText); + + /// Set QStyle by name + void setStyle(const QString& name); //@} /** @name User Commands */ diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index a21133643a..4a1ec8a1c4 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1371,6 +1371,7 @@ SET(FreeCADGui_CPP_SRCS ExpressionCompleter.cpp FileHandler.cpp FileHandler.h + FreeCADStyle.cpp GuiApplication.cpp GuiApplicationNativeEventAware.cpp GuiConsole.cpp @@ -1408,6 +1409,7 @@ SET(FreeCADGui_SRCS ExpressionBindingPy.h ExpressionCompleter.h FreeCADGuiInit.py + FreeCADStyle.h GraphicsViewZoom.h GuiApplication.h GuiApplicationNativeEventAware.h diff --git a/src/Gui/FreeCADStyle.cpp b/src/Gui/FreeCADStyle.cpp new file mode 100644 index 0000000000..09e32fe641 --- /dev/null +++ b/src/Gui/FreeCADStyle.cpp @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2025 Kacper Donat * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: 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.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#include "FreeCADStyle.h" + +using namespace Gui; + +bool FreeCADStyle::eventFilter(QObject* obj, QEvent* event) +{ + // This is a hacky fix for https://github.com/FreeCAD/FreeCAD/issues/23607 + // Basically after widget is shown or polished we enforce it's minimum size to at least cover + // the minimum size hint - something that QSS ignores if min-width is specified + if (event->type() == QEvent::Polish || event->type() == QEvent::Show) { + if (auto* btn = qobject_cast(obj)) { + btn->setMinimumWidth(std::max(btn->minimumSizeHint().width(), btn->minimumWidth())); + } + } + + return QObject::eventFilter(obj, event); +} diff --git a/src/Gui/FreeCADStyle.h b/src/Gui/FreeCADStyle.h new file mode 100644 index 0000000000..d795a295b1 --- /dev/null +++ b/src/Gui/FreeCADStyle.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/**************************************************************************** + * * + * Copyright (c) 2025 Kacper Donat * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: 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.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + ***************************************************************************/ + +#ifndef FREECAD_FREECADSTYLE_H +#define FREECAD_FREECADSTYLE_H + +#include +#include +#include +#include + +namespace Gui +{ + +class GuiExport FreeCADStyle: public QProxyStyle +{ + Q_OBJECT + +public: + FreeCADStyle() + : QProxyStyle(QStringLiteral("Fusion")) + {} + +protected: + bool eventFilter(QObject* obj, QEvent* event) override; +}; + +} // namespace Gui + +#endif // FREECAD_FREECADSTYLE_H diff --git a/src/Gui/PreferencePacks/FreeCAD Dark/FreeCAD Dark.cfg b/src/Gui/PreferencePacks/FreeCAD Dark/FreeCAD Dark.cfg index 430b53146f..3bd3e35e9e 100644 --- a/src/Gui/PreferencePacks/FreeCAD Dark/FreeCAD Dark.cfg +++ b/src/Gui/PreferencePacks/FreeCAD Dark/FreeCAD Dark.cfg @@ -25,7 +25,7 @@ Freecad Overlay.qss - Fusion + FreeCAD FreeCAD.qss FreeCAD Dark diff --git a/src/Gui/PreferencePacks/FreeCAD Light/FreeCAD Light.cfg b/src/Gui/PreferencePacks/FreeCAD Light/FreeCAD Light.cfg index 7f13118993..a67328d221 100644 --- a/src/Gui/PreferencePacks/FreeCAD Light/FreeCAD Light.cfg +++ b/src/Gui/PreferencePacks/FreeCAD Light/FreeCAD Light.cfg @@ -22,7 +22,7 @@ Freecad Overlay.qss - Fusion + FreeCAD FreeCAD.qss FreeCAD Light diff --git a/src/Gui/PreferencePages/DlgSettingsGeneral.cpp b/src/Gui/PreferencePages/DlgSettingsGeneral.cpp index 0bb37c9a44..3cdc709534 100644 --- a/src/Gui/PreferencePages/DlgSettingsGeneral.cpp +++ b/src/Gui/PreferencePages/DlgSettingsGeneral.cpp @@ -275,10 +275,7 @@ void DlgSettingsGeneral::saveSettings() hGrp->SetBool("TiledBackground", ui->tiledBackground->isChecked()); if (themeChanged) { - auto qtStyle = QString::fromStdString(hGrp->GetASCII("QtStyle")); - saveThemes(); - qApp->setStyle(qtStyle); } } diff --git a/src/Gui/StartupProcess.cpp b/src/Gui/StartupProcess.cpp index 2df30da339..5e83fbcc44 100644 --- a/src/Gui/StartupProcess.cpp +++ b/src/Gui/StartupProcess.cpp @@ -22,6 +22,7 @@ **************************************************************************/ #include +#include #ifdef FC_OS_WIN32 # include @@ -37,6 +38,7 @@ #include #include #include + #include #include @@ -52,6 +54,8 @@ #include "MainWindow.h" #include "Language/Translator.h" #include "Dialogs/DlgVersionMigrator.h" +#include "FreeCADStyle.h" + #include #include @@ -309,19 +313,24 @@ void StartupPostProcess::setCursorFlashing() QApplication::setCursorFlashTime(blinkTime); } + void StartupPostProcess::setQtStyle() { + static ParamHandlers handlers; + ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("MainWindow"); - auto qtStyle = hGrp->GetASCII("QtStyle"); - if (qtStyle.empty()) { - qtStyle = "Fusion"; - hGrp->SetASCII("QtStyle", qtStyle); - } - else if (qtStyle == "System") { - // Special value to not set a QtStyle explicitly - return; - } - QApplication::setStyle(QString::fromStdString(qtStyle)); + + const auto setStyleFromParameters = [hGrp]() { + const auto style = hGrp->GetASCII("QtStyle"); + + Application::Instance->setStyle(QString::fromStdString(style)); + }; + + auto handler = handlers.addHandler(hGrp, "QtStyle", [setStyleFromParameters](const ParamKey*) { + setStyleFromParameters(); + }); + + setStyleFromParameters(); } void StartupPostProcess::checkOpenGL()