mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-13 05:20:00 -08:00
The Home tab buttons draw their label as a QPainterPath: a black stroke, then a white fill. Upstream #7539 (2026-11-04) moved the label from the stylesheet's sans-serif/Helvetica Neue to the theme's InterfaceDefault font, which on macOS is the system font, SF Pro. Its glyph outlines have overlapping contours, and QPainterPath fills with Qt::OddEvenFill by default, so every overlap stayed unfilled and showed the black stroke underneath as dark notches inside the letters. The same symptom was upstream issue 6490, fixed in January for the old font. Qt::WindingFill fills overlapping contours. Checked on macOS with Homebrew Qt 6.12: the notches are gone.
126 lines
4.5 KiB
C++
126 lines
4.5 KiB
C++
#include "home_styled_button.h"
|
|
|
|
#include "../../theme_manager.h"
|
|
|
|
#include <QBrush>
|
|
#include <QFont>
|
|
#include <QFontMetrics>
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QPen>
|
|
#include <QPointF>
|
|
#include <QSize>
|
|
#include <QSizePolicy>
|
|
#include <QStyle>
|
|
#include <QStyleOptionButton>
|
|
#include <QtGlobal>
|
|
#include <qnamespace.h>
|
|
|
|
class QWidget;
|
|
|
|
HomeStyledButton::HomeStyledButton(const QString &text, QPair<QColor, QColor> _gradientColors, QWidget *parent)
|
|
: QPushButton(text, parent), gradientColors(_gradientColors)
|
|
{
|
|
// Keep the font/style-derived height even when the home page has ample space.
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
setStyleSheet(generateButtonStylesheet(gradientColors));
|
|
applyInterfaceDefaultFont();
|
|
connect(themeManager, &ThemeManager::fontsChanged, this, &HomeStyledButton::applyInterfaceDefaultFont);
|
|
}
|
|
|
|
void HomeStyledButton::applyInterfaceDefaultFont()
|
|
{
|
|
// Family comes from the InterfaceDefault theme role; the 34px size and
|
|
// bold weight previously carried by the stylesheet stay caller-side.
|
|
QFont buttonFont = themeManager->appFont(AppFont::InterfaceDefault);
|
|
buttonFont.setPixelSize(34);
|
|
buttonFont.setWeight(QFont::Bold);
|
|
setFont(buttonFont);
|
|
}
|
|
|
|
void HomeStyledButton::updateStylesheet(const QPair<QColor, QColor> &colors)
|
|
{
|
|
gradientColors = colors;
|
|
setStyleSheet(generateButtonStylesheet(gradientColors));
|
|
}
|
|
|
|
QString HomeStyledButton::generateButtonStylesheet(const QPair<QColor, QColor> &colors)
|
|
{
|
|
QColor baseGradientStart = colors.first;
|
|
QColor baseGradientEnd = colors.second;
|
|
|
|
QColor hoverGradientStart = baseGradientStart.lighter(120); // 20% lighter
|
|
QColor hoverGradientEnd = baseGradientEnd.lighter(120);
|
|
|
|
QColor pressedGradientStart = baseGradientStart.darker(130); // 30% darker
|
|
QColor pressedGradientEnd = baseGradientEnd.darker(130);
|
|
|
|
// Disabled: more gray, less saturated
|
|
QColor disabledGradientStart = baseGradientStart.toHsv();
|
|
disabledGradientStart.setHsv(disabledGradientStart.hue(), disabledGradientStart.saturation() * 0.2,
|
|
disabledGradientStart.value() * 0.6);
|
|
QColor disabledGradientEnd = baseGradientEnd.toHsv();
|
|
disabledGradientEnd.setHsv(disabledGradientEnd.hue(), disabledGradientEnd.saturation() * 0.2,
|
|
disabledGradientEnd.value() * 0.6);
|
|
|
|
return QString(R"(
|
|
QPushButton {
|
|
padding: 30px;
|
|
color: white;
|
|
border: 2px solid %1;
|
|
border-radius: 20px;
|
|
background: qlineargradient(x1:0, y1:1, x2:0, y2:0,
|
|
stop:0 %2, stop:1 %3);
|
|
}
|
|
QPushButton:hover {
|
|
background: qlineargradient(x1:0, y1:1, x2:0, y2:0,
|
|
stop:0 %4, stop:1 %5);
|
|
}
|
|
QPushButton:pressed {
|
|
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
|
stop:0 %6, stop:1 %7);
|
|
}
|
|
QPushButton:disabled {
|
|
color: #aaaaaa;
|
|
border: 2px solid #888888;
|
|
background: qlineargradient(x1:0, y1:1, x2:0, y2:0,
|
|
stop:0 %8, stop:1 %9);
|
|
}
|
|
)")
|
|
.arg(baseGradientStart.name())
|
|
.arg(baseGradientStart.name())
|
|
.arg(baseGradientEnd.name())
|
|
.arg(hoverGradientStart.name())
|
|
.arg(hoverGradientEnd.name())
|
|
.arg(pressedGradientStart.name())
|
|
.arg(pressedGradientEnd.name())
|
|
.arg(disabledGradientStart.name())
|
|
.arg(disabledGradientEnd.name());
|
|
}
|
|
|
|
void HomeStyledButton::paintEvent(QPaintEvent *event)
|
|
{
|
|
Q_UNUSED(event); // Event is just used for update clipping, we redraw the whole widget.
|
|
QStyleOptionButton opt;
|
|
initStyleOption(&opt);
|
|
opt.text.clear(); // prevent style from drawing text
|
|
|
|
QPainter painter(this);
|
|
style()->drawControl(QStyle::CE_PushButton, &opt, &painter, this);
|
|
|
|
// Draw white text with a black outline
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
painter.setRenderHint(QPainter::TextAntialiasing);
|
|
|
|
QFontMetrics fm(font());
|
|
QSize textSize = fm.size(Qt::TextSingleLine, text());
|
|
QPointF center((width() - textSize.width()) / 2.0, (height() + textSize.height() / 2.0) / 2.0);
|
|
|
|
QPainterPath path;
|
|
path.addText(center, font(), text());
|
|
path.setFillRule(Qt::WindingFill);
|
|
|
|
QPen pen(Qt::black, 4.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
|
|
painter.strokePath(path, pen);
|
|
painter.fillPath(path, Qt::white);
|
|
}
|