Gui: Respect both content size and minimum width for buttons

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.
This commit is contained in:
Kacper Donat
2025-12-06 22:45:53 +01:00
committed by Chris Hennes
parent 16032ae34c
commit aefd2592a8
9 changed files with 150 additions and 15 deletions

View File

@@ -39,6 +39,7 @@
#include <QTextStream>
#include <QTimer>
#include <QWindow>
#include <QStyleFactory>
#include <QLoggingCategory>
#include <fmt/format.h>
@@ -141,6 +142,7 @@
#include "Inventor/SoFCPlacementIndicatorKit.h"
#include "QtWidgets.h"
#include <FreeCADStyle.h>
#include <OverlayManager.h>
#include <ParamHandler.h>
#include <Base/ServiceProvider.h>
@@ -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<FreeCADStyle*>(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

View File

@@ -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 */

View File

@@ -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

40
src/Gui/FreeCADStyle.cpp Normal file
View File

@@ -0,0 +1,40 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2025 Kacper Donat <kacper@kadet.net> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#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<QPushButton*>(obj)) {
btn->setMinimumWidth(std::max(btn->minimumSizeHint().width(), btn->minimumWidth()));
}
}
return QObject::eventFilter(obj, event);
}

50
src/Gui/FreeCADStyle.h Normal file
View File

@@ -0,0 +1,50 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2025 Kacper Donat <kacper@kadet.net> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#ifndef FREECAD_FREECADSTYLE_H
#define FREECAD_FREECADSTYLE_H
#include <FCGlobal.h>
#include <QProxyStyle>
#include <QEvent>
#include <QPushButton>
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

View File

@@ -25,7 +25,7 @@
</FCParamGroup>
<FCParamGroup Name="MainWindow">
<FCText Name="OverlayActiveStyleSheet">Freecad Overlay.qss</FCText>
<FCText Name="QtStyle">Fusion</FCText>
<FCText Name="QtStyle">FreeCAD</FCText>
<FCText Name="StyleSheet">FreeCAD.qss</FCText>
<FCText Name="Theme">FreeCAD Dark</FCText>
</FCParamGroup>

View File

@@ -22,7 +22,7 @@
</FCParamGroup>
<FCParamGroup Name="MainWindow">
<FCText Name="OverlayActiveStyleSheet">Freecad Overlay.qss</FCText>
<FCText Name="QtStyle">Fusion</FCText>
<FCText Name="QtStyle">FreeCAD</FCText>
<FCText Name="StyleSheet">FreeCAD.qss</FCText>
<FCText Name="Theme">FreeCAD Light</FCText>
</FCParamGroup>

View File

@@ -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);
}
}

View File

@@ -22,6 +22,7 @@
**************************************************************************/
#include <FCConfig.h>
#include <ParamHandler.h>
#ifdef FC_OS_WIN32
# include <windows.h>
@@ -37,6 +38,7 @@
#include <QThread>
#include <QTimer>
#include <QWindow>
#include <Inventor/SoDB.h>
#include <set>
@@ -52,6 +54,8 @@
#include "MainWindow.h"
#include "Language/Translator.h"
#include "Dialogs/DlgVersionMigrator.h"
#include "FreeCADStyle.h"
#include <App/Application.h>
#include <Base/Console.h>
@@ -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()