Mac: Animated expanding scrollbars on 10.8
authorGabriel de Dietrich <gabriel.dedietrich@digia.com>
Mon, 3 Dec 2012 18:00:03 +0000 (19:00 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 6 Dec 2012 15:45:52 +0000 (16:45 +0100)
Change-Id: Ib57d0347a7828ac7582b0fa95adf8d437694cd41
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
src/widgets/styles/qmacstyle_mac.mm
src/widgets/styles/qmacstyle_mac_p_p.h

index ba34a74..649e7f2 100644 (file)
@@ -2181,11 +2181,11 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
             switch (d->aquaSizeConstrain(opt, widget)) {
             case QAquaSizeUnknown:
             case QAquaSizeLarge:
-                ret = 9;
+                ret = QSysInfo::macVersion() >= QSysInfo::MV_10_8 ? 16 : 9;
                 break;
             case QAquaSizeMini:
             case QAquaSizeSmall:
-                ret = 7;
+                ret =  QSysInfo::macVersion() >= QSysInfo::MV_10_8 ? 14 : 7;
                 break;
             }
             break;
@@ -4909,6 +4909,11 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
             if (cc == CC_ScrollBar && proxy()->styleHint(SH_ScrollBar_Transient)) {
                 bool wasActive = false;
                 CGFloat opacity = 1.0;
+                CGFloat expandScale = 1.0;
+                CGFloat expandOffset = -1.0;
+                bool shouldExpand = false;
+                const CGFloat maxExpandScale = tdi.kind == kThemeSmallScrollBar ? 11.0 / 7.0 : 13.0 / 9.0;
+
                 if (QObject *styleObject = opt->styleObject) {
                     int oldPos = styleObject->property("_q_stylepos").toInt();
                     int oldMin = styleObject->property("_q_stylemin").toInt();
@@ -4936,23 +4941,24 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
                         styleObject->setProperty("_q_stylestate", static_cast<int>(slider->state));
                         styleObject->setProperty("_q_stylecontrols", static_cast<uint>(slider->activeSubControls));
 
+                        QScrollbarAnimation *anim  = qobject_cast<QScrollbarAnimation *>(d->animation(styleObject));
                         if (transient) {
-                            QFadeOutAnimation *anim  = qobject_cast<QFadeOutAnimation *>(d->animation(styleObject));
                             if (!anim) {
-                                anim = new QFadeOutAnimation(styleObject);
+                                anim = new QScrollbarAnimation(styleObject);
+                                anim->setFadingOut();
                                 d->startAnimation(anim);
-                            } else {
+                            } else if (anim->isFadingOut()) {
                                 // the scrollbar was already fading out while the
                                 // state changed -> restart the fade out animation
                                 anim->setCurrentTime(0);
                             }
-                        } else {
+                        } else if (anim && anim->isFadingOut()) {
                             d->stopAnimation(styleObject);
                         }
                     }
 
-                    QFadeOutAnimation *anim = qobject_cast<QFadeOutAnimation *>(d->animation(styleObject));
-                    if (anim) {
+                    QScrollbarAnimation *anim = qobject_cast<QScrollbarAnimation *>(d->animation(styleObject));
+                    if (anim && anim->isFadingOut()) {
                         // once a scrollbar was active (hovered/pressed), it retains
                         // the active look even if it's no longer active while fading out
                         if (oldActiveControls)
@@ -4961,6 +4967,24 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
                         wasActive = anim->wasActive();
                         opacity = anim->currentValue();
                     }
+
+                    shouldExpand = (opt->activeSubControls || wasActive) && QSysInfo::macVersion() >= QSysInfo::MV_10_8;
+                    if (shouldExpand) {
+                        if (!anim && !oldActiveControls) {
+                            // Start expand animation only once and when entering
+                            anim = new QScrollbarAnimation(styleObject);
+                            anim->setExpanding();
+                            d->startAnimation(anim);
+                        }
+                        if (anim && !anim->isFadingOut()) {
+                            expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
+                            expandOffset = 5.5 * anim->currentValue() - 1;
+                        } else {
+                            // Keep expanded state after the animation ends, and when fading out
+                            expandScale = maxExpandScale;
+                            expandOffset = 4.5;
+                        }
+                    }
                 }
 
                 const bool isHorizontal = slider->orientation == Qt::Horizontal;
@@ -4985,29 +5009,27 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
                 [scroller setBounds:NSMakeRect(0, 0, slider->rect.width(), slider->rect.height())];
                 [scroller setScrollerStyle:NSScrollerStyleOverlay];
 
-                // first we draw only the track, by using a disabled scroller
-                if (opt->activeSubControls || wasActive) {
-                    CGContextBeginTransparencyLayerWithRect(cg, qt_hirectForQRect(slider->rect),
-                                                            NULL);
-                    CGContextSetAlpha(cg, opacity);
-
-                    [scroller setFrame:[scroller bounds]];
-                    [scroller setEnabled:(slider->state & State_Enabled) ? YES : NO];
-                    [scroller drawKnobSlotInRect:[scroller bounds] highlight:NO];
+                CGContextBeginTransparencyLayer(cg, NULL);
+                CGContextSetAlpha(cg, opacity);
 
-                    CGContextEndTransparencyLayer(cg);
+                // Draw the track when hovering
+                if (opt->activeSubControls || wasActive) {
+                    CGRect rect = [scroller bounds];
+                    if (shouldExpand) {
+                        if (isHorizontal)
+                            rect.origin.y += 4.5 - expandOffset;
+                        else
+                            rect.origin.x += 4.5 - expandOffset;
+                    }
+                    [scroller drawKnobSlotInRect:rect highlight:YES];
                 }
 
-                CGContextBeginTransparencyLayerWithRect(cg, qt_hirectForQRect(slider->rect), NULL);
-                CGContextSetAlpha(cg, opacity);
-
                 const qreal length = slider->maximum - slider->minimum + slider->pageStep;
                 const qreal proportion = slider->pageStep / length;
                 qreal value = (slider->sliderValue - slider->minimum) / length;
                 if (isHorizontal && slider->direction == Qt::RightToLeft)
                     value = 1.0 - value - proportion;
 
-                [scroller setEnabled:(slider->state & State_Enabled) ? YES : NO];
                 [scroller setKnobProportion:1.0];
 
                 const int minKnobWidth = 26;
@@ -5017,13 +5039,23 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
                     const qreal width = qMax<qreal>(minKnobWidth, plannedWidth);
                     const qreal totalWidth = slider->rect.width() + plannedWidth - width;
                     [scroller setFrame:NSMakeRect(0, 0, width, slider->rect.height())];
-                    CGContextTranslateCTM(cg, value * totalWidth, 1);
+                    if (shouldExpand) {
+                        CGContextScaleCTM(cg, 1, expandScale);
+                        CGContextTranslateCTM(cg, value * totalWidth, -expandOffset);
+                    } else {
+                        CGContextTranslateCTM(cg, value * totalWidth, 1);
+                    }
                 } else {
                     const qreal plannedHeight = proportion * slider->rect.height();
                     const qreal height = qMax<qreal>(minKnobWidth, plannedHeight);
                     const qreal totalHeight = slider->rect.height() + plannedHeight - height;
                     [scroller setFrame:NSMakeRect(0, 0, slider->rect.width(), height)];
-                    CGContextTranslateCTM(cg, 1, value * totalHeight);
+                    if (shouldExpand) {
+                        CGContextScaleCTM(cg, expandScale, 1);
+                        CGContextTranslateCTM(cg, -expandOffset, value * totalHeight);
+                    } else {
+                        CGContextTranslateCTM(cg, 1, value * totalHeight);
+                    }
                 }
                 if (length > 0.0) {
                     [scroller layout];
index c2e5a02..a23c45f 100644 (file)
@@ -211,32 +211,47 @@ public:
 #endif
 };
 
-class QFadeOutAnimation : public QNumberStyleAnimation
+class QScrollbarAnimation : public QNumberStyleAnimation
 {
     Q_OBJECT
 
 public:
-    QFadeOutAnimation(QObject *target) : QNumberStyleAnimation(target), _active(false)
+    QScrollbarAnimation(QObject *target) : QNumberStyleAnimation(target), _active(false)
+    { }
+
+    bool wasActive() const { return _active; }
+    void setActive(bool active) { _active = active; }
+
+    bool isFadingOut() const { return _isFadingOut; }
+
+    void setFadingOut()
     {
+        _isFadingOut = true;
         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; }
+    void setExpanding()
+    {
+        _isFadingOut = false;
+        setDuration(QMacStylePrivate::ScrollBarFadeOutDuration);
+        setStartValue(0.0);
+        setEndValue(1.0);
+    }
 
 private slots:
     void updateCurrentTime(int time)
     {
         QNumberStyleAnimation::updateCurrentTime(time);
-        if (qFuzzyIsNull(currentValue()))
+        if (_isFadingOut && qFuzzyIsNull(currentValue()))
             target()->setProperty("visible", false);
     }
 
 private:
     bool _active;
+    bool _isFadingOut;
 };
 
 QT_END_NAMESPACE