From 0340db7f2fcff211f99d6ccc92bd98669a406581 Mon Sep 17 00:00:00 2001 From: blue Date: Sun, 1 May 2022 23:19:52 +0300 Subject: [PATCH] first successfull attempt to visualize selection on message body --- ui/widgets/messageline/feedview.cpp | 56 +++++++++++------ ui/widgets/messageline/feedview.h | 3 + ui/widgets/messageline/messagedelegate.cpp | 70 ++++++++++++++-------- ui/widgets/messageline/messagedelegate.h | 5 +- 4 files changed, 92 insertions(+), 42 deletions(-) diff --git a/ui/widgets/messageline/feedview.cpp b/ui/widgets/messageline/feedview.cpp index 0758dd9..f467f43 100644 --- a/ui/widgets/messageline/feedview.cpp +++ b/ui/widgets/messageline/feedview.cpp @@ -52,7 +52,10 @@ FeedView::FeedView(QWidget* parent): dividerFont(), dividerMetrics(dividerFont), mousePressed(false), - anchorHovered(false) + dragging(false), + anchorHovered(false), + dragStartPoint(), + dragEndPoint() { horizontalScrollBar()->setRange(0, 0); verticalScrollBar()->setSingleStep(approximateSingleMessageHeight); @@ -304,7 +307,7 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt void FeedView::paintEvent(QPaintEvent* event) { - //qDebug() << "paint" << event->rect(); + qDebug() << "paint" << event->rect(); const QAbstractItemModel* m = model(); QWidget* vp = viewport(); QRect zone = event->rect().translated(0, -vo); @@ -427,19 +430,31 @@ void FeedView::mouseMoveEvent(QMouseEvent* event) return; } - mousePressed = false; - //qDebug() << event; + dragEndPoint = event->localPos().toPoint(); + if (mousePressed) { + QPoint distance = dragStartPoint - dragEndPoint; + if (distance.manhattanLength() > 5) { + dragging = true; + } + } QAbstractItemView::mouseMoveEvent(event); if (specialDelegate) { - QPoint point = event->localPos().toPoint(); - QModelIndex index = indexAt(point); + QModelIndex index = indexAt(dragEndPoint); if (index.isValid()) { QRect rect = visualRect(index); - MessageDelegate* del = static_cast(itemDelegate()); - if (rect.contains(point)) { - setAnchorHovered(del->isAnchorHovered(point, index, rect)); + if (rect.contains(dragEndPoint)) { + MessageDelegate* del = static_cast(itemDelegate()); + if (dragging) { + setAnchorHovered(false); + if (del->mouseDrag(dragStartPoint, dragEndPoint, index, rect)) { + qDebug() << "asking to repaint" << rect; + setDirtyRegion(rect); + } + } else { + setAnchorHovered(del->isAnchorHovered(dragEndPoint, index, rect)); + } } else { setAnchorHovered(false); } @@ -453,22 +468,29 @@ void FeedView::mousePressEvent(QMouseEvent* event) { QAbstractItemView::mousePressEvent(event); mousePressed = event->button() == Qt::LeftButton; + if (mousePressed) { + dragStartPoint = event->localPos().toPoint(); + } } void FeedView::mouseReleaseEvent(QMouseEvent* event) { QAbstractItemView::mouseReleaseEvent(event); - if (mousePressed && specialDelegate) { - QPoint point = event->localPos().toPoint(); - QModelIndex index = indexAt(point); - if (index.isValid()) { - QRect rect = visualRect(index); - MessageDelegate* del = static_cast(itemDelegate()); - if (rect.contains(point)) { - del->leftClick(point, index, rect); + if (mousePressed) { + if (!dragging && specialDelegate) { + QPoint point = event->localPos().toPoint(); + QModelIndex index = indexAt(point); + if (index.isValid()) { + QRect rect = visualRect(index); + MessageDelegate* del = static_cast(itemDelegate()); + if (rect.contains(point)) { + del->leftClick(point, index, rect); + } } } + dragging = false; + mousePressed = false; } } diff --git a/ui/widgets/messageline/feedview.h b/ui/widgets/messageline/feedview.h index 7a00dd7..c0d6254 100644 --- a/ui/widgets/messageline/feedview.h +++ b/ui/widgets/messageline/feedview.h @@ -99,7 +99,10 @@ private: QFont dividerFont; QFontMetrics dividerMetrics; bool mousePressed; + bool dragging; bool anchorHovered; + QPoint dragStartPoint; + QPoint dragEndPoint; static const std::set geometryChangingRoles; diff --git a/ui/widgets/messageline/messagedelegate.cpp b/ui/widgets/messageline/messagedelegate.cpp index ca2e0a6..197248a 100644 --- a/ui/widgets/messageline/messagedelegate.cpp +++ b/ui/widgets/messageline/messagedelegate.cpp @@ -56,7 +56,9 @@ MessageDelegate::MessageDelegate(QObject* parent): pencilIcons(new std::map()), previews(new std::map()), idsToKeep(new std::set()), - clearingWidgets(false) + clearingWidgets(false), + currentId(""), + selection(0, 0) { bodyRenderer->setDocumentMargin(0); @@ -438,6 +440,37 @@ bool MessageDelegate::isAnchorHovered(const QPoint& point, const QModelIndex& in return anchor.size() > 0; } +bool MessageDelegate::mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint) +{ + QVariant vi = index.data(Models::MessageFeed::Bulk); + Models::FeedItem data = qvariant_cast(vi); + if (data.text.size() > 0) { + QRect localHint = getHoveredMessageBodyRect(index, data, sizeHint); + + if (localHint.contains(start)) { + QPoint translated = start - localHint.topLeft(); + + bodyRenderer->setHtml(Shared::processMessageBody(data.text)); + bodyRenderer->setTextWidth(localHint.size().width()); + selection.first = bodyRenderer->documentLayout()->hitTest(translated, Qt::HitTestAccuracy::FuzzyHit); + selection.second = bodyRenderer->documentLayout()->hitTest(end - localHint.topLeft(), Qt::HitTestAccuracy::FuzzyHit); + + currentId = data.id; + + return true; + } + } + return false; +} + +QString MessageDelegate::clearSelection() +{ + QString lastSelectedId = currentId; + currentId = ""; + selection = std::pair(0, 0); + return lastSelectedId; +} + void MessageDelegate::initializeFonts(const QFont& font) { bodyFont = font; @@ -664,32 +697,21 @@ int MessageDelegate::paintBody(const Models::FeedItem& data, QPainter* painter, if (data.text.size() > 0) { bodyRenderer->setHtml(Shared::processMessageBody(data.text)); bodyRenderer->setTextWidth(option.rect.size().width()); - painter->setBackgroundMode(Qt::BGMode::OpaqueMode); painter->save(); -// QTextCursor cursor(bodyRenderer); -// cursor.setPosition(2, QTextCursor::KeepAnchor); painter->translate(option.rect.topLeft()); -// QTextFrameFormat format = bodyRenderer->rootFrame()->frameFormat(); -// format.setBackground(option.palette.brush(QPalette::Active, QPalette::Highlight)); -// bodyRenderer->rootFrame()->setFrameFormat(format); + + if (data.id == currentId) { + QTextCursor cursor(bodyRenderer); + cursor.setPosition(selection.first, QTextCursor::MoveAnchor); + cursor.setPosition(selection.second, QTextCursor::KeepAnchor); + QTextCharFormat format = cursor.charFormat(); + format.setBackground(option.palette.color(QPalette::Active, QPalette::Highlight)); + format.setForeground(option.palette.color(QPalette::Active, QPalette::HighlightedText)); + cursor.setCharFormat(format); + } + bodyRenderer->drawContents(painter); -// QColor c = option.palette.color(QPalette::Active, QPalette::Highlight); -// QTextBlock b = bodyRenderer->begin(); -// QTextBlockFormat format = b.blockFormat(); -// format.setBackground(option.palette.brush(QPalette::Active, QPalette::Highlight)); -// format.setProperty(QTextFormat::BackgroundBrush, option.palette.brush(QPalette::Active, QPalette::Highlight)); -// QTextCursor cursor(bodyRenderer); -// cursor.setBlockFormat(format); -// b = bodyRenderer->begin(); -// while (b.isValid() > 0) { -// QTextLayout* lay = b.layout(); -// QTextLayout::FormatRange range; -// range.format = b.charFormat(); -// range.start = 0; -// range.length = 2; -// lay->draw(painter, option.rect.topLeft(), {range}); -// b = b.next(); -// } + painter->restore(); QSize bodySize(std::ceil(bodyRenderer->idealWidth()), std::ceil(bodyRenderer->size().height())); diff --git a/ui/widgets/messageline/messagedelegate.h b/ui/widgets/messageline/messagedelegate.h index df883f7..2aea240 100644 --- a/ui/widgets/messageline/messagedelegate.h +++ b/ui/widgets/messageline/messagedelegate.h @@ -59,6 +59,8 @@ public: void beginClearWidgets(); void leftClick(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const; bool isAnchorHovered(const QPoint& point, const QModelIndex& index, const QRect& sizeHint) const; + bool mouseDrag(const QPoint& start, const QPoint& end, const QModelIndex& index, const QRect& sizeHint); + QString clearSelection(); static int avatarHeight; static int margin; @@ -116,7 +118,8 @@ private: std::map* previews; std::set* idsToKeep; bool clearingWidgets; - + QString currentId; + std::pair selection; }; #endif // MESSAGEDELEGATE_H