From 13663ad5f894f035a47efd5704e84f07d68b3df2 Mon Sep 17 00:00:00 2001 From: redsky17 Date: Fri, 8 Feb 2019 01:58:00 +0000 Subject: [PATCH] Improve color generation performance Colors are generated asynchronously now and the TimelineItem is updated when the color generation finishes. This allows the UI to stay responsive while new colors are being generated. --- src/Utils.cpp | 9 ----- src/timeline/TimelineItem.cpp | 64 +++++++++++++++++++++++++---------- src/timeline/TimelineItem.h | 7 ++++ 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 1d1dbeb2..0d3e9384 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -399,7 +399,6 @@ utils::hashQString(const QString &input) QString utils::generateContrastingHexColor(const QString &input, const QString &background) { - nhlog::ui()->debug("Background hex {}", background.toStdString()); const QColor backgroundCol(background); const qreal backgroundLum = luminance(background); @@ -407,8 +406,6 @@ utils::generateContrastingHexColor(const QString &input, const QString &backgrou auto hash = hashQString(input); // create a hue value based on the hash of the input. auto userHue = qAbs(hash % 360); - nhlog::ui()->debug( - "User Hue {} : {}", input.toStdString(), QString::number(userHue).toStdString()); // start with moderate saturation and lightness values. auto sat = 220; auto lightness = 125; @@ -430,7 +427,6 @@ utils::generateContrastingHexColor(const QString &input, const QString &backgrou // saturation instead. if (lightness == 242 || lightness == 13) { qreal newSat = qBound(26.0, sat * 1.25, 242.0); - nhlog::ui()->info("newSat {}", QString::number(newSat).toStdString()); inputColor.setHsl(userHue, qFloor(newSat), lightness); auto tmpLum = luminance(inputColor); @@ -477,11 +473,6 @@ utils::generateContrastingHexColor(const QString &input, const QString &backgrou // get the hex value of the generated color. auto colorHex = inputColor.name(); - nhlog::ui()->debug("Hex Generated for {}: [hex: {}, contrast: {}, luminance: {}]", - input.toStdString(), - colorHex.toStdString(), - QString::number(contrast).toStdString(), - QString::number(lum).toStdString()); return colorHex; } diff --git a/src/timeline/TimelineItem.cpp b/src/timeline/TimelineItem.cpp index 1c90eade..d23dbf49 100644 --- a/src/timeline/TimelineItem.cpp +++ b/src/timeline/TimelineItem.cpp @@ -14,6 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include @@ -197,6 +198,12 @@ TimelineItem::init() connect(markAsRead_, &QAction::triggered, this, &TimelineItem::sendReadReceipt); connect(viewRawMessage_, &QAction::triggered, this, &TimelineItem::openRawMessageViewer); + colorGenerating_ = new QFutureWatcher(this); + connect(colorGenerating_, + &QFutureWatcher::finished, + this, + &TimelineItem::finishedGeneratingColor); + topLayout_ = new QHBoxLayout(this); mainLayout_ = new QVBoxLayout; messageLayout_ = new QHBoxLayout; @@ -557,6 +564,12 @@ TimelineItem::TimelineItem(const mtx::events::RoomEvent adjustMessageLayout(); } +TimelineItem::~TimelineItem() +{ + colorGenerating_->cancel(); + colorGenerating_->waitForFinished(); +} + void TimelineItem::markSent() { @@ -607,16 +620,39 @@ TimelineItem::generateBody(const QString &body) void TimelineItem::refreshAuthorColor() { + // Cancel and wait if we are already generating the color. + if (colorGenerating_->isRunning()) { + colorGenerating_->cancel(); + colorGenerating_->waitForFinished(); + } if (userName_) { + // generate user's unique color. + std::function generate = [this]() { + QString userColor = utils::generateContrastingHexColor( + userName_->toolTip(), backgroundColor().name()); + return userColor; + }; + QString userColor = Cache::userColor(userName_->toolTip()); + + // If the color is empty, then generate it asynchronously if (userColor.isEmpty()) { - // This attempts to refresh this item since it's not drawn - // which allows us to get the background color accurately. - qApp->style()->polish(this); - // generate user's unique color. - auto backCol = backgroundColor().name(); - userColor = - utils::generateContrastingHexColor(userName_->toolTip(), backCol); + colorGenerating_->setFuture(QtConcurrent::run(generate)); + } else { + userName_->setStyleSheet("QLabel { color : " + userColor + "; }"); + } + } +} + +void +TimelineItem::finishedGeneratingColor() +{ + nhlog::ui()->debug("finishedGeneratingColor for: {}", userName_->toolTip().toStdString()); + QString userColor = colorGenerating_->result(); + + if (!userColor.isEmpty()) { + // another TimelineItem might have inserted in the meantime. + if (Cache::userColor(userName_->toolTip()).isEmpty()) { Cache::insertUserColor(userName_->toolTip(), userColor); } userName_->setStyleSheet("QLabel { color : " + userColor + "; }"); @@ -656,17 +692,9 @@ TimelineItem::generateUserName(const QString &user_id, const QString &displaynam userName_->setAlignment(Qt::AlignLeft | Qt::AlignTop); userName_->setFixedWidth(QFontMetrics(userName_->font()).width(userName_->text())); - // TimelineItem isn't displayed. This forces the QSS to get - // loaded. - QString userColor = Cache::userColor(user_id); - if (userColor.isEmpty()) { - qApp->style()->polish(this); - // generate user's unique color. - auto backCol = backgroundColor().name(); - userColor = utils::generateContrastingHexColor(user_id, backCol); - Cache::insertUserColor(user_id, userColor); - } - userName_->setStyleSheet("QLabel { color : " + userColor + "; }"); + // Set the user color asynchronously if it hasn't been generated yet, + // otherwise this will just set it. + refreshAuthorColor(); auto filter = new UserProfileFilter(user_id, userName_); userName_->installEventFilter(filter); diff --git a/src/timeline/TimelineItem.h b/src/timeline/TimelineItem.h index f81aa658..7bf6a076 100644 --- a/src/timeline/TimelineItem.h +++ b/src/timeline/TimelineItem.h @@ -26,6 +26,8 @@ #include #include +#include + #include "AvatarProvider.h" #include "RoomInfoListItem.h" #include "Utils.h" @@ -204,6 +206,8 @@ public: const QString &room_id, QWidget *parent); + ~TimelineItem(); + void setBackgroundColor(const QColor &color) { backgroundColor_ = color; } QColor backgroundColor() const { return backgroundColor_; } @@ -229,6 +233,7 @@ signals: public slots: void refreshAuthorColor(); + void finishedGeneratingColor(); protected: void paintEvent(QPaintEvent *event) override; @@ -264,6 +269,8 @@ private: //! has been acknowledged by the server. bool isReceived_ = false; + QFutureWatcher *colorGenerating_; + QString replaceEmoji(const QString &body); QString event_id_; QString room_id_;