diff --git a/CMakeLists.txt b/CMakeLists.txt index 8240fac..a1b1313 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,8 +9,8 @@ set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") set(META_APP_DESCRIPTION "Common Qt related C++ classes and routines used by my applications such as dialogs, widgets and models") set(META_VERSION_MAJOR 6) -set(META_VERSION_MINOR 0) -set(META_VERSION_PATCH 7) +set(META_VERSION_MINOR 1) +set(META_VERSION_PATCH 0) set(META_APP_VERSION ${META_VERSION_MAJOR}.${META_VERSION_MINOR}.${META_VERSION_PATCH}) project(${META_PROJECT_NAME}) diff --git a/widgets/buttonoverlay.cpp b/widgets/buttonoverlay.cpp index 62b5c37..fecd571 100644 --- a/widgets/buttonoverlay.cpp +++ b/widgets/buttonoverlay.cpp @@ -1,8 +1,11 @@ #include "./buttonoverlay.h" #include "./iconbutton.h" +#include +#include #include #include +#include #include #include #include @@ -14,31 +17,60 @@ namespace QtUtilities { /*! * \class ButtonOverlay - * \brief The ButtonOverlay class is used to display buttons on top of other - * widgets. + * \brief The ButtonOverlay class is used to display buttons on top of other widgets. * - * The class creates a new layout manager and sets it to the widget which is - * specified - * when constructing an instance. Thus this widget must not already have a - * layout manager. + * This class had been created before QLineEdit's functions setClearButtonEnabled() and + * addAction() have been available. (These functions have been available only since Qt 5.2.) * - * The class is used to implement widget customization like ClearLineEidt and - * ClearComboBox. + * The downside of the "custom approach" compared to QLineEdit's own functions is that the + * buttons are shown over the text as the text margins are not updated accordingly. Hence + * the ButtonOverlay class has been updated to use QLineEdit's functions internally when the + * specified widget is QLineEdit-based and its QLineEdit has been passed to the constructor. + * However, when using any functions which can not be implemented using QLineEdit's own + * functions, the ButtonOverlay has to fallback to its "custom approach". All functions which + * cause this have a remark in their documentation. + * + * When QLineEdit's functions can not be used, the ButtonOverlay class creates a new layout + * manager and sets it to the widget specified when constructing an instance. Thus this widget + * must not already have a layout manager. + * + * The class is used to implement widget customization like ClearLineEidt and ClearComboBox + * and most of the times it makes sense to use these widgets instead of using ButtonOverlay + * directly. */ /*! * \brief Constructs a button overlay for the specified \a widget. * \param widget Specifies the widget to display the buttons on. + * \remarks This function enforces the "custom approach" mentioned in the class documentation + * and should therefore be avoided. */ ButtonOverlay::ButtonOverlay(QWidget *widget) : m_widget(widget) - , m_buttonWidget(new QWidget(widget)) - , m_buttonLayout(new QHBoxLayout(m_buttonWidget)) + , m_buttonWidget(nullptr) + , m_buttonLayout(nullptr) , m_clearButton(nullptr) - , m_infoButton(nullptr) + , m_infoButtonOrAction(nullptr) { - buttonLayout()->setAlignment(Qt::AlignCenter | Qt::AlignRight); - widget->setLayout(m_buttonLayout); + fallbackToUsingCustomLayout(); +} + +/*! + * \brief Constructs a button overlay for the specified \a widget. + * \param widget Specifies the widget to display the buttons on. + * \param lineEdit Specifies the line edit used by \a widget to use the QLineEdit's functions + * for adding actions instead of a custom layout. + */ +ButtonOverlay::ButtonOverlay(QWidget *widget, QLineEdit *lineEdit) + : m_widget(widget) + , m_buttonWidget(lineEdit) + , m_buttonLayout(nullptr) + , m_clearButton(nullptr) + , m_infoButtonOrAction(nullptr) +{ + if (!m_buttonWidget) { + fallbackToUsingCustomLayout(); + } } /*! @@ -48,17 +80,60 @@ ButtonOverlay::~ButtonOverlay() { } +/*! + * \brief Returns whether the "custom approach" mentioned in the class documentation is used. + */ +bool ButtonOverlay::isUsingCustomLayout() const +{ + return m_buttonLayout != nullptr; +} + +/*! + * \brief Returns the layout manager holding the buttons. + * \remarks This function enforces the "custom approach" mentioned in the class documentation + * and should therefore be avoided. + */ +QHBoxLayout *ButtonOverlay::buttonLayout() +{ + fallbackToUsingCustomLayout(); + return m_buttonLayout; +} + +/*! + * \brief Returns whether the clear button is enabled. + */ +bool ButtonOverlay::isClearButtonEnabled() const +{ + if (isUsingCustomLayout()) { + return m_clearButton != nullptr; + } + return lineEditForWidget()->isClearButtonEnabled(); +} + +/*! + * \brief Returns whether the info button is enabled. + */ +bool ButtonOverlay::isInfoButtonEnabled() const +{ + return m_infoButtonOrAction != nullptr; +} + /*! * \brief Sets whether the clear button is enabled. */ void ButtonOverlay::setClearButtonEnabled(bool enabled) { - if (isClearButtonEnabled() && !enabled) { + if (auto *const le = lineEditForWidget()) { + le->setClearButtonEnabled(enabled); + return; + } + const auto clearButtonEnabled = isClearButtonEnabled(); + if (clearButtonEnabled && !enabled) { // disable clear button m_buttonLayout->removeWidget(m_clearButton); delete m_clearButton; m_clearButton = nullptr; - } else if (!isClearButtonEnabled() && enabled) { + } else if (!clearButtonEnabled && enabled) { // enable clear button m_clearButton = new IconButton; m_clearButton->setHidden(isCleared()); @@ -80,18 +155,27 @@ void ButtonOverlay::setClearButtonEnabled(bool enabled) */ void ButtonOverlay::enableInfoButton(const QPixmap &pixmap, const QString &infoText) { - if (!m_infoButton) { - m_infoButton = new IconButton; - m_infoButton->setGeometry(0, 0, 16, 16); - QObject::connect(m_infoButton, &IconButton::clicked, std::bind(&ButtonOverlay::showInfo, this)); + if (auto *const le = lineEditForWidget()) { + disableInfoButton(); + auto *const action = le->addAction(QIcon(pixmap), QLineEdit::TrailingPosition); + action->setToolTip(infoText); + QObject::connect(action, &QAction::triggered, std::bind(&ButtonOverlay::showInfo, this)); + m_infoButtonOrAction = action; + return; + } + auto *infoButton = static_cast(m_infoButtonOrAction); + if (!infoButton) { + m_infoButtonOrAction = infoButton = new IconButton; + infoButton->setGeometry(0, 0, 16, 16); + QObject::connect(infoButton, &IconButton::clicked, std::bind(&ButtonOverlay::showInfo, this)); if (m_clearButton) { - m_buttonLayout->insertWidget(m_buttonLayout->count() - 2, m_infoButton); + m_buttonLayout->insertWidget(m_buttonLayout->count() - 2, infoButton); } else { - m_buttonLayout->addWidget(m_infoButton); + m_buttonLayout->addWidget(infoButton); } } - m_infoButton->setPixmap(pixmap); - m_infoButton->setToolTip(infoText); + infoButton->setPixmap(pixmap); + infoButton->setToolTip(infoText); } /*! @@ -100,10 +184,17 @@ void ButtonOverlay::enableInfoButton(const QPixmap &pixmap, const QString &infoT */ void ButtonOverlay::disableInfoButton() { - if (m_infoButton) { - m_buttonLayout->removeWidget(m_infoButton); - delete m_infoButton; - m_infoButton = nullptr; + if (auto *const le = lineEditForWidget()) { + if (auto *const infoAction = static_cast(m_infoButtonOrAction)) { + le->removeAction(infoAction); + m_infoButtonOrAction = nullptr; + } + return; + } + if (auto *infoButton = static_cast(m_infoButtonOrAction)) { + m_buttonLayout->removeWidget(infoButton); + delete infoButton; + m_infoButtonOrAction = nullptr; } } @@ -111,9 +202,13 @@ void ButtonOverlay::disableInfoButton() * \brief Adds a custom \a button. * * The button overlay takes ownership over the specified \a button. + * + * \remarks This function enforces the "custom approach" mentioned in the class documentation + * and should therefore be avoided. */ void ButtonOverlay::addCustomButton(QWidget *button) { + fallbackToUsingCustomLayout(); m_buttonLayout->addWidget(button); } @@ -121,9 +216,13 @@ void ButtonOverlay::addCustomButton(QWidget *button) * \brief Inserts a custom \a button at the specified \a index. * * The button overlay takes ownership over the specified \a button. + * + * \remarks This function enforces the "custom approach" mentioned in the class documentation + * and should therefore be avoided. */ void ButtonOverlay::insertCustomButton(int index, QWidget *button) { + fallbackToUsingCustomLayout(); m_buttonLayout->insertWidget(index, button); } @@ -131,16 +230,20 @@ void ButtonOverlay::insertCustomButton(int index, QWidget *button) * \brief Removes the specified custom \a button. * * 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); } /*! * \brief Updates the visibility of the clear button. * - * This method is meant to be called when subclassing. + * This function is meant to be called when subclassing. */ void ButtonOverlay::updateClearButtonVisibility(bool visible) { @@ -152,12 +255,75 @@ void ButtonOverlay::updateClearButtonVisibility(bool visible) /*! * \brief Clears the related widget. * - * This method is meant to be implemented when subclassing. + * This function is meant to be implemented when subclassing to support the clear button. */ void ButtonOverlay::handleClearButtonClicked() { } +/*! + * \brief Applies additional handling when the button layout has been created. + * + * This function is meant to be implemented when subclassing when additional handling is + * required. + */ +void ButtonOverlay::handleCustomLayoutCreated() +{ +} + +/*! + * \brief Switches to the "custom approach". + * \remarks This function is internally used when any legacy function is called + * or when the QLineEdit for the specified widget can not be determined. + */ +void ButtonOverlay::fallbackToUsingCustomLayout() +{ + // skip if custom layout is already used + if (isUsingCustomLayout()) { + return; + } + + // disable QLineEdit's clear button and actions; save configuration + const auto clearButtonEnabled = isClearButtonEnabled(); + if (clearButtonEnabled) { + setClearButtonEnabled(false); + } + auto *const iconAction = static_cast(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(); + } + + // initialize custom layout + m_buttonLayout = new QHBoxLayout(m_buttonWidget); + m_buttonWidget = new QWidget(m_widget); + m_buttonLayout->setAlignment(Qt::AlignCenter | Qt::AlignRight); + m_widget->setLayout(m_buttonLayout); + handleCustomLayoutCreated(); + + // restore old configuration + if (clearButtonEnabled) { + setClearButtonEnabled(true); + } + if (iconAction) { + enableInfoButton(infoPixmap, infoText); + } +} + +/*! + * \brief Returns the QLineEdit used to implement the button overlay. + * \remarks This is always nullptr in case the "custom approach" is used. + */ +QLineEdit *ButtonOverlay::lineEditForWidget() const +{ + return isUsingCustomLayout() ? nullptr : static_cast(m_buttonWidget); +} + /*! * \brief Returns whether the related widget is cleared. * @@ -172,17 +338,27 @@ bool ButtonOverlay::isCleared() const * \brief Shows the info text using a tool tip. * * This method is called when the info button is clicked. + * + * \todo Don't use QCursor::pos() here because it will not work under Wayland. */ void ButtonOverlay::showInfo() { - if (m_infoButton) { - QToolTip::showText(QCursor::pos(), m_infoButton->toolTip(), m_infoButton); + if (!isUsingCustomLayout()) { + if (auto *const infoAction = static_cast(m_infoButtonOrAction)) { + QToolTip::showText(QCursor::pos(), infoAction->toolTip(), m_widget); + } + return; + } + if (auto *const infoButton = static_cast(m_infoButtonOrAction)) { + QToolTip::showText(QCursor::pos(), infoButton->toolTip(), infoButton); } } /*! * \brief Sets the contents margins of the button layout so the overlay buttons will only be shown over the \a editFieldRect and * not interfere with e.g. spin box buttons. + * \remarks This function enforces the "custom approach" mentioned in the class documentation + * and should therefore be avoided. Of course it makes sense to call it within handleCustomLayoutCreated(). */ void ButtonOverlay::setContentsMarginsFromEditFieldRectAndFrameWidth(const QRect &editFieldRect, int frameWidth, int padding) { diff --git a/widgets/buttonoverlay.h b/widgets/buttonoverlay.h index 77a159b..08cb54c 100644 --- a/widgets/buttonoverlay.h +++ b/widgets/buttonoverlay.h @@ -11,6 +11,7 @@ QT_FORWARD_DECLARE_CLASS(QString) QT_FORWARD_DECLARE_CLASS(QPixmap) QT_FORWARD_DECLARE_CLASS(QMargins) QT_FORWARD_DECLARE_CLASS(QRect) +QT_FORWARD_DECLARE_CLASS(QLineEdit) namespace QtUtilities { @@ -29,8 +30,10 @@ class QT_UTILITIES_EXPORT ButtonOverlay { public: explicit ButtonOverlay(QWidget *widget); + explicit ButtonOverlay(QWidget *widget, QLineEdit *lineEdit); virtual ~ButtonOverlay(); + bool isUsingCustomLayout() const; QHBoxLayout *buttonLayout(); bool isClearButtonEnabled() const; void setClearButtonEnabled(bool enabled); @@ -45,8 +48,11 @@ public: protected: void updateClearButtonVisibility(bool visible); virtual void handleClearButtonClicked(); + virtual void handleCustomLayoutCreated(); private: + void fallbackToUsingCustomLayout(); + QLineEdit *lineEditForWidget() const; void showInfo(); void setContentsMarginsFromEditFieldRectAndFrameWidth(const QRect &editFieldRect, int frameWidth, int padding = 0); @@ -54,32 +60,9 @@ private: QWidget *m_buttonWidget; QHBoxLayout *m_buttonLayout; IconButton *m_clearButton; - IconButton *m_infoButton; + void *m_infoButtonOrAction; }; -/*! - * \brief Returns the layout manager holding the buttons. - */ -inline QHBoxLayout *ButtonOverlay::buttonLayout() -{ - return m_buttonLayout; -} - -/*! - * \brief Returns whether the clear button is enabled. - */ -inline bool ButtonOverlay::isClearButtonEnabled() const -{ - return m_clearButton != nullptr; -} - -/*! - * \brief Returns whether the info button is enabled. - */ -inline bool ButtonOverlay::isInfoButtonEnabled() const -{ - return m_infoButton != nullptr; -} } // namespace QtUtilities #endif // WIDGETS_BUTTONOVERLAY_H diff --git a/widgets/clearcombobox.cpp b/widgets/clearcombobox.cpp index f1aff92..a06354e 100644 --- a/widgets/clearcombobox.cpp +++ b/widgets/clearcombobox.cpp @@ -11,20 +11,22 @@ namespace QtUtilities { * \brief A QComboBox with an embedded button for clearing its contents. */ +/// \cond +static inline auto *getComboBoxLineEdit(QComboBox *comboBox) +{ + comboBox->setEditable(true); + return comboBox->lineEdit(); +} +/// \endcond + /*! * \brief Constructs a clear combo box. + * \remarks The combo box is initialized to be editable and which must not be changed. */ ClearComboBox::ClearComboBox(QWidget *parent) : QComboBox(parent) - , ButtonOverlay(this) + , ButtonOverlay(this, getComboBoxLineEdit(this)) { - const QStyle *const s = style(); - QStyleOptionComboBox opt; - opt.initFrom(this); - setContentsMarginsFromEditFieldRectAndFrameWidth( - s->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this), s->pixelMetric(QStyle::PM_ComboBoxFrameWidth, &opt, this)); - setClearButtonEnabled(isEditable()); - connect(this, &ClearComboBox::currentTextChanged, this, &ClearComboBox::handleTextChanged); } /*! @@ -47,6 +49,16 @@ void ClearComboBox::handleClearButtonClicked() clearEditText(); } +void ClearComboBox::handleCustomLayoutCreated() +{ + const QStyle *const s = style(); + QStyleOptionComboBox opt; + opt.initFrom(this); + setContentsMarginsFromEditFieldRectAndFrameWidth( + s->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this), s->pixelMetric(QStyle::PM_ComboBoxFrameWidth, &opt, this)); + connect(this, &ClearComboBox::currentTextChanged, this, &ClearComboBox::handleTextChanged); +} + bool ClearComboBox::isCleared() const { return currentText().isEmpty(); diff --git a/widgets/clearcombobox.h b/widgets/clearcombobox.h index 1738113..fc7ef44 100644 --- a/widgets/clearcombobox.h +++ b/widgets/clearcombobox.h @@ -19,6 +19,7 @@ public: private Q_SLOTS: void handleTextChanged(const QString &text); void handleClearButtonClicked() override; + void handleCustomLayoutCreated() override; }; } // namespace QtUtilities diff --git a/widgets/clearlineedit.cpp b/widgets/clearlineedit.cpp index 7c39d13..f3ddc72 100644 --- a/widgets/clearlineedit.cpp +++ b/widgets/clearlineedit.cpp @@ -15,15 +15,9 @@ namespace QtUtilities { */ ClearLineEdit::ClearLineEdit(QWidget *parent) : QLineEdit(parent) - , ButtonOverlay(this) + , ButtonOverlay(this, this) { - const QStyle *const s = style(); - QStyleOptionFrame opt; - opt.initFrom(this); - setContentsMarginsFromEditFieldRectAndFrameWidth(s->subElementRect(QStyle::SE_LineEditContents, &opt, this), - s->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, m_widget), s->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &opt, m_widget)); ButtonOverlay::setClearButtonEnabled(true); - connect(this, &ClearLineEdit::textChanged, this, &ClearLineEdit::handleTextChanged); } /*! @@ -46,6 +40,16 @@ void ClearLineEdit::handleClearButtonClicked() clear(); } +void ClearLineEdit::handleCustomLayoutCreated() +{ + const QStyle *const s = style(); + QStyleOptionFrame opt; + opt.initFrom(this); + setContentsMarginsFromEditFieldRectAndFrameWidth(s->subElementRect(QStyle::SE_LineEditContents, &opt, this), + s->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, m_widget), s->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &opt, m_widget)); + connect(this, &ClearLineEdit::textChanged, this, &ClearLineEdit::handleTextChanged); +} + bool ClearLineEdit::isCleared() const { return text().isEmpty(); diff --git a/widgets/clearlineedit.h b/widgets/clearlineedit.h index 352eb1b..cd60fc0 100644 --- a/widgets/clearlineedit.h +++ b/widgets/clearlineedit.h @@ -23,6 +23,7 @@ public: private Q_SLOTS: void handleTextChanged(const QString &text); void handleClearButtonClicked() override; + void handleCustomLayoutCreated() override; }; } // namespace QtUtilities diff --git a/widgets/clearplaintextedit.cpp b/widgets/clearplaintextedit.cpp index 6b188cc..0ddeb19 100644 --- a/widgets/clearplaintextedit.cpp +++ b/widgets/clearplaintextedit.cpp @@ -21,18 +21,8 @@ ClearPlainTextEdit::ClearPlainTextEdit(QWidget *parent) : QPlainTextEdit(parent) , ButtonOverlay(viewport()) { - // set alignment to show buttons in the bottom right corner - ButtonOverlay::buttonLayout()->setAlignment(Qt::AlignBottom | Qt::AlignRight); - const QStyle *const s = style(); - QStyleOptionFrame opt; - opt.initFrom(this); - setContentsMarginsFromEditFieldRectAndFrameWidth(s->subElementRect(QStyle::SE_FrameContents, &opt, this), - s->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, m_widget), s->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &opt, m_widget)); + handleCustomLayoutCreated(); ButtonOverlay::setClearButtonEnabled(true); - connect(this, &QPlainTextEdit::textChanged, this, &ClearPlainTextEdit::handleTextChanged); - // ensure button layout is realigned when scrolling - connect(verticalScrollBar(), &QScrollBar::actionTriggered, this, &ClearPlainTextEdit::handleScroll); - connect(this, &QPlainTextEdit::cursorPositionChanged, this, &ClearPlainTextEdit::handleScroll); } /*! @@ -58,6 +48,21 @@ void ClearPlainTextEdit::handleClearButtonClicked() cursor.removeSelectedText(); } +void ClearPlainTextEdit::handleCustomLayoutCreated() +{ + // set alignment to show buttons in the bottom right corner + ButtonOverlay::buttonLayout()->setAlignment(Qt::AlignBottom | Qt::AlignRight); + const QStyle *const s = style(); + QStyleOptionFrame opt; + opt.initFrom(this); + setContentsMarginsFromEditFieldRectAndFrameWidth(s->subElementRect(QStyle::SE_FrameContents, &opt, this), + s->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, m_widget), s->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &opt, m_widget)); + connect(this, &QPlainTextEdit::textChanged, this, &ClearPlainTextEdit::handleTextChanged); + // ensure button layout is realigned when scrolling + connect(verticalScrollBar(), &QScrollBar::actionTriggered, this, &ClearPlainTextEdit::handleScroll); + connect(this, &QPlainTextEdit::cursorPositionChanged, this, &ClearPlainTextEdit::handleScroll); +} + void ClearPlainTextEdit::handleScroll() { buttonLayout()->update(); diff --git a/widgets/clearplaintextedit.h b/widgets/clearplaintextedit.h index cb39265..03aef0e 100644 --- a/widgets/clearplaintextedit.h +++ b/widgets/clearplaintextedit.h @@ -19,6 +19,7 @@ public: private Q_SLOTS: void handleTextChanged(); void handleClearButtonClicked() override; + void handleCustomLayoutCreated() override; void handleScroll(); }; diff --git a/widgets/clearspinbox.cpp b/widgets/clearspinbox.cpp index 308ea07..85bf7c9 100644 --- a/widgets/clearspinbox.cpp +++ b/widgets/clearspinbox.cpp @@ -18,16 +18,10 @@ namespace QtUtilities { */ ClearSpinBox::ClearSpinBox(QWidget *parent) : QSpinBox(parent) - , ButtonOverlay(this) + , ButtonOverlay(this, lineEdit()) , m_minimumHidden(false) { - const QStyle *const s = style(); - QStyleOptionSpinBox opt; - opt.initFrom(this); - setContentsMarginsFromEditFieldRectAndFrameWidth( - s->subControlRect(QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxEditField, this), s->pixelMetric(QStyle::PM_SpinBoxFrameWidth, &opt, this)); - setClearButtonEnabled(true); - connect(this, static_cast(&ClearSpinBox::valueChanged), this, &ClearSpinBox::handleValueChanged); + ButtonOverlay::setClearButtonEnabled(true); } /*! @@ -50,6 +44,16 @@ void ClearSpinBox::handleClearButtonClicked() setValue(minimum()); } +void ClearSpinBox::handleCustomLayoutCreated() +{ + const QStyle *const s = style(); + QStyleOptionSpinBox opt; + opt.initFrom(this); + setContentsMarginsFromEditFieldRectAndFrameWidth( + s->subControlRect(QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxEditField, this), s->pixelMetric(QStyle::PM_SpinBoxFrameWidth, &opt, this)); + connect(this, static_cast(&ClearSpinBox::valueChanged), this, &ClearSpinBox::handleValueChanged); +} + bool ClearSpinBox::isCleared() const { return value() == minimum(); diff --git a/widgets/clearspinbox.h b/widgets/clearspinbox.h index 9736384..1aee2df 100644 --- a/widgets/clearspinbox.h +++ b/widgets/clearspinbox.h @@ -34,6 +34,7 @@ protected: private Q_SLOTS: void handleValueChanged(int value); void handleClearButtonClicked() override; + void handleCustomLayoutCreated() override; private: bool m_minimumHidden;