Gui: Add SplitButton widget

This adds SplitButton widget that has one primary action and possibly
more secondary ones accessible via menu.
This commit is contained in:
Kacper Donat
2025-11-26 23:35:36 +01:00
parent 4e74031e06
commit c500408a6d
7 changed files with 191 additions and 7 deletions

View File

@@ -2603,6 +2603,18 @@ void Application::setStyleSheet(const QString& qssFile, bool tiledBackground)
mw->setProperty("fc_currentStyleSheet", qssFile);
mw->setProperty("fc_tiledBackground", tiledBackground);
QString defaultStyleSheet = [this]() {
QFile f("qss:defaults.qss");
if (!f.open(QFile::ReadOnly)) {
return QString();
}
QTextStream in(&f);
return replaceVariablesInQss(in.readAll());
}();
if (!qssFile.isEmpty()) {
// Search for stylesheet in user-defined search paths.
// For qss they are set-up in runApplication() with the prefix "qss"
@@ -2622,7 +2634,7 @@ void Application::setStyleSheet(const QString& qssFile, bool tiledBackground)
QString styleSheetContent = replaceVariablesInQss(str.readAll());
qApp->setStyleSheet(styleSheetContent);
qApp->setStyleSheet(defaultStyleSheet + QStringLiteral("\n") + styleSheetContent);
ActionStyleEvent e(ActionStyleEvent::Clear);
qApp->sendEvent(mw, &e);
@@ -2650,13 +2662,13 @@ void Application::setStyleSheet(const QString& qssFile, bool tiledBackground)
}
else {
if (tiledBackground) {
qApp->setStyleSheet(QString());
qApp->setStyleSheet(defaultStyleSheet);
ActionStyleEvent e(ActionStyleEvent::Restore);
qApp->sendEvent(getMainWindow(), &e);
mdi->setBackground(QPixmap(QLatin1String("images:background.png")));
}
else {
qApp->setStyleSheet(QString());
qApp->setStyleSheet(defaultStyleSheet);
ActionStyleEvent e(ActionStyleEvent::Restore);
qApp->sendEvent(getMainWindow(), &e);
mdi->setBackground(QBrush(QColor(160, 160, 160)));

View File

@@ -1226,6 +1226,7 @@ SET(Widget_CPP_SRCS
ElideLabel.cpp
ElideCheckBox.cpp
FontScaledSVG.cpp
SplitButton.cpp
)
SET(Widget_HPP_SRCS
ComboLinks.h
@@ -1251,6 +1252,7 @@ SET(Widget_HPP_SRCS
ElideLabel.h
ElideCheckBox.h
FontScaledSVG.h
SplitButton.h
)
SET(Widget_SRCS
${Widget_CPP_SRCS}

62
src/Gui/SplitButton.cpp Normal file
View File

@@ -0,0 +1,62 @@
// 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 "SplitButton.h"
#include <QHBoxLayout>
using namespace Gui;
SplitButton::SplitButton(QWidget* parent)
: SplitButton(QStringLiteral(""), parent)
{}
SplitButton::SplitButton(const QString& text, QWidget* parent)
: QWidget(parent)
, m_main(new QPushButton(text, this))
, m_menuButton(new QToolButton(this))
, m_menu(new QMenu(this))
{
auto* layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->addWidget(m_main);
layout->addWidget(m_menuButton);
// Behavior
m_main->setAutoDefault(false);
m_main->setDefault(false);
m_menuButton->setMenu(m_menu);
m_menuButton->setPopupMode(QToolButton::InstantPopup);
m_menuButton->setArrowType(Qt::DownArrow);
m_menuButton->setToolButtonStyle(Qt::ToolButtonIconOnly);
connect(m_main, &QPushButton::clicked, this, &SplitButton::defaultClicked);
connect(m_menu, &QMenu::triggered, this, &SplitButton::triggered);
// Styling to make it look like a single split button
m_main->setProperty("splitRole", "main");
m_menuButton->setProperty("splitRole", "menu");
}

69
src/Gui/SplitButton.h Normal file
View File

@@ -0,0 +1,69 @@
// 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_FCSPLITBUTTON_H
#define FREECAD_FCSPLITBUTTON_H
#include <QWidget>
#include <QPushButton>
#include <QToolButton>
#include <QMenu>
namespace Gui
{
class SplitButton: public QWidget
{
Q_OBJECT
public:
explicit SplitButton(QWidget* parent = nullptr);
explicit SplitButton(const QString& text, QWidget* parent = nullptr);
QPushButton* mainButton() const
{
return m_main;
}
QToolButton* menuButton() const
{
return m_menuButton;
}
QMenu* menu() const
{
return m_menu;
}
Q_SIGNALS:
void defaultClicked();
void triggered(QAction*);
private:
QPushButton* m_main;
QToolButton* m_menuButton;
QMenu* m_menu;
};
} // namespace Gui
#endif // FREECAD_FCSPLITBUTTON_H

View File

@@ -1,9 +1,10 @@
SET(Stylesheets_Files
"FreeCAD.qss"
#remove below after testing new stylesheet system 8/6/2025
"FreeCAD Dark.qss"
"FreeCAD Light.qss"
"FreeCAD.qss"
"defaults.qss"
#remove below after testing new stylesheet system 8/6/2025
"FreeCAD Dark.qss"
"FreeCAD Light.qss"
)
SET(Parameters_Files

View File

@@ -1369,6 +1369,24 @@ QToolButton::menu-arrow:hover {
image: url(qss:@IconsLocationFolderName/arrow-down-@StylesheetIconsColor.svg);
}
/* Gui::SplitButton --------------------------------------------------------- */
Gui--SplitButton QPushButton[splitRole="main"] {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
Gui--SplitButton QToolButton[splitRole="menu"] {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
Gui--SplitButton QToolButton::menu-indicator {
image: none;
border-image: none;
}
/* QCommandLinkButton -----------------------------------------------------
--------------------------------------------------------------------------- */

View File

@@ -0,0 +1,20 @@
/*
* This is a file with default QSS styles that will be preincluded for all themes. It should cover only the styles for
* our own controls and not alter visuals of stuff like buttons etc. This is created so we can use QSS to add color
* to links or control certain aspects of program looks that should be shared across all styles, including classic.
*/
/* Gui::SplitButton --------------------------------------------------------- */
Gui--SplitButton QToolButton[splitRole="menu"] {
width: 24px;
margin: 0;
padding: 0;
min-height: 0px;
max-height: none;
}
Gui--SplitButton QToolButton::menu-indicator {
image: none;
border-image: none;
}