summaryrefslogtreecommitdiffstats
path: root/src/tagchip.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-03 15:42:40 +0200
committerDanilo M. <danix@danix.xyz>2026-08-03 15:42:40 +0200
commiteb35acda4207392c10b4b1192b3b057bcad99a47 (patch)
treec962e91fc502ec57d92df386e773033fe42fd17b /src/tagchip.cpp
parentafd20c9527fa77ba60901707c7bc73b2af926a67 (diff)
parentf62ced3c2c85675e746bff7ef8aca5c75c9737e0 (diff)
downloadqtmaildir-eb35acda4207392c10b4b1192b3b057bcad99a47.tar.gz
qtmaildir-eb35acda4207392c10b4b1192b3b057bcad99a47.zip
Merge branch 'feature/qaction-menus'
Menus, a toolbar and a generated shortcut reference, built on converting the action registry from a hash of callbacks to QActions. Along the way: three default key bindings that had never fired, a shortcut dialog taller than the screen, thread list columns that could not be resized, no visible feedback that a tag action had landed, and a tags column so wide it was unreadable. Backlog items 3, 8, 9, 13 and 14 done; 11 partly.
Diffstat (limited to 'src/tagchip.cpp')
-rw-r--r--src/tagchip.cpp126
1 files changed, 126 insertions, 0 deletions
diff --git a/src/tagchip.cpp b/src/tagchip.cpp
new file mode 100644
index 0000000..2e21419
--- /dev/null
+++ b/src/tagchip.cpp
@@ -0,0 +1,126 @@
+/*
+ * qtmaildir - a Qt6 mail client for notmuch-indexed Maildirs
+ * Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tagchip.h"
+
+#include <QApplication>
+#include <QFontMetrics>
+#include <QPainter>
+
+#include "tagcolors.h"
+#include "threadlistmodel.h"
+
+namespace TagChip {
+
+QSize sizeFor(const QFontMetrics &metrics, const QString &text)
+{
+ return QSize(metrics.horizontalAdvance(text) + kPaddingX * 2,
+ metrics.height() + kPaddingY * 2);
+}
+
+void paint(QPainter *painter, const QRect &rect, const QString &text,
+ const QColor &background)
+{
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(background);
+ painter->drawRoundedRect(rect, kRadius, kRadius);
+
+ painter->setPen(TagColors::textColourOn(background));
+ painter->drawText(rect, Qt::AlignCenter, text);
+ painter->restore();
+}
+
+} // namespace TagChip
+
+void SubjectDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ const QString account =
+ index.data(ThreadListModel::AccountLabelRole).toString();
+ if (account.isEmpty()) {
+ QStyledItemDelegate::paint(painter, option, index);
+ return;
+ }
+
+ // Draw the row's own background and selection first, then the chip and the
+ // subject on top, so a selected or struck-through row still looks right.
+ QStyleOptionViewItem chrome = option;
+ initStyleOption(&chrome, index);
+ chrome.text.clear();
+ const QWidget *widget = option.widget;
+ QStyle *style = widget ? widget->style() : QApplication::style();
+ style->drawControl(QStyle::CE_ItemViewItem, &chrome, painter, widget);
+
+ const QFontMetrics metrics(option.font);
+ const QSize chipSize = TagChip::sizeFor(metrics, account);
+ const QRect chipRect(option.rect.left() + TagChip::kSpacing,
+ option.rect.top()
+ + (option.rect.height() - chipSize.height()) / 2,
+ chipSize.width(), chipSize.height());
+
+ const QColor colour =
+ index.data(ThreadListModel::AccountColourRole).value<QColor>();
+ TagChip::paint(painter, chipRect, account,
+ colour.isValid() ? colour : QColor(0x55, 0x55, 0x5f));
+
+ // The subject follows the chip, elided so a long one cannot overflow.
+ QRect textRect = option.rect;
+ textRect.setLeft(chipRect.right() + TagChip::kSpacing * 2);
+ if (textRect.width() <= 0)
+ return;
+
+ painter->save();
+ // The model supplies the row's colours; honouring them keeps a deleted
+ // thread white-on-red here as everywhere else.
+ const QVariant foreground = index.data(Qt::ForegroundRole);
+ if (foreground.isValid())
+ painter->setPen(foreground.value<QBrush>().color());
+ else if (option.state & QStyle::State_Selected)
+ painter->setPen(option.palette.highlightedText().color());
+ else
+ painter->setPen(option.palette.text().color());
+
+ // The model's font carries bold for unread and strike-out for deleted.
+ // initStyleOption() already resolved it into chrome.font; using it rather
+ // than option.font is what keeps those cues on a delegate-drawn subject.
+ const QVariant fontData = index.data(Qt::FontRole);
+ const QFont rowFont = fontData.isValid() ? fontData.value<QFont>()
+ : chrome.font;
+ painter->setFont(rowFont);
+ const QFontMetrics rowMetrics(rowFont);
+ painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft,
+ rowMetrics.elidedText(index.data(Qt::DisplayRole).toString(),
+ Qt::ElideRight, textRect.width()));
+ painter->restore();
+}
+
+QSize SubjectDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QSize size = QStyledItemDelegate::sizeHint(option, index);
+ const QString account =
+ index.data(ThreadListModel::AccountLabelRole).toString();
+ if (!account.isEmpty()) {
+ const QFontMetrics metrics(option.font);
+ size.setWidth(size.width() + TagChip::sizeFor(metrics, account).width()
+ + TagChip::kSpacing * 3);
+ }
+ return size;
+}