Remove hardcoded font sizes, margins etc

- Fixes small font issue on MacOs
This commit is contained in:
Konstantinos Sideris 2017-07-01 12:46:58 +03:00
parent 82b48d926d
commit 730a56f58e
5 changed files with 132 additions and 69 deletions

View file

@ -1,23 +1,45 @@
SRC := $(shell find include src -type f -type f \( -iname "*.cc" -o -iname "*.h" \)) SRC := $(shell find include src -type f -type f \( -iname "*.cc" -o -iname "*.h" \))
# Linux specific helpers
debug: debug:
@cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug @cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug
@cmake --build build @cmake --build build
release-debug: release-debug:
@cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo @cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
@cmake --build build @cmake --build build
test:
@cmake -DBUILD_TESTS=ON -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
@cmake --build build
@cd build && GTEST_COLOR=1 ctest --verbose
# MacOS specific helpers
mdebug:
@cmake -DBUILD_TESTS=OFF \
-H. \
-GNinja \
-Bbuild \
-DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 \
-DCMAKE_BUILD_TYPE=Debug
@cmake --build build
mrelease:
@cmake -DBUILD_TESTS=OFF \
-H. \
-GNinja \
-Bbuild \
-DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 \
-DCMAKE_BUILD_TYPE=RelWithDebInfo
@cmake --build build
run: run:
@./build/nheko @./build/nheko
lint: lint:
@clang-format -i $(SRC) @clang-format -i $(SRC)
test:
@cmake -DBUILD_TESTS=ON -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
@cmake --build build
@cd build && GTEST_COLOR=1 ctest --verbose
clean: clean:
rm -rf build rm -rf build

View file

@ -75,6 +75,12 @@ private:
QPixmap roomAvatar_; QPixmap roomAvatar_;
// Sizes are relative to the default font size of the Widget.
static const float UnreadCountFontRatio;
static const float RoomNameFontRatio;
static const float RoomDescriptionFontRatio;
static const float RoomAvatarLetterFontRatio;
Menu *menu_; Menu *menu_;
QAction *toggleNotifications_; QAction *toggleNotifications_;

View file

@ -69,13 +69,14 @@ private:
QHBoxLayout *headerLayout_; // Username (&) Timestamp QHBoxLayout *headerLayout_; // Username (&) Timestamp
int MessageMargin;
const int AvatarSize = 36;
const float TimestampFontRatio = 0.8;
Avatar *userAvatar_; Avatar *userAvatar_;
QLabel *timestamp_; QLabel *timestamp_;
QLabel *userName_; QLabel *userName_;
QLabel *body_; QLabel *body_;
QFont bodyFont_;
QFont usernameFont_;
QFont timestampFont_;
}; };

View file

@ -24,6 +24,11 @@
#include "RoomState.h" #include "RoomState.h"
#include "Theme.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, RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
RoomState state, RoomState state,
QString room_id, QString room_id,
@ -84,10 +89,9 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
else else
p.fillRect(rect(), QColor("#F8FBFE")); p.fillRect(rect(), QColor("#F8FBFE"));
QFont font("Open Sans", 10); QFont font;
QFontMetrics metrics(font); QFontMetrics metrics(font);
p.setFont(font);
p.setPen(QColor("#333")); p.setPen(QColor("#333"));
QRect avatarRegion(Padding, Padding, IconSize, IconSize); QRect avatarRegion(Padding, Padding, IconSize, IconSize);
@ -101,6 +105,9 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
p.setPen(pen); 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); auto name = metrics.elidedText(state_.getName(), Qt::ElideRight, (width() - IconSize - 2 * Padding) * 0.8);
p.drawText(QPoint(2 * Padding + IconSize, Padding + metrics.height()), name); p.drawText(QPoint(2 * Padding + IconSize, Padding + metrics.height()), name);
@ -109,11 +116,14 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
p.setPen(pen); p.setPen(pen);
} }
double descPercentage = 0.95; double descPercentage = 0.90;
if (unreadMsgCount_ > 0) if (unreadMsgCount_ > 0)
descPercentage = 0.8; 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); auto description = metrics.elidedText(state_.getTopic(), Qt::ElideRight, width() * descPercentage - 2 * Padding - IconSize);
p.drawText(QPoint(2 * Padding + IconSize, bottom_y), description); 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); p.drawEllipse(avatarRegion.center(), IconSize / 2, IconSize / 2);
font.setPointSize(13); font.setPointSize(this->font().pointSize() * RoomAvatarLetterFontRatio);
p.setFont(font); p.setFont(font);
p.setPen(QColor("#333")); p.setPen(QColor("#333"));
p.setBrush(Qt::NoBrush); p.setBrush(Qt::NoBrush);
@ -158,13 +168,13 @@ void RoomInfoListItem::paintEvent(QPaintEvent *event)
if (isPressed_) if (isPressed_)
brush.setColor(textColor); brush.setColor(textColor);
QFont unreadCountFont;
unreadCountFont.setPointSize(this->font().pointSize() * UnreadCountFontRatio);
unreadCountFont.setBold(true);
p.setBrush(brush); p.setBrush(brush);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setFont(unreadCountFont);
QFont msgFont("Open Sans", 8);
msgFont.setStyleName("Bold");
p.setFont(msgFont);
int diameter = 20; int diameter = 20;

