diff options
-rw-r--r-- | src/widgets/widgets/qlineedit.cpp | 5 | ||||
-rw-r--r-- | src/widgets/widgets/qlineedit_p.cpp | 98 | ||||
-rw-r--r-- | src/widgets/widgets/qlineedit_p.h | 15 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp | 3 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp | 79 |
5 files changed, 169 insertions, 31 deletions
diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index 242a4405ca..2ae2e16c89 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -488,7 +488,10 @@ void QLineEdit::setClearButtonEnabled(bool enable) QAction *clearAction = new QAction(d->clearButtonIcon(), QString(), this); clearAction->setEnabled(!isReadOnly()); clearAction->setObjectName(QLatin1String(clearButtonActionNameC)); - d->addAction(clearAction, 0, QLineEdit::TrailingPosition, QLineEditPrivate::SideWidgetClearButton | QLineEditPrivate::SideWidgetFadeInWithText); + + int flags = QLineEditPrivate::SideWidgetClearButton | QLineEditPrivate::SideWidgetFadeInWithText; + auto widgetAction = d->addAction(clearAction, nullptr, QLineEdit::TrailingPosition, flags); + widgetAction->setVisible(!text().isEmpty()); } else { QAction *clearAction = findChild<QAction *>(QLatin1String(clearButtonActionNameC)); Q_ASSERT(clearAction); diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index df8d534afa..6dcb2dd693 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -392,9 +392,47 @@ void QLineEditIconButton::setOpacity(qreal value) } #if QT_CONFIG(animation) +bool QLineEditIconButton::shouldHideWithText() const +{ + return m_hideWithText; +} + +void QLineEditIconButton::setHideWithText(bool hide) +{ + m_hideWithText = hide; +} + +void QLineEditIconButton::onAnimationFinished() +{ + if (shouldHideWithText() && isVisible() && !m_wasHidden) { + hide(); + + // Invalidate previous geometry to take into account new size of side widgets + if (auto le = lineEditPrivate()) + le->updateGeometry_helper(true); + } +} + +void QLineEditIconButton::animateShow(bool visible) +{ + m_wasHidden = visible; + + if (shouldHideWithText() && !isVisible()) { + show(); + + // Invalidate previous geometry to take into account new size of side widgets + if (auto le = lineEditPrivate()) + le->updateGeometry_helper(true); + } + + startOpacityAnimation(visible ? 1.0 : 0.0); +} + void QLineEditIconButton::startOpacityAnimation(qreal endValue) { QPropertyAnimation *animation = new QPropertyAnimation(this, QByteArrayLiteral("opacity")); + connect(animation, &QPropertyAnimation::finished, this, &QLineEditIconButton::onAnimationFinished); + animation->setDuration(160); animation->setEndValue(endValue); animation->start(QAbstractAnimation::DeleteWhenStopped); @@ -409,6 +447,16 @@ void QLineEditIconButton::updateCursor() } #endif // QT_CONFIG(toolbutton) +#if QT_CONFIG(animation) && QT_CONFIG(toolbutton) +static void displayWidgets(const QLineEditPrivate::SideWidgetEntryList &widgets, bool display) +{ + for (const auto &e : widgets) { + if (e.flags & QLineEditPrivate::SideWidgetFadeInWithText) + static_cast<QLineEditIconButton *>(e.widget)->animateShow(display); + } +} +#endif + void QLineEditPrivate::_q_textChanged(const QString &text) { if (hasSideWidgets()) { @@ -416,15 +464,9 @@ void QLineEditPrivate::_q_textChanged(const QString &text) if (!newTextSize || !lastTextSize) { lastTextSize = newTextSize; #if QT_CONFIG(animation) && QT_CONFIG(toolbutton) - const bool fadeIn = newTextSize > 0; - for (const SideWidgetEntry &e : leadingSideWidgets) { - if (e.flags & SideWidgetFadeInWithText) - static_cast<QLineEditIconButton *>(e.widget)->animateShow(fadeIn); - } - for (const SideWidgetEntry &e : trailingSideWidgets) { - if (e.flags & SideWidgetFadeInWithText) - static_cast<QLineEditIconButton *>(e.widget)->animateShow(fadeIn); - } + const bool display = newTextSize > 0; + displayWidgets(leadingSideWidgets, display); + displayWidgets(trailingSideWidgets, display); #endif } } @@ -541,8 +583,15 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE QLineEditIconButton *toolButton = new QLineEditIconButton(q); toolButton->setIcon(newAction->icon()); toolButton->setOpacity(lastTextSize > 0 || !(flags & SideWidgetFadeInWithText) ? 1 : 0); - if (flags & SideWidgetClearButton) + if (flags & SideWidgetClearButton) { QObject::connect(toolButton, SIGNAL(clicked()), q, SLOT(_q_clearButtonClicked())); + +#if QT_CONFIG(animation) + // The clear button is handled only by this widget. The button should be really + // shown/hidden in order to calculate size hints correctly. + toolButton->setHideWithText(true); +#endif + } toolButton->setDefaultAction(newAction); w = toolButton; #else @@ -606,33 +655,26 @@ void QLineEditPrivate::removeAction(QAction *action) #endif // QT_CONFIG(action) } -static bool isSideWidgetVisible(const QLineEditPrivate::SideWidgetEntry &e) +static int effectiveTextMargin(int defaultMargin, const QLineEditPrivate::SideWidgetEntryList &widgets, + const QLineEditPrivate::SideWidgetParameters ¶meters) { - return e.widget->isVisible(); + if (widgets.empty()) + return defaultMargin; + + return defaultMargin + (parameters.margin + parameters.widgetWidth) * + int(std::count_if(widgets.begin(), widgets.end(), + [](const QLineEditPrivate::SideWidgetEntry &e) { + return e.widget->isVisibleTo(e.widget->parentWidget()); })); } int QLineEditPrivate::effectiveLeftTextMargin() const { - int result = leftTextMargin; - if (!leftSideWidgetList().empty()) { - const SideWidgetParameters p = sideWidgetParameters(); - result += (p.margin + p.widgetWidth) - * int(std::count_if(leftSideWidgetList().begin(), leftSideWidgetList().end(), - isSideWidgetVisible)); - } - return result; + return effectiveTextMargin(leftTextMargin, leftSideWidgetList(), sideWidgetParameters()); } int QLineEditPrivate::effectiveRightTextMargin() const { - int result = rightTextMargin; - if (!rightSideWidgetList().empty()) { - const SideWidgetParameters p = sideWidgetParameters(); - result += (p.margin + p.widgetWidth) - * int(std::count_if(rightSideWidgetList().begin(), rightSideWidgetList().end(), - isSideWidgetVisible)); - } - return result; + return effectiveTextMargin(rightTextMargin, rightSideWidgetList(), sideWidgetParameters()); } diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h index 7cd91dfc29..12a2f1ddfd 100644 --- a/src/widgets/widgets/qlineedit_p.h +++ b/src/widgets/widgets/qlineedit_p.h @@ -90,7 +90,10 @@ public: qreal opacity() const { return m_opacity; } void setOpacity(qreal value); #if QT_CONFIG(animation) - void animateShow(bool visible) { startOpacityAnimation(visible ? 1.0 : 0.0); } + void animateShow(bool visible); + + bool shouldHideWithText() const; + void setHideWithText(bool hide); #endif protected: @@ -100,6 +103,10 @@ protected: private slots: void updateCursor(); +#if QT_CONFIG(animation) + void onAnimationFinished(); +#endif + private: #if QT_CONFIG(animation) void startOpacityAnimation(qreal endValue); @@ -107,6 +114,12 @@ private: QLineEditPrivate *lineEditPrivate() const; qreal m_opacity; + +#if QT_CONFIG(animation) + bool m_hideWithText = false; + bool m_wasHidden = false; +#endif + }; #endif // QT_CONFIG(toolbutton) diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 448e2030bc..95799905de 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -4451,10 +4451,11 @@ void tst_QLineEdit::clearButtonVisibleAfterSettingText_QTBUG_45518() QTRY_VERIFY(clearButton->opacity() > 0); QTRY_COMPARE(clearButton->cursor().shape(), Qt::ArrowCursor); - QTest::mouseClick(clearButton, Qt::LeftButton, 0, clearButton->rect().center()); + QTest::mouseClick(clearButton, Qt::LeftButton, nullptr, clearButton->rect().center()); QTRY_COMPARE(edit.text(), QString()); QTRY_COMPARE(clearButton->opacity(), qreal(0)); + QVERIFY(clearButton->isHidden()); QTRY_COMPARE(clearButton->cursor().shape(), clearButton->parentWidget()->cursor().shape()); edit.setClearButtonEnabled(false); diff --git a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp index 301801ed2e..d6c165642e 100644 --- a/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp +++ b/tests/auto/widgets/widgets/qtoolbar/tst_qtoolbar.cpp @@ -42,6 +42,7 @@ #include <qlineedit.h> #include <qkeysequence.h> #include <qmenu.h> +#include <qlabel.h> #include <private/qtoolbarextension_p.h> QT_FORWARD_DECLARE_CLASS(QAction) @@ -80,6 +81,8 @@ private slots: void task191727_layout(); void task197996_visibility(); + + void extraCpuConsumption(); // QTBUG-54676 }; @@ -1098,5 +1101,81 @@ void tst_QToolBar::task197996_visibility() QTRY_VERIFY(toolBar->widgetForAction(pAction)->isVisible()); } +class ShowHideEventCounter : public QObject +{ +public: + using QObject::QObject; + + bool eventFilter(QObject *watched, QEvent *event) override + { + if (qobject_cast<QLineEdit*>(watched) && !event->spontaneous()) { + if (event->type() == QEvent::Show) + ++m_showEventsCount; + + if (event->type() == QEvent::Hide) + ++m_hideEventsCount; + } + + return QObject::eventFilter(watched, event); + } + + uint showEventsCount() const { return m_showEventsCount; } + uint hideEventsCount() const { return m_hideEventsCount; } + +private: + uint m_showEventsCount = 0; + uint m_hideEventsCount = 0; +}; + +void tst_QToolBar::extraCpuConsumption() +{ + QMainWindow mainWindow; + + auto tb = new QToolBar(&mainWindow); + tb->setMovable(false); + + auto extensions = tb->findChildren<QToolBarExtension *>(); + QVERIFY(!extensions.isEmpty()); + + auto extensionButton = extensions.at(0); + QVERIFY(extensionButton); + + tb->addWidget(new QLabel("Lorem ipsum dolor sit amet")); + + auto le = new QLineEdit; + le->setClearButtonEnabled(true); + le->setText("Lorem ipsum"); + tb->addWidget(le); + + mainWindow.addToolBar(tb); + mainWindow.show(); + QVERIFY(QTest::qWaitForWindowActive(&mainWindow)); + + auto eventCounter = new ShowHideEventCounter(&mainWindow); + le->installEventFilter(eventCounter); + + auto defaultSize = mainWindow.size(); + + // Line edit should be hidden now and extension button should be displayed + for (double p = 0.7; extensionButton->isHidden() || qFuzzyCompare(p, 0.); p -= 0.01) { + mainWindow.resize(int(defaultSize.width() * p), defaultSize.height()); + } + QVERIFY(!extensionButton->isHidden()); + + // Line edit should be visible, but smaller + for (double p = 0.75; !extensionButton->isHidden() || qFuzzyCompare(p, 1.); p += 0.01) { + mainWindow.resize(int(defaultSize.width() * p), defaultSize.height()); + } + QVERIFY(extensionButton->isHidden()); + + // Dispatch all pending events + qApp->sendPostedEvents(); + qApp->processEvents(); + + QCOMPARE(eventCounter->showEventsCount(), eventCounter->hideEventsCount()); + QCOMPARE(eventCounter->showEventsCount(), uint(1)); + QCOMPARE(eventCounter->hideEventsCount(), uint(1)); +} + QTEST_MAIN(tst_QToolBar) #include "tst_qtoolbar.moc" |