chatgui: MsgIsOutgoingRole support for outgoing message alignment
This commit is contained in:
1 parent
fbc1bff1e1
commit
e8920fe00e
5 files changed
+198
-33
No files matched your search
@@ -65,6 +65,33 @@ MessageDelegate::Layout MessageDelegate::calcLayout(
|
||||
|
||||
bool hasQuote = index.data(MsgHasQuoteRole).toBool();
|
||||
QString text = index.data(MsgTextRole).toString();
|
||||
L.isOutgoing = index.data(MsgIsOutgoingRole).toBool();
|
||||
|
||||
L.emojiCount = detectEmojiOnly(text);
|
||||
L.emojiOnly = (L.emojiCount >= 1);
|
||||
|
||||
if (L.emojiOnly) {
|
||||
QFontMetrics fm(option.font);
|
||||
int lineH = fm.lineSpacing();
|
||||
|
||||
int availW = L.viewWidth - kMarginH - kAvatar - kGap - kMarginH;
|
||||
bool narrow = (availW < 400);
|
||||
int contentEdge = !L.isOutgoing
|
||||
? (narrow ? kMarginH : (kMarginH + kAvatar + kGap))
|
||||
: L.viewWidth - (narrow ? kMarginH : (kMarginH + kAvatar + kGap));
|
||||
|
||||
int eSize = (L.emojiCount == 1) ? lineH * 4 : lineH * 2;
|
||||
int emojiGap = lineH / 2;
|
||||
int totalW = L.emojiCount * eSize + (L.emojiCount - 1) * emojiGap;
|
||||
int x = !L.isOutgoing
|
||||
? (contentEdge + kPadH)
|
||||
: (contentEdge - kPadH - totalW);
|
||||
|
||||
L.emojiArea = QRect(x, kGap * 2, totalW, eSize);
|
||||
L.totalHeight = eSize + kGap * 2 + kItemGap;
|
||||
L.bubbleRect = QRect();
|
||||
return L;
|
||||
}
|
||||
QString qText = hasQuote ? index.data(MsgQuoteTextRole).toString() : QString();
|
||||
|
||||
int availW = L.viewWidth - kMarginH - kAvatar - kGap - kMarginH;
|
||||
@@ -77,14 +104,18 @@ MessageDelegate::Layout MessageDelegate::calcLayout(
|
||||
QFontMetrics fm(option.font);
|
||||
int contentW = calcMaxLineWidth(option.font, text, limitW);
|
||||
|
||||
QString author = index.data(MsgAuthorRole).toString();
|
||||
QFont boldFm = option.font;
|
||||
boldFm.setBold(true);
|
||||
int authorW = QFontMetrics(boldFm).horizontalAdvance(author);
|
||||
contentW = qMax(contentW, authorW);
|
||||
if (!L.isOutgoing) {
|
||||
QString author = index.data(MsgAuthorRole).toString();
|
||||
QFont boldFm = option.font;
|
||||
boldFm.setBold(true);
|
||||
int authorW = QFontMetrics(boldFm).horizontalAdvance(author);
|
||||
contentW = qMax(contentW, authorW);
|
||||
}
|
||||
|
||||
if (hasQuote) {
|
||||
QString qAuthor = index.data(MsgQuoteAuthorRole).toString();
|
||||
QFont boldFm = option.font;
|
||||
boldFm.setBold(true);
|
||||
int qAuthorW = QFontMetrics(boldFm).horizontalAdvance(qAuthor);
|
||||
contentW = qMax(contentW, qAuthorW + kQuoteBarW + kQuotePadH + 4);
|
||||
int qTextW = qMin(contentW + 8, limitW);
|
||||
@@ -107,23 +138,39 @@ MessageDelegate::Layout MessageDelegate::calcLayout(
|
||||
|
||||
int textH = measureTextHeight(option.font, text, textW);
|
||||
int authorH = fm.height();
|
||||
int bubbleH = kPadTop + authorH + 2 + (hasQuote ? qH + kQuoteGap : 0) + textH + kStatusH + kPadBot;
|
||||
int bubbleH = L.isOutgoing
|
||||
? kPadTop + (hasQuote ? qH + kQuoteGap : 0) + textH + kStatusH + kPadBot
|
||||
: kPadTop + authorH + 2 + (hasQuote ? qH + kQuoteGap : 0) + textH + kStatusH + kPadBot;
|
||||
L.totalHeight = qMax(bubbleH, kAvatar) + kItemGap;
|
||||
|
||||
int contentLeft = L.narrow ? kMarginH : (kMarginH + kAvatar + kGap);
|
||||
int contentEdge = L.isOutgoing
|
||||
? L.viewWidth - (L.narrow ? kMarginH : (kMarginH + kAvatar + kGap))
|
||||
: (L.narrow ? kMarginH : (kMarginH + kAvatar + kGap));
|
||||
|
||||
L.bubbleRect = QRect(contentLeft, 0, bubbleW, bubbleH);
|
||||
if (!L.isOutgoing)
|
||||
L.bubbleRect = QRect(contentEdge, 0, bubbleW, bubbleH);
|
||||
else
|
||||
L.bubbleRect = QRect(contentEdge - bubbleW, 0, bubbleW, bubbleH);
|
||||
|
||||
int contentTop = kPadTop;
|
||||
|
||||
L.authorRect = QRect(contentLeft + kPadH, contentTop, textW, authorH);
|
||||
contentTop += authorH + 2;
|
||||
if (!L.isOutgoing) {
|
||||
L.authorRect = QRect(contentEdge + kPadH, contentTop, textW, authorH);
|
||||
contentTop += authorH + 2;
|
||||
}
|
||||
|
||||
if (hasQuote) {
|
||||
L.quoteRect = QRect(contentLeft + kPadH, contentTop, bubbleW - 2 * kPadH, qH);
|
||||
L.quoteBarRect = QRect(L.quoteRect.left(), L.quoteRect.top(),
|
||||
kQuoteBarW, qH);
|
||||
int tx = L.quoteBarRect.right() + kQuotePadH;
|
||||
int qX = !L.isOutgoing
|
||||
? (contentEdge + kPadH)
|
||||
: (contentEdge - kPadH - (bubbleW - 2 * kPadH));
|
||||
L.quoteRect = QRect(qX, contentTop, bubbleW - 2 * kPadH, qH);
|
||||
if (!L.isOutgoing)
|
||||
L.quoteBarRect = QRect(L.quoteRect.left(), L.quoteRect.top(), kQuoteBarW, qH);
|
||||
else
|
||||
L.quoteBarRect = QRect(L.quoteRect.right() - kQuoteBarW, L.quoteRect.top(), kQuoteBarW, qH);
|
||||
int tx = !L.isOutgoing
|
||||
? (L.quoteBarRect.right() + kQuotePadH)
|
||||
: (L.quoteRect.left() + kQuotePadH);
|
||||
L.quoteAuthorRect = QRect(tx, L.quoteRect.top() + kQuotePadV,
|
||||
L.quoteRect.width() - kQuoteBarW - kQuotePadH,
|
||||
QFontMetrics(option.font).height());
|
||||
@@ -134,15 +181,18 @@ MessageDelegate::Layout MessageDelegate::calcLayout(
|
||||
contentTop += qH + kQuoteGap;
|
||||
}
|
||||
|
||||
L.textRect = QRect(contentLeft + kPadH, contentTop,
|
||||
textW, textH);
|
||||
L.statusRect = QRect(contentLeft + kPadH,
|
||||
contentTop + textH + 2,
|
||||
textW, kStatusH);
|
||||
int txRect = !L.isOutgoing
|
||||
? (contentEdge + kPadH)
|
||||
: (contentEdge - kPadH - textW);
|
||||
L.textRect = QRect(txRect, contentTop, textW, textH);
|
||||
L.statusRect = QRect(txRect, contentTop + textH + 2, textW, kStatusH);
|
||||
|
||||
if (!L.narrow) {
|
||||
int avatarY = L.bubbleRect.bottom() - kAvatar;
|
||||
L.avatarRect = QRect(kMarginH, avatarY, kAvatar, kAvatar);
|
||||
if (!L.isOutgoing)
|
||||
L.avatarRect = QRect(kMarginH, avatarY, kAvatar, kAvatar);
|
||||
else
|
||||
L.avatarRect = QRect(L.viewWidth - kMarginH - kAvatar, avatarY, kAvatar, kAvatar);
|
||||
}
|
||||
|
||||
return L;
|
||||
@@ -349,6 +399,56 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
|
||||
|
||||
Layout L = calcLayout(option, index);
|
||||
|
||||
if (L.emojiOnly) {
|
||||
QString msgText = index.data(MsgTextRole).toString();
|
||||
QString trimmed = msgText.trimmed();
|
||||
QFontMetrics fm(option.font);
|
||||
int lineH = fm.lineSpacing();
|
||||
int eSize = (L.emojiCount == 1) ? lineH * 4 : lineH * 2;
|
||||
|
||||
int x = L.emojiArea.left();
|
||||
int y = L.emojiArea.top();
|
||||
int pos = 0;
|
||||
while (pos < trimmed.length()) {
|
||||
if (trimmed.at(pos).isSpace()) { ++pos; continue; }
|
||||
QString emojiStr;
|
||||
for (const auto &cat : builtinEmojiSet())
|
||||
for (const auto &e : cat.items) {
|
||||
if (e.unicode.length() > trimmed.length() - pos) continue;
|
||||
if (QStringView(trimmed).mid(pos, e.unicode.length()) == e.unicode) {
|
||||
emojiStr = e.unicode;
|
||||
pos += e.unicode.length();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (emojiStr.isEmpty()) { ++pos; continue; }
|
||||
|
||||
bool animated = g_animatedEmojiMap.contains(emojiStr);
|
||||
if (animated) {
|
||||
LottieIcon *icon = AnimTimer::instance()->icon(g_animatedEmojiMap[emojiStr]);
|
||||
if (icon && icon->isValid()) {
|
||||
QImage frame = icon->renderFrame(icon->currentFrame(), QSize(eSize, eSize));
|
||||
painter->drawImage(x, y, frame);
|
||||
} else {
|
||||
QFont big = option.font;
|
||||
big.setPointSize((int)(big.pointSize() * (L.emojiCount == 1 ? 4.0 : 2.0)));
|
||||
painter->setFont(big);
|
||||
painter->setPen(option.palette.text().color());
|
||||
painter->drawText(QRect(x, y, eSize, eSize), Qt::AlignCenter, emojiStr);
|
||||
}
|
||||
} else {
|
||||
QFont big = option.font;
|
||||
big.setPointSize((int)(big.pointSize() * (L.emojiCount == 1 ? 4.0 : 2.0)));
|
||||
painter->setFont(big);
|
||||
painter->setPen(option.palette.text().color());
|
||||
painter->drawText(QRect(x, y, eSize, eSize), Qt::AlignCenter, emojiStr);
|
||||
}
|
||||
x += eSize + lineH / 2;
|
||||
}
|
||||
painter->restore();
|
||||
return;
|
||||
}
|
||||
|
||||
auto *cv = qobject_cast<const ChatView *>(option.widget);
|
||||
bool singleTextSel = false;
|
||||
bool multiRowSel = false;
|
||||
@@ -379,12 +479,14 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
|
||||
if (!L.narrow)
|
||||
drawAvatar(painter, L, index);
|
||||
|
||||
QFont authorFont = option.font;
|
||||
authorFont.setBold(true);
|
||||
painter->setFont(authorFont);
|
||||
painter->setPen(QColor(0x33, 0x90, 0xEC));
|
||||
painter->drawText(L.authorRect, Qt::AlignLeft | Qt::AlignVCenter,
|
||||
index.data(MsgAuthorRole).toString());
|
||||
if (!L.isOutgoing) {
|
||||
QFont authorFont = option.font;
|
||||
authorFont.setBold(true);
|
||||
painter->setFont(authorFont);
|
||||
painter->setPen(QColor(0x33, 0x90, 0xEC));
|
||||
painter->drawText(L.authorRect, Qt::AlignLeft | Qt::AlignVCenter,
|
||||
index.data(MsgAuthorRole).toString());
|
||||
}
|
||||
|
||||
painter->setPen(option.palette.text().color());
|
||||
QFont textFont = option.font;
|
||||
@@ -458,17 +560,30 @@ void MessageDelegate::drawBubble(QPainter *p, const Layout &L, const QStyleOptio
|
||||
body.addRoundedRect(b, r, r);
|
||||
|
||||
QPainterPath tail;
|
||||
qreal tx = b.left();
|
||||
qreal ty = b.bottom();
|
||||
tail.moveTo(tx, ty - r);
|
||||
tail.lineTo(tx - t, ty - t / 2.0);
|
||||
tail.lineTo(tx + r, ty);
|
||||
if (!L.isOutgoing) {
|
||||
qreal tx = b.left();
|
||||
qreal ty = b.bottom();
|
||||
tail.moveTo(tx, ty - r);
|
||||
tail.lineTo(tx - t, ty - t / 2.0);
|
||||
tail.lineTo(tx + r, ty);
|
||||
} else {
|
||||
qreal tx = b.right();
|
||||
qreal ty = b.bottom();
|
||||
tail.moveTo(tx, ty - r);
|
||||
tail.lineTo(tx + t, ty - t / 2.0);
|
||||
tail.lineTo(tx - r, ty);
|
||||
}
|
||||
tail.closeSubpath();
|
||||
|
||||
QPainterPath combined = body.united(tail);
|
||||
|
||||
QColor base = opt.palette.window().color();
|
||||
QColor bubbleFill = base.lighter(135);
|
||||
QColor bubbleFill;
|
||||
if (!L.isOutgoing) {
|
||||
QColor base = opt.palette.window().color();
|
||||
bubbleFill = base.lighter(135);
|
||||
} else {
|
||||
bubbleFill = QColor(0xE1, 0xF5, 0xE1);
|
||||
}
|
||||
p->setPen(Qt::NoPen);
|
||||
p->setBrush(bubbleFill);
|
||||
p->drawPath(combined);
|
||||
|
||||
Reference in new issue
Block a user