diff options
author | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2016-12-20 19:12:36 -0800 |
---|---|---|
committer | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2017-01-06 19:41:54 +0000 |
commit | 0e810e27a5e5a6c2e244ca439fbdf4f4ccc5b3da (patch) | |
tree | 18e1e9ce5c7351dc5515321155d2b8b2892bdf32 /src/widgets/styles/qmacstyle_mac.mm | |
parent | 64f4108c3a18c3e72da98b74efbf36dc3b8e08e9 (diff) |
QMacStyle: Fix drawing of PE_IndicatorMenuCheckMark
... And refactor to use it for drawing CE_MenuItem.
This removes a couple calls to HITheme. Instead, we
use CoreText to render the checkmark character. Notice
that this is what we were doing with HITheme for
CE_MenuItem. Drawing PE_IndicatorMenuCheckMark was
done manually, and in a way that has not been updated.
Notice also that the choice of color from the palette
has also been fixed to look for the State_Selected state
instead of the State_On state, in accordance with
QCommonStyle. In fact, on macOS, the checkmark is never
rendered when the State_On bit is clear. Moreover, we
systematically pick the checkmark color from the style
option palette.
[ChangeLog][QtWidgets][QMacStyle] PE_IndicatorMenuCheckMark
looks for State_On instead of the State_Selected to set its
highlighted state. Its color is picked from the style option
palette.
Change-Id: Ib033df357fd83080cb4320c43949f75bb079c8a5
Task-number: QTBUG-57470
Reviewed-by: Jake Petroules <jake.petroules@qt.io>
Diffstat (limited to 'src/widgets/styles/qmacstyle_mac.mm')
-rw-r--r-- | src/widgets/styles/qmacstyle_mac.mm | 154 |
1 files changed, 74 insertions, 80 deletions
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index cacf894978..b10f2d7d03 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -3301,32 +3301,60 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai } break; case PE_IndicatorMenuCheckMark: { - const int checkw = 8; - const int checkh = 8; - const int xoff = qMax(0, (opt->rect.width() - checkw) / 2); - const int yoff = qMax(0, (opt->rect.width() - checkh) / 2); - const int x1 = xoff + opt->rect.x(); - const int y1 = yoff + opt->rect.y() + checkw/2; - const int x2 = xoff + opt->rect.x() + checkw/4; - const int y2 = yoff + opt->rect.y() + checkh; - const int x3 = xoff + opt->rect.x() + checkw; - const int y3 = yoff + opt->rect.y(); - - QVector<QLineF> a(2); - a << QLineF(x1, y1, x2, y2); - a << QLineF(x2, y2, x3, y3); - if (opt->palette.currentColorGroup() == QPalette::Active) { - if (opt->state & State_On) - p->setPen(QPen(opt->palette.highlightedText().color(), 3)); - else - p->setPen(QPen(opt->palette.text().color(), 3)); - } else { - p->setPen(QPen(QColor(100, 100, 100), 3)); - } - p->save(); - p->setRenderHint(QPainter::Antialiasing); - p->drawLines(a); - p->restore(); + if (!(opt->state & State_On)) + break; + QColor pc; + if (opt->state & State_Selected) + pc = opt->palette.highlightedText().color(); + else + pc = opt->palette.text().color(); + QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(static_cast<CGFloat>(pc.redF()), + static_cast<CGFloat>(pc.greenF()), + static_cast<CGFloat>(pc.blueF()), + static_cast<CGFloat>(pc.alphaF())); + // kCTFontUIFontSystem and others give the same result + // as kCTFontUIFontMenuItemMark. However, the latter is + // more reminiscent to HITheme's kThemeMenuItemMarkFont. + // See also the font for small- and mini-sized widgets, + // where we end up using the generic system font type. + const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem : + (opt->state & State_Small) ? kCTFontUIFontSmallSystem : + kCTFontUIFontMenuItemMark; + // Similarly for the font size, where there is a small difference + // between regular combobox and item view items, and and menu items. + // However, we ignore any difference for small- and mini-sized widgets. + const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0; + QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL); + + CGContextSaveGState(cg); + CGContextSetShouldSmoothFonts(cg, NO); // Same as HITheme and Cocoa menu checkmarks + + // Baseline alignment tweaks for QComboBox and QMenu + const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 : + (opt->state & State_Small) ? 1.0 : + 0.75; + + CGContextTranslateCTM(cg, 0, opt->rect.bottom()); + CGContextScaleCTM(cg, 1, -1); + // Translate back to the original position and add rect origin and offset + CGContextTranslateCTM(cg, opt->rect.x(), vOffset); + + // CTFont has severe difficulties finding the checkmark character among its + // glyphs. Fortunately, CTLine knows its ways inside the Cocoa labyrinth. + static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName }; + static const int numValues = sizeof(keys) / sizeof(keys[0]); + const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor }; + Q_STATIC_ASSERT((sizeof(values) / sizeof(values[0])) == numValues); + QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, + numValues, NULL, NULL); + // U+2713: CHECK MARK + QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"\u2713", attributes); + QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString); + + CTLineDraw((CTLineRef)line, cg); + CGContextFlush(cg); // CTLineDraw's documentation says it doesn't flush + + CGContextRestoreGState(cg); break; } case PE_IndicatorViewItemCheck: case PE_IndicatorRadioButton: @@ -4412,61 +4440,27 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter p->setPen(mi->palette.buttonText().color()); if (mi->checked) { - // Use the HIThemeTextInfo foo to draw the check mark correctly, if we do it, - // we somehow need to use a special encoding as it doesn't look right with our - // drawText(). - p->save(); - CGContextSetShouldAntialias(cg, true); - CGContextSetShouldSmoothFonts(cg, true); - QColor textColor = p->pen().color(); - CGFloat colorComp[] = { static_cast<CGFloat>(textColor.redF()), static_cast<CGFloat>(textColor.greenF()), - static_cast<CGFloat>(textColor.blueF()), static_cast<CGFloat>(textColor.alphaF()) }; - CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace()); - CGContextSetFillColor(cg, colorComp); - HIThemeTextInfo tti; - tti.version = qt_mac_hitheme_version; - tti.state = tds; - if (active && enabled) - tti.state = kThemeStatePressed; - switch (widgetSize) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - tti.fontID = kThemeMenuItemMarkFont; - break; - case QAquaSizeSmall: - tti.fontID = kThemeSmallSystemFont; - break; - case QAquaSizeMini: - tti.fontID = kThemeMiniSystemFont; - break; - } - tti.horizontalFlushness = kHIThemeTextHorizontalFlushLeft; - tti.verticalFlushness = kHIThemeTextVerticalFlushCenter; - tti.options = kHIThemeTextBoxOptionNone; - tti.truncationPosition = kHIThemeTextTruncationNone; - tti.truncationMaxLines = 1; - QCFString checkmark; -#if 0 - if (mi->checkType == QStyleOptionMenuItem::Exclusive) - checkmark = QString(QChar(kDiamondUnicode)); - else -#endif - checkmark = QString(QChar(kCheckUnicode)); - int mw = checkcol + macItemFrame; - int mh = contentRect.height() - 2 * macItemFrame; - int xp = contentRect.x(); - xp += macItemFrame; - CGFloat outWidth, outHeight, outBaseline; - HIThemeGetTextDimensions(checkmark, 0, &tti, &outWidth, &outHeight, - &outBaseline); + QStyleOption checkmarkOpt; + checkmarkOpt.initFrom(w); + + const int mw = checkcol + macItemFrame; + const int mh = contentRect.height() + macItemFrame; + const int xp = contentRect.x() + macItemFrame; + checkmarkOpt.rect = QRect(xp, contentRect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh); + + checkmarkOpt.state |= State_On; // Always on. Never rendered when off. + checkmarkOpt.state.setFlag(State_Selected, active); + checkmarkOpt.state.setFlag(State_Enabled, enabled); if (widgetSize == QAquaSizeMini) - outBaseline += 1; - QRect r(xp, contentRect.y(), mw, mh); - r.translate(0, p->fontMetrics().ascent() - int(outBaseline) + 1); - HIRect bounds = qt_hirectForQRect(r); - HIThemeDrawTextBox(checkmark, &bounds, &tti, - cg, kHIThemeOrientationNormal); - p->restore(); + checkmarkOpt.state |= State_Mini; + else if (widgetSize == QAquaSizeSmall) + checkmarkOpt.state |= State_Small; + + // We let drawPrimitive(PE_IndicatorMenuCheckMark) pick the right color + checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color()); + checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color()); + + proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p, w); } if (!mi->icon.isNull()) { QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal |