summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@digia.com>2012-10-30 13:47:20 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-11-02 19:49:22 +0100
commit3c2bfbff5f4c836de32628710ab7701b0db083f7 (patch)
tree4e6c262f6cbaa4978bcf47b239423fe305af50bb /src
parent020196d16b6c25e16bf80483f08e0007a27eab13 (diff)
Mac: refactor scrollbar animations
Get rid of QWidget-centric QMacStyle::eventFilter() and implement the fade out animations for scrollbars using QNumberStyleAnimation-based QFadeOutAnimation. Change-Id: I2000fa50d46b153e981ceafc12a53932a196382e Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/widgets/styles/qcommonstyle.cpp3
-rw-r--r--src/widgets/styles/qmacstyle_mac.h3
-rw-r--r--src/widgets/styles/qmacstyle_mac.mm259
-rw-r--r--src/widgets/styles/qmacstyle_mac_p.h54
-rw-r--r--src/widgets/styles/qstyle.cpp3
-rw-r--r--src/widgets/styles/qstyle.h1
-rw-r--r--src/widgets/widgets/qabstractscrollarea.cpp41
-rw-r--r--src/widgets/widgets/qabstractscrollarea.h1
-rw-r--r--src/widgets/widgets/qabstractscrollarea_p.h3
-rw-r--r--src/widgets/widgets/qscrollarea.cpp2
-rw-r--r--src/widgets/widgets/qscrollbar.cpp56
-rw-r--r--src/widgets/widgets/qscrollbar.h1
-rw-r--r--src/widgets/widgets/qscrollbar_p.h89
-rw-r--r--src/widgets/widgets/widgets.pri1
14 files changed, 274 insertions, 243 deletions
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 2b6d843723..96a2078905 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -5016,6 +5016,9 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
case SH_RequestSoftwareInputPanel:
ret = RSIP_OnMouseClickAndAlreadyFocused;
break;
+ case SH_ScrollBar_Transient:
+ ret = false;
+ break;
default:
ret = 0;
break;
diff --git a/src/widgets/styles/qmacstyle_mac.h b/src/widgets/styles/qmacstyle_mac.h
index 2e4d2ffa4c..1de1dbbdd8 100644
--- a/src/widgets/styles/qmacstyle_mac.h
+++ b/src/widgets/styles/qmacstyle_mac.h
@@ -125,9 +125,6 @@ public:
Qt::Orientation orientation, const QStyleOption *option = 0,
const QWidget *widget = 0) const;
-protected:
- bool eventFilter(QObject *, QEvent *);
-
private:
Q_DISABLE_COPY(QMacStyle)
Q_DECLARE_PRIVATE(QMacStyle)
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
index 0da18c6f6a..901208a342 100644
--- a/src/widgets/styles/qmacstyle_mac.mm
+++ b/src/widgets/styles/qmacstyle_mac.mm
@@ -127,9 +127,9 @@ QMacStylePrivate *mPrivate;
{
Q_UNUSED(notification);
QEvent event(QEvent::StyleChange);
- Q_FOREACH (const QObject* target, mPrivate->animationTargets()) {
- if (target)
- QCoreApplication::sendEvent(const_cast<QObject*>(target), &event);
+ foreach (QWidget *widget, QApplication::allWidgets()) {
+ if (QScrollBar *scrollBar = qobject_cast<QScrollBar *>(widget))
+ QCoreApplication::sendEvent(scrollBar, &event);
}
}
@end
@@ -178,38 +178,6 @@ static bool isVerticalTabs(const QTabBar::Shape shape) {
|| shape == QTabBar::TriangularWest);
}
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
-/*!
- Returns the QAbstractScrollArea the scroll bar \a sb is in. If \a sb is not
- inside of a QAbstractScrollArea, this returns 0.
- \internal
- */
-static const QAbstractScrollArea *scrollBarsScrollArea(const QScrollBar *sb)
-{
- const QWidget *w = sb;
- const QAbstractScrollArea *sa = 0;
- while (w != 0 && sa == 0) {
- sa = qobject_cast<const QAbstractScrollArea *>(w);
- w = w->parentWidget();
- }
- return sa;
-}
-
-/*!
- For a scroll bar \a sb within a scroll area, this function returns all other scroll
- bars within the same scroll area.
- \internal
- */
-static QList<const QScrollBar *> scrollBarsSiblings(const QScrollBar *sb)
-{
- const QAbstractScrollArea *sa = scrollBarsScrollArea(sb);
- Q_ASSERT(sa != 0);
- QList<const QScrollBar *> list = sa->findChildren<const QScrollBar *>();
- list.removeOne(sb);
- return list;
-}
-#endif
-
void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
{
// draw background circle
@@ -1678,24 +1646,6 @@ QMacStylePrivate::QMacStylePrivate()
}
-bool QMacStylePrivate::addWidget(QWidget *w)
-{
- //already knew of it
- if (w == defaultButton || animation(w))
- return false;
-
- Q_Q(QMacStyle);
- if (qobject_cast<QScrollBar *>(w)) {
- w->installEventFilter(q);
- return true;
- }
- if (w->isWindow()) {
- w->installEventFilter(q);
- return true;
- }
- return false;
-}
-
ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
{
ThemeDrawState tds = kThemeStateActive;
@@ -1713,73 +1663,6 @@ ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
return tds;
}
-/*! \reimp */
-bool QMacStyle::eventFilter(QObject *o, QEvent *e)
-{
- //animate
- Q_D(QMacStyle);
- if (QScrollBar *sb = qobject_cast<QScrollBar *>(o)) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- // take care of fading out overlaying scrollbars (and only those!) when inactive
- const QAbstractScrollArea *scrollArea = scrollBarsScrollArea(sb);
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 &&
- [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay && scrollArea) {
- QMacStylePrivate::OverlayScrollBarInfo& info = d->scrollBarInfos[sb];
- const qint64 dt = QDateTime::currentMSecsSinceEpoch();
- const qreal elapsed = dt - info.lastUpdate;
- const CGFloat opacity = 1.0 - qMax(0.0, (elapsed - QMacStylePrivate::ScrollBarFadeOutDelay)
- / QMacStylePrivate::ScrollBarFadeOutDuration);
- switch (e->type()) {
- case QEvent::MouseMove:
- // whenever the mouse moves on a not 100% transparent scroll bar,
- // the fade out is stopped and it's set to 100% opaque
- if (opacity > 0.0) {
- info.hovered = true;
- info.lastUpdate = dt;
- info.lastHovered = info.lastUpdate;
- sb->update();
- break;
- }
-
- // fall through
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonRelease:
- case QEvent::MouseButtonDblClick:
- // all mouse events which happens on a transparent scroll bar are
- // translated and passed to the scroll area's viewport
- if (opacity <= 0.0) {
- QMouseEvent* mouse = static_cast<QMouseEvent *>(e);
- QWidget* viewport = scrollArea->viewport();
- const QPoint scrollAreaPos = sb->mapTo(scrollArea, mouse->pos());
- const QPoint viewportPos = viewport->mapFromParent(scrollAreaPos);
- QMouseEvent me(mouse->type(), viewportPos, mouse->windowPos(),
- mouse->globalPos(), mouse->button(), mouse->buttons(),
- mouse->modifiers());
- QCoreApplication::sendEvent(viewport, &me);
- mouse->setAccepted(me.isAccepted());
- return true;
- }
- break;
- case QEvent::Leave:
- case QEvent::WindowDeactivate:
- // mouse leave and window deactivate sets the scrollbar to not-hovered
- // -> triggers fade out
- info.hovered = false;
- break;
- if (!info.hovered) {
- e->setAccepted(false);
- return true;
- }
- break;
- default:
- break;
- }
- }
-#endif
- }
- return false;
-}
-
void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
QPainter *p, const QStyleOption *opt) const
{
@@ -2006,8 +1889,6 @@ void QMacStyle::unpolish(QApplication *)
void QMacStyle::polish(QWidget* w)
{
- Q_D(QMacStyle);
- d->addWidget(w);
if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) {
// Set a clear brush so that the metal shines through.
QPalette pal = w->palette();
@@ -2059,13 +1940,13 @@ void QMacStyle::polish(QWidget* w)
if (qobject_cast<QScrollBar*>(w)) {
w->setAttribute(Qt::WA_OpaquePaintEvent, false);
+ w->setAttribute(Qt::WA_Hover, true);
w->setMouseTracking(true);
}
}
void QMacStyle::unpolish(QWidget* w)
{
- Q_D(QMacStyle);
if ((qobject_cast<QMenu*>(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) {
QPalette pal = qApp->palette(w);
w->setPalette(pal);
@@ -2093,8 +1974,8 @@ void QMacStyle::unpolish(QWidget* w)
if (qobject_cast<QScrollBar*>(w)) {
w->setAttribute(Qt::WA_OpaquePaintEvent, true);
+ w->setAttribute(Qt::WA_Hover, false);
w->setMouseTracking(false);
- d->scrollBarInfos.remove(w);
}
}
@@ -2303,8 +2184,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
case PM_ScrollBarExtent: {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 &&
- [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay &&
- scrollBarsScrollArea(qobject_cast<const QScrollBar *>(widget))) {
+ [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay) {
switch (d->aquaSizeConstrain(opt, widget)) {
case QAquaSizeUnknown:
case QAquaSizeLarge:
@@ -2831,6 +2711,12 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_DockWidget_ButtonsHaveFrame:
ret = false;
break;
+ case SH_ScrollBar_Transient:
+ ret = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+ ret &= [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay;
+#endif
+ break;
default:
ret = QCommonStyle::styleHint(sh, opt, w, hret);
break;
@@ -5023,59 +4909,65 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- const qint64 dt = QDateTime::currentMSecsSinceEpoch();
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 &&
- [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay &&
- scrollBarsScrollArea(qobject_cast<const QScrollBar *>(widget)) &&
- cc == CC_ScrollBar) {
- QMacStylePrivate::OverlayScrollBarInfo& info = d->scrollBarInfos[widget];
- bool showSiblings = false;
- if (info.lastValue != slider->sliderPosition ||
- info.lastMinimum != slider->minimum ||
- info.lastMaximum != slider->maximum ||
- info.lastSize != slider->rect.size()) {
- info.lastValue = slider->sliderPosition;
- info.lastMinimum = slider->minimum;
- info.lastSize = slider->rect.size();
- info.lastMaximum = slider->maximum;
- info.lastUpdate = dt;
- showSiblings = true;
- }
-
- const QList<const QScrollBar *> siblings =
- scrollBarsSiblings(qobject_cast<const QScrollBar *>(widget));
- // keep last update (last change of value) time of all siblings in sync
- Q_FOREACH (const QScrollBar *sibling, siblings) {
- info.lastUpdate = qMax(info.lastUpdate,
- d->scrollBarInfos.value(sibling).lastUpdate);
- info.cleared = false;
- if (d->scrollBarInfos.value(sibling).hovered)
- info.lastUpdate = dt;
- }
-
- qreal elapsed = dt - info.lastHovered;
- CGFloat opacity = 1.0 - qMax(0.0,
- (elapsed - QMacStylePrivate::ScrollBarFadeOutDelay) /
- QMacStylePrivate::ScrollBarFadeOutDuration);
- const bool isHorizontal = slider->orientation == Qt::Horizontal;
-
- if (info.hovered) {
- info.lastHovered = dt;
- info.lastUpdate = dt;
+ if (cc == CC_ScrollBar && proxy()->styleHint(SH_ScrollBar_Transient)) {
+ QObject *styleObject = opt->styleObject;
+ int oldPos = styleObject->property("_q_stylepos").toInt();
+ int oldMin = styleObject->property("_q_stylemin").toInt();
+ int oldMax = styleObject->property("_q_stylemax").toInt();
+ QRect oldRect = styleObject->property("_q_stylerect").toRect();
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ uint oldActiveControls = styleObject->property("_q_stylecontrols").toUInt();
+
+ // a scrollbar is transient when the the scrollbar itself and
+ // its sibling are both inactive (ie. not pressed/hovered/moved)
+ bool transient = !opt->activeSubControls && !(slider->state & State_On);
+
+ CGFloat opacity = 0.0;
+ if (!transient ||
+ oldPos != slider->sliderPosition ||
+ oldMin != slider->minimum ||
+ oldMax != slider->maximum ||
+ oldRect != slider->rect ||
+ oldState != slider->state ||
+ oldActiveControls != slider->activeSubControls) {
+
+ // if the scrollbar is transient or its attributes, geometry or
+ // state has changed, the opacity is reset back to 100% opaque
opacity = 1.0;
- // if the current scroll bar is hovered, none of the others might fade out
- Q_FOREACH (const QScrollBar *sibling, siblings) {
- d->scrollBarInfos[sibling].lastUpdate = info.lastUpdate;
+
+ styleObject->setProperty("_q_stylepos", slider->sliderPosition);
+ styleObject->setProperty("_q_stylemin", slider->minimum);
+ styleObject->setProperty("_q_stylemax", slider->maximum);
+ styleObject->setProperty("_q_stylerect", slider->rect);
+ styleObject->setProperty("_q_stylestate", static_cast<int>(slider->state));
+ styleObject->setProperty("_q_stylecontrols", static_cast<uint>(slider->activeSubControls));
+
+ if (transient) {
+ QFadeOutAnimation *anim = qobject_cast<QFadeOutAnimation *>(d->animation(styleObject));
+ if (!anim) {
+ anim = new QFadeOutAnimation(styleObject);
+ d->startAnimation(anim);
+ } else {
+ // the scrollbar was already fading out while the
+ // state changed -> restart the fade out animation
+ anim->setCurrentTime(0);
+ }
+ } else {
+ d->stopAnimation(styleObject);
}
}
- // when one scroll bar was changed, all its siblings need a redraw as well, since
- // either both scroll bars within a scroll area shall be visible or none
- if (showSiblings) {
- Q_FOREACH (const QScrollBar *sibling, siblings)
- const_cast<QScrollBar *>(sibling)->update();
+ QFadeOutAnimation *anim = qobject_cast<QFadeOutAnimation *>(d->animation(styleObject));
+ if (anim) {
+ // once a scrollbar was active (hovered/pressed), it retains
+ // the active look even if it's no longer active while fading out
+ if (oldActiveControls)
+ anim->setActive(true);
+ opacity = anim->currentValue();
}
+ const bool isHorizontal = slider->orientation == Qt::Horizontal;
+
CGContextSaveGState(cg);
[NSGraphicsContext saveGraphicsState];
@@ -5085,7 +4977,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
[scroller initWithFrame:NSMakeRect(0, 0, slider->rect.width(), slider->rect.height())];
// mac os behaviour: as soon as one color channel is >= 128,
// the bg is considered bright, scroller is dark
- const QColor bgColor = widget->palette().color(QPalette::Base);
+ const QColor bgColor = opt->palette.color(QPalette::Base);
const bool isDarkBg = bgColor.red() < 128 && bgColor.green() < 128 &&
bgColor.blue() < 128;
if (isDarkBg)
@@ -5102,7 +4994,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
[scroller setScrollerStyle:NSScrollerStyleOverlay];
// first we draw only the track, by using a disabled scroller
- if (opacity > 0.0) {
+ if (opt->activeSubControls || (anim && anim->wasActive())) {
CGContextBeginTransparencyLayerWithRect(cg, qt_hirectForQRect(slider->rect),
NULL);
CGContextSetAlpha(cg, opacity);
@@ -5115,21 +5007,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
CGContextEndTransparencyLayer(cg);
}
- // afterwards we draw the knob, since we cannot drow the know w/o the track,
- // we simulate a scrollbar with a knob from 0.0 to 1.0
- elapsed = dt - info.lastUpdate;
- opacity = 1.0 - qMax(0.0, (elapsed - QMacStylePrivate::ScrollBarFadeOutDelay) /
- QMacStylePrivate::ScrollBarFadeOutDuration);
- info.cleared = opacity <= 0.0;
-
- if (info.animating && info.cleared) {
- d->stopAnimation(slider->styleObject);
- info.animating = false;
- } else if (!info.animating && !info.cleared) {
- d->startAnimation(new QStyleAnimation(slider->styleObject));
- info.animating = true;
- }
-
CGContextBeginTransparencyLayerWithRect(cg, qt_hirectForQRect(slider->rect), NULL);
CGContextSetAlpha(cg, opacity);
@@ -5170,6 +5047,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
} else
#endif
{
+ d->stopAnimation(opt->styleObject);
+
HIThemeDrawTrack(&tdi, tracking ? 0 : &macRect, cg,
kHIThemeOrientationNormal);
if (cc == CC_Slider && slider->subControls & SC_SliderTickmarks) {
diff --git a/src/widgets/styles/qmacstyle_mac_p.h b/src/widgets/styles/qmacstyle_mac_p.h
index af1c88d50d..f01d1e14c5 100644
--- a/src/widgets/styles/qmacstyle_mac_p.h
+++ b/src/widgets/styles/qmacstyle_mac_p.h
@@ -158,9 +158,6 @@ public:
static const qreal ScrollBarFadeOutDuration;
static const qreal ScrollBarFadeOutDelay;
- // Stuff from QAquaAnimate:
- bool addWidget(QWidget *);
-
enum Animates { AquaPushButton, AquaProgressBar, AquaListViewItemOpen, AquaScrollBar };
static ThemeDrawState getDrawState(QStyle::State flags);
QAquaWidgetSize aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
@@ -201,29 +198,6 @@ public:
mutable QPointer<QObject> defaultButton;
mutable QPointer<QObject> autoDefaultButton;
- struct OverlayScrollBarInfo {
- OverlayScrollBarInfo()
- : lastValue(-1),
- lastMinimum(-1),
- lastMaximum(-1),
- lastUpdate(QDateTime::currentMSecsSinceEpoch()),
- hovered(false),
- lastHovered(0),
- cleared(false),
- animating(false)
- {}
- int lastValue;
- int lastMinimum;
- int lastMaximum;
- QSize lastSize;
- qint64 lastUpdate;
- bool hovered;
- qint64 lastHovered;
- bool cleared;
- bool animating;
- };
- mutable QMap<const QWidget*, OverlayScrollBarInfo> scrollBarInfos;
-
struct ButtonState {
int frame;
enum { ButtonDark, ButtonLight } dir;
@@ -237,6 +211,34 @@ public:
#endif
};
+class QFadeOutAnimation : public QNumberStyleAnimation
+{
+ Q_OBJECT
+
+public:
+ QFadeOutAnimation(QObject *target) : QNumberStyleAnimation(target), _active(false)
+ {
+ setDuration(QMacStylePrivate::ScrollBarFadeOutDelay + QMacStylePrivate::ScrollBarFadeOutDuration);
+ setDelay(QMacStylePrivate::ScrollBarFadeOutDelay);
+ setStartValue(1.0);
+ setEndValue(0.0);
+ }
+
+ bool wasActive() const { return _active; }
+ void setActive(bool active) { _active = active; }
+
+private slots:
+ void updateCurrentTime(int time)
+ {
+ QNumberStyleAnimation::updateCurrentTime(time);
+ if (qFuzzyIsNull(currentValue()))
+ target()->setProperty("visible", false);
+ }
+
+private:
+ bool _active;
+};
+
QT_END_NAMESPACE
#endif // QMACSTYLE_MAC_P_H
diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp
index f0d1d2319c..76d6efadee 100644
--- a/src/widgets/styles/qstyle.cpp
+++ b/src/widgets/styles/qstyle.cpp
@@ -1887,6 +1887,9 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
\value SH_RequestSoftwareInputPanel Determines when a software input panel should
be requested by input widgets. Returns an enum of type QStyle::RequestSoftwareInputPanel.
+ \value SH_ScrollBar_Transient Determines if the style supports transient scroll bars. Transient
+ scroll bars appear when the content is scrolled and disappear when they are no longer needed.
+
\sa styleHint()
*/
diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h
index 48491b3e3e..387645ae11 100644
--- a/src/widgets/styles/qstyle.h
+++ b/src/widgets/styles/qstyle.h
@@ -698,6 +698,7 @@ public:
SH_DockWidget_ButtonsHaveFrame,
SH_ToolButtonStyle,
SH_RequestSoftwareInputPanel,
+ SH_ScrollBar_Transient,
// Add new style hint values here
SH_CustomBase = 0xf0000000
diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp
index 8aa5534366..3c21d767be 100644
--- a/src/widgets/widgets/qabstractscrollarea.cpp
+++ b/src/widgets/widgets/qabstractscrollarea.cpp
@@ -57,6 +57,7 @@
#include <QDebug>
#include "qabstractscrollarea_p.h"
+#include "qscrollbar_p.h"
#include <qwidget.h>
#include <private/qapplication_p.h>
@@ -183,6 +184,7 @@ QAbstractScrollAreaScrollBarContainer::QAbstractScrollAreaScrollBarContainer(Qt:
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(scrollBar);
+ layout->setSizeConstraint(QLayout::SetMaximumSize);
}
/*! \internal
@@ -266,6 +268,8 @@ void QAbstractScrollAreaPrivate::replaceScrollBar(QScrollBar *scrollBar,
scrollBar->setSliderPosition(oldBar->sliderPosition());
scrollBar->setTracking(oldBar->hasTracking());
scrollBar->setValue(oldBar->value());
+ scrollBar->installEventFilter(q);
+ oldBar->removeEventFilter(q);
delete oldBar;
QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
@@ -286,6 +290,7 @@ void QAbstractScrollAreaPrivate::init()
hbar = scrollBarContainers[Qt::Horizontal]->scrollBar;
hbar->setRange(0,0);
scrollBarContainers[Qt::Horizontal]->setVisible(false);
+ hbar->installEventFilter(q);
QObject::connect(hbar, SIGNAL(valueChanged(int)), q, SLOT(_q_hslide(int)));
QObject::connect(hbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
scrollBarContainers[Qt::Vertical] = new QAbstractScrollAreaScrollBarContainer(Qt::Vertical, q);
@@ -293,6 +298,7 @@ void QAbstractScrollAreaPrivate::init()
vbar = scrollBarContainers[Qt::Vertical]->scrollBar;
vbar->setRange(0,0);
scrollBarContainers[Qt::Vertical]->setVisible(false);
+ vbar->installEventFilter(q);
QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(_q_vslide(int)));
QObject::connect(vbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
viewportFilter.reset(new QAbstractScrollAreaFilter(this));
@@ -323,10 +329,10 @@ void QAbstractScrollAreaPrivate::layoutChildren()
{
Q_Q(QAbstractScrollArea);
bool needh = (hbarpolicy == Qt::ScrollBarAlwaysOn
- || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum()));
+ || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum() && !hbar->sizeHint().isEmpty()));
bool needv = (vbarpolicy == Qt::ScrollBarAlwaysOn
- || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum()));
+ || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum() && !vbar->sizeHint().isEmpty()));
QStyleOption opt(0);
opt.init(q);
@@ -648,6 +654,7 @@ void QAbstractScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
d->layoutChildren();
if (oldPolicy != d->vbarpolicy)
d->scrollBarPolicyChanged(Qt::Vertical, d->vbarpolicy);
+ d->setScrollBarTransient(d->vbar, policy == Qt::ScrollBarAsNeeded);
}
@@ -709,6 +716,7 @@ void QAbstractScrollArea::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy polic
d->layoutChildren();
if (oldPolicy != d->hbarpolicy)
d->scrollBarPolicyChanged(Qt::Horizontal, d->hbarpolicy);
+ d->setScrollBarTransient(d->hbar, policy == Qt::ScrollBarAsNeeded);
}
/*!
@@ -921,6 +929,20 @@ void QAbstractScrollArea::setViewportMargins(const QMargins &margins)
margins.right(), margins.bottom());
}
+/*! \internal */
+bool QAbstractScrollArea::eventFilter(QObject *o, QEvent *e)
+{
+ Q_D(QAbstractScrollArea);
+ if ((o == d->hbar || o == d->vbar) && (e->type() == QEvent::HoverEnter || e->type() == QEvent::HoverLeave)) {
+ Qt::ScrollBarPolicy policy = o == d->hbar ? d->vbarpolicy : d->hbarpolicy;
+ if (policy == Qt::ScrollBarAsNeeded) {
+ QScrollBar *sibling = o == d->hbar ? d->vbar : d->hbar;
+ d->setScrollBarTransient(sibling, e->type() == QEvent::HoverLeave);
+ }
+ }
+ return QFrame::eventFilter(o, e);
+}
+
/*!
\fn bool QAbstractScrollArea::event(QEvent *event)
@@ -1421,12 +1443,26 @@ bool QAbstractScrollAreaPrivate::canStartScrollingAt( const QPoint &startPos )
return true;
}
+void QAbstractScrollAreaPrivate::flashScrollBars()
+{
+ if (hbarpolicy == Qt::ScrollBarAsNeeded)
+ hbar->d_func()->flash();
+ if (vbarpolicy == Qt::ScrollBarAsNeeded)
+ vbar->d_func()->flash();
+}
+
+void QAbstractScrollAreaPrivate::setScrollBarTransient(QScrollBar *scrollBar, bool transient)
+{
+ scrollBar->d_func()->setTransient(transient);
+}
+
void QAbstractScrollAreaPrivate::_q_hslide(int x)
{
Q_Q(QAbstractScrollArea);
int dx = xoffset - x;
xoffset = x;
q->scrollContentsBy(dx, 0);
+ flashScrollBars();
}
void QAbstractScrollAreaPrivate::_q_vslide(int y)
@@ -1435,6 +1471,7 @@ void QAbstractScrollAreaPrivate::_q_vslide(int y)
int dy = yoffset - y;
yoffset = y;
q->scrollContentsBy(0, dy);
+ flashScrollBars();
}
void QAbstractScrollAreaPrivate::_q_showOrHideScrollBars()
diff --git a/src/widgets/widgets/qabstractscrollarea.h b/src/widgets/widgets/qabstractscrollarea.h
index 560df9dcae..5ac140241e 100644
--- a/src/widgets/widgets/qabstractscrollarea.h
+++ b/src/widgets/widgets/qabstractscrollarea.h
@@ -96,6 +96,7 @@ protected:
void setViewportMargins(int left, int top, int right, int bottom);
void setViewportMargins(const QMargins &margins);
+ bool eventFilter(QObject *, QEvent *);
bool event(QEvent *);
virtual bool viewportEvent(QEvent *);
diff --git a/src/widgets/widgets/qabstractscrollarea_p.h b/src/widgets/widgets/qabstractscrollarea_p.h
index d77d97e03f..7e2ca741b1 100644
--- a/src/widgets/widgets/qabstractscrollarea_p.h
+++ b/src/widgets/widgets/qabstractscrollarea_p.h
@@ -92,6 +92,9 @@ public:
virtual void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) {}
bool canStartScrollingAt( const QPoint &startPos );
+ void flashScrollBars();
+ void setScrollBarTransient(QScrollBar *scrollBar, bool transient);
+
void _q_hslide(int);
void _q_vslide(int);
void _q_showOrHideScrollBars();
diff --git a/src/widgets/widgets/qscrollarea.cpp b/src/widgets/widgets/qscrollarea.cpp
index be7ce10c8c..576f77a7b7 100644
--- a/src/widgets/widgets/qscrollarea.cpp
+++ b/src/widgets/widgets/qscrollarea.cpp
@@ -331,7 +331,7 @@ bool QScrollArea::eventFilter(QObject *o, QEvent *e)
if (o == d->widget && e->type() == QEvent::Resize)
d->updateScrollBars();
- return false;
+ return QAbstractScrollArea::eventFilter(o, e);
}
/*!
diff --git a/src/widgets/widgets/qscrollbar.cpp b/src/widgets/widgets/qscrollbar.cpp
index aa45b4f54e..199aaf93de 100644
--- a/src/widgets/widgets/qscrollbar.cpp
+++ b/src/widgets/widgets/qscrollbar.cpp
@@ -55,7 +55,7 @@
#include "qaccessible.h"
#endif
#include <limits.h>
-#include "qabstractslider_p.h"
+#include "qscrollbar_p.h"
QT_BEGIN_NAMESPACE
@@ -201,26 +201,6 @@ QT_BEGIN_NAMESPACE
\sa QScrollArea, QSlider, QDial, QSpinBox, {fowler}{GUI Design Handbook: Scroll Bar}, {Sliders Example}
*/
-class QScrollBarPrivate : public QAbstractSliderPrivate
-{
- Q_DECLARE_PUBLIC(QScrollBar)
-public:
- QStyle::SubControl pressedControl;
- bool pointerOutsidePressedControl;
-
- int clickOffset, snapBackPosition;
-
- void activateControl(uint control, int threshold = 500);
- void stopRepeatAction();
- int pixelPosToRangeValue(int pos) const;
- void init();
- bool updateHoverControl(const QPoint &pos);
- QStyle::SubControl newHoverControl(const QPoint &pos);
-
- QStyle::SubControl hoverControl;
- QRect hoverRect;
-};
-
bool QScrollBarPrivate::updateHoverControl(const QPoint &pos)
{
Q_Q(QScrollBar);
@@ -249,6 +229,29 @@ QStyle::SubControl QScrollBarPrivate::newHoverControl(const QPoint &pos)
return hoverControl;
}
+void QScrollBarPrivate::setTransient(bool value)
+{
+ Q_Q(QScrollBar);
+ if (transient != value) {
+ transient = value;
+ if (transient) {
+ if (q->isVisible() && q->style()->styleHint(QStyle::SH_ScrollBar_Transient))
+ q->update();
+ } else if (!q->isVisible()) {
+ q->show();
+ }
+ }
+}
+
+void QScrollBarPrivate::flash()
+{
+ Q_Q(QScrollBar);
+ if (!flashed && q->style()->styleHint(QStyle::SH_ScrollBar_Transient)) {
+ flashed = true;
+ q->show();
+ }
+}
+
void QScrollBarPrivate::activateControl(uint control, int threshold)
{
QAbstractSlider::SliderAction action = QAbstractSlider::SliderNoAction;
@@ -322,6 +325,8 @@ void QScrollBar::initStyleOption(QStyleOptionSlider *option) const
option->upsideDown = d->invertedAppearance;
if (d->orientation == Qt::Horizontal)
option->state |= QStyle::State_Horizontal;
+ if (d->flashed || !d->transient)
+ option->state |= QStyle::State_On;
}
@@ -379,6 +384,8 @@ void QScrollBarPrivate::init()
invertedControls = true;
pressedControl = hoverControl = QStyle::SC_None;
pointerOutsidePressedControl = false;
+ transient = q->style()->styleHint(QStyle::SH_ScrollBar_Transient);
+ flashed = false;
q->setFocusPolicy(Qt::NoFocus);
QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::Slider);
if (orientation == Qt::Vertical)
@@ -476,6 +483,9 @@ bool QScrollBar::event(QEvent *event)
if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
d_func()->updateHoverControl(he->pos());
break;
+ case QEvent::StyleChange:
+ d_func()->setTransient(style()->styleHint(QStyle::SH_ScrollBar_Transient));
+ break;
default:
break;
}
@@ -521,6 +531,10 @@ void QScrollBar::paintEvent(QPaintEvent *)
opt.activeSubControls = (QStyle::SubControl)d->hoverControl;
}
style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p, this);
+ if (d->flashed && style()->styleHint(QStyle::SH_ScrollBar_Transient)) {
+ d->flashed = false;
+ update();
+ }
}
/*!
diff --git a/src/widgets/widgets/qscrollbar.h b/src/widgets/widgets/qscrollbar.h
index 48863616ff..3e9ac8a47f 100644
--- a/src/widgets/widgets/qscrollbar.h
+++ b/src/widgets/widgets/qscrollbar.h
@@ -83,6 +83,7 @@ protected:
private:
+ friend class QAbstractScrollAreaPrivate;
friend Q_WIDGETS_EXPORT QStyleOptionSlider qt_qscrollbarStyleOption(QScrollBar *scrollBar);
Q_DISABLE_COPY(QScrollBar)
diff --git a/src/widgets/widgets/qscrollbar_p.h b/src/widgets/widgets/qscrollbar_p.h
new file mode 100644
index 0000000000..fb4f5b07da
--- /dev/null
+++ b/src/widgets/widgets/qscrollbar_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSCROLLBAR_P_H
+#define QSCROLLBAR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qabstractslider_p.h"
+#include "qstyle.h"
+
+QT_BEGIN_NAMESPACE
+
+class QScrollBarPrivate : public QAbstractSliderPrivate
+{
+ Q_DECLARE_PUBLIC(QScrollBar)
+public:
+ QStyle::SubControl pressedControl;
+ bool pointerOutsidePressedControl;
+
+ int clickOffset, snapBackPosition;
+
+ void activateControl(uint control, int threshold = 500);
+ void stopRepeatAction();
+ int pixelPosToRangeValue(int pos) const;
+ void init();
+ bool updateHoverControl(const QPoint &pos);
+ QStyle::SubControl newHoverControl(const QPoint &pos);
+
+ QStyle::SubControl hoverControl;
+ QRect hoverRect;
+
+ bool transient;
+ void setTransient(bool value);
+
+ bool flashed;
+ void flash();
+};
+
+QT_END_NAMESPACE
+
+#endif // QSCROLLBAR_P_H
diff --git a/src/widgets/widgets/widgets.pri b/src/widgets/widgets/widgets.pri
index c86bc1eff7..797f3e9b76 100644
--- a/src/widgets/widgets/widgets.pri
+++ b/src/widgets/widgets/widgets.pri
@@ -46,6 +46,7 @@ HEADERS += \
widgets/qradiobutton.h \
widgets/qrubberband.h \
widgets/qscrollbar.h \
+ widgets/qscrollbar_p.h \
widgets/qscrollarea_p.h \
widgets/qsizegrip.h \
widgets/qslider.h \