summaryrefslogtreecommitdiffstats
path: root/src/plugins/styles
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dedietrich@qt.io>2017-05-17 13:15:18 -0700
committerGabriel de Dietrich <gabriel.dedietrich@qt.io>2017-06-01 17:56:12 +0000
commit83cbb314609250131d45b14678bbefda8b76bcb1 (patch)
tree6a1daa6fbbb05858391359a7779a8b518f7b339b /src/plugins/styles
parent8b6d6d4832ea8ed5f9857d5ddf06408ee9d0b4e0 (diff)
QMacStyle: Remove HITheme APIs to render QProgresssBar
We use NSProgressIndicator in a similar fashion as we do with NSScroller for transient scrollers. Also changed the signature of QCocoaDrawRectBlock. Change-Id: I0fef8e327494fb557af2c2bab2aafa57c2e69564 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Diffstat (limited to 'src/plugins/styles')
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm191
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p_p.h6
2 files changed, 147 insertions, 50 deletions
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index 7124f1a468..8be5baf287 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -141,6 +141,68 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
}
@end
+@interface QT_MANGLE_NAMESPACE(QIndeterminateProgressIndicator) : NSProgressIndicator
+
+@property (readonly, nonatomic) NSInteger animators;
+
+- (instancetype)init;
+
+- (void)startAnimation;
+- (void)stopAnimation;
+
+- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view;
+
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QIndeterminateProgressIndicator);
+
+@implementation QIndeterminateProgressIndicator
+
+- (instancetype)init
+{
+ if ((self = [super init])) {
+ _animators = 0;
+ self.indeterminate = YES;
+ self.usesThreadedAnimation = NO;
+ self.alphaValue = 0.0;
+ }
+
+ return self;
+}
+
+- (void)startAnimation
+{
+ if (_animators == 0) {
+ self.hidden = NO;
+ [super startAnimation:self];
+ }
+ ++_animators;
+}
+
+- (void)stopAnimation
+{
+ --_animators;
+ if (_animators == 0) {
+ [super stopAnimation:self];
+ self.hidden = YES;
+ [self removeFromSuperviewWithoutNeedingDisplay];
+ }
+}
+
+- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view
+{
+ // The alphaValue change is not strictly necessary, but feels safer.
+ self.alphaValue = 1.0;
+ if (self.superview != view)
+ [view addSubview:self];
+ if (!CGRectEqualToRect(self.frame, rect))
+ self.frame = rect;
+ [self drawRect:rect];
+ self.alphaValue = 0.0;
+}
+
+@end
+
QT_BEGIN_NAMESPACE
// The following constants are used for adjusting the size
@@ -1859,6 +1921,10 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
bv = [[NSPopUpButton alloc] init];
else if (widget.first == QCocoaComboBox)
bv = [[NSComboBox alloc] init];
+ else if (widget.first == QCocoaProgressIndicator)
+ bv = [[NSProgressIndicator alloc] init];
+ else if (widget.first == QCocoaIndeterminateProgressIndicator)
+ bv = [[QIndeterminateProgressIndicator alloc] init];
else if (widget.first == QCocoaHorizontalScroller)
bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
else if (widget.first == QCocoaVerticalScroller)
@@ -1923,6 +1989,19 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const
default:
break;
}
+ } else if ([bv isKindOfClass:[NSProgressIndicator class]]) {
+ auto *pi = static_cast<NSProgressIndicator *>(bv);
+ pi.indeterminate = (widget.first == QCocoaIndeterminateProgressIndicator);
+ switch (widget.second) {
+ case QStyleHelper::SizeSmall:
+ pi.controlSize = NSSmallControlSize;
+ break;
+ case QStyleHelper::SizeMini:
+ pi.controlSize = NSMiniControlSize;
+ break;
+ default:
+ break;
+ }
}
const_cast<QMacStylePrivate *>(this)->cocoaControls.insert(widget, bv);
@@ -1999,12 +2078,12 @@ void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const
CGContextTranslateCTM(ctx, offset.x(), offset.y());
- NSRect rect = NSMakeRect(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
+ const CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
[backingStoreNSView addSubview:view];
view.frame = rect;
if (drawRectBlock)
- drawRectBlock(rect, (CGContextRef)ctx);
+ drawRectBlock(ctx, rect);
else
[view drawRect:rect];
[view removeFromSuperviewWithoutNeedingDisplay];
@@ -3589,6 +3668,18 @@ static inline QPixmap darkenPixmap(const QPixmap &pixmap)
+void QMacStylePrivate::setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const
+{
+ if (vertical) {
+ CGContextTranslateCTM(cg, rect.size.height, 0);
+ CGContextRotateCTM(cg, M_PI_2);
+ }
+ if (vertical != reverse) {
+ CGContextTranslateCTM(cg, rect.size.width, 0);
+ CGContextScaleCTM(cg, -1, 1);
+ }
+}
+
void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
const QWidget *w) const
{
@@ -4474,66 +4565,68 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
}
break;
+ case CE_ProgressBarLabel:
+ case CE_ProgressBarGroove:
+ // Do nothing. All done in CE_ProgressBarContents. Only keep these for proxy style overrides.
+ break;
case CE_ProgressBarContents:
if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
- HIThemeTrackDrawInfo tdi;
- tdi.version = qt_mac_hitheme_version;
- tdi.reserved = 0;
- bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
+ QMacAutoReleasePool pool;
+ const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
const bool vertical = pb->orientation == Qt::Vertical;
const bool inverted = pb->invertedAppearance;
bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
if (inverted)
reverse = !reverse;
- switch (d->aquaSizeConstrain(opt, w)) {
- case QStyleHelper::SizeDefault:
- case QStyleHelper::SizeLarge:
- tdi.kind = !isIndeterminate ? kThemeLargeProgressBar
- : kThemeLargeIndeterminateBar;
- break;
- case QStyleHelper::SizeMini:
- case QStyleHelper::SizeSmall:
- tdi.kind = !isIndeterminate ? kThemeProgressBar : kThemeIndeterminateBar;
- break;
- }
- tdi.bounds = pb->rect.toCGRect();
- tdi.max = pb->maximum;
- tdi.min = pb->minimum;
- tdi.value = pb->progress;
- tdi.attributes = vertical ? 0 : kThemeTrackHorizontal;
+ QRect rect = pb->rect;
+ if (vertical)
+ rect = rect.transposed();
+ const CGRect cgRect = rect.toCGRect();
+
+ const auto aquaSize = d->effectiveAquaSizeConstrain(opt, w);
+ const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
+ QIndeterminateProgressIndicator *ipi = nil;
+ if (isIndeterminate || animation)
+ ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QCocoaIndeterminateProgressIndicator, aquaSize }));
if (isIndeterminate) {
- if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject)))
- tdi.trackInfo.progress.phase = animation->animationStep();
- else if (opt->styleObject)
- d->startAnimation(new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject));
+ // QIndeterminateProgressIndicator derives from NSProgressIndicator. We use a single
+ // instance that we start animating as soon as one of the progress bars is indeterminate.
+ // Since they will be in sync (as it's the case in Cocoa), we just need to draw it with
+ // the right geometry when the animation triggers an update. However, we can't hide it
+ // entirely between frames since that would stop the animation, so we just set its alpha
+ // value to 0. Same if we remove it from its superview. See QIndeterminateProgressIndicator
+ // implementation for details.
+ if (!animation && opt->styleObject) {
+ auto *animation = new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject);
+ // NSProgressIndicator is heavier to draw than the HITheme API, so we reduce the frame rate a notch.
+ animation->setFrameRate(QStyleAnimation::TwentyFps);
+ d->startAnimation(animation);
+ [ipi startAnimation];
+ }
+
+ d->setupNSGraphicsContext(cg, NO);
+ d->setupVerticalInvertedXform(cg, reverse, vertical, cgRect);
+ [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
+ d->restoreNSGraphicsContext(cg);
} else {
- d->stopAnimation(opt->styleObject);
- }
- if (!(pb->state & State_Active))
- tdi.enableState = kThemeTrackInactive;
- else if (!(pb->state & State_Enabled))
- tdi.enableState = kThemeTrackDisabled;
- else
- tdi.enableState = kThemeTrackActive;
- HIThemeOrientation drawOrientation = kHIThemeOrientationNormal;
- if (reverse) {
- if (vertical) {
- drawOrientation = kHIThemeOrientationInverted;
- } else {
- CGContextSaveGState(cg);
- CGContextTranslateCTM(cg, pb->rect.width(), 0);
- CGContextScaleCTM(cg, -1, 1);
+ if (animation) {
+ d->stopAnimation(opt->styleObject);
+ [ipi stopAnimation];
}
+
+ const QCocoaWidget cw = { QCocoaProgressIndicator, aquaSize };
+ auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
+ d->drawNSViewInRect(cw, pi, rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) {
+ d->setupVerticalInvertedXform(ctx, reverse, vertical, rect);
+ pi.minValue = pb->minimum;
+ pi.maxValue = pb->maximum;
+ pi.doubleValue = pb->progress;
+ [pi drawRect:rect];
+ });
}
- HIThemeDrawTrack(&tdi, 0, cg, drawOrientation);
- if (reverse && !vertical)
- CGContextRestoreGState(cg);
}
break;
- case CE_ProgressBarLabel:
- case CE_ProgressBarGroove:
- break;
case CE_SizeGrip: {
if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) {
HIThemeGrowBoxDrawInfo gdi;
@@ -5481,7 +5574,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
sl.maxValue = slider->maximum;
sl.intValue = slider->sliderValue;
sl.enabled = slider->state & QStyle::State_Enabled;
- d->drawNSViewInRect(cw, sl, opt->rect, p, widget != 0, ^(NSRect rect, CGContextRef ctx) {
+ d->drawNSViewInRect(cw, sl, opt->rect, p, widget != 0, ^(CGContextRef ctx, const CGRect &rect) {
const bool isSierraOrLater = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra;
if (slider->upsideDown) {
if (isHorizontal) {
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
index 2c701713c8..03282e1bbc 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
@@ -141,6 +141,8 @@ enum QCocoaWidgetKind {
QCocoaComboBox, // Editable QComboBox
QCocoaDisclosureButton, // Disclosure triangle, like in QTreeView
QCocoaPopupButton, // Non-editable QComboBox
+ QCocoaProgressIndicator,
+ QCocoaIndeterminateProgressIndicator,
QCocoaPullDownButton, // QPushButton with menu
QCocoaPushButton,
QCocoaRadioButton,
@@ -153,7 +155,7 @@ enum QCocoaWidgetKind {
typedef QPair<QCocoaWidgetKind, QStyleHelper::WidgetSizePolicy> QCocoaWidget;
-typedef void (^QCocoaDrawRectBlock)(NSRect, CGContextRef);
+typedef void (^QCocoaDrawRectBlock)(CGContextRef, const CGRect &);
#define SIZE(large, small, mini) \
(controlSize == QStyleHelper::SizeLarge ? (large) : controlSize == QStyleHelper::SizeSmall ? (small) : (mini))
@@ -233,6 +235,8 @@ public:
void setupNSGraphicsContext(CGContextRef cg, bool flipped) const;
void restoreNSGraphicsContext(CGContextRef cg) const;
+ void setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const;
+
void drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, QCocoaDrawRectBlock drawRectBlock = nil) const;
void resolveCurrentNSView(QWindow *window);