View file

@ -19,6 +19,7 @@
#include <QDebug> #include <QDebug>
#include <QFontDatabase> #include <QFontDatabase>
#include <QRegExp> #include <QRegExp>
#include <QTextEdit>
#include "AvatarProvider.h" #include "AvatarProvider.h"
#include "ImageItem.h" #include "ImageItem.h"
@ -38,24 +39,35 @@ void TimelineItem::init()
userName_ = nullptr; userName_ = nullptr;
body_ = nullptr; body_ = nullptr;
QFontDatabase db; // Initialize layout spacing variables based on the current font.
QFontMetrics fm(this->font());
bodyFont_ = db.font("Open Sans", "Regular", 10); const int baseWidth = fm.width('A');
usernameFont_ = db.font("Open Sans", "Bold", 10); MessageMargin = baseWidth * 1.5;
timestampFont_ = db.font("Open Sans", "Regular", 7);
topLayout_ = new QHBoxLayout(this); topLayout_ = new QHBoxLayout(this);
sideLayout_ = new QVBoxLayout(); sideLayout_ = new QVBoxLayout();
mainLayout_ = new QVBoxLayout(); mainLayout_ = new QVBoxLayout();
headerLayout_ = new QHBoxLayout(); headerLayout_ = new QHBoxLayout();
topLayout_->setContentsMargins(7, 0, 0, 0); topLayout_->setContentsMargins(MessageMargin, MessageMargin, 0, 0);
topLayout_->setSpacing(9); topLayout_->setSpacing(0);
topLayout_->addLayout(sideLayout_); topLayout_->addLayout(sideLayout_);
topLayout_->addLayout(mainLayout_, 1); 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) TimelineItem::TimelineItem(const QString &userid, const QString &color, QString body, QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
@ -71,12 +83,13 @@ TimelineItem::TimelineItem(const QString &userid, const QString &color, QString
mainLayout_->addLayout(headerLayout_); mainLayout_->addLayout(headerLayout_);
mainLayout_->addWidget(body_); mainLayout_->addWidget(body_);
mainLayout_->setMargin(0);
mainLayout_->setSpacing(0);
AvatarProvider::resolve(userid, this); AvatarProvider::resolve(userid, this);
} }
/*
* For messages created locally. Only the text is displayed.
*/
TimelineItem::TimelineItem(QString body, QWidget *parent) TimelineItem::TimelineItem(QString body, QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
@ -90,11 +103,15 @@ TimelineItem::TimelineItem(QString body, QWidget *parent)
setupSimpleLayout(); setupSimpleLayout();
mainLayout_->addWidget(body_); 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) : QWidget(parent)
{ {
init(); init();
@ -113,12 +130,13 @@ TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Im
mainLayout_->addLayout(headerLayout_); mainLayout_->addLayout(headerLayout_);
mainLayout_->addLayout(imageLayout); mainLayout_->addLayout(imageLayout);
mainLayout_->setContentsMargins(0, 4, 0, 0);
mainLayout_->setSpacing(0);
AvatarProvider::resolve(event.sender(), this); 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) TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
@ -135,10 +153,11 @@ TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Im
imageLayout->addStretch(1); imageLayout->addStretch(1);
mainLayout_->addLayout(imageLayout); 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) TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, bool with_sender, const QString &color, QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
@ -159,22 +178,19 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, bool
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
mainLayout_->addLayout(headerLayout_); mainLayout_->addLayout(headerLayout_);
mainLayout_->addWidget(body_);
mainLayout_->setMargin(0);
mainLayout_->setSpacing(0);
AvatarProvider::resolve(event.sender(), this); AvatarProvider::resolve(event.sender(), this);
} else { } else {
generateBody(body); generateBody(body);
setupSimpleLayout(); setupSimpleLayout();
}
mainLayout_->addWidget(body_); mainLayout_->addWidget(body_);
mainLayout_->setMargin(0);
mainLayout_->setSpacing(2);
}
} }
/*
* Used to display remote text messages.
*/
TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool with_sender, const QString &color, QWidget *parent) TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool with_sender, const QString &color, QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
@ -189,37 +205,30 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool w
if (with_sender) { if (with_sender) {
auto displayName = TimelineViewManager::displayName(event.sender()); auto displayName = TimelineViewManager::displayName(event.sender());
generateBody(displayName, color, body);
generateBody(displayName, color, body);
setupAvatarLayout(displayName); setupAvatarLayout(displayName);
mainLayout_->addLayout(headerLayout_); mainLayout_->addLayout(headerLayout_);
mainLayout_->addWidget(body_);
mainLayout_->setMargin(0);
mainLayout_->setSpacing(0);
AvatarProvider::resolve(event.sender(), this); AvatarProvider::resolve(event.sender(), this);
} else { } else {
generateBody(body); generateBody(body);
setupSimpleLayout(); setupSimpleLayout();
}
mainLayout_->addWidget(body_); mainLayout_->addWidget(body_);
mainLayout_->setMargin(0);
mainLayout_->setSpacing(2);
}
} }
// Only the body is displayed. // Only the body is displayed.
void TimelineItem::generateBody(const QString &body) 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_ = new QLabel(this);
body_->setWordWrap(true); body_->setWordWrap(true);
body_->setFont(bodyFont_);
body_->setText(content.arg(replaceEmoji(body))); body_->setText(content.arg(replaceEmoji(body)));
body_->setAlignment(Qt::AlignTop); body_->setMargin(0);
body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction);
body_->setOpenExternalLinks(true); 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 userContent("<span style=\"color: %1\"> %2 </span>");
QString bodyContent("<span style=\"color: #171717;\"> %1 </span>"); QString bodyContent("<span style=\"color: #171717;\"> %1 </span>");
QFont usernameFont;
usernameFont.setBold(true);
userName_ = new QLabel(this); userName_ = new QLabel(this);
userName_->setFont(usernameFont_); userName_->setFont(usernameFont);
userName_->setText(userContent.arg(color).arg(sender)); userName_->setText(userContent.arg(color).arg(sender));
userName_->setAlignment(Qt::AlignTop);
if (body.isEmpty()) if (body.isEmpty())
return; return;
body_ = new QLabel(this); body_ = new QLabel(this);
body_->setFont(bodyFont_);
body_->setWordWrap(true); body_->setWordWrap(true);
body_->setAlignment(Qt::AlignTop);
body_->setText(bodyContent.arg(replaceEmoji(body))); body_->setText(bodyContent.arg(replaceEmoji(body)));
body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction); body_->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextBrowserInteraction);
body_->setOpenExternalLinks(true); body_->setOpenExternalLinks(true);
body_->setMargin(0);
} }
void TimelineItem::generateTimestamp(const QDateTime &time) void TimelineItem::generateTimestamp(const QDateTime &time)
{ {
QString msg("<span style=\"color: #5d6565;\"> %1 </span>"); 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_ = new QLabel(this);
timestamp_->setFont(timestampFont_); timestamp_->setFont(timestampFont);
timestamp_->setText(msg.arg(time.toString("HH:mm"))); timestamp_->setText(msg.arg(time.toString("HH:mm")));
timestamp_->setAlignment(Qt::AlignTop); timestamp_->setContentsMargins(0, topMargin, 0, 0);
timestamp_->setStyleSheet("margin-top: 2px;");
} }
QString TimelineItem::replaceEmoji(const QString &body) QString TimelineItem::replaceEmoji(const QString &body)
@ -274,7 +289,7 @@ QString TimelineItem::replaceEmoji(const QString &body)
// TODO: Be more precise here. // TODO: Be more precise here.
if (code > 9000) 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 else
fmtBody += c; fmtBody += c;
} }
@ -284,13 +299,13 @@ QString TimelineItem::replaceEmoji(const QString &body)
void TimelineItem::setupAvatarLayout(const QString &userName) void TimelineItem::setupAvatarLayout(const QString &userName)
{ {
topLayout_->setContentsMargins(7, 6, 0, 0); topLayout_->setContentsMargins(MessageMargin, MessageMargin, 0, 0);
userAvatar_ = new Avatar(this); userAvatar_ = new Avatar(this);
userAvatar_->setLetter(QChar(userName[0]).toUpper()); userAvatar_->setLetter(QChar(userName[0]).toUpper());
userAvatar_->setBackgroundColor(QColor("#eee")); userAvatar_->setBackgroundColor(QColor("#eee"));
userAvatar_->setTextColor(QColor("black")); userAvatar_->setTextColor(QColor("black"));
userAvatar_->setSize(32); userAvatar_->setSize(AvatarSize);
// TODO: The provided user name should be a UserId class // TODO: The provided user name should be a UserId class
if (userName[0] == '@' && userName.size() > 1) if (userName[0] == '@' && userName.size() > 1)
@ -298,20 +313,29 @@ void TimelineItem::setupAvatarLayout(const QString &userName)
sideLayout_->addWidget(userAvatar_); sideLayout_->addWidget(userAvatar_);
sideLayout_->addStretch(1); sideLayout_->addStretch(1);
sideLayout_->setMargin(0);
sideLayout_->setSpacing(0);
headerLayout_->addWidget(userName_); headerLayout_->addWidget(userName_);
headerLayout_->addWidget(timestamp_, 1); headerLayout_->addWidget(timestamp_, 1);
headerLayout_->setMargin(0);
} }
void TimelineItem::setupSimpleLayout() void TimelineItem::setupSimpleLayout()
{ {
sideLayout_->addWidget(timestamp_); 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) void TimelineItem::setUserAvatar(const QImage &avatar)