Allow adding custom actions to button overlay

Of course it would is possible to add actions directly to the line edit.
These new helper functions have the advantage that they provide a fallback
to the old button overlay implementation in case line edit actions can not
be used.
This commit is contained in:
Martchus 2020-06-09 23:24:24 +02:00
parent 5974690006
commit ee7539cf6e
4 changed files with 117 additions and 17 deletions

View File

@ -5,6 +5,7 @@
#include <QComboBox>
#include <QCursor>
#include <QHBoxLayout>
#include <QIcon>
#include <QLineEdit>
#include <QStyle>
#include <QStyleOption>
@ -227,17 +228,52 @@ void ButtonOverlay::insertCustomButton(int index, QWidget *button)
}
/*!
* \brief Removes the specified custom \a button.
* \brief Removes the specified custom \a button; does nothing if \a button has not been added.
*
* The ownership of widget remains the same as when it was added.
*
* \remarks This function enforces the "custom approach" mentioned in the class documentation
* and should therefore be avoided.
*/
void ButtonOverlay::removeCustomButton(QWidget *button)
{
fallbackToUsingCustomLayout();
m_buttonLayout->removeWidget(button);
if (isUsingCustomLayout()) {
m_buttonLayout->removeWidget(button);
}
}
/*!
* \brief Adds a custom \a action.
*/
void ButtonOverlay::addCustomAction(QAction *action)
{
if (auto *const le = lineEditForWidget()) {
le->addAction(action, QLineEdit::TrailingPosition);
} else {
addCustomButton(IconButton::fromAction(action, reinterpret_cast<std::uintptr_t>(this)));
}
}
/*!
* \brief Inserts a custom \a action at the specified \a index.
*/
void ButtonOverlay::insertCustomAction(int index, QAction *action)
{
if (auto *const le = lineEditForWidget()) {
const auto actions = le->actions();
le->insertAction(index < actions.size() ? actions[index] : nullptr, action);
} else {
insertCustomButton(index, IconButton::fromAction(action, reinterpret_cast<std::uintptr_t>(this)));
}
}
/*!
* \brief Removes the specified custom \a action; does nothing if \a action has not been added.
*/
void ButtonOverlay::removeCustomAction(QAction *action)
{
if (auto *const le = lineEditForWidget()) {
le->removeAction(action);
} else {
removeCustomButton(IconButton::fromAction(action, reinterpret_cast<std::uintptr_t>(this)));
}
}
/*!
@ -284,19 +320,23 @@ void ButtonOverlay::fallbackToUsingCustomLayout()
}
// disable QLineEdit's clear button and actions; save configuration
const auto clearButtonEnabled = isClearButtonEnabled();
if (clearButtonEnabled) {
setClearButtonEnabled(false);
}
auto *const iconAction = static_cast<QAction *>(m_infoButtonOrAction);
auto clearButtonEnabled = false;
auto *iconAction = static_cast<QAction *>(m_infoButtonOrAction);
QPixmap infoPixmap;
QString infoText;
if (iconAction) {
const auto icon = iconAction->icon();
const auto sizes = icon.availableSizes();
infoPixmap = icon.pixmap(sizes.empty() ? QSize(16, 16) : sizes.front());
infoText = iconAction->toolTip();
disableInfoButton();
QList<QAction *> actions;
if (auto const *le = lineEditForWidget()) {
if ((clearButtonEnabled = le->isClearButtonEnabled())) {
setClearButtonEnabled(false);
}
if ((iconAction = static_cast<QAction *>(m_infoButtonOrAction))) {
const auto icon = iconAction->icon();
const auto sizes = icon.availableSizes();
infoPixmap = icon.pixmap(sizes.empty() ? QSize(16, 16) : sizes.front());
infoText = iconAction->toolTip();
disableInfoButton();
}
actions = le->actions();
}
// initialize custom layout
@ -313,6 +353,9 @@ void ButtonOverlay::fallbackToUsingCustomLayout()
if (iconAction) {
enableInfoButton(infoPixmap, infoText);
}
for (auto *const action : actions) {
addCustomAction(action);
}
}
/*!

View File

@ -5,6 +5,7 @@
#include <QtGlobal>
QT_FORWARD_DECLARE_CLASS(QAction)
QT_FORWARD_DECLARE_CLASS(QWidget)
QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
QT_FORWARD_DECLARE_CLASS(QString)
@ -43,6 +44,9 @@ public:
void addCustomButton(QWidget *button);
void insertCustomButton(int index, QWidget *button);
void removeCustomButton(QWidget *button);
void addCustomAction(QAction *action);
void insertCustomAction(int index, QAction *action);
void removeCustomAction(QAction *action);
virtual bool isCleared() const;
protected:

View File

@ -1,10 +1,14 @@
#include "./iconbutton.h"
#include <c++utilities/conversion/stringbuilder.h>
#include <QKeyEvent>
#include <QStyle>
#include <QStyleOptionFocusRect>
#include <QStylePainter>
using namespace CppUtilities;
namespace QtUtilities {
/*!
@ -29,6 +33,46 @@ IconButton::~IconButton()
{
}
/*!
* \brief Creates an IconButton for the specified \a action.
* \remarks Calling this function on the same action twice with the same \a id yields the
* same instance.
*/
IconButton *IconButton::fromAction(QAction *action, std::uintptr_t id)
{
const auto propertyName = argsToString("iconButton-", id);
const auto existingIconButton = action->property(propertyName.data());
if (!existingIconButton.isNull()) {
return existingIconButton.value<IconButton *>();
}
auto *const iconButton = new IconButton;
iconButton->assignDataFromAction(action);
action->setProperty(propertyName.data(), QVariant::fromValue(iconButton));
connect(action, &QAction::changed, iconButton, &IconButton::assignDataFromActionChangedSignal);
connect(iconButton, &IconButton::clicked, action, &QAction::trigger);
return iconButton;
}
/*!
* \brief Internally called to assign data from a QAction to the icon button.
*/
void IconButton::assignDataFromActionChangedSignal()
{
assignDataFromAction(qobject_cast<const QAction *>(QObject::sender()));
}
/*!
* \brief Internally called to assign data from a QAction to the icon button.
*/
void IconButton::assignDataFromAction(const QAction *action)
{
auto const icon = action->icon();
const auto sizes = icon.availableSizes();
const auto text = action->text();
setPixmap(icon.pixmap(sizes.empty() ? QSize(16, 16) : sizes.front()));
setToolTip(text.isEmpty() ? action->toolTip() : text);
}
QSize IconButton::sizeHint() const
{
#if QT_VERSION >= 0x050100
@ -77,4 +121,5 @@ void IconButton::keyReleaseEvent(QKeyEvent *event)
QAbstractButton::keyReleaseEvent(event);
event->accept();
}
} // namespace QtUtilities

View File

@ -4,8 +4,11 @@
#include "../global.h"
#include <QAbstractButton>
#include <QAction>
#include <QPixmap>
#include <cstdint>
namespace QtUtilities {
class QT_UTILITIES_EXPORT IconButton : public QAbstractButton {
@ -16,6 +19,7 @@ public:
explicit IconButton(QWidget *parent = nullptr);
~IconButton() override;
static IconButton *fromAction(QAction *action, std::uintptr_t id = 0);
const QPixmap &pixmap() const;
void setPixmap(const QPixmap &pixmap);
QSize sizeHint() const override;
@ -25,6 +29,10 @@ protected:
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
private Q_SLOTS:
void assignDataFromActionChangedSignal();
void assignDataFromAction(const QAction *action);
private:
QPixmap m_pixmap;
};