From d6068e031609c8e0aa69203116fc865afb7a2097 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 3 Feb 2023 19:46:15 +0530 Subject: [PATCH] Also draw the arrow dark when in dark theme with highlight --- .../gui2/progress_indicator/CalibreStyle.cpp | 85 +++++++++++++++++++ src/calibre/gui2/tag_browser/view.py | 1 + src/calibre/gui2/viewer/toc.py | 1 + 3 files changed, 87 insertions(+) diff --git a/src/calibre/gui2/progress_indicator/CalibreStyle.cpp b/src/calibre/gui2/progress_indicator/CalibreStyle.cpp index e7727c3622..b54c6de5b1 100644 --- a/src/calibre/gui2/progress_indicator/CalibreStyle.cpp +++ b/src/calibre/gui2/progress_indicator/CalibreStyle.cpp @@ -7,6 +7,7 @@ #include "QProgressIndicator.h" #include +#include #include #include #include @@ -61,6 +62,82 @@ static inline QByteArray detectDesktopEnvironment() return QByteArrayLiteral("UNKNOWN"); } +#ifdef Q_OS_DARWIN +static const qreal qstyleBaseDpi = 72; +#else +static const qreal qstyleBaseDpi = 96; +#endif + +qreal dpiScaled(qreal value, qreal dpi) +{ + return value * dpi / qstyleBaseDpi; +} + +static QPixmap styleCachePixmap(const QSize &size) +{ + const qreal pixelRatio = qApp->devicePixelRatio(); + QPixmap cachePixmap = QPixmap(size * pixelRatio); + cachePixmap.setDevicePixelRatio(pixelRatio); + return cachePixmap; +} + + +static void draw_arrow(Qt::ArrowType type, QPainter *painter, const QStyleOption *option, const QRect &rect, const QColor &color) +{ + if (rect.isEmpty()) + return; + + const qreal dpi = option->fontMetrics.fontDpi(); + const int arrowWidth = int(dpiScaled(14, dpi)); + const int arrowHeight = int(dpiScaled(8, dpi)); + + const int arrowMax = qMin(arrowHeight, arrowWidth); + const int rectMax = qMin(rect.height(), rect.width()); + const int size = qMin(arrowMax, rectMax); + + QPixmap cachePixmap; + QString cacheKey = QString("calibre-tree-view-arrow-%1-%2-%3").arg((unsigned long)color.rgba()).arg((unsigned long)type).arg(size); + 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); +} + CalibreStyle::CalibreStyle(int transient_scroller) : QProxyStyle(QString::fromUtf8("Fusion")), transient_scroller(transient_scroller) { setObjectName(QString("calibre")); @@ -212,6 +289,14 @@ void CalibreStyle::drawPrimitive(PrimitiveElement element, const QStyleOption * } break; // }}} + case PE_IndicatorBranch: // {{{ + if (option->state & State_MouseOver && option->state & State_Children && widget && widget->property("hovered_item_is_highlighted").toBool() && is_color_dark(option->palette.color(QPalette::Window))) {; + if (option->rect.width() <= 1 || option->rect.height() <= 1) return; + Qt::ArrowType arrow = Qt::ArrowType::DownArrow; + if (!(option->state & State_Open)) arrow = Qt::ArrowType::RightArrow; + draw_arrow(arrow, painter, option, option->rect, QColor(Qt::black)); + return; + } break; // }}} case PE_IndicatorToolBarSeparator: // {{{ // Make toolbar separators stand out a bit more in dark themes { diff --git a/src/calibre/gui2/tag_browser/view.py b/src/calibre/gui2/tag_browser/view.py index 9da187b594..2e0d22a4a0 100644 --- a/src/calibre/gui2/tag_browser/view.py +++ b/src/calibre/gui2/tag_browser/view.py @@ -241,6 +241,7 @@ class TagsView(QTreeView): # {{{ '''.replace('PAD', str(gprefs['tag_browser_item_padding'])) + ( '' if gprefs['tag_browser_old_look'] else stylish_tb) + QApplication.instance().palette_manager.tree_view_hover_style() ) + self.setProperty('hovered_item_is_highlighted', True) def set_look_and_feel(self, first=False): self.set_style_sheet() diff --git a/src/calibre/gui2/viewer/toc.py b/src/calibre/gui2/viewer/toc.py index 05c7373993..5eca6cc0c0 100644 --- a/src/calibre/gui2/viewer/toc.py +++ b/src/calibre/gui2/viewer/toc.py @@ -89,6 +89,7 @@ class TOCView(QTreeView): } ''' + QApplication.instance().palette_manager.tree_view_hover_style()) + self.setProperty('hovered_item_is_highlighted', True) def mouseMoveEvent(self, ev): if self.indexAt(ev.pos()).isValid():