Fix CategoryListWidget icons

- Correct colouring of selected icon
- Better selection rectangle correction
This commit is contained in:
Janek Bevendorff 2020-03-18 15:59:05 +01:00
parent 7168bcdbe5
commit 2f12294639
2 changed files with 55 additions and 24 deletions

View File

@ -21,6 +21,7 @@
#include <QBitmap> #include <QBitmap>
#include <QDir> #include <QDir>
#include <QLibrary> #include <QLibrary>
#include <QPainter>
#include <QStyle> #include <QStyle>
#include "config-keepassx.h" #include "config-keepassx.h"
@ -124,23 +125,24 @@ QIcon Resources::icon(const QString& name, bool recolor)
icon = QIcon::fromTheme(name); icon = QIcon::fromTheme(name);
if (getMainWindow() && recolor) { if (getMainWindow() && recolor) {
QPixmap pixmap = icon.pixmap(128, 128); QImage img = icon.pixmap(128, 128).toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
icon = {}; icon = {};
QPalette palette = getMainWindow()->palette(); QPalette palette = getMainWindow()->palette();
QPainter painter(&img);
painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
auto mask = QBitmap::fromImage(pixmap.toImage().createAlphaMask()); painter.fillRect(0, 0, img.width(), img.height(), palette.color(QPalette::Normal, QPalette::WindowText));
pixmap.fill(palette.color(QPalette::WindowText)); icon.addPixmap(QPixmap::fromImage(img), QIcon::Normal);
pixmap.setMask(mask);
icon.addPixmap(pixmap, QIcon::Mode::Normal);
pixmap.fill(palette.color(QPalette::HighlightedText)); painter.fillRect(0, 0, img.width(), img.height(), palette.color(QPalette::Active, QPalette::ButtonText));
pixmap.setMask(mask); icon.addPixmap(QPixmap::fromImage(img), QIcon::Active);
icon.addPixmap(pixmap, QIcon::Mode::Selected);
pixmap.fill(palette.color(QPalette::Disabled, QPalette::WindowText)); painter.fillRect(0, 0, img.width(), img.height(), palette.color(QPalette::Active, QPalette::HighlightedText));
pixmap.setMask(mask); icon.addPixmap(QPixmap::fromImage(img), QIcon::Selected);
icon.addPixmap(pixmap, QIcon::Mode::Disabled);
painter.fillRect(0, 0, img.width(), img.height(), palette.color(QPalette::Disabled, QPalette::WindowText));
icon.addPixmap(QPixmap::fromImage(img), QIcon::Disabled);
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
icon.setIsMask(true); icon.setIsMask(true);

View File

@ -168,22 +168,43 @@ public:
const QWidget* widget) const override const QWidget* widget) const override
{ {
painter->save(); painter->save();
if (widget && PE_PanelItemViewItem == element) {
if (PE_PanelItemViewItem == element) {
// Qt on Windows and the Fusion/Phantom base styles draw selection backgrounds only for // Qt on Windows and the Fusion/Phantom base styles draw selection backgrounds only for
// the actual text/icon bounding box, not over the full width of a list item. // the actual text/icon bounding box, not over the full width of a list item.
// We therefore need to translate and stretch the painter before we can // State_On is relevant only for the Windows hack below.
// tell Qt to draw its native styles. if (option->state & State_HasFocus || option->state & State_On) {
// Since we are scaling horizontally, we also need to move the right and left painter->fillRect(option->rect, widget->palette().color(QPalette::Active, QPalette::Highlight));
// edge pixels outside the drawing area to avoid thick border lines. } else if (option->state & State_Selected) {
QRect itemRect = subElementRect(QStyle::SE_ItemViewItemFocusRect, option, widget).adjusted(1, 0, 1, 0); painter->fillRect(option->rect, widget->palette().color(QPalette::Inactive, QPalette::Highlight));
painter->scale(static_cast<float>(option->rect.width()) / itemRect.width(), 1.0); }
painter->translate(option->rect.left() - itemRect.left() + 1, 0); } else if (PE_FrameFocusRect == element) {
// don't draw the native focus rect
} else {
QProxyStyle::drawPrimitive(element, option, painter, widget);
} }
QProxyStyle::drawPrimitive(element, option, painter, widget);
painter->restore(); painter->restore();
} }
#ifdef Q_OS_WIN
void drawControl(ControlElement element,
const QStyleOption* option,
QPainter* painter,
const QWidget* widget) const override
{
// Qt on Windows swallows State_HasFocus somewhere in its intestines,
// so we abuse State_On here to indicate the selection focus and
// hack into the text colour palette. Forgive me.
if (QStyle::CE_ItemViewItem == element && option->state & State_HasFocus) {
QStyleOptionViewItem newOpt(*qstyleoption_cast<const QStyleOptionViewItem*>(option));
newOpt.state |= State_On;
newOpt.palette.setColor(QPalette::All, QPalette::Text, widget->palette().color(QPalette::HighlightedText));
QProxyStyle::drawControl(element, &newOpt, painter, widget);
return;
}
QProxyStyle::drawControl(element, option, painter, widget);
}
#endif
}; };
void CategoryListWidgetDelegate::paint(QPainter* painter, void CategoryListWidgetDelegate::paint(QPainter* painter,
@ -209,7 +230,16 @@ void CategoryListWidgetDelegate::paint(QPainter* painter,
int paddingTop = fontRect.height() < 30 ? 15 : 10; int paddingTop = fontRect.height() < 30 ? 15 : 10;
int left = opt.rect.left() + opt.rect.width() / 2 - iconSize.width() / 2; int left = opt.rect.left() + opt.rect.width() / 2 - iconSize.width() / 2;
painter->drawPixmap(left, opt.rect.top() + paddingTop, icon.pixmap(iconSize));
auto mode = QIcon::Normal;
if ((opt.state & QStyle::State_Enabled) == 0) {
mode = QIcon::Disabled;
} else if (opt.state & QStyle::State_HasFocus) {
mode = QIcon::Selected;
} else if (opt.state & QStyle::State_Active) {
mode = QIcon::Active;
}
painter->drawPixmap(left, opt.rect.top() + paddingTop, icon.pixmap(iconSize, mode));
painter->restore(); painter->restore();
} }
@ -231,7 +261,6 @@ int CategoryListWidgetDelegate::minWidth() const
// add some padding // add some padding
maxWidth += 10; maxWidth += 10;
return maxWidth < m_size.height() ? m_size.height() : maxWidth; return maxWidth < m_size.height() ? m_size.height() : maxWidth;
} }
@ -245,5 +274,5 @@ QSize CategoryListWidgetDelegate::sizeHint(const QStyleOptionViewItem& option, c
w = m_listWidget->width(); w = m_listWidget->width();
} }
return QSize(w, m_size.height()); return {w, m_size.height()};
} }