diff --git a/src/RoomInfoListItem.cc b/src/RoomInfoListItem.cc
index be1b4133..eec53ce4 100644
--- a/src/RoomInfoListItem.cc
+++ b/src/RoomInfoListItem.cc
@@ -24,6 +24,11 @@
#include "RoomState.h"
#include "Theme.h"
+const float RoomInfoListItem::UnreadCountFontRatio = 0.8;
+const float RoomInfoListItem::RoomNameFontRatio = 1.1;
+const float RoomInfoListItem::RoomDescriptionFontRatio = 1.1;
+const float RoomInfoListItem::RoomAvatarLetterFontRatio = 1.8;
+
RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
RoomState state,
QString room_id,
@@ -84,10 +89,9 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
else
p.fillRect(rect(), QColor("#F8FBFE"));
- QFont font("Open Sans", 10);
-
+ QFont font;
QFontMetrics metrics(font);
- p.setFont(font);
+
p.setPen(QColor("#333"));
QRect avatarRegion(Padding, Padding, IconSize, IconSize);
@@ -101,6 +105,9 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
p.setPen(pen);
}
+ font.setPointSize(this->font().pointSize() * RoomNameFontRatio);
+ p.setFont(font);
+
auto name = metrics.elidedText(state_.getName(), Qt::ElideRight, (width() - IconSize - 2 * Padding) * 0.8);
p.drawText(QPoint(2 * Padding + IconSize, Padding + metrics.height()), name);
@@ -109,11 +116,14 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
p.setPen(pen);
}
- double descPercentage = 0.95;
+ double descPercentage = 0.90;
if (unreadMsgCount_ > 0)
descPercentage = 0.8;
+ font.setPointSize(this->font().pointSize() * RoomDescriptionFontRatio);
+ p.setFont(font);
+
auto description = metrics.elidedText(state_.getTopic(), Qt::ElideRight, width() * descPercentage - 2 * Padding - IconSize);
p.drawText(QPoint(2 * Padding + IconSize, bottom_y), description);
}
@@ -131,7 +141,7 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
p.drawEllipse(avatarRegion.center(), IconSize / 2, IconSize / 2);
- font.setPointSize(13);
+ font.setPointSize(this->font().pointSize() * RoomAvatarLetterFontRatio);
p.setFont(font);
p.setPen(QColor("#333"));
p.setBrush(Qt::NoBrush);
@@ -158,13 +168,13 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
if (isPressed_)
brush.setColor(textColor);
+ QFont unreadCountFont;
+ unreadCountFont.setPointSize(this->font().pointSize() * UnreadCountFontRatio);
+ unreadCountFont.setBold(true);
+
p.setBrush(brush);
p.setPen(Qt::NoPen);
-
- QFont msgFont("Open Sans", 8);
- msgFont.setStyleName("Bold");
-
- p.setFont(msgFont);
+ p.setFont(unreadCountFont);
int diameter = 20;
diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc
index cf8d5e85..12ebcfde 100644
--- a/src/TimelineItem.cc
+++ b/src/TimelineItem.cc
@@ -19,6 +19,7 @@
#include <QDebug>
#include <QFontDatabase>
#include <QRegExp>
+#include <QTextEdit>
#include "AvatarProvider.h"
#include "ImageItem.h"
@@ -38,24 +39,35 @@ void TimelineItem::init()
userName_ = nullptr;
body_ = nullptr;
- QFontDatabase db;
-
- bodyFont_ = db.font("Open Sans", "Regular", 10);
- usernameFont_ = db.font("Open Sans", "Bold", 10);
- timestampFont_ = db.font("Open Sans", "Regular", 7);
+ // Initialize layout spacing variables based on the current font.
+ QFontMetrics fm(this->font());
+ const int baseWidth = fm.width('A');
+ MessageMargin = baseWidth * 1.5;
topLayout_ = new QHBoxLayout(this);
sideLayout_ = new QVBoxLayout();
mainLayout_ = new QVBoxLayout();
headerLayout_ = new QHBoxLayout();
- topLayout_->setContentsMargins(7, 0, 0, 0);
- topLayout_->setSpacing(9);
+ topLayout_->setContentsMargins(MessageMargin, MessageMargin, 0, 0);
+ topLayout_->setSpacing(0);
topLayout_->addLayout(sideLayout_);
topLayout_->addLayout(mainLayout_, 1);
+
+ sideLayout_->setMargin(0);
+ sideLayout_->setSpacing(0);
+
+ mainLayout_->setContentsMargins(baseWidth * 2, 0, 0, 0);
+ mainLayout_->setSpacing(0);
+
+ headerLayout_->setMargin(0);
+ headerLayout_->setSpacing(baseWidth / 2);
}
+/*
+ * For messages created locally. The avatar and the username are displayed.
+ */
TimelineItem::TimelineItem(const QString &userid, const QString &color, QString body, QWidget *parent)
: QWidget(parent)
{
@@ -71,12 +83,13 @@ TimelineItem::TimelineItem(const QString &userid, const QString &color, QString
mainLayout_->addLayout(headerLayout_);
mainLayout_->addWidget(body_);
- mainLayout_->setMargin(0);
- mainLayout_->setSpacing(0);
AvatarProvider::resolve(userid, this);
}
+/*
+ * For messages created locally. Only the text is displayed.
+ */
TimelineItem::TimelineItem(QString body, QWidget *parent)
: QWidget(parent)
{
@@ -90,11 +103,15 @@ TimelineItem::TimelineItem(QString body, QWidget *parent)
setupSimpleLayout();
mainLayout_->addWidget(body_);
- mainLayout_->setMargin(0);
- mainLayout_->setSpacing(2);
}
-TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, const QString &color, QWidget *parent)
+/*
+ * Used to display images. The avatar and the username are displayed.
+ */
+TimelineItem::TimelineItem(ImageItem *image,
+ const events::MessageEvent<msgs::Image> &event,
+ const QString &color,
+ QWidget *parent)
: QWidget(parent)
{
init();
@@ -113,12 +130,13 @@ TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Im
mainLayout_->addLayout(headerLayout_);
mainLayout_->addLayout(imageLayout);
- mainLayout_->setContentsMargins(0, 4, 0, 0);
- mainLayout_->setSpacing(0);
AvatarProvider::resolve(event.sender(), this);
}
+/*
+ * Used to display images. Only the image is displayed.
+ */
TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, QWidget *parent)
: QWidget(parent)
{
@@ -135,10 +153,11 @@ TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Im
imageLayout->addStretch(1);
mainLayout_->addLayout(imageLayout);
- mainLayout_->setContentsMargins(0, 4, 0, 0);
- mainLayout_->setSpacing(2);
}
+/*
+ * Used to display remote notice messages.
+ */
TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, bool with_sender, const QString &color, QWidget *parent)
: QWidget(parent)
{
@@ -159,22 +178,19 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, bool
setupAvatarLayout(displayName);
mainLayout_->addLayout(headerLayout_);
- mainLayout_->addWidget(body_);
- mainLayout_->setMargin(0);
- mainLayout_->setSpacing(0);
AvatarProvider::resolve(event.sender(), this);
} else {
generateBody(body);
-
setupSimpleLayout();
-
- mainLayout_->addWidget(body_);
- mainLayout_->setMargin(0);
- mainLayout_->setSpacing(2);
}
+
+ mainLayout_->addWidget(body_);
}
+/*
+ * Used to display remote text messages.
+ */
TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool with_sender, const QString &color, QWidget *parent)
: QWidget(parent)
{
@@ -189,37 +205,30 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool w
if (with_sender) {
auto displayName = TimelineViewManager::displayName(event.sender());
- generateBody(displayName, color, body);
+ generateBody(displayName, color, body);
setupAvatarLayout(displayName);
mainLayout_->addLayout(headerLayout_);
- mainLayout_->addWidget(body_);
- mainLayout_->setMargin(0);
- mainLayout_->setSpacing(0);
AvatarProvider::resolve(event.sender(), this);
} else {
generateBody(body);
-
setupSimpleLayout();
-
- mainLayout_->addWidget(body_);
- mainLayout_->setMargin(0);
- mainLayout_->setSpacing(2);
}
+
+ mainLayout_->addWidget(body_);
}
// Only the body is displayed.
void TimelineItem::generateBody(const QString &body)
{
- QString content("<span style=\"color: #171919;\">%1</span>");
+ QString content("<span style=\"color: black;\"> %1 </span>");
body_ = new QLabel(this);
body_->setWordWrap(true);
- body_->setFont(bodyFont_);
body_->setText(content.arg(replaceEmoji(body)));
- body_->setAlignment(Qt::AlignTop);
+ body_->setMargin(0);
body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction);
body_->setOpenExternalLinks(true);
@@ -237,32 +246,38 @@ void TimelineItem::generateBody(const QString &userid, const QString &color, con
QString userContent("<span style=\"color: %1\"> %2 </span>");
QString bodyContent("<span style=\"color: #171717;\"> %1 </span>");
+ QFont usernameFont;
+ usernameFont.setBold(true);
+
userName_ = new QLabel(this);
- userName_->setFont(usernameFont_);
+ userName_->setFont(usernameFont);
userName_->setText(userContent.arg(color).arg(sender));
- userName_->setAlignment(Qt::AlignTop);
if (body.isEmpty())
return;
body_ = new QLabel(this);
- body_->setFont(bodyFont_);
body_->setWordWrap(true);
- body_->setAlignment(Qt::AlignTop);
body_->setText(bodyContent.arg(replaceEmoji(body)));
body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction);
body_->setOpenExternalLinks(true);
+ body_->setMargin(0);
}
void TimelineItem::generateTimestamp(const QDateTime &time)
{
QString msg("<span style=\"color: #5d6565;\"> %1 </span>");
+ QFont timestampFont;
+ timestampFont.setPointSize(this->font().pointSize() * TimestampFontRatio);
+
+ QFontMetrics fm(timestampFont);
+ int topMargin = QFontMetrics(this->font()).height() - fm.height();
+
timestamp_ = new QLabel(this);
- timestamp_->setFont(timestampFont_);
+ timestamp_->setFont(timestampFont);
timestamp_->setText(msg.arg(time.toString("HH:mm")));
- timestamp_->setAlignment(Qt::AlignTop);
- timestamp_->setStyleSheet("margin-top: 2px;");
+ timestamp_->setContentsMargins(0, topMargin, 0, 0);
}
QString TimelineItem::replaceEmoji(const QString &body)
@@ -274,7 +289,7 @@ QString TimelineItem::replaceEmoji(const QString &body)
// TODO: Be more precise here.
if (code > 9000)
- fmtBody += "<span style=\"font-family: Emoji One; font-size: 16px\">" + QString(c) + "</span>";
+ fmtBody += "<span style=\"font-family: Emoji One; font-size: 14px\">" + QString(c) + "</span>";
else
fmtBody += c;
}
@@ -284,13 +299,13 @@ QString TimelineItem::replaceEmoji(const QString &body)
void TimelineItem::setupAvatarLayout(const QString &userName)
{
- topLayout_->setContentsMargins(7, 6, 0, 0);
+ topLayout_->setContentsMargins(MessageMargin, MessageMargin, 0, 0);
userAvatar_ = new Avatar(this);
userAvatar_->setLetter(QChar(userName[0]).toUpper());
userAvatar_->setBackgroundColor(QColor("#eee"));
userAvatar_->setTextColor(QColor("black"));
- userAvatar_->setSize(32);
+ userAvatar_->setSize(AvatarSize);
// TODO: The provided user name should be a UserId class
if (userName[0] == '@' && userName.size() > 1)
@@ -298,20 +313,29 @@ void TimelineItem::setupAvatarLayout(const QString &userName)
sideLayout_->addWidget(userAvatar_);
sideLayout_->addStretch(1);
- sideLayout_->setMargin(0);
- sideLayout_->setSpacing(0);
headerLayout_->addWidget(userName_);
headerLayout_->addWidget(timestamp_, 1);
- headerLayout_->setMargin(0);
}
void TimelineItem::setupSimpleLayout()
{
sideLayout_->addWidget(timestamp_);
- sideLayout_->addStretch(1);
- topLayout_->setContentsMargins(9, 0, 0, 0);
+ // Keep only the time in plain text.
+ QTextEdit htmlText(timestamp_->text());
+ QString plainText = htmlText.toPlainText();
+
+ // Align the end of the avatar bubble with the end of the timestamp for
+ // messages with and without avatar. Otherwise their bodies would not be aligned.
+ int timestampWidth = timestamp_->fontMetrics().boundingRect(plainText).width();
+ int offset = std::max(0, AvatarSize - timestampWidth) / 2;
+
+ int defaultFontHeight = QFontMetrics(this->font()).height();
+
+ timestamp_->setAlignment(Qt::AlignTop);
+ timestamp_->setContentsMargins(offset, defaultFontHeight - timestamp_->fontMetrics().height(), offset, 0);
+ topLayout_->setContentsMargins(MessageMargin, MessageMargin / 3, 0, 0);
}
void TimelineItem::setUserAvatar(const QImage &avatar)
|