Utils: Add push button with menu and default click action

QPushButton has the functionality of setting a menu, but that replaces
the normal "click" functionality, and always opens the menu on click.

QToolButton can have a menu and the user can still click on it to just
click. But, QToolButton looks very different, and in combination with
other, normal push buttons very alien.

Create a push button that only shows the menu when clicking on/near the
menu indicator, and otherwise just sends the clicked() signal like a
non-menu push button.

Change-Id: Id6ba367e40c370275f67f0fbf77521c2e974b3b8
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Eike Ziller
2022-11-29 10:30:11 +01:00
parent 69ce2a4047
commit a499058a6f
4 changed files with 122 additions and 0 deletions

View File

@@ -106,6 +106,8 @@ add_qtc_library(Utils
namevaluevalidator.cpp namevaluevalidator.h
navigationtreeview.cpp navigationtreeview.h
networkaccessmanager.cpp networkaccessmanager.h
optionpushbutton.h
optionpushbutton.cpp
osspecificaspects.h
outputformat.h
outputformatter.cpp outputformatter.h

View File

@@ -0,0 +1,87 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "optionpushbutton.h"
#include <QMouseEvent>
#include <QPushButton>
#include <QStyleOptionButton>
namespace Utils {
/*!
\class Utils::OptionPushButton
\brief The OptionPushButton class implements a QPushButton for which the menu is only opened
if the user presses the menu indicator.
Use OptionPushButton::setOptionalMenu() to set the menu and its actions.
If the users clicks on the menu indicator of the push button, this menu is opened, and
its actions are triggered when the user selects them.
If the user clicks anywhere else on the button, the QAbstractButton::clicked() signal is
sent, as if the button didn't have a menu.
Note: You may not call QPushButton::setMenu(). Use OptionPushButton::setOptionalMenu() instead.
*/
/*!
Constructs an option push button with parent \a parent.
*/
OptionPushButton::OptionPushButton(QWidget *parent)
: QPushButton(parent)
{}
/*!
Constructs an option push button with text \a text and parent \a parent.
*/
OptionPushButton::OptionPushButton(const QString &text, QWidget *parent)
: QPushButton(text, parent)
{}
/*!
Associates the popup menu \a menu with this push button.
This menu is shown if the user clicks on the menu indicator that is shown.
If the user clicks anywhere else on the button, QAbstractButton::clicked() is sent instead.
Ownership of the menu is not transferred to the push button.
*/
void OptionPushButton::setOptionalMenu(QMenu *menu)
{
setMenu(menu);
// hack away that QPushButton opens the menu on "pressed"
disconnect(this, SIGNAL(pressed()), this, SLOT(_q_popupPressed()));
}
/*!
\internal
*/
void OptionPushButton::mouseReleaseEvent(QMouseEvent *event)
{
if (!menu() || event->button() != Qt::LeftButton)
return QPushButton::mouseReleaseEvent(event);
setDown(false);
const QRect r = rect();
if (!r.contains(event->position().toPoint()))
return;
QStyleOptionButton option;
initStyleOption(&option);
// for Mac style
const QRect contentRect = style()->subElementRect(QStyle::SE_PushButtonContents, &option, this);
// for Common style
const int menuButtonSize = style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &option, this);
// see: newBtn.rect = QRect(ir.right() - mbi - 2, ir.height()/2 - mbi/2 + 3, mbi - 6, mbi - 6);
// in QCommonStyle::drawControl, CE_PushButtonBevel, QStyleOptionButton::HasMenu
static const int magicBorder = 4;
const int clickX = event->position().toPoint().x();
if ((option.direction == Qt::LeftToRight
&& clickX <= std::min(contentRect.right(), r.right() - menuButtonSize - magicBorder))
|| (option.direction == Qt::RightToLeft
&& clickX >= std::max(contentRect.left(), r.left() + menuButtonSize + magicBorder))) {
click();
} else {
showMenu();
}
}
} // namespace Utils

View File

@@ -0,0 +1,31 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include "utils_global.h"
#include <QPushButton>
QT_BEGIN_NAMESPACE
class QMenu;
class QMouseEvent;
QT_END_NAMESPACE
namespace Utils {
class QTCREATOR_UTILS_EXPORT OptionPushButton : public QPushButton
{
Q_OBJECT
public:
OptionPushButton(QWidget *parent = nullptr);
OptionPushButton(const QString &text, QWidget *parent = nullptr);
void setOptionalMenu(QMenu *menu);
protected:
void mouseReleaseEvent(QMouseEvent *event) override;
};
} // namespace Utils

View File

@@ -208,6 +208,8 @@ Project {
"navigationtreeview.h",
"networkaccessmanager.cpp",
"networkaccessmanager.h",
"optionpushbutton.h",
"optionpushbutton.cpp",
"osspecificaspects.h",
"outputformat.h",
"outputformatter.cpp",