[network/ruqola] src/widgets/room/delegate: Fix layout

Laurent Montel <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 818c71118bc25d9977f8cd56ff91d4e1b42e4c5b by Laurent Montel.
Committed on 14/08/2026 at 17:39.
Pushed by mlaurent into branch 'master'.

Fix layout

M  +5    -3    src/widgets/room/delegate/messageattachmentdelegatehelperbase.cpp
M  +10   -3    src/widgets/room/delegate/messageattachmentdelegatehelperimage.cpp
M  +23   -11   src/widgets/room/delegate/messageattachmentdelegatehelpertext.cpp
M  +1    -0    src/widgets/room/delegate/messageattachmentdelegatehelpertext.h

https://invent.kde.org/network/ruqola/-/commit/818c71118bc25d9977f8cd56ff91d4e1b42e4c5b

diff --git a/src/widgets/room/delegate/messageattachmentdelegatehelperbase.cpp b/src/widgets/room/delegate/messageattachmentdelegatehelperbase.cpp
index 7789b13eeb..cccb391d1a 100644
--- a/src/widgets/room/delegate/messageattachmentdelegatehelperbase.cpp
+++ b/src/widgets/room/delegate/messageattachmentdelegatehelperbase.cpp
@@ -101,14 +101,16 @@ bool MessageAttachmentDelegateHelperBase::handleMouseEvent(const MessageAttachme
         mTextSelectionImpl->setMightStartDrag(false);
         mCurrentIndex = QModelIndex();
         if (const auto *doc = documentFromAttachment(msgAttach, attachmentsRect.width())) {
-            const QPoint pos = mouseEvent->pos();
-            const int charPos = charPosition(doc, msgAttach, attachmentsRect, pos, option);
+            // The document is laid out below the attachment header, so hit testing needs the adapted
+            // position, not the raw viewport one.
+            const QPoint relativePos = adaptMousePosition(mouseEvent->pos(), msgAttach, attachmentsRect, option);
+            const int charPos = doc->documentLayout()->hitTest(relativePos, Qt::FuzzyHit);
             qCDebug(RUQOLAWIDGETS_SELECTION_LOG) << "pressed at pos" << charPos;
             if (charPos == -1) {
                 return false;
             }
             // TODO fix mTextSelectionImpl->contains with attachment
-            if (mTextSelectionImpl->textSelection()->contains(index, charPos) && doc->documentLayout()->hitTest(pos, Qt::ExactHit) != -1) {
+            if (mTextSelectionImpl->textSelection()->contains(index, charPos) && doc->documentLayout()->hitTest(relativePos, Qt::ExactHit) != -1) {
                 mTextSelectionImpl->setMightStartDrag(true);
                 mCurrentIndex = index;
                 return true;
diff --git a/src/widgets/room/delegate/messageattachmentdelegatehelperimage.cpp b/src/widgets/room/delegate/messageattachmentdelegatehelperimage.cpp
index dc9ad39b48..2dbfc936dd 100644
--- a/src/widgets/room/delegate/messageattachmentdelegatehelperimage.cpp
+++ b/src/widgets/room/delegate/messageattachmentdelegatehelperimage.cpp
@@ -158,9 +158,11 @@ bool MessageAttachmentDelegateHelperImage::handleMouseEvent(const MessageAttachm
             job->setInfo(info);
             job->start();
             return true;
-        } else if (!layout.pixmap.isNull()) {
+        } else if (layout.isShown && !layout.pixmap.isNull()) {
+            // imageSize is in device pixels (as the cached pixmap is), draw() paints it scaled down by the dpr.
+            const qreal dpr = layout.pixmap.devicePixelRatioF();
             const int imageY = attachmentsRect.y() + layout.titleSize.height() + DelegatePaintUtil::margin();
-            const QRect imageRect(attachmentsRect.x(), imageY, layout.imageSize.width(), layout.imageSize.height());
+            const QRect imageRect(attachmentsRect.x(), imageY, layout.imageSize.width() / dpr, layout.imageSize.height() / dpr);
             if (imageRect.contains(pos)) {
                 auto parentWidget = const_cast<QWidget *>(option.widget);
                 auto dlg = new ShowImageDialog(mRocketChatAccount, parentWidget);
@@ -259,7 +261,12 @@ QPoint MessageAttachmentDelegateHelperImage::adaptMousePosition(const QPoint &po
                                                                 const QStyleOptionViewItem &option)
 {
     const ImageLayout layout = layoutImage(msgAttach, option, attachmentsRect.width(), attachmentsRect.height());
-    const QPoint relativePos = pos - attachmentsRect.topLeft() - QPoint(0, layout.imageSize.height() + layout.titleSize.height() + DelegatePaintUtil::margin());
+    // Same vertical layout as draw(): title | margin [| image | margin] | description
+    int descriptionY = layout.titleSize.height() + DelegatePaintUtil::margin();
+    if (layout.isShown && !layout.pixmap.isNull()) {
+        descriptionY += layout.imageSize.height() / layout.pixmap.devicePixelRatioF() + DelegatePaintUtil::margin();
+    }
+    const QPoint relativePos = pos - attachmentsRect.topLeft() - QPoint(0, descriptionY);
     return relativePos;
 }
 
diff --git a/src/widgets/room/delegate/messageattachmentdelegatehelpertext.cpp b/src/widgets/room/delegate/messageattachmentdelegatehelpertext.cpp
index 119e07cd1f..fe081814f6 100644
--- a/src/widgets/room/delegate/messageattachmentdelegatehelpertext.cpp
+++ b/src/widgets/room/delegate/messageattachmentdelegatehelpertext.cpp
@@ -85,7 +85,15 @@ QPoint MessageAttachmentDelegateHelperText::adaptMousePosition(const QPoint &pos
 
 QPoint MessageAttachmentDelegateHelperText::relativePos(const QPoint &pos, const TextLayout &layout, QRect attachmentsRect) const
 {
-    return pos - attachmentsRect.topLeft() - QPoint(0, layout.titleRect.height() + DelegatePaintUtil::margin());
+    // draw() only pushes the document below a title row when there is a title.
+    const int documentY = layout.title.isEmpty() ? 0 : qRound(layout.titleRect.height()) + DelegatePaintUtil::margin();
+    return pos - attachmentsRect.topLeft() - QPoint(0, documentY);
+}
+
+bool MessageAttachmentDelegateHelperText::documentIsShown(const TextLayout &layout)
+{
+    // Same condition as draw(): a collapsed attachment paints its title only, so there is nothing to hit test.
+    return layout.isShown || layout.title.isEmpty();
 }
 
 bool MessageAttachmentDelegateHelperText::handleMouseEvent(const MessageAttachment &msgAttach,
@@ -114,15 +122,16 @@ bool MessageAttachmentDelegateHelperText::handleMouseEvent(const MessageAttachme
                 return true;
             }
         }
-        // Clicks on links
-        auto *doc = documentAttachmentForIndex(msgAttach, attachmentsRect.width());
-        if (doc) {
-            // Fix mouse position (we have layout.titleSize.height() + DelegatePaintUtil::margin() too)
-            const QPoint mouseClickPos = relativePos(pos, layout, attachmentsRect);
-            const QString link = doc->documentLayout()->anchorAt(mouseClickPos);
-            if (!link.isEmpty()) {
-                Q_EMIT mRocketChatAccount->openLinkRequested(link);
-                return true;
+        // Clicks on links (only when the text is actually painted, see documentIsShown())
+        if (documentIsShown(layout)) {
+            if (auto *doc = documentAttachmentForIndex(msgAttach, attachmentsRect.width())) {
+                // Fix mouse position (we have layout.titleSize.height() + DelegatePaintUtil::margin() too)
+                const QPoint mouseClickPos = relativePos(pos, layout, attachmentsRect);
+                const QString link = doc->documentLayout()->anchorAt(mouseClickPos);
+                if (!link.isEmpty()) {
+                    Q_EMIT mRocketChatAccount->openLinkRequested(link);
+                    return true;
+                }
             }
         }
         // don't return true here, we need to send mouse release events to other helpers (ex: click on image)
@@ -245,12 +254,15 @@ bool MessageAttachmentDelegateHelperText::handleHelpEvent(QHelpEvent *helpEvent,
         }
     }
 
+    if (!documentIsShown(layout)) {
+        return false;
+    }
     const auto *doc = documentAttachmentForIndex(msgAttach, messageRect.width());
     if (!doc) {
         return false;
     }
 
-    const QPoint pos = helpEvent->pos() - messageRect.topLeft() - QPoint(0, layout.titleRect.height() + DelegatePaintUtil::margin());
+    const QPoint pos = relativePos(helpEvent->pos(), layout, messageRect);
     QString formattedTooltip;
     if (MessageDelegateUtils::generateToolTip(doc, pos, formattedTooltip)) {
         QToolTip::showText(helpEvent->globalPos(), formattedTooltip);
diff --git a/src/widgets/room/delegate/messageattachmentdelegatehelpertext.h b/src/widgets/room/delegate/messageattachmentdelegatehelpertext.h
index 3ab30b9197..ecaf6515ba 100644
--- a/src/widgets/room/delegate/messageattachmentdelegatehelpertext.h
+++ b/src/widgets/room/delegate/messageattachmentdelegatehelpertext.h
@@ -48,4 +48,5 @@ private:
                                                                        QRect attachmentsRect,
                                                                        const QStyleOptionViewItem &option) override;
     [[nodiscard]] LIBRUQOLAWIDGETS_NO_EXPORT QPoint relativePos(const QPoint &pos, const TextLayout &layout, QRect attachmentsRect) const;
+    [[nodiscard]] LIBRUQOLAWIDGETS_NO_EXPORT static bool documentIsShown(const TextLayout &layout);
 };
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.