Remove flickering by updating auto-complete menu items in-place

Instead of deleting the current items and creating new ones.
This commit is contained in:
Konstantinos Sideris 2018-05-03 17:29:02 +03:00
parent d6ac72ab3f
commit 7dab863738
2 changed files with 105 additions and 21 deletions

View file

@ -53,11 +53,14 @@ class UserItem : public PopupItem
public: public:
UserItem(QWidget *parent, const QString &user_id); UserItem(QWidget *parent, const QString &user_id);
QString selectedText() const { return userId_; } QString selectedText() const { return userId_; }
void updateItem(const QString &user_id);
protected: protected:
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
private: private:
void resolveAvatar(const QString &user_id);
QLabel *userName_; QLabel *userName_;
QString userId_; QString userId_;
}; };
@ -69,6 +72,7 @@ class RoomItem : public PopupItem
public: public:
RoomItem(QWidget *parent, const RoomSearchResult &res); RoomItem(QWidget *parent, const RoomSearchResult &res);
QString selectedText() const { return roomId_; } QString selectedText() const { return roomId_; }
void updateItem(const RoomSearchResult &res);
protected: protected:
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
@ -124,12 +128,16 @@ private:
void resetSelection() { selectedItem_ = -1; } void resetSelection() { selectedItem_ = -1; }
void selectFirstItem() { selectedItem_ = 0; } void selectFirstItem() { selectedItem_ = 0; }
void selectLastItem() { selectedItem_ = layout_->count() - 1; } void selectLastItem() { selectedItem_ = layout_->count() - 1; }
void removeItems() void removeLayoutItemsAfter(size_t startingPos)
{ {
size_t posToRemove = layout_->count() - 1;
QLayoutItem *item; QLayoutItem *item;
while ((item = layout_->takeAt(0)) != 0) { while (startingPos <= posToRemove && (item = layout_->takeAt(posToRemove)) != 0) {
delete item->widget(); delete item->widget();
delete item; delete item;
posToRemove = layout_->count() - 1;
} }
} }

View file

@ -5,7 +5,6 @@
#include "SuggestionsPopup.hpp" #include "SuggestionsPopup.hpp"
#include "Utils.h" #include "Utils.h"
#include <QDebug>
#include <QPaintEvent> #include <QPaintEvent>
#include <QPainter> #include <QPainter>
#include <QStyleOption> #include <QStyleOption>
@ -60,10 +59,39 @@ UserItem::UserItem(QWidget *parent, const QString &user_id)
topLayout_->addWidget(avatar_); topLayout_->addWidget(avatar_);
topLayout_->addWidget(userName_, 1); topLayout_->addWidget(userName_, 1);
AvatarProvider::resolve(ChatPage::instance()->currentRoom(), resolveAvatar(user_id);
userId_, }
this,
[this](const QImage &img) { avatar_->setImage(img); }); void
UserItem::updateItem(const QString &user_id)
{
userId_ = user_id;
auto displayName = Cache::displayName(ChatPage::instance()->currentRoom(), userId_);
// If it's a matrix id we use the second letter.
if (displayName.size() > 1 && displayName.at(0) == '@')
avatar_->setLetter(QChar(displayName.at(1)));
else
avatar_->setLetter(utils::firstChar(displayName));
userName_->setText(displayName);
resolveAvatar(user_id);
}
void
UserItem::resolveAvatar(const QString &user_id)
{
AvatarProvider::resolve(
ChatPage::instance()->currentRoom(), userId_, this, [this, user_id](const QImage &img) {
// The user on the widget when the avatar is resolved,
// might be different from the user that made the call.
if (user_id == userId_)
avatar_->setImage(img);
else
// We try to resolve the avatar again.
resolveAvatar(userId_);
});
} }
void void
@ -96,6 +124,24 @@ RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
avatar_->setImage(res.img); avatar_->setImage(res.img);
} }
void
RoomItem::updateItem(const RoomSearchResult &result)
{
roomId_ = QString::fromStdString(std::move(result.room_id));
auto name =
QFontMetrics(QFont()).elidedText(QString::fromStdString(std::move(result.info.name)),
Qt::ElideRight,
parentWidget()->width() - 10);
roomName_->setText(name);
if (!result.img.isNull())
avatar_->setImage(result.img);
else
avatar_->setLetter(utils::firstChar(name));
}
void void
RoomItem::mousePressEvent(QMouseEvent *event) RoomItem::mousePressEvent(QMouseEvent *event)
{ {
@ -119,17 +165,33 @@ SuggestionsPopup::SuggestionsPopup(QWidget *parent)
void void
SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms) SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms)
{ {
removeItems();
if (rooms.empty()) { if (rooms.empty()) {
hide(); hide();
return; return;
} }
for (const auto &r : rooms) { const size_t layoutCount = layout_->count();
auto room = new RoomItem(this, r); const size_t roomCount = rooms.size();
layout_->addWidget(room);
connect(room, &RoomItem::clicked, this, &SuggestionsPopup::itemSelected); // Remove the extra widgets from the layout.
if (roomCount < layoutCount)
removeLayoutItemsAfter(roomCount - 1);
for (size_t i = 0; i < roomCount; ++i) {
auto item = layout_->itemAt(i);
// Create a new widget if there isn't already one in that
// layout position.
if (!item) {
auto room = new RoomItem(this, rooms.at(i));
connect(room, &RoomItem::clicked, this, &SuggestionsPopup::itemSelected);
layout_->addWidget(room);
} else {
// Update the current widget with the new data.
auto room = qobject_cast<RoomItem *>(item->widget());
if (room)
room->updateItem(rooms.at(i));
}
} }
resetSelection(); resetSelection();
@ -143,24 +205,38 @@ SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms)
void void
SuggestionsPopup::addUsers(const QVector<SearchResult> &users) SuggestionsPopup::addUsers(const QVector<SearchResult> &users)
{ {
removeItems();
if (users.isEmpty()) { if (users.isEmpty()) {
hide(); hide();
return; return;
} }
for (const auto &u : users) { const size_t layoutCount = layout_->count();
auto user = new UserItem(this, u.user_id); const size_t userCount = users.size();
layout_->addWidget(user);
connect(user, &UserItem::clicked, this, &SuggestionsPopup::itemSelected); // Remove the extra widgets from the layout.
if (userCount < layoutCount)
removeLayoutItemsAfter(userCount - 1);
for (size_t i = 0; i < userCount; ++i) {
auto item = layout_->itemAt(i);
// Create a new widget if there isn't already one in that
// layout position.
if (!item) {
auto user = new UserItem(this, users.at(i).user_id);
connect(user, &UserItem::clicked, this, &SuggestionsPopup::itemSelected);
layout_->addWidget(user);
} else {
// Update the current widget with the new data.
auto userWidget = qobject_cast<UserItem *>(item->widget());
if (userWidget)
userWidget->updateItem(users.at(i).user_id);
}
} }
resetSelection(); resetSelection();
adjustSize(); adjustSize();
resize(geometry().width(), 40 * users.size());
selectNextSuggestion(); selectNextSuggestion();
} }