QMacStyle: Use NSView rendering for some inactive widgets on 10.10

Right now, we use them for inactive non-editable combo box, check
box, and radio button only on Yosemite. We keep as much as possible
the previous behavior on older versions.

In addition, we add a way for QQuickStyleItem to specify the window
the item is on. This is currently without effect, since we don't
seem to take the inactive window state into account.

Task-number: QTBUG-40833
Change-Id: I2fb2a99e6adf1972f881195b79b07ce85a960273
Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
This commit is contained in:
Gabriel de Dietrich 2014-09-04 19:11:23 +02:00
parent c1b46b98ed
commit 982b9b7ec2
4 changed files with 142 additions and 3 deletions

View File

@ -1702,7 +1702,7 @@ void QMacStylePrivate::setAutoDefaultButton(QObject *button) const
} }
QMacStylePrivate::QMacStylePrivate() QMacStylePrivate::QMacStylePrivate()
: mouseDown(false) : mouseDown(false), backingStoreNSView(nil)
{ {
defaultButtonStart = CFAbsoluteTimeGetCurrent(); defaultButtonStart = CFAbsoluteTimeGetCurrent();
memset(&buttonState, 0, sizeof(ButtonState)); memset(&buttonState, 0, sizeof(ButtonState));
@ -1715,6 +1715,12 @@ QMacStylePrivate::QMacStylePrivate()
} }
QMacStylePrivate::~QMacStylePrivate()
{
Q_FOREACH (NSView *b, buttons)
[b release];
}
ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags) ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
{ {
ThemeDrawState tds = kThemeStateActive; ThemeDrawState tds = kThemeStateActive;
@ -1732,6 +1738,97 @@ ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
return tds; return tds;
} }
NSView *QMacStylePrivate::buttonOfKind(ThemeButtonKind kind) const
{
NSView *bv = buttons[kind];
if (!bv) {
if (kind == kThemePopupButton)
bv = [[NSPopUpButton alloc] init];
else if (kind == kThemeComboBox)
bv = [[NSComboBox alloc] init];
else
bv = [[NSButton alloc] init];
switch (kind) {
case kThemeArrowButton: {
NSButton *bc = (NSButton *)bv;
bc.buttonType = NSOnOffButton;
bc.bezelStyle = NSDisclosureBezelStyle;
break;
}
case kThemeCheckBox:
case kThemeCheckBoxSmall:
case kThemeCheckBoxMini: {
NSButton *bc = (NSButton *)bv;
bc.buttonType = NSSwitchButton;
break;
}
case kThemeRadioButton:
case kThemeRadioButtonSmall:
case kThemeRadioButtonMini: {
NSButton *bc = (NSButton *)bv;
bc.buttonType = NSRadioButton;
break;
}
case kThemePushButton:
case kThemePushButtonSmall:
case kThemePushButtonMini: {
NSButton *bc = (NSButton *)bv;
bc.buttonType = NSMomentaryPushButton;
bc.bezelStyle = NSRoundedBezelStyle;
break;
}
default:
break;
}
// if (kind == kThemePushButtonSmall
// || kind == kThemePopupButtonSmall
// || kind == kThemeCheckBoxSmall
// || kind == kThemeRadioButtonSmall)
// bc.controlSize = NSSmallControlSize;
// else if (kind == kThemePushButtonMini
// || kind == kThemePopupButtonMini
// || kind == kThemeCheckBoxMini
// || kind == kThemeRadioButtonMini)
// bc.controlSize = NSMiniControlSize;
if ([bv isKindOfClass:[NSButton class]]) {
NSButton *bc = (NSButton *)bv;
bc.title = nil;
}
const_cast<QMacStylePrivate *>(this)->buttons.insert(kind, bv);
}
return bv;
}
void QMacStylePrivate::drawNSViewInRect(NSView *view, const QRect &qtRect, QPainter *p) const
{
QMacCGContext ctx(p);
CGContextSaveGState(ctx);
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext
graphicsContextWithGraphicsPort:ctx flipped:YES]];
CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
[backingStoreNSView addSubview:view];
view.frame = rect;
[view drawRect:rect];
[view removeFromSuperviewWithoutNeedingDisplay];
[NSGraphicsContext restoreGraphicsState];
CGContextRestoreGState(ctx);
}
void QMacStylePrivate::resolveCurrentNSView(QWindow *window)
{
backingStoreNSView = window ? (NSView *)window->winId() : nil;
}
void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi, void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
QPainter *p, const QStyleOption *opt) const QPainter *p, const QStyleOption *opt) const
{ {
@ -1742,6 +1839,9 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD
finalyoff = 0; finalyoff = 0;
const bool combo = opt->type == QStyleOption::SO_ComboBox; const bool combo = opt->type == QStyleOption::SO_ComboBox;
const bool editableCombo = bdi->kind == kThemeComboBox
|| bdi->kind == kThemeComboBoxSmall
|| bdi->kind == kThemeComboBoxMini;
const bool button = opt->type == QStyleOption::SO_Button; const bool button = opt->type == QStyleOption::SO_Button;
const bool pressed = bdi->state == kThemeStatePressed; const bool pressed = bdi->state == kThemeStatePressed;
const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion > QSysInfo::MV_10_9; const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion > QSysInfo::MV_10_9;
@ -1789,7 +1889,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD
if (!combo && !button && bdi->value == kThemeButtonOff) { if (!combo && !button && bdi->value == kThemeButtonOff) {
pm = activePixmap; pm = activePixmap;
} else if ((combo && !usingYosemiteOrLater) || button) { } else if (!usingYosemiteOrLater && (combo || button)) {
QImage image = activePixmap.toImage(); QImage image = activePixmap.toImage();
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
@ -1816,7 +1916,17 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD
} }
} }
pm = QPixmap::fromImage(image); pm = QPixmap::fromImage(image);
} else if (combo && usingYosemiteOrLater) { } else if ((usingYosemiteOrLater && combo && !editableCombo) || button) {
NSButton *bc = (NSButton *)buttonOfKind(bdi->kind);
[bc highlight:pressed];
bc.enabled = bdi->state != kThemeStateUnavailable && bdi->state != kThemeStateUnavailableInactive;
bc.state = bdi->value == kThemeButtonOn ? NSOnState :
bdi->value == kThemeButtonMixed ? NSMixedState : NSOffState;
p->translate(0, 1);
drawNSViewInRect(bc, opt->rect, p);
p->translate(0, -1);
return;
} else if (usingYosemiteOrLater && editableCombo) {
QImage image = activePixmap.toImage(); QImage image = activePixmap.toImage();
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
@ -2944,6 +3054,9 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
Q_D(const QMacStyle); Q_D(const QMacStyle);
ThemeDrawState tds = d->getDrawState(opt->state); ThemeDrawState tds = d->getDrawState(opt->state);
QMacCGContext cg(p); QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
switch (pe) { switch (pe) {
case PE_IndicatorArrowUp: case PE_IndicatorArrowUp:
case PE_IndicatorArrowDown: case PE_IndicatorArrowDown:
@ -3358,6 +3471,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
Q_D(const QMacStyle); Q_D(const QMacStyle);
ThemeDrawState tds = d->getDrawState(opt->state); ThemeDrawState tds = d->getDrawState(opt->state);
QMacCGContext cg(p); QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
switch (ce) { switch (ce) {
case CE_HeaderSection: case CE_HeaderSection:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) { if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
@ -5075,6 +5191,9 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
Q_D(const QMacStyle); Q_D(const QMacStyle);
ThemeDrawState tds = d->getDrawState(opt->state); ThemeDrawState tds = d->getDrawState(opt->state);
QMacCGContext cg(p); QMacCGContext cg(p);
QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
switch (cc) { switch (cc) {
case CC_Slider: case CC_Slider:
case CC_ScrollBar: case CC_ScrollBar:

View File

@ -145,6 +145,7 @@ class QMacStylePrivate : public QCommonStylePrivate
Q_DECLARE_PUBLIC(QMacStyle) Q_DECLARE_PUBLIC(QMacStyle)
public: public:
QMacStylePrivate(); QMacStylePrivate();
~QMacStylePrivate();
// Ideally these wouldn't exist, but since they already exist we need some accessors. // Ideally these wouldn't exist, but since they already exist we need some accessors.
static const int PushButtonLeftOffset; static const int PushButtonLeftOffset;
@ -194,6 +195,11 @@ public:
void setAutoDefaultButton(QObject *button) const; void setAutoDefaultButton(QObject *button) const;
NSView *buttonOfKind(ThemeButtonKind kind) const;
void drawNSViewInRect(NSView *view, const QRect &rect, QPainter *p) const;
void resolveCurrentNSView(QWindow *window);
public: public:
mutable QPointer<QObject> pressedButton; mutable QPointer<QObject> pressedButton;
mutable QPointer<QObject> defaultButton; mutable QPointer<QObject> defaultButton;
@ -212,6 +218,8 @@ public:
void *nsscroller; void *nsscroller;
#endif #endif
void *indicatorBranchButtonCell; void *indicatorBranchButtonCell;
NSView *backingStoreNSView;
QHash<ThemeButtonKind , NSView *> buttons;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -47,6 +47,7 @@
#include <qmath.h> #include <qmath.h>
#include <qscrollbar.h> #include <qscrollbar.h>
#include <qabstractscrollarea.h> #include <qabstractscrollarea.h>
#include <qwindow.h>
#include "qstylehelper_p.h" #include "qstylehelper_p.h"
#include <qstringbuilder.h> #include <qstringbuilder.h>
@ -397,5 +398,14 @@ QColor backgroundColor(const QPalette &pal, const QWidget* widget)
return widget->parentWidget()->parentWidget()->palette().color(QPalette::Base); return widget->parentWidget()->parentWidget()->palette().color(QPalette::Base);
return pal.color(QPalette::Base); return pal.color(QPalette::Base);
} }
QWindow *styleObjectWindow(QObject *so)
{
if (so)
return so->property("_q_styleObjectWindow").value<QWindow *>();
return 0;
}
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -68,6 +68,7 @@ class QPainter;
class QPixmap; class QPixmap;
class QStyleOptionSlider; class QStyleOptionSlider;
class QStyleOption; class QStyleOption;
class QWindow;
namespace QStyleHelper namespace QStyleHelper
{ {
@ -87,6 +88,7 @@ namespace QStyleHelper
bool hasAncestor(QObject *obj, QAccessible::Role role); bool hasAncestor(QObject *obj, QAccessible::Role role);
#endif #endif
QColor backgroundColor(const QPalette &pal, const QWidget* widget = 0); QColor backgroundColor(const QPalette &pal, const QWidget* widget = 0);
QWindow *styleObjectWindow(QObject *so);
} }