|
|
@@ -100,8 +100,8 @@ void ChatMessageDelegate::paint(QPainter *painter,
|
|
|
int nameHeight = message.senderName.isEmpty() ? 0 : nameFm.height();
|
|
|
int nameSpacing = message.senderName.isEmpty() ? 0 : 2;
|
|
|
|
|
|
- // 计算各个元素的位置
|
|
|
- QSize textSize = calculateTextSize(option.fontMetrics, message.text);
|
|
|
+ // 计算内容大小(文本或图片)
|
|
|
+ QSize contentSize = calculateContentSize(message, option.fontMetrics);
|
|
|
|
|
|
// 计算头像位置
|
|
|
QRectF avatarRect;
|
|
|
@@ -123,15 +123,15 @@ void ChatMessageDelegate::paint(QPainter *painter,
|
|
|
if (message.type == MessageType::Left) {
|
|
|
bubbleRect = QRectF(avatarRect.right() + ChatConstants::BUBBLE_SPACING,
|
|
|
option.rect.top() + nameHeight + nameSpacing,
|
|
|
- textSize.width() + 2 * ChatConstants::BUBBLE_PADDING,
|
|
|
- textSize.height() + 2 * ChatConstants::BUBBLE_PADDING);
|
|
|
+ contentSize.width() + 2 * ChatConstants::BUBBLE_PADDING,
|
|
|
+ contentSize.height() + 2 * ChatConstants::BUBBLE_PADDING);
|
|
|
} else {
|
|
|
- bubbleRect = QRectF(option.rect.right() - textSize.width()
|
|
|
+ bubbleRect = QRectF(option.rect.right() - contentSize.width()
|
|
|
- 2 * ChatConstants::BUBBLE_PADDING - ChatConstants::AVATAR_SIZE
|
|
|
- 2 * ChatConstants::BUBBLE_SPACING,
|
|
|
option.rect.top() + nameHeight + nameSpacing,
|
|
|
- textSize.width() + 2 * ChatConstants::BUBBLE_PADDING,
|
|
|
- textSize.height() + 2 * ChatConstants::BUBBLE_PADDING);
|
|
|
+ contentSize.width() + 2 * ChatConstants::BUBBLE_PADDING,
|
|
|
+ contentSize.height() + 2 * ChatConstants::BUBBLE_PADDING);
|
|
|
}
|
|
|
|
|
|
// 绘制名字
|
|
|
@@ -165,28 +165,44 @@ void ChatMessageDelegate::paint(QPainter *painter,
|
|
|
// 绘制头像
|
|
|
drawAvatar(painter, avatarRect, message.avatar);
|
|
|
|
|
|
- // 绘制文本(带选择高亮)
|
|
|
- QRectF textRect = bubbleRect.adjusted(ChatConstants::BUBBLE_PADDING,
|
|
|
- ChatConstants::BUBBLE_PADDING,
|
|
|
- -ChatConstants::BUBBLE_PADDING,
|
|
|
- -ChatConstants::BUBBLE_PADDING);
|
|
|
- painter->setPen(ThemeManager::instance().color("colorText"));
|
|
|
-
|
|
|
+ // 绘制内容(文本、图片或混合内容)
|
|
|
+ QRectF contentRect = bubbleRect.adjusted(ChatConstants::BUBBLE_PADDING,
|
|
|
+ ChatConstants::BUBBLE_PADDING,
|
|
|
+ -ChatConstants::BUBBLE_PADDING,
|
|
|
+ -ChatConstants::BUBBLE_PADDING);
|
|
|
+
|
|
|
// 检查是否是当前选中的消息
|
|
|
bool isCurrentMessage = (index == m_currentMessageIndex);
|
|
|
- drawTextWithSelection(painter, textRect, message.text, option.fontMetrics, isCurrentMessage);
|
|
|
+
|
|
|
+ if (message.hasImage() && message.hasText()) {
|
|
|
+ // 混合内容:图片在上,文字在下
|
|
|
+ QSize imageSize = calculateImageSize(message.imagePath, contentRect.width(), contentRect.height() * 0.7);
|
|
|
+ QRectF imageRect(contentRect.left(), contentRect.top(), imageSize.width(), imageSize.height());
|
|
|
+ QRectF textRect(contentRect.left(), imageRect.bottom() + 4, contentRect.width(), contentRect.height() - imageSize.height() - 4);
|
|
|
+
|
|
|
+ drawImage(painter, imageRect, message.imagePath);
|
|
|
+ painter->setPen(ThemeManager::instance().color("colorText"));
|
|
|
+ drawTextWithSelection(painter, textRect, message.text, option.fontMetrics, isCurrentMessage);
|
|
|
+ } else if (message.hasImage()) {
|
|
|
+ // 纯图片消息
|
|
|
+ drawImage(painter, contentRect, message.imagePath);
|
|
|
+ } else {
|
|
|
+ // 纯文本消息
|
|
|
+ painter->setPen(ThemeManager::instance().color("colorText"));
|
|
|
+ drawTextWithSelection(painter, contentRect, message.text, option.fontMetrics, isCurrentMessage);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
QSize ChatMessageDelegate::sizeHint(const QStyleOptionViewItem &option,
|
|
|
const QModelIndex &index) const
|
|
|
{
|
|
|
const ChatMessage message = index.data().value<ChatMessage>();
|
|
|
- QSize textSize = calculateTextSize(option.fontMetrics, message.text);
|
|
|
+ QSize contentSize = calculateContentSize(message, option.fontMetrics);
|
|
|
|
|
|
// 系统消息特殊处理
|
|
|
if (message.type == MessageType::System) {
|
|
|
- int width = qMin(textSize.width() + 2 * ChatConstants::BUBBLE_PADDING, viewportWidth() / 2);
|
|
|
- int height = textSize.height() + 2 * ChatConstants::BUBBLE_PADDING
|
|
|
+ int width = qMin(contentSize.width() + 2 * ChatConstants::BUBBLE_PADDING, viewportWidth() / 2);
|
|
|
+ int height = contentSize.height() + 2 * ChatConstants::BUBBLE_PADDING
|
|
|
+ ChatConstants::TIMESTAMP_HEIGHT + 2 * ChatConstants::BUBBLE_SPACING;
|
|
|
return QSize(width, height);
|
|
|
}
|
|
|
@@ -198,9 +214,9 @@ QSize ChatMessageDelegate::sizeHint(const QStyleOptionViewItem &option,
|
|
|
int nameHeight = message.senderName.isEmpty() ? 0 : nameFm.height();
|
|
|
int nameSpacing = message.senderName.isEmpty() ? 0 : 2;
|
|
|
|
|
|
- int width = textSize.width() + 2 * ChatConstants::BUBBLE_PADDING + ChatConstants::AVATAR_SIZE
|
|
|
+ int width = contentSize.width() + 2 * ChatConstants::BUBBLE_PADDING + ChatConstants::AVATAR_SIZE
|
|
|
+ 2 * ChatConstants::BUBBLE_SPACING;
|
|
|
- int height = qMax(textSize.height() + 2 * ChatConstants::BUBBLE_PADDING,
|
|
|
+ int height = qMax(contentSize.height() + 2 * ChatConstants::BUBBLE_PADDING,
|
|
|
ChatConstants::AVATAR_SIZE)
|
|
|
+ ChatConstants::TIMESTAMP_HEIGHT
|
|
|
+ nameHeight + nameSpacing;
|
|
|
@@ -465,3 +481,97 @@ int ChatMessageDelegate::getPositionFromPoint(const QPoint &pos,
|
|
|
int position = layout->hitTest(pos, Qt::FuzzyHit);
|
|
|
return position;
|
|
|
}
|
|
|
+
|
|
|
+void ChatMessageDelegate::drawImage(QPainter *painter, const QRectF &rect, const QString &imagePath) const
|
|
|
+{
|
|
|
+ if (imagePath.isEmpty())
|
|
|
+ return;
|
|
|
+
|
|
|
+ // 检查缓存中是否已有图片
|
|
|
+ if (!m_imageCache.contains(imagePath)) {
|
|
|
+ QPixmap image(imagePath);
|
|
|
+ if (!image.isNull()) {
|
|
|
+ // 计算合适的缩放尺寸
|
|
|
+ QSize rectSize = rect.size().toSize();
|
|
|
+ QSize targetSize = image.size().scaled(rectSize.width(), rectSize.height(), Qt::KeepAspectRatio);
|
|
|
+ image = image.scaled(targetSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
|
+ const_cast<ChatMessageDelegate *>(this)->m_imageCache.insert(imagePath, image);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (m_imageCache.contains(imagePath)) {
|
|
|
+ const QPixmap &image = m_imageCache[imagePath];
|
|
|
+ // 居中绘制图片
|
|
|
+ QRectF imageRect = rect;
|
|
|
+ if (image.width() < rect.width()) {
|
|
|
+ imageRect.setX(rect.x() + (rect.width() - image.width()) / 2);
|
|
|
+ imageRect.setWidth(image.width());
|
|
|
+ }
|
|
|
+ if (image.height() < rect.height()) {
|
|
|
+ imageRect.setY(rect.y() + (rect.height() - image.height()) / 2);
|
|
|
+ imageRect.setHeight(image.height());
|
|
|
+ }
|
|
|
+
|
|
|
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
|
|
|
+ painter->drawPixmap(imageRect.toRect(), image);
|
|
|
+
|
|
|
+ // 绘制图片边框
|
|
|
+ painter->setPen(QPen(QColor(200, 200, 200), 1));
|
|
|
+ painter->setBrush(Qt::NoBrush);
|
|
|
+ painter->drawRoundedRect(imageRect, 4, 4);
|
|
|
+ } else {
|
|
|
+ // 绘制占位符
|
|
|
+ painter->setPen(Qt::NoPen);
|
|
|
+ painter->setBrush(QColor(240, 240, 240));
|
|
|
+ painter->drawRoundedRect(rect, 4, 4);
|
|
|
+
|
|
|
+ painter->setPen(QColor(150, 150, 150));
|
|
|
+ painter->drawText(rect, Qt::AlignCenter, "图片加载失败");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+QSize ChatMessageDelegate::calculateImageSize(const QString &imagePath, int maxWidth, int maxHeight) const
|
|
|
+{
|
|
|
+ if (imagePath.isEmpty())
|
|
|
+ return QSize(100, 100); // 默认尺寸
|
|
|
+
|
|
|
+ QPixmap image(imagePath);
|
|
|
+ if (image.isNull())
|
|
|
+ return QSize(100, 100);
|
|
|
+
|
|
|
+ QSize imageSize = image.size();
|
|
|
+
|
|
|
+ // 限制最大尺寸
|
|
|
+ if (imageSize.width() > maxWidth || imageSize.height() > maxHeight) {
|
|
|
+ imageSize = imageSize.scaled(maxWidth, maxHeight, Qt::KeepAspectRatio);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 限制最小尺寸
|
|
|
+ if (imageSize.width() < 50) imageSize.setWidth(50);
|
|
|
+ if (imageSize.height() < 50) imageSize.setHeight(50);
|
|
|
+
|
|
|
+ return imageSize;
|
|
|
+}
|
|
|
+
|
|
|
+QSize ChatMessageDelegate::calculateContentSize(const ChatMessage &message, const QFontMetrics &fm) const
|
|
|
+{
|
|
|
+ if (message.hasImage() && message.hasText()) {
|
|
|
+ // 混合内容:图片 + 文本
|
|
|
+ int maxWidth = viewportWidth() - 2 * ChatConstants::BUBBLE_PADDING - ChatConstants::AVATAR_SIZE - 2 * ChatConstants::BUBBLE_SPACING;
|
|
|
+
|
|
|
+ QSize imageSize = calculateImageSize(message.imagePath, maxWidth, 200);
|
|
|
+ QSize textSize = calculateTextSize(fm, message.text);
|
|
|
+
|
|
|
+ int width = qMax(imageSize.width(), textSize.width());
|
|
|
+ int height = imageSize.height() + textSize.height() + 4; // 4px间距
|
|
|
+
|
|
|
+ return QSize(width, height);
|
|
|
+ } else if (message.hasImage()) {
|
|
|
+ // 纯图片消息
|
|
|
+ int maxWidth = viewportWidth() - 2 * ChatConstants::BUBBLE_PADDING - ChatConstants::AVATAR_SIZE - 2 * ChatConstants::BUBBLE_SPACING;
|
|
|
+ return calculateImageSize(message.imagePath, maxWidth, 300);
|
|
|
+ } else {
|
|
|
+ // 纯文本消息
|
|
|
+ return calculateTextSize(fm, message.text);
|
|
|
+ }
|
|
|
+}
|