From 7e1cabf49c03c1e0c2926dcfcf82adedbf98940e Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Fri, 14 Aug 2026 12:49:37 +0200 Subject: 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. --- src/tagstrip.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) (limited to 'src/tagstrip.cpp') 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 #include #include @@ -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()) { -- cgit v1.2.3 From 811bea0640dbfd27ca2c47b0288716ca608e5abb Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Fri, 14 Aug 2026 12:50:42 +0200 Subject: refactor(tags): name what the overflow chip's x actually is The loop was assigning a variable it never read, overwritten on every pass and used only after, which reads as an accumulator and is not one. The overflow chip's position is derived where it is used instead. --- src/tagstrip.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/tagstrip.cpp') diff --git a/src/tagstrip.cpp b/src/tagstrip.cpp index 7e671ce..565a054 100644 --- a/src/tagstrip.cpp +++ b/src/tagstrip.cpp @@ -163,17 +163,20 @@ void TagStrip::paintEvent(QPaintEvent *) const QFontMetrics metrics(font()); const int top = (height() - (metrics.height() + TagChip::kPaddingY * 2)) / 2; - int x = 0; 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, rect, tag, colour); - x = rect.right() + 1 + TagChip::kSpacing; + TagChip::paint(&painter, chipRectAt(i), tag, colour); } if (!m_hidden.isEmpty()) { + // After the last visible chip. right() is inclusive, so +1 makes it an + // exclusive edge before the gap is added. The overflow chip is not in + // m_visible and so has no chipRectAt() of its own. + const QRect last = chipRectAt(m_visible.size() - 1); + const int x = last.right() + 1 + TagChip::kSpacing; + const QString text = overflowText(m_hidden.size()); const QSize size = TagChip::sizeFor(metrics, text); TagChip::paint(&painter, QRect(QPoint(x, top), size), text, -- cgit v1.2.3