Qt Utilities: widgets/buttonoverlay.cpp Source File

Qt Utilities 6.21.1 Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models

Loading...
Searching...
No Matches
buttonoverlay.cpp
Go to the documentation of this file.
1#include "./buttonoverlay.h"
2#include "./iconbutton.h"
3
4#include <QAction>
5#include <QComboBox>
6#include <QCursor>
7#include <QHBoxLayout>
8#include <QIcon>
9#include <QLineEdit>
10#include <QStyle>
11#include <QStyleOption>
12#include <QToolTip>
13#include <QWidget>
14
15#include <functional>
16
17namespace QtUtilities {
18
42
49ButtonOverlay::ButtonOverlay(QWidget *widget)
50 : m_widget(widget)
51 , m_buttonWidget(nullptr)
52 , m_buttonLayout(nullptr)
53 , m_clearButton(nullptr)
54 , m_infoButtonOrAction(nullptr)
55{
56 fallbackToUsingCustomLayout();
57}
58
65 ButtonOverlay::ButtonOverlay(QWidget *widget, QLineEdit *lineEdit)
66 : m_widget(widget)
67 , m_buttonWidget(lineEdit)
68 , m_buttonLayout(nullptr)
69 , m_clearButton(nullptr)
70 , m_infoButtonOrAction(nullptr)
71{
72 if (!m_buttonWidget) {
73 fallbackToUsingCustomLayout();
74 }
75}
76
80ButtonOverlay::~ButtonOverlay()
81{
82}
83
87 bool ButtonOverlay::isUsingCustomLayout() const
88{
89 return m_buttonLayout != nullptr;
90}
91
97QHBoxLayout *ButtonOverlay::buttonLayout()
98{
99 fallbackToUsingCustomLayout();
100 return m_buttonLayout;
101}
102
106 bool ButtonOverlay::isClearButtonEnabled() const
107{
108 if (isUsingCustomLayout()) {
109 return m_clearButton != nullptr;
110 }
111 return lineEditForWidget()->isClearButtonEnabled();
112}
113
117 bool ButtonOverlay::isInfoButtonEnabled() const
118{
119 return m_infoButtonOrAction != nullptr;
120}
121
125 void ButtonOverlay::setClearButtonEnabled(bool enabled)
126{
127 if (auto *const le = lineEditForWidget()) {
128 le->setClearButtonEnabled(enabled);
129 return;
130 }
131 const auto clearButtonEnabled = isClearButtonEnabled();
132 if (clearButtonEnabled && !enabled) {
133 // disable clear button
134 m_buttonLayout->removeWidget(m_clearButton);
135 delete m_clearButton;
136 m_clearButton = nullptr;
137 } else if (!clearButtonEnabled && enabled) {
138 // enable clear button
139 m_clearButton = new IconButton;
140 m_clearButton->setHidden(isCleared());
141 m_clearButton->setPixmap(QIcon::fromTheme(QStringLiteral("edit-clear")).pixmap(IconButton::defaultPixmapSize));
142 m_clearButton->setGeometry(QRect(QPoint(), IconButton::defaultPixmapSize));
143 m_clearButton->setToolTip(QObject::tr("Clear"));
144 QObject::connect(m_clearButton, &IconButton::clicked, std::bind(&ButtonOverlay::handleClearButtonClicked, this));
145 m_buttonLayout->addWidget(m_clearButton);
146 }
147}
148
157 void ButtonOverlay::enableInfoButton(const QPixmap &pixmap, const QString &infoText)
158{
159 if (auto *const le = lineEditForWidget()) {
160 disableInfoButton();
161 auto *const action = le->addAction(QIcon(pixmap), QLineEdit::TrailingPosition);
162 action->setToolTip(infoText);
163 QObject::connect(action, &QAction::triggered, std::bind(&ButtonOverlay::showInfo, this));
164 m_infoButtonOrAction = action;
165 return;
166 }
167 auto *infoButton = static_cast<IconButton *>(m_infoButtonOrAction);
168 if (!infoButton) {
169 m_infoButtonOrAction = infoButton = new IconButton;
170 infoButton->setGeometry(QRect(QPoint(), IconButton::defaultPixmapSize));
171 if (m_clearButton) {
172 m_buttonLayout->insertWidget(m_buttonLayout->count() - 2, infoButton);
173 } else {
174 m_buttonLayout->addWidget(infoButton);
175 }
176 }
177 infoButton->setPixmap(pixmap);
178 infoButton->setToolTip(infoText);
179}
180
185 void ButtonOverlay::disableInfoButton()
186{
187 if (auto *const le = lineEditForWidget()) {
188 if (auto *const infoAction = static_cast<QAction *>(m_infoButtonOrAction)) {
189 le->removeAction(infoAction);
190 m_infoButtonOrAction = nullptr;
191 }
192 return;
193 }
194 if (auto *infoButton = static_cast<IconButton *>(m_infoButtonOrAction)) {
195 m_buttonLayout->removeWidget(infoButton);
196 delete infoButton;
197 m_infoButtonOrAction = nullptr;
198 }
199}
200
209 void ButtonOverlay::addCustomButton(QWidget *button)
210{
211 fallbackToUsingCustomLayout();
212 m_buttonLayout->addWidget(button);
213}
214
223 void ButtonOverlay::insertCustomButton(int index, QWidget *button)
224{
225 fallbackToUsingCustomLayout();
226 m_buttonLayout->insertWidget(index, button);
227}
228
234 void ButtonOverlay::removeCustomButton(QWidget *button)
235{
236 if (isUsingCustomLayout()) {
237 m_buttonLayout->removeWidget(button);
238 }
239}
240
244 void ButtonOverlay::addCustomAction(QAction *action)
245{
246 if (auto *const le = lineEditForWidget()) {
247 le->addAction(action, QLineEdit::TrailingPosition);
248 } else {
249 addCustomButton(IconButton::fromAction(action, reinterpret_cast<std::uintptr_t>(this)));
250 }
251}
252
256 void ButtonOverlay::insertCustomAction(int index, QAction *action)
257{
258 if (auto *const le = lineEditForWidget()) {
259 const auto actions = le->actions();
260 le->insertAction(index < actions.size() ? actions[index] : nullptr, action);
261 } else {
262 insertCustomButton(index, IconButton::fromAction(action, reinterpret_cast<std::uintptr_t>(this)));
263 }
264}
265
269 void ButtonOverlay::removeCustomAction(QAction *action)
270{
271 if (auto *const le = lineEditForWidget()) {
272 le->removeAction(action);
273 } else {
274 removeCustomButton(IconButton::fromAction(action, reinterpret_cast<std::uintptr_t>(this)));
275 }
276}
277
283 void ButtonOverlay::updateClearButtonVisibility(bool visible)
284{
285 if (m_clearButton) {
286 m_clearButton->setVisible(visible);
287 }
288}
289
295 void ButtonOverlay::handleClearButtonClicked()
296{
297}
298
305 void ButtonOverlay::handleCustomLayoutCreated()
306{
307}
308
314void ButtonOverlay::fallbackToUsingCustomLayout()
315{
316 // skip if custom layout is already used
317 if (isUsingCustomLayout()) {
318 return;
319 }
320
321 // disable QLineEdit's clear button and actions; save configuration
322 auto clearButtonEnabled = false;
323 auto *iconAction = static_cast<QAction *>(m_infoButtonOrAction);
324 QPixmap infoPixmap;
325 QString infoText;
326 QList<QAction *> actions;
327 if (auto *const le = lineEditForWidget()) {
328 if ((clearButtonEnabled = le->isClearButtonEnabled())) {
329 setClearButtonEnabled(false);
330 }
331 if ((iconAction = static_cast<QAction *>(m_infoButtonOrAction))) {
332 const auto icon = iconAction->icon();
333 const auto sizes = icon.availableSizes();
334 infoPixmap = icon.pixmap(sizes.empty() ? IconButton::defaultPixmapSize : sizes.front());
335 infoText = iconAction->toolTip();
336 disableInfoButton();
337 }
338 actions = le->actions();
339 for (auto *const action : actions) {
340 le->removeAction(action);
341 }
342 }
343
344 // initialize custom layout
345 m_buttonLayout = new QHBoxLayout(m_buttonWidget);
346 m_buttonWidget = new QWidget(m_widget);
347 m_buttonLayout->setAlignment(Qt::AlignCenter | Qt::AlignRight);
348 m_widget->setLayout(m_buttonLayout);
349 handleCustomLayoutCreated();
350
351 // restore old configuration
352 if (clearButtonEnabled) {
353 setClearButtonEnabled(true);
354 }
355 if (iconAction) {
356 enableInfoButton(infoPixmap, infoText);
357 }
358 for (auto *const action : actions) {
359 addCustomAction(action);
360 }
361}
362
367QLineEdit *ButtonOverlay::lineEditForWidget() const
368{
369 return isUsingCustomLayout() ? nullptr : static_cast<QLineEdit *>(m_buttonWidget);
370}
371
377 bool ButtonOverlay::isCleared() const
378{
379 return false;
380}
381
391void ButtonOverlay::showInfo()
392{
393 if (lineEditForWidget()) {
394 if (auto *const infoAction = static_cast<QAction *>(m_infoButtonOrAction)) {
395 if (const auto pos = QCursor::pos(); !pos.isNull()) {
396 QToolTip::showText(pos, infoAction->toolTip(), m_widget);
397 }
398 }
399 return;
400 }
401 if (auto *const infoButton = static_cast<IconButton *>(m_infoButtonOrAction)) {
402 QToolTip::showText(infoButton->mapToGlobal(infoButton->rect().center()), infoButton->toolTip(), infoButton);
403 }
404}
405
412void ButtonOverlay::setContentsMarginsFromEditFieldRectAndFrameWidth(const QRect &editFieldRect, int frameWidth, int padding)
413{
414 const auto margins = m_widget->contentsMargins();
415 const auto buttonWidth = m_widget->width() - editFieldRect.width();
416 buttonLayout()->setContentsMargins(margins.left() + frameWidth + padding, margins.top() + frameWidth,
417 margins.right() + frameWidth + padding + buttonWidth, margins.bottom() + frameWidth);
418}
419
420} // namespace QtUtilities
buttonoverlay.h
QtUtilities::ButtonOverlay::isCleared
virtual bool isCleared() const
Returns whether the related widget is cleared.
Definition buttonoverlay.cpp:377
QtUtilities::ButtonOverlay::updateClearButtonVisibility
void updateClearButtonVisibility(bool visible)
Updates the visibility of the clear button.
Definition buttonoverlay.cpp:283
QtUtilities::ButtonOverlay::buttonLayout
QHBoxLayout * buttonLayout()
Returns the layout manager holding the buttons.
Definition buttonoverlay.cpp:97
QtUtilities::ButtonOverlay::handleCustomLayoutCreated
virtual void handleCustomLayoutCreated()
Applies additional handling when the button layout has been created.
Definition buttonoverlay.cpp:305
QtUtilities::ButtonOverlay::ButtonOverlay
ButtonOverlay(QWidget *widget)
Constructs a button overlay for the specified widget.
Definition buttonoverlay.cpp:49
QtUtilities::ButtonOverlay::insertCustomAction
void insertCustomAction(int index, QAction *action)
Inserts a custom action at the specified index.
Definition buttonoverlay.cpp:256
QtUtilities::ButtonOverlay::isInfoButtonEnabled
bool isInfoButtonEnabled() const
Returns whether the info button is enabled.
Definition buttonoverlay.cpp:117
QtUtilities::ButtonOverlay::enableInfoButton
void enableInfoButton(const QPixmap &pixmap, const QString &infoText)
Shows an info button with the specified pixmap and infoText.
Definition buttonoverlay.cpp:157
QtUtilities::ButtonOverlay::removeCustomButton
void removeCustomButton(QWidget *button)
Removes the specified custom button; does nothing if button has not been added.
Definition buttonoverlay.cpp:234
QtUtilities::ButtonOverlay::isClearButtonEnabled
bool isClearButtonEnabled() const
Returns whether the clear button is enabled.
Definition buttonoverlay.cpp:106
QtUtilities::ButtonOverlay::handleClearButtonClicked
virtual void handleClearButtonClicked()
Clears the related widget.
Definition buttonoverlay.cpp:295
QtUtilities::ButtonOverlay::insertCustomButton
void insertCustomButton(int index, QWidget *button)
Inserts a custom button at the specified index.
Definition buttonoverlay.cpp:223
QtUtilities::ButtonOverlay::isUsingCustomLayout
bool isUsingCustomLayout() const
Returns whether the "custom approach" mentioned in the class documentation is used.
Definition buttonoverlay.cpp:87
QtUtilities::ButtonOverlay::addCustomButton
void addCustomButton(QWidget *button)
Adds a custom button.
Definition buttonoverlay.cpp:209
QtUtilities::ButtonOverlay::~ButtonOverlay
virtual ~ButtonOverlay()
Destroys the button overlay.
Definition buttonoverlay.cpp:80
QtUtilities::ButtonOverlay::removeCustomAction
void removeCustomAction(QAction *action)
Removes the specified custom action; does nothing if action has not been added.
Definition buttonoverlay.cpp:269
QtUtilities::ButtonOverlay::disableInfoButton
void disableInfoButton()
Hides an info button if one is shown.
Definition buttonoverlay.cpp:185
QtUtilities::ButtonOverlay::addCustomAction
void addCustomAction(QAction *action)
Adds a custom action.
Definition buttonoverlay.cpp:244
QtUtilities::ButtonOverlay::setClearButtonEnabled
void setClearButtonEnabled(bool enabled)
Sets whether the clear button is enabled.
Definition buttonoverlay.cpp:125
QtUtilities::IconButton
A simple QAbstractButton implementation displaying a QPixmap.
Definition iconbutton.h:15
QtUtilities::IconButton::setPixmap
void setPixmap(const QPixmap &pixmap)
Sets the pixmap.
Definition iconbutton.h:54
QtUtilities::IconButton::defaultPixmapSize
static constexpr auto defaultPixmapSize
Definition iconbutton.h:28
QtUtilities::IconButton::fromAction
static IconButton * fromAction(QAction *action, std::uintptr_t id=0)
Creates an IconButton for the specified action.
Definition iconbutton.cpp:41
iconbutton.h
QtUtilities
!
Definition trylocker.h:8