aboutsummaryrefslogtreecommitdiffstats
path: root/src/tagstrip.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-14 12:49:37 +0200
committerDanilo M. <danix@danix.xyz>2026-08-14 12:49:37 +0200
commit7e1cabf49c03c1e0c2926dcfcf82adedbf98940e (patch)
tree624dd47cea8d1faa0db7cbf4d04fce6bef6bf906 /src/tagstrip.cpp
parent83f42ab460820e9fd1b96653e14c08b5d51a2166 (diff)
downloadqtmaildir-7e1cabf49c03c1e0c2926dcfcf82adedbf98940e.tar.gz
qtmaildir-7e1cabf49c03c1e0c2926dcfcf82adedbf98940e.zip
feat(tags): hit-test a chip in the tag strip
chipRectAt() is the single source of a chip's geometry, used by paintEvent and by the hit test, so the drawn chip and the clickable chip cannot drift. The +N chip yields nothing: it stands for a list of tags rather than one, so there is no single value a search could be built from.
Diffstat (limited to 'src/tagstrip.cpp')
-rw-r--r--src/tagstrip.cpp54
1 files changed, 50 insertions, 4 deletions
diff --git a/src/tagstrip.cpp b/src/tagstrip.cpp
index bad116a..7e671ce 100644
--- a/src/tagstrip.cpp
+++ b/src/tagstrip.cpp
@@ -18,6 +18,7 @@
#include "tagstrip.h"
+#include <QContextMenuEvent>
#include <QFontMetrics>
#include <QPainter>
@@ -109,6 +110,50 @@ void TagStrip::resizeEvent(QResizeEvent *event)
relayout();
}
+QRect TagStrip::chipRectAt(int index) const
+{
+ if (index < 0 || index >= m_visible.size())
+ return {};
+
+ const QFontMetrics metrics(font());
+
+ // Reproduces paintEvent's own vertical placement exactly, which is derived
+ // from the font's height rather than from the chip's, so a chip whose text
+ // is shorter than the line still lands on the same baseline.
+ const int top = (height() - (metrics.height() + TagChip::kPaddingY * 2)) / 2;
+
+ int x = 0;
+ for (int i = 0; i < index; ++i)
+ x += TagChip::sizeFor(metrics, m_visible.at(i)).width() + TagChip::kSpacing;
+
+ return QRect(QPoint(x, top), TagChip::sizeFor(metrics, m_visible.at(index)));
+}
+
+QString TagStrip::chipAt(const QPoint &point) const
+{
+ for (int i = 0; i < m_visible.size(); ++i) {
+ if (chipRectAt(i).contains(point))
+ return m_visible.at(i);
+ }
+ // Deliberately nothing for the overflow chip and for empty space: the +N
+ // chip names a list, not a tag.
+ return {};
+}
+
+void TagStrip::contextMenuEvent(QContextMenuEvent *event)
+{
+ const QString tag = chipAt(event->pos());
+ if (tag.isEmpty()) {
+ // Ignored rather than accepted, so a parent that offers its own menu
+ // still gets the chance to show it.
+ event->ignore();
+ return;
+ }
+
+ event->accept();
+ emit tagContextMenuRequested(tag, event->globalPos());
+}
+
void TagStrip::paintEvent(QPaintEvent *)
{
if (m_visible.isEmpty())
@@ -119,12 +164,13 @@ void TagStrip::paintEvent(QPaintEvent *)
const int top = (height() - (metrics.height() + TagChip::kPaddingY * 2)) / 2;
int x = 0;
- for (const QString &tag : m_visible) {
- const QSize size = TagChip::sizeFor(metrics, tag);
+ for (int i = 0; i < m_visible.size(); ++i) {
+ const QString &tag = m_visible.at(i);
+ const QRect rect = chipRectAt(i);
const QColor colour = m_tagColors ? m_tagColors->colourFor(tag)
: TagColors().colourFor(tag);
- TagChip::paint(&painter, QRect(QPoint(x, top), size), tag, colour);
- x += size.width() + TagChip::kSpacing;
+ TagChip::paint(&painter, rect, tag, colour);
+ x = rect.right() + 1 + TagChip::kSpacing;
}
if (!m_hidden.isEmpty()) {