From d58161e749348a9e11e063b1bbb3dbbc0aa46c5e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 22 Oct 2012 19:27:05 +0200 Subject: QMacStyle: make default button animations independent of QWidget Change-Id: I63c078050288e3151a9c6aad5d4ae28a58afd84f Reviewed-by: Gabriel de Dietrich --- src/widgets/styles/qmacstyle_mac.mm | 168 +++++++++++--------------------- src/widgets/styles/qmacstyle_mac_p.h | 8 +- src/widgets/widgets/qabstractbutton.cpp | 2 + src/widgets/widgets/qpushbutton.cpp | 2 +- 4 files changed, 65 insertions(+), 115 deletions(-) (limited to 'src') diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 2b6f271a40..a227e06d77 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1683,46 +1683,6 @@ QMacStylePrivate::QMacStylePrivate() } -bool QMacStylePrivate::animatable(QMacStylePrivate::Animates as, const QObject *obj) const -{ - if (!obj) - return false; - - if (as == AquaPushButton) { - QPushButton *pb = const_cast(qobject_cast(obj)); - if (pb && pb->window()->isActiveWindow() && !mouseDown) { - if (pb != defaultButton) { - // Changed on its own, update the value. - const_cast(this)->stopAnimate(as, defaultButton); - const_cast(this)->startAnimate(as, pb); - } - return true; - } - } - return animation(obj); -} - -void QMacStylePrivate::stopAnimate(QMacStylePrivate::Animates as, QObject *obj) -{ - stopAnimation(obj); - if (as == AquaPushButton && defaultButton) { - stopAnimation(defaultButton); - QPushButton *tmp = defaultButton; - defaultButton = 0; - tmp->update(); - } else if (as == AquaScrollBar) { - scrollBarInfos.remove(qobject_cast(obj)); - } -} - -void QMacStylePrivate::startAnimate(QMacStylePrivate::Animates as, QObject *obj) -{ - if (!animation(obj)) - startAnimation(new QStyleAnimation(obj)); - if (as == AquaPushButton) - defaultButton = qobject_cast(obj); -} - bool QMacStylePrivate::addWidget(QWidget *w) { //already knew of it @@ -1730,17 +1690,9 @@ bool QMacStylePrivate::addWidget(QWidget *w) return false; Q_Q(QMacStyle); - if (QPushButton *btn = qobject_cast(w)) { - btn->installEventFilter(q); - if (btn->isDefault() || (btn->autoDefault() && btn->hasFocus())) - startAnimate(AquaPushButton, btn); + if (qobject_cast(w)) { + w->installEventFilter(q); return true; - } else { - bool isScrollBar = (qobject_cast(w)); - if (isScrollBar) { - w->installEventFilter(q); - return true; - } } if (w->isWindow()) { w->installEventFilter(q); @@ -1749,16 +1701,6 @@ bool QMacStylePrivate::addWidget(QWidget *w) return false; } -void QMacStylePrivate::removeWidget(QWidget *w) -{ - QPushButton *btn = qobject_cast(w); - if (btn && btn == defaultButton) { - stopAnimate(AquaPushButton, btn); - } else if (qobject_cast(w)) { - stopAnimate(AquaScrollBar, w); - } -} - ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags) { ThemeDrawState tds = kThemeStateActive; @@ -1839,49 +1781,6 @@ bool QMacStyle::eventFilter(QObject *o, QEvent *e) } } #endif - } else if (QPushButton *btn = qobject_cast(o)) { - switch (e->type()) { - default: - break; - case QEvent::FocusIn: - if (btn->autoDefault()) - d->startAnimate(QMacStylePrivate::AquaPushButton, btn); - break; - case QEvent::Destroy: - case QEvent::Hide: - if (btn == d->defaultButton) - d->stopAnimate(QMacStylePrivate::AquaPushButton, btn); - break; - case QEvent::MouseButtonPress: - // It is very confusing to keep the button pulsing, so just stop the animation. - if (static_cast(e)->button() == Qt::LeftButton) - d->mouseDown = true; - d->stopAnimate(QMacStylePrivate::AquaPushButton, btn); - break; - case QEvent::MouseButtonRelease: - if (static_cast(e)->button() == Qt::LeftButton) - d->mouseDown = false; - // fall through - case QEvent::FocusOut: - case QEvent::Show: - case QEvent::WindowActivate: { - QList list = btn->window()->findChildren(); - for (int i = 0; i < list.size(); ++i) { - QPushButton *pBtn = list.at(i); - if ((e->type() == QEvent::FocusOut - && (pBtn->isDefault() || (pBtn->autoDefault() && pBtn->hasFocus())) - && pBtn != btn) - || ((e->type() == QEvent::Show || e->type() == QEvent::MouseButtonRelease - || e->type() == QEvent::WindowActivate) - && pBtn->isDefault())) { - if (pBtn->window()->isActiveWindow()) { - d->startAnimate(QMacStylePrivate::AquaPushButton, pBtn); - } - break; - } - } - break; } - } } return false; } @@ -2172,7 +2071,6 @@ void QMacStyle::polish(QWidget* w) void QMacStyle::unpolish(QWidget* w) { Q_D(QMacStyle); - d->removeWidget(w); if ((qobject_cast(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) { QPalette pal = qApp->palette(w); w->setPalette(pal); @@ -2201,6 +2099,7 @@ void QMacStyle::unpolish(QWidget* w) if (qobject_cast(w)) { w->setAttribute(Qt::WA_OpaquePaintEvent, true); w->setMouseTracking(false); + d->scrollBarInfos.remove(w); } } @@ -3633,13 +3532,64 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter break; } + // a focused auto-default button within an active window + // takes precedence over a normal default button + if (btn->features & QStyleOptionButton::AutoDefaultButton + && opt->state & State_Active && opt->state & State_HasFocus) { + d->autoDefaultButton = opt->styleObject; + if (!d->animation(opt->styleObject)) + d->startAnimation(new QStyleAnimation(opt->styleObject)); + } else if (d->autoDefaultButton == opt->styleObject) { + if (QStyleAnimation *animation = d->animation(opt->styleObject)) { + animation->updateTarget(); + d->stopAnimation(opt->styleObject); + } + d->autoDefaultButton = 0; + } + + if (!d->autoDefaultButton) { + if (btn->features & QStyleOptionButton::DefaultButton && opt->state & State_Active) { + d->defaultButton = opt->styleObject; + if (!d->animation(opt->styleObject)) + d->startAnimation(new QStyleAnimation(opt->styleObject)); + } else if (d->defaultButton == opt->styleObject) { + if (QStyleAnimation *animation = d->animation(opt->styleObject)) { + animation->updateTarget(); + d->stopAnimation(opt->styleObject); + } + d->defaultButton = 0; + } + } + + // TODO: find out the pressed button in a qwidget independent way + extern QWidget *qt_button_down; // qwidgetwindow.cpp + if (opt->styleObject == qt_button_down) + d->pressedButton = opt->styleObject; + else if (d->pressedButton == opt->styleObject) + d->pressedButton = 0; + + // the default button animation is paused meanwhile any button + // is pressed or an auto-default button is animated instead + if (QStyleAnimation *defaultAnimation = d->animation(d->defaultButton)) { + if (d->pressedButton || d->autoDefaultButton) { + if (defaultAnimation->state() == QStyleAnimation::Running) { + defaultAnimation->pause(); + defaultAnimation->updateTarget(); + } + } else if (defaultAnimation->state() == QStyleAnimation::Paused) { + defaultAnimation->resume(); + } + } + HIThemeButtonDrawInfo bdi; d->initHIThemePushButton(btn, w, tds, &bdi); - if (btn->features & QStyleOptionButton::DefaultButton - && d->animatable(QMacStylePrivate::AquaPushButton, w)) { - bdi.adornment |= kThemeAdornmentDefault; - bdi.animation.time.start = d->defaultButtonStart; - bdi.animation.time.current = CFAbsoluteTimeGetCurrent(); + if (!d->pressedButton) { + QStyleAnimation* animation = d->animation(opt->styleObject); + if (animation && animation->state() == QStyleAnimation::Running) { + bdi.adornment |= kThemeAdornmentDefault; + bdi.animation.time.start = d->defaultButtonStart; + bdi.animation.time.current = CFAbsoluteTimeGetCurrent(); + } } // Unlike Carbon, we want the button to always be drawn inside its bounds. // Therefore, make the button a bit smaller, so that even if it got focus, diff --git a/src/widgets/styles/qmacstyle_mac_p.h b/src/widgets/styles/qmacstyle_mac_p.h index 66691c63f7..ec6f7c75b4 100644 --- a/src/widgets/styles/qmacstyle_mac_p.h +++ b/src/widgets/styles/qmacstyle_mac_p.h @@ -160,12 +160,8 @@ public: // Stuff from QAquaAnimate: bool addWidget(QWidget *); - void removeWidget(QWidget *); enum Animates { AquaPushButton, AquaProgressBar, AquaListViewItemOpen, AquaScrollBar }; - bool animatable(Animates, const QObject *) const; - void stopAnimate(Animates, QObject *); - void startAnimate(Animates, QObject *); static ThemeDrawState getDrawState(QStyle::State flags); QAquaWidgetSize aquaSizeConstrain(const QStyleOption *option, const QWidget *widg, QStyle::ContentsType ct = QStyle::CT_CustomBase, @@ -201,7 +197,9 @@ public: QPixmap generateBackgroundPattern() const; public: - QPointer defaultButton; //default push buttons + mutable QPointer pressedButton; + mutable QPointer defaultButton; + mutable QPointer autoDefaultButton; struct OverlayScrollBarInfo { OverlayScrollBarInfo() diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp index 5d879c8930..eba63045fe 100644 --- a/src/widgets/widgets/qabstractbutton.cpp +++ b/src/widgets/widgets/qabstractbutton.cpp @@ -1113,6 +1113,8 @@ void QAbstractButton::mouseReleaseEvent(QMouseEvent *e) } if (!d->down) { + // refresh is required by QMacStyle to resume the default button animation + d->refresh(); e->ignore(); return; } diff --git a/src/widgets/widgets/qpushbutton.cpp b/src/widgets/widgets/qpushbutton.cpp index 5e8d7d16bd..0aeec551d6 100644 --- a/src/widgets/widgets/qpushbutton.cpp +++ b/src/widgets/widgets/qpushbutton.cpp @@ -329,7 +329,7 @@ void QPushButton::initStyleOption(QStyleOptionButton *option) const if (d->menu) option->features |= QStyleOptionButton::HasMenu; #endif - if (autoDefault() || d->defaultButton) + if (autoDefault()) option->features |= QStyleOptionButton::AutoDefaultButton; if (d->defaultButton) option->features |= QStyleOptionButton::DefaultButton; -- cgit v1.2.3