Fusion: draw DPI-scaled arrows

Replace the "hard-coded" fusion_arrow.png with qt_fusion_draw_arrow()
that scales appropriately on high DPI screens.

Task-number: QTBUG-40277
Change-Id: I2c4a134de757a39d7744977bd41accff69810521
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
J-P Nurmi 2017-04-07 01:17:38 +02:00
parent edcc71be87
commit 63d08003cf
3 changed files with 87 additions and 138 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

View File

@ -190,55 +190,6 @@ static QColor mergedColors(const QColor &colorA, const QColor &colorB, int facto
return tmp;
}
static QPixmap colorizedImage(const QString &fileName, const QColor &color, int rotation = 0) {
QString pixmapName = QLatin1String("$qt_ia-") % fileName % HexString<uint>(color.rgba()) % QString::number(rotation);
QPixmap pixmap;
if (!QPixmapCache::find(pixmapName, pixmap)) {
QImage image(fileName);
if (image.format() != QImage::Format_ARGB32_Premultiplied)
image = image.convertToFormat( QImage::Format_ARGB32_Premultiplied);
int width = image.width();
int height = image.height();
int source = color.rgba();
unsigned char sourceRed = qRed(source);
unsigned char sourceGreen = qGreen(source);
unsigned char sourceBlue = qBlue(source);
for (int y = 0; y < height; ++y)
{
QRgb *data = (QRgb*) image.scanLine(y);
for (int x = 0 ; x < width ; x++) {
QRgb col = data[x];
unsigned int colorDiff = (qBlue(col) - qRed(col));
unsigned char gray = qGreen(col);
unsigned char red = gray + qt_div_255(sourceRed * colorDiff);
unsigned char green = gray + qt_div_255(sourceGreen * colorDiff);
unsigned char blue = gray + qt_div_255(sourceBlue * colorDiff);
unsigned char alpha = qt_div_255(qAlpha(col) * qAlpha(source));
data[x] = qRgba(std::min(alpha, red),
std::min(alpha, green),
std::min(alpha, blue),
alpha);
}
}
if (rotation != 0) {
QTransform transform;
transform.translate(-image.width()/2, -image.height()/2);
transform.rotate(rotation);
transform.translate(image.width()/2, image.height()/2);
image = image.transformed(transform);
}
pixmap = QPixmap::fromImage(image);
QPixmapCache::insert(pixmapName, pixmap);
}
return pixmap;
}
// The default button and handle gradient
static QLinearGradient qt_fusion_gradient(const QRect &rect, const QBrush &baseColor, Direction direction = TopDown)
{
@ -276,6 +227,59 @@ static QLinearGradient qt_fusion_gradient(const QRect &rect, const QBrush &baseC
return gradient;
}
static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QStyleOption *option, const QRect &rect, const QColor &color)
{
const int arrowWidth = QStyleHelper::dpiScaled(14);
const int arrowHeight = QStyleHelper::dpiScaled(8);
const int arrowMax = qMin(arrowHeight, arrowWidth);
const int rectMax = qMin(rect.height(), rect.width());
const int size = qMin(arrowMax, rectMax);
QPixmap cachePixmap;
QString cacheKey = QStyleHelper::uniqueName(QLatin1String("fusion-arrow"), option, rect.size())
% HexString<uint>(type)
% HexString<uint>(color.rgba());
if (!QPixmapCache::find(cacheKey, cachePixmap)) {
cachePixmap = styleCachePixmap(rect.size());
cachePixmap.fill(Qt::transparent);
QPainter cachePainter(&cachePixmap);
QRectF arrowRect;
arrowRect.setWidth(size);
arrowRect.setHeight(arrowHeight * size / arrowWidth);
if (type == Qt::LeftArrow || type == Qt::RightArrow)
arrowRect = arrowRect.transposed();
arrowRect.moveTo((rect.width() - arrowRect.width()) / 2.0,
(rect.height() - arrowRect.height()) / 2.0);
QPolygonF triangle;
triangle.reserve(3);
switch (type) {
case Qt::DownArrow:
triangle << arrowRect.topLeft() << arrowRect.topRight() << QPointF(arrowRect.center().x(), arrowRect.bottom());
break;
case Qt::RightArrow:
triangle << arrowRect.topLeft() << arrowRect.bottomLeft() << QPointF(arrowRect.right(), arrowRect.center().y());
break;
case Qt::LeftArrow:
triangle << arrowRect.topRight() << arrowRect.bottomRight() << QPointF(arrowRect.left(), arrowRect.center().y());
break;
default:
triangle << arrowRect.bottomLeft() << arrowRect.bottomRight() << QPointF(arrowRect.center().x(), arrowRect.top());
break;
}
cachePainter.setPen(Qt::NoPen);
cachePainter.setBrush(color);
cachePainter.setRenderHint(QPainter::Antialiasing);
cachePainter.drawPolygon(triangle);
QPixmapCache::insert(cacheKey, cachePixmap);
}
painter->drawPixmap(rect, cachePixmap);
}
static void qt_fusion_draw_mdibutton(QPainter *painter, const QStyleOptionTitleBar *option, const QRect &tmp, bool hover, bool sunken)
{
@ -513,43 +517,22 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
if (option->rect.width() <= 1 || option->rect.height() <= 1)
break;
QColor arrowColor = option->palette.foreground().color();
QPixmap arrow;
int rotation = 0;
arrowColor.setAlpha(160);
Qt::ArrowType arrow = Qt::UpArrow;
switch (elem) {
case PE_IndicatorArrowDown:
rotation = 180;
arrow = Qt::DownArrow;
break;
case PE_IndicatorArrowRight:
rotation = 90;
arrow = Qt::RightArrow;
break;
case PE_IndicatorArrowLeft:
rotation = -90;
arrow = Qt::LeftArrow;
break;
default:
break;
}
arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, rotation);
if (arrow.isNull())
break;
QRect rect = option->rect;
QRect arrowRect;
int imageMax = qMin(arrow.height(), arrow.width());
int rectMax = qMin(rect.height(), rect.width());
int size = qMin(imageMax, rectMax);
arrowRect.setWidth(size);
arrowRect.setHeight(size);
if (arrow.width() > arrow.height())
arrowRect.setHeight(arrow.height() * size / arrow.width());
else
arrowRect.setWidth(arrow.width() * size / arrow.height());
arrowRect.moveTopLeft(rect.center() - arrowRect.center());
painter->save();
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->drawPixmap(arrowRect, arrow);
painter->restore();
qt_fusion_draw_arrow(arrow, painter, option, option->rect, arrowColor);
}
break;
case PE_IndicatorViewItemCheck:
@ -563,29 +546,23 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
case PE_IndicatorHeaderArrow:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
QRect r = header->rect;
QPixmap arrow;
QColor arrowColor = header->palette.foreground().color();
QPoint offset = QPoint(0, -1);
arrowColor.setAlpha(180);
QPoint offset = QPoint(0, -2);
#if defined(Q_OS_LINUX)
if (header->sortIndicator & QStyleOptionHeader::SortUp) {
arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor);
qt_fusion_draw_arrow(Qt::UpArrow, painter, option, r.translated(offset), arrowColor);
} else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, 180);
qt_fusion_draw_arrow(Qt::DownArrow, painter, option, r.translated(offset), arrowColor);
}
#else
if (header->sortIndicator & QStyleOptionHeader::SortUp) {
arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, 180);
qt_fusion_draw_arrow(Qt::DownArrow, painter, option, r.translated(offset), arrowColor);
} else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor);
qt_fusion_draw_arrow(Qt::UpArrow, painter, option, r.translated(offset), arrowColor);
}
#endif
if (!arrow.isNull()) {
r.setSize(QSize(arrow.width()/2, arrow.height()/2));
r.moveCenter(header->rect.center());
painter->drawPixmap(r.translated(offset), arrow);
}
}
break;
case PE_IndicatorButtonDropDown:
@ -2039,7 +2016,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
QRect r = rect.adjusted(0, 1, 0, -1);
QPainter cachePainter(&cache);
QColor arrowColor = spinBox->palette.foreground().color();
arrowColor.setAlpha(220);
arrowColor.setAlpha(160);
bool isEnabled = (spinBox->state & State_Enabled);
bool hover = isEnabled && (spinBox->state & State_MouseOver);
@ -2150,23 +2127,10 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
} else if (spinBox->buttonSymbols == QAbstractSpinBox::UpDownArrows){
// arrows
painter->setRenderHint(QPainter::SmoothPixmapTransform);
QPixmap upArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"),
(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) ? arrowColor : disabledColor);
QRectF upArrowRect = QRectF(upRect.center().x() - upArrow.width() / 4.0 + 1.0,
upRect.center().y() - upArrow.height() / 4.0 + 1.0,
upArrow.width() / 2.0, upArrow.height() / 2.0);
cachePainter.drawPixmap(upArrowRect, upArrow, QRectF(QPointF(0.0, 0.0), upArrow.size()));
QPixmap downArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"),
(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) ? arrowColor : disabledColor, 180);
QRectF downArrowRect = QRectF(downRect.center().x() - downArrow.width() / 4.0 + 1.0,
downRect.center().y() - downArrow.height() / 4.0 + 1.0,
downArrow.width() / 2.0, downArrow.height() / 2.0);
cachePainter.drawPixmap(downArrowRect, downArrow, QRectF(QPointF(0.0, 0.0), downArrow.size()));
qt_fusion_draw_arrow(Qt::UpArrow, &cachePainter, option, upRect.adjusted(0, 0, 0, 1),
(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) ? arrowColor : disabledColor);
qt_fusion_draw_arrow(Qt::DownArrow, &cachePainter, option, downRect,
(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) ? arrowColor : disabledColor);
}
cachePainter.end();
@ -2403,8 +2367,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
bool hover = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_MouseOver);
bool sunken = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_Sunken);
qt_fusion_draw_mdibutton(painter, titleBar, shadeButtonRect, hover, sunken);
QPixmap arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), textColor);
painter->drawPixmap(shadeButtonRect.adjusted(5, 7, -5, -7), arrow);
qt_fusion_draw_arrow(Qt::UpArrow, painter, option, shadeButtonRect.adjusted(5, 7, -5, -7), textColor);
}
}
@ -2415,8 +2378,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
bool hover = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_MouseOver);
bool sunken = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_Sunken);
qt_fusion_draw_mdibutton(painter, titleBar, unshadeButtonRect, hover, sunken);
QPixmap arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), textColor, 180);
painter->drawPixmap(unshadeButtonRect.adjusted(5, 7, -5, -7), arrow);
qt_fusion_draw_arrow(Qt::DownArrow, painter, option, unshadeButtonRect.adjusted(5, 7, -5, -7), textColor);
}
}
@ -2544,7 +2506,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
alphaOutline.setAlpha(180);
QColor arrowColor = option->palette.foreground().color();
arrowColor.setAlpha(220);
arrowColor.setAlpha(160);
const QColor bgColor = QStyleHelper::backgroundColor(option->palette, widget);
const bool isDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
@ -2688,20 +2650,16 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
painter->drawLine(pixmapRect.bottomLeft(), pixmapRect.bottomRight());
}
QRect upRect = scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, horizontal ? -2 : -1, horizontal ? -1 : -2);
painter->setBrush(Qt::NoBrush);
painter->setPen(d->innerContrastLine());
painter->drawRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0 , horizontal ? -2 : -1, horizontal ? -1 : -2));
painter->drawRect(upRect);
// Arrows
int rotation = 0;
Qt::ArrowType arrowType = Qt::UpArrow;
if (option->state & State_Horizontal)
rotation = option->direction == Qt::LeftToRight ? -90 : 90;
QRect upRect = scrollBarSubLine.translated(horizontal ? -2 : -1, 0);
QPixmap arrowPixmap = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, rotation);
painter->drawPixmap(QRectF(upRect.center().x() - arrowPixmap.width() / 4.0 + 2.0,
upRect.center().y() - arrowPixmap.height() / 4.0 + 1.0,
arrowPixmap.width() / 2.0, arrowPixmap.height() / 2.0),
arrowPixmap, QRectF(QPoint(0.0, 0.0), arrowPixmap.size()));
arrowType = option->direction == Qt::LeftToRight ? Qt::LeftArrow : Qt::RightArrow;
qt_fusion_draw_arrow(arrowType, painter, option, upRect, arrowColor);
}
// The AddLine (down/right) button
@ -2729,19 +2687,15 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
painter->drawLine(pixmapRect.topLeft(), pixmapRect.topRight());
}
QRect downRect = scrollBarAddLine.adjusted(1, 1, -1, -1);
painter->setPen(d->innerContrastLine());
painter->setBrush(Qt::NoBrush);
painter->drawRect(scrollBarAddLine.adjusted(1, 1, -1, -1));
painter->drawRect(downRect);
int rotation = 180;
Qt::ArrowType arrowType = Qt::DownArrow;
if (option->state & State_Horizontal)
rotation = option->direction == Qt::LeftToRight ? 90 : -90;
QRect downRect = scrollBarAddLine.translated(-1, 1);
QPixmap arrowPixmap = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, rotation);
painter->drawPixmap(QRectF(downRect.center().x() - arrowPixmap.width() / 4.0 + 2.0,
downRect.center().y() - arrowPixmap.height() / 4.0,
arrowPixmap.width() / 2.0, arrowPixmap.height() / 2.0),
arrowPixmap, QRectF(QPoint(0.0, 0.0), arrowPixmap.size()));
arrowType = option->direction == Qt::LeftToRight ? Qt::RightArrow : Qt::LeftArrow;
qt_fusion_draw_arrow(arrowType, painter, option, downRect, arrowColor);
}
}
@ -2831,12 +2785,8 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
if (comboBox->subControls & SC_ComboBoxArrow) {
// Draw the up/down arrow
QColor arrowColor = option->palette.buttonText().color();
arrowColor.setAlpha(220);
QPixmap downArrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, 180);
cachePainter.drawPixmap(QRectF(downArrowRect.center().x() - downArrow.width() / 4.0 + 1.0,
downArrowRect.center().y() - downArrow.height() / 4.0 + 1.0,
downArrow.width() / 2.0, downArrow.height() / 2.0),
downArrow, QRectF(QPointF(0.0, 0.0), downArrow.size()));
arrowColor.setAlpha(160);
qt_fusion_draw_arrow(Qt::DownArrow, &cachePainter, option, downArrowRect, arrowColor);
}
cachePainter.end();
QPixmapCache::insert(pixmapName, cache);
@ -3528,8 +3478,8 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom
switch (subControl) {
case SC_ComboBoxArrow:
rect = visualRect(option->direction, option->rect, rect);
rect.setRect(rect.right() - 18, rect.top() - 2,
19, rect.height() + 4);
rect.setRect(rect.right() - QStyleHelper::dpiScaled(18), rect.top() - 2,
QStyleHelper::dpiScaled(19), rect.height() + 4);
rect = visualRect(option->direction, option->rect, rect);
break;
case SC_ComboBoxEditField: {

View File

@ -128,7 +128,6 @@
<file>images/media-volume-16.png</file>
<file>images/media-volume-muted-16.png</file>
<file>images/fusion_groupbox.png</file>
<file>images/fusion_arrow.png</file>
</qresource>
<qresource prefix="/qt-project.org/styles/macstyle">
<file>images/closedock-16.png</file>