Browse Source

Use invite text layout for selection and wrapped emoji positions

master
evgeny 1 week ago
parent
commit
17179c9c4a
  1. 31
      tools/chatgui/src/messagedelegate.cpp
  2. 14
      tools/chatgui/tests/test_invite_links.cpp

31
tools/chatgui/src/messagedelegate.cpp

@ -823,6 +823,9 @@ static void drawAnimatedEmojiOverlay(QPainter *p, const QFont &font,
if (!para.isEmpty()) { if (!para.isEmpty()) {
QTextLayout layout(para, font); QTextLayout layout(para, font);
if (text.contains(QStringLiteral("utun://"))) {
QTextOption wrap; wrap.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); layout.setTextOption(wrap);
}
layout.beginLayout(); layout.beginLayout();
qreal localY = 0; qreal localY = 0;
while (true) { while (true) {
@ -839,7 +842,7 @@ static void drawAnimatedEmojiOverlay(QPainter *p, const QFont &font,
const QString &unicode = it.key(); const QString &unicode = it.key();
int pos = text.indexOf(unicode, ls); int pos = text.indexOf(unicode, ls);
while (pos >= 0 && pos + unicode.length() <= le) { while (pos >= 0 && pos + unicode.length() <= le) {
int linePos = pos - globalChar - line.textStart(); int linePos = pos - globalChar;
int cp1 = linePos, cp2 = linePos + unicode.length(); int cp1 = linePos, cp2 = linePos + unicode.length();
qreal x1 = line.cursorToX(&cp1); qreal x1 = line.cursorToX(&cp1);
qreal x2 = line.cursorToX(&cp2); qreal x2 = line.cursorToX(&cp2);
@ -1368,14 +1371,34 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
painter->setFont(textFont); painter->setFont(textFont);
QString msgText = index.data(MsgTextRole).toString(); QString msgText = index.data(MsgTextRole).toString();
if (msgText.contains(QStringLiteral("utun://"))) { const bool hasInvite = msgText.contains(QStringLiteral("utun://"));
if (hasInvite) {
QString display = msgText; display.replace('\n', QChar(0x2028)); QString display = msgText; display.replace('\n', QChar(0x2028));
QTextLayout layout(display, textFont); QTextLayout layout(display, textFont);
layoutInviteText(layout, L.textRect.width()); layoutInviteText(layout, L.textRect.width());
layout.draw(painter, L.textRect.topLeft()); QVector<QTextLayout::FormatRange> selections;
if (singleTextSel && cv) {
auto cursorAt = [&](const QPoint& point) {
for (int i = 0; i < layout.lineCount(); ++i) {
const auto line = layout.lineAt(i);
if (point.y() < line.y() + line.height()) return line.xToCursor(point.x());
}
return msgText.length();
};
const auto& selection = cv->textSelection();
int start = cursorAt(selection.clickPos - L.textRect.topLeft());
int end = cursorAt(selection.dragPos - L.textRect.topLeft());
if (start > end) qSwap(start, end);
if (start == end && end < msgText.length()) ++end;
const_cast<ChatView*>(cv)->setTextSelChars(start, end);
QTextLayout::FormatRange range;
range.start = start; range.length = end - start; range.format.setBackground(QColor(0x33, 0x90, 0xEC, 60));
selections.append(range);
}
layout.draw(painter, L.textRect.topLeft(), selections);
} else painter->drawText(L.textRect, Qt::AlignLeft | Qt::TextWordWrap, msgText); } else painter->drawText(L.textRect, Qt::AlignLeft | Qt::TextWordWrap, msgText);
if (singleTextSel && cv) { if (singleTextSel && cv && !hasInvite) {
const auto &ts = cv->textSelection(); const auto &ts = cv->textSelection();
QPoint localP1(ts.clickPos.x() - L.textRect.left(), QPoint localP1(ts.clickPos.x() - L.textRect.left(),
ts.clickPos.y() - L.textRect.top()); ts.clickPos.y() - L.textRect.top());

14
tools/chatgui/tests/test_invite_links.cpp

@ -53,6 +53,20 @@ private slots:
QCOMPARE(clicked.count(), 1); QCOMPARE(clicked.last().first().toString(), first); QCOMPARE(clicked.count(), 1); QCOMPARE(clicked.last().first().toString(), first);
QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, secondPoint); QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, secondPoint);
QCOMPARE(clicked.count(), 2); QCOMPARE(clicked.last().first().toString(), second); QCOMPARE(clicked.count(), 2); QCOMPARE(clicked.last().first().toString(), second);
/* Выделение использует те же перенесённые строки, что и отрисовка ссылки. */
QPoint dragEnd = firstPoint + QPoint(20, 0);
QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, firstPoint);
QMouseEvent drag(QEvent::MouseMove, dragEnd, view.viewport()->mapToGlobal(dragEnd),
Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
QApplication::sendEvent(view.viewport(), &drag);
QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, dragEnd);
QTest::qWait(20);
QCOMPARE(clicked.count(), 2);
const auto selection = view.textSelection();
QVERIFY(selection.startChar >= text.indexOf(first));
QVERIFY(selection.endChar <= text.indexOf(first) + first.length());
QVERIFY(selection.endChar > selection.startChar);
QVERIFY(selection.endChar - selection.startChar < 20);
} }
void memberPlusTargetsOtherMembersOnly() { void memberPlusTargetsOtherMembersOnly() {

Loading…
Cancel
Save