From e94642a9b0806f2e5dfd9a2f8c76ce5b420c3424 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 25 Aug 2014 19:07:11 +0200 Subject: QMacStyle: Fix push buttons focus ring on Yosemite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HITheme renders the focus ring in a way that diminishes contrast on the focused button edges. The same issue seems to affect combo boxes, check boxes, and radio buttons. We refactor the code that was used to draw CE_FocusFrame into qt_drawFocusRingOnPath(). We use it to render our own path for the push button contour. This should also allow us to implement the focus ring animation in the future. As a side note, notice how the square button part (kThemeBevelButton) is a complete joke. Not only we impose the wrong button kind and let HITheme do what it can with it, but we also prevent ourselves from using it by never adding padding for the focus ring. Hopefully, we can fix this whole button sizing and padding mess in 5.5 or 6.0, whatever breaks less apps around. Task-number: QTBUG-40833 Change-Id: Ib9e7829d99b38dc926c55b31c3d6d5d32b691867 Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qmacstyle_mac.mm | 58 +++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 9 deletions(-) (limited to 'src/widgets/styles') diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 277ad47090..0845a5eb02 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1098,6 +1098,19 @@ static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSiz } #endif +static void qt_drawFocusRingOnPath(CGContextRef cg, NSBezierPath *focusRingPath) +{ + CGContextSaveGState(cg); + [NSGraphicsContext setCurrentContext:[NSGraphicsContext + graphicsContextWithGraphicsPort:(CGContextRef)cg flipped:NO]]; + [NSGraphicsContext saveGraphicsState]; + NSSetFocusRingStyle(NSFocusRingOnly); + [focusRingPath setClip]; // Clear clip path to avoid artifacts when rendering the cursor at zero pos + [focusRingPath fill]; + [NSGraphicsContext restoreGraphicsState]; + CGContextRestoreGState(cg); +} + QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg, QStyle::ContentsType ct, QSize szHint, QSize *insz) const { @@ -3573,6 +3586,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter d->initHIThemePushButton(btn, w, tds, &bdi); if (yosemiteOrLater) { + // HITheme is not drawing a nice focus frame around buttons. + // We'll do it ourselves further down. + bdi.adornment &= ~kThemeAdornmentFocus; + // We can't rely on an animation existing to test for the default look. That means a bit // more logic (notice that the logic is slightly different for the bevel and the label). if (tds == kThemeStateActive @@ -3625,6 +3642,37 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter else HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0); + if (yosemiteOrLater && btn->state & State_HasFocus) { + CGRect focusRect = newRect; + if (bdi.kind == kThemePushButton) + focusRect.size.height += 1; // Another thing HITheme and Cocoa seem to disagree about. + else if (bdi.kind == kThemePushButtonMini) + focusRect.size.height = 15; // Our QPushButton sizes are really weird + + if (bdi.adornment & kThemeAdornmentDefault || bdi.state == kThemeStatePressed) { + if (bdi.kind == kThemePushButtonSmall) { + focusRect = CGRectInset(focusRect, -1, 0); + } else if (bdi.kind == kThemePushButtonMini) { + focusRect = CGRectInset(focusRect, 1, 0); + } + } else { + if (bdi.kind == kThemePushButton) { + focusRect = CGRectInset(focusRect, 1, 1); + } else if (bdi.kind == kThemePushButtonSmall) { + focusRect = CGRectInset(focusRect, 0, 2); + } else if (bdi.kind == kThemePushButtonMini) { + focusRect = CGRectInset(focusRect, 2, 1); + } + } + + NSBezierPath *pushButtonFocusRingPath; + if (bdi.kind == kThemeBevelButton) + pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:focusRect]; + else + pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:focusRect xRadius:4 yRadius:4]; + qt_drawFocusRingOnPath(cg, pushButtonFocusRingPath); + } + if (hasMenu) { int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w); QRect ir = btn->rect; @@ -4089,16 +4137,8 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter int yOff = proxy()->pixelMetric(PM_FocusFrameVMargin, opt, w); NSRect rect = NSMakeRect(xOff+opt->rect.x(), yOff+opt->rect.y(), opt->rect.width() - 2 * xOff, opt->rect.height() - 2 * yOff); - CGContextSaveGState(cg); - [NSGraphicsContext setCurrentContext:[NSGraphicsContext - graphicsContextWithGraphicsPort:(CGContextRef)cg flipped:NO]]; - [NSGraphicsContext saveGraphicsState]; - NSSetFocusRingStyle(NSFocusRingOnly); NSBezierPath *focusFramePath = [NSBezierPath bezierPathWithRect:rect]; - [focusFramePath setClip]; // Clear clip path to avoid artifacts when rendering the cursor at zero pos - [focusFramePath fill]; - [NSGraphicsContext restoreGraphicsState]; - CGContextRestoreGState(cg); + qt_drawFocusRingOnPath(cg, focusFramePath); break; } case CE_MenuItem: case CE_MenuEmptyArea: -- cgit v1.2.3