diff --git a/tools/chatgui/src/accountdelegate.cpp b/tools/chatgui/src/accountdelegate.cpp index 7d5535c7..db7440d1 100644 --- a/tools/chatgui/src/accountdelegate.cpp +++ b/tools/chatgui/src/accountdelegate.cpp @@ -1,6 +1,7 @@ #include "accountdelegate.h" #include "flagpainter.h" #include "memberlistmodel.h" +#include "debug_ui.h" #include #include #include @@ -9,8 +10,16 @@ static QRect inviteButtonRect(const QRect& row) { return QRect(row.right() - 31, row.center().y() - 14, 28, 28); } +static QRect avatarRect(const QRect& row) { + const int size = MemberListModel::kAvatarSize; + return QRect(row.left() + 4, row.top() + (row.height() - size) / 2, size, size); +} + AccountDelegate::AccountDelegate(QObject *parent) - : QStyledItemDelegate(parent) {} + : QStyledItemDelegate(parent) { + GUI_DEBUG("AccountDelegate: row height=%dpx avatar=%dpx gap=%dpx", MemberListModel::kRowHeight, + MemberListModel::kAvatarSize, MemberListModel::kRowHeight - MemberListModel::kAvatarSize); +} void AccountDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -24,11 +33,11 @@ void AccountDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio painter->fillRect(option.rect, option.palette.alternateBase()); const int margin = 4; - const int iconSz = 24; + const int iconSz = MemberListModel::kAvatarSize; QIcon icon = qvariant_cast(index.data(Qt::DecorationRole)); if (!icon.isNull()) - icon.paint(painter, option.rect.left() + margin, option.rect.top() + (option.rect.height() - iconSz) / 2, iconSz, iconSz); + icon.paint(painter, avatarRect(option.rect)); const int x = option.rect.left() + iconSz + margin * 3; const bool canInvite = !index.data(Qt::UserRole + 2).toBool(); @@ -96,7 +105,7 @@ bool AccountDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, cons event->type() != QEvent::MouseButtonDblClick) return false; auto* mouse = static_cast(event); if (mouse->button() != Qt::LeftButton) return false; - const bool onAvatar=QRect(option.rect.left()+4,option.rect.center().y()-12,24,24).contains(mouse->pos()); + const bool onAvatar = avatarRect(option.rect).contains(mouse->pos()); if (event->type()==QEvent::MouseButtonPress) { m_avatarPress=onAvatar ? index : QModelIndex(); m_avatarPosition=mouse->pos(); } @@ -119,5 +128,5 @@ bool AccountDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, cons QSize AccountDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { (void)option; (void)index; - return QSize(160, 36); + return QSize(160, MemberListModel::kRowHeight); } diff --git a/tools/chatgui/src/accountlist.cpp b/tools/chatgui/src/accountlist.cpp index 7f8e0c1e..34131914 100644 --- a/tools/chatgui/src/accountlist.cpp +++ b/tools/chatgui/src/accountlist.cpp @@ -96,7 +96,7 @@ AccountList::AccountList(DbManager* db, QWidget *parent) m_listView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_listView->setSelectionMode(QAbstractItemView::SingleSelection); m_listView->setMouseTracking(true); - m_listView->setIconSize(QSize(24, 24)); + m_listView->setIconSize(QSize(MemberListModel::kAvatarSize, MemberListModel::kAvatarSize)); m_listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_listView->setContextMenuPolicy(Qt::CustomContextMenu); diff --git a/tools/chatgui/src/memberlistmodel.cpp b/tools/chatgui/src/memberlistmodel.cpp index 93a2f156..2e4967e2 100644 --- a/tools/chatgui/src/memberlistmodel.cpp +++ b/tools/chatgui/src/memberlistmodel.cpp @@ -17,12 +17,14 @@ extern "C" { static void applyPhoto(MemberListItem& item, const QString& channel) { auto* manager = AvatarManager::instance(); if (!manager) return; const QImage image = manager->image(channel, item.nodeId); if (image.isNull()) return; - QPixmap pixmap(24, 24); pixmap.fill(Qt::transparent); + const int size = MemberListModel::kAvatarSize; + QPixmap pixmap(size, size); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); - QPainterPath clip; clip.addEllipse(QRectF(0, 0, 24, 24)); painter.setClipPath(clip); - painter.drawImage(QRect(0, 0, 24, 24), image); painter.setClipping(false); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + QPainterPath clip; clip.addEllipse(QRectF(0, 0, size, size)); painter.setClipPath(clip); + painter.drawImage(QRect(0, 0, size, size), image); painter.setClipping(false); painter.setPen(QPen(Qt::white, 1)); painter.setBrush(item.online ? QColor("#4CAF50") : QColor("#9E9E9E")); - painter.drawEllipse(QRect(17, 17, 6, 6)); painter.end(); item.avatar = pixmap; + painter.drawEllipse(QRect(size - 7, size - 7, 6, 6)); painter.end(); item.avatar = pixmap; } MemberListModel::MemberListModel(QObject* parent) @@ -136,16 +138,17 @@ static void deserialize_member(const uint8_t* src, MemberListItem& item) { item.name = QString::fromUtf8(name); QColor c = item.online ? QColor("#4CAF50") : QColor("#9E9E9E"); - QPixmap pm(24, 24); pm.fill(Qt::transparent); + const int size = MemberListModel::kAvatarSize; + QPixmap pm(size, size); pm.fill(Qt::transparent); QPainter p(&pm); p.setRenderHint(QPainter::Antialiasing); p.setBrush(c); p.setPen(Qt::NoPen); - p.drawEllipse(2, 2, 20, 20); + p.drawEllipse(0, 0, size, size); p.setPen(Qt::white); - QFont f; f.setBold(true); f.setPixelSize(12); + QFont f; f.setBold(true); f.setPixelSize(size / 2); p.setFont(f); - p.drawText(QRect(0, 0, 24, 24), Qt::AlignCenter, item.name.left(1)); + p.drawText(QRect(0, 0, size, size), Qt::AlignCenter, item.name.left(1)); p.end(); item.avatar = pm; } diff --git a/tools/chatgui/src/memberlistmodel.h b/tools/chatgui/src/memberlistmodel.h index b0901df8..5aad3b03 100644 --- a/tools/chatgui/src/memberlistmodel.h +++ b/tools/chatgui/src/memberlistmodel.h @@ -27,6 +27,10 @@ struct MemberListItem { class MemberListModel : public QAbstractListModel { Q_OBJECT public: + /* Высота строки 36 px, между аватарками остаётся 2 px. */ + static constexpr int kRowHeight = 36; + static constexpr int kAvatarSize = kRowHeight - 2; + explicit MemberListModel(QObject* parent = nullptr); int rowCount(const QModelIndex& parent = QModelIndex()) const override; diff --git a/tools/chatgui/src/messagedelegate.cpp b/tools/chatgui/src/messagedelegate.cpp index e0c48e13..a8c6a796 100644 --- a/tools/chatgui/src/messagedelegate.cpp +++ b/tools/chatgui/src/messagedelegate.cpp @@ -83,7 +83,9 @@ QString MessageDelegate::linkAt(const QStyleOptionViewItem& option, const QModel } MessageDelegate::MessageDelegate(QObject *parent) - : QStyledItemDelegate(parent) {} + : QStyledItemDelegate(parent) { + GUI_DEBUG("MessageDelegate: avatar size=%dpx", kAvatar); +} struct VoicePlayState { uint64_t playbackId = 0; @@ -442,7 +444,7 @@ MessageDelegate::Layout MessageDelegate::calcLayout( } if (!L.narrow) { - int avatarY = L.bubbleRect.bottom() - kAvatar; + int avatarY = qMax(0, L.bubbleRect.bottom() + 1 - kAvatar); if (!L.isOutgoing) L.avatarRect = QRect(kMarginH, avatarY, kAvatar, kAvatar); else @@ -484,7 +486,7 @@ MessageDelegate::Layout MessageDelegate::calcLayout( L.videoDurBadgeRect = QRect(bx + thW - 66, thH - 26, 58, 18); if (!L.narrow) { - int avatarY = L.bubbleRect.bottom() - kAvatar; + int avatarY = qMax(0, L.bubbleRect.bottom() + 1 - kAvatar); if (!L.isOutgoing) L.avatarRect = QRect(kMarginH, avatarY, kAvatar, kAvatar); else @@ -519,7 +521,7 @@ MessageDelegate::Layout MessageDelegate::calcLayout( L.imageBadgeRect = QRect(bx + thW - 150, thH - 26, 142, 18); if (!L.narrow) { - int avatarY = L.bubbleRect.bottom() - kAvatar; + int avatarY = qMax(0, L.bubbleRect.bottom() + 1 - kAvatar); if (!L.isOutgoing) L.avatarRect = QRect(kMarginH, avatarY, kAvatar, kAvatar); else @@ -557,7 +559,7 @@ MessageDelegate::Layout MessageDelegate::calcLayout( L.statusRect = QRect(bx + kPadH + ih + 8 - 48, kPadTop + th + 2, L.bubbleWidth - 2*kPadH - ih - 8 + 48 - 40, th); if (!L.narrow) { - int avatarY = L.bubbleRect.bottom() - kAvatar; + int avatarY = qMax(0, L.bubbleRect.bottom() + 1 - kAvatar); if (!L.isOutgoing) L.avatarRect = QRect(kMarginH, avatarY, kAvatar, kAvatar); else @@ -687,7 +689,7 @@ MessageDelegate::Layout MessageDelegate::calcLayout( L.statusRect = QRect(txRect, contentTop + textH + 2, textW, kStatusH); if (!L.narrow) { - int avatarY = L.bubbleRect.bottom() - kAvatar; + int avatarY = qMax(0, L.bubbleRect.bottom() + 1 - kAvatar); if (!L.isOutgoing) L.avatarRect = QRect(kMarginH, avatarY, kAvatar, kAvatar); else @@ -1617,6 +1619,7 @@ void MessageDelegate::drawAvatar(QPainter *p, const Layout &L, p->setRenderHint(QPainter::Antialiasing); QPainterPath clip; clip.addEllipse(L.avatarRect); + p->setRenderHint(QPainter::SmoothPixmapTransform); p->setClipPath(clip); p->drawPixmap(L.avatarRect, av); p->restore(); diff --git a/tools/chatgui/src/messagedelegate.h b/tools/chatgui/src/messagedelegate.h index c1d7dc86..cab3d54f 100644 --- a/tools/chatgui/src/messagedelegate.h +++ b/tools/chatgui/src/messagedelegate.h @@ -52,6 +52,8 @@ enum MessageDataRole { class MessageDelegate : public QStyledItemDelegate { Q_OBJECT public: + static constexpr int kAvatar = 54; + explicit MessageDelegate(QObject *parent = nullptr); void paint(QPainter *painter, const QStyleOptionViewItem &option, @@ -128,7 +130,6 @@ private: void drawAvatar(QPainter *p, const Layout &L, const QModelIndex &index) const; - static constexpr int kAvatar = 36; static constexpr int kGap = 8; static constexpr int kRadius = 10; static constexpr int kPadH = 12; diff --git a/tools/chatgui/src/messagelist.cpp b/tools/chatgui/src/messagelist.cpp index d6dcc9ac..743b0164 100644 --- a/tools/chatgui/src/messagelist.cpp +++ b/tools/chatgui/src/messagelist.cpp @@ -77,7 +77,7 @@ static QIcon makeRadioIcon(const QColor& color) { return icon; } -static QPixmap makeAvatar(const QColor &color, const QString &letter, int size = 36) { +static QPixmap makeAvatar(const QColor &color, const QString &letter, int size = MessageDelegate::kAvatar) { QPixmap pix(size, size); pix.fill(Qt::transparent); QPainter p(&pix);