Add PaintContext for Dialogs::Ui::RowPainter.

This commit is contained in:
John Preston 2022-09-29 11:52:18 +04:00
parent 4724ef91f6
commit 1401b19994
12 changed files with 374 additions and 346 deletions

View file

@ -314,7 +314,7 @@ StickersBox::CounterWidget::CounterWidget(
: RpWidget(parent) {
setAttribute(Qt::WA_TransparentForMouseEvents);
_st.sizeId = Dialogs::Ui::UnreadBadgeInStickersBox;
_st.sizeId = Dialogs::Ui::UnreadBadgeSize::StickersBox;
_st.textTop = st::stickersFeaturedBadgeTextTop;
_st.size = st::stickersFeaturedBadgeSize;
_st.padding = st::stickersFeaturedBadgePadding;

View file

@ -176,7 +176,7 @@ InnerWidget::InnerWidget(
session().data().sendActionManager().animationUpdated(
) | rpl::start_with_next([=](
const Data::SendActionManager::AnimationUpdate &update) {
const auto updateRect = Ui::RowPainter::sendActionAnimationRect(
const auto updateRect = Ui::RowPainter::SendActionAnimationRect(
update.left,
update.width,
update.height,
@ -481,16 +481,17 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
const auto key = row->key();
const auto isActive = (key == active);
const auto isSelected = (key == selected);
Ui::RowPainter::paint(
p,
row,
validateVideoUserpic(row),
_filterId,
fullWidth,
isActive,
isSelected,
ms,
videoPaused);
Ui::RowPainter::Paint(p, row, validateVideoUserpic(row), {
.folder = _openedFolder,
.forum = _openedForum,
.filter = _filterId,
.now = ms,
.width = fullWidth,
.active = isActive,
.selected = isSelected,
.paused = videoPaused,
.narrow = (fullWidth < st::columnMinimalWidthLeft),
});
if (xadd || yadd) {
p.translate(-xadd, -yadd);
}
@ -601,16 +602,17 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
: (from == (isPressed()
? _filteredPressed
: _filteredSelected));
Ui::RowPainter::paint(
p,
_filterResults[from],
validateVideoUserpic(row),
_filterId,
fullWidth,
active,
selected,
ms,
videoPaused);
Ui::RowPainter::Paint(p, row, validateVideoUserpic(row), {
.folder = _openedFolder,
.forum = _openedForum,
.filter = _filterId,
.now = ms,
.width = fullWidth,
.active = active,
.selected = selected,
.paused = videoPaused,
.narrow = (fullWidth < st::columnMinimalWidthLeft),
});
p.translate(0, st::dialogsRowHeight);
}
}
@ -639,14 +641,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
const auto selected = (from == (isPressed()
? _peerSearchPressed
: _peerSearchSelected));
paintPeerSearchResult(
p,
result.get(),
fullWidth,
active,
selected,
ms,
videoPaused);
paintPeerSearchResult(p, result.get(), {
.now = ms,
.width = fullWidth,
.active = active,
.selected = selected,
.paused = videoPaused,
});
p.translate(0, st::dialogsRowHeight);
}
}
@ -702,15 +703,19 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
: (from == (isPressed()
? _searchedPressed
: _searchedSelected));
Ui::RowPainter::paint(
p,
result.get(),
fullWidth,
active,
selected,
ms,
videoPaused,
showUnreadInSearchResults);
Ui::RowPainter::Paint(p, result.get(), {
.folder = _openedFolder,
.forum = _openedForum,
.filter = _filterId,
.now = ms,
.width = fullWidth,
.active = active,
.selected = selected,
.paused = videoPaused,
.search = true,
.narrow = (fullWidth < st::columnMinimalWidthLeft),
.displayUnreadInfo = showUnreadInSearchResults,
});
p.translate(0, st::dialogsRowHeight);
}
}
@ -798,15 +803,17 @@ bool InnerWidget::isSearchResultActive(
void InnerWidget::paintPeerSearchResult(
Painter &p,
not_null<const PeerSearchResult*> result,
int fullWidth,
bool active,
bool selected,
crl::time now,
bool paused) {
QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
if (!active) {
result->row.paintRipple(p, 0, 0, fullWidth);
const Ui::PaintContext &context) {
QRect fullRect(0, 0, context.width, st::dialogsRowHeight);
p.fillRect(
fullRect,
(context.active
? st::dialogsBgActive
: context.selected
? st::dialogsBgOver
: st::dialogsBg));
if (!context.active) {
result->row.paintRipple(p, 0, 0, context.width);
}
auto peer = result->peer;
@ -814,7 +821,7 @@ void InnerWidget::paintPeerSearchResult(
userpicPeer->paintUserpicLeft(p, result->row.userpicView(), st::dialogsPadding.x(), st::dialogsPadding.y(), width(), st::dialogsPhotoSize);
auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding;
auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
auto namewidth = context.width - nameleft - st::dialogsPadding.x();
QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height);
if (result->name.isEmpty()) {
@ -825,52 +832,52 @@ void InnerWidget::paintPeerSearchResult(
}
// draw chat icon
if (auto chatTypeIcon = Ui::ChatTypeIcon(peer, active, selected)) {
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
if (const auto chatTypeIcon = Ui::ChatTypeIcon(peer, context)) {
chatTypeIcon->paint(p, rectForName.topLeft(), context.width);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}
const auto badgeWidth = result->badge.drawGetWidth(
p,
rectForName,
result->name.maxWidth(),
fullWidth,
context.width,
{
.peer = peer,
.verified = (active
.verified = (context.active
? &st::dialogsVerifiedIconActive
: selected
: context.selected
? &st::dialogsVerifiedIconOver
: &st::dialogsVerifiedIcon),
.premium = (active
.premium = (context.active
? &st::dialogsPremiumIconActive
: selected
: context.selected
? &st::dialogsPremiumIconOver
: &st::dialogsPremiumIcon),
.scam = (active
.scam = (context.active
? &st::dialogsScamFgActive
: selected
: context.selected
? &st::dialogsScamFgOver
: &st::dialogsScamFg),
.premiumFg = (active
.premiumFg = (context.active
? &st::dialogsVerifiedIconBgActive
: selected
: context.selected
? &st::dialogsVerifiedIconBgOver
: &st::dialogsVerifiedIconBg),
.preview = (active
.preview = (context.active
? st::dialogsScamFgActive
: selected
: context.selected
? st::windowBgRipple
: st::windowBgOver)->c,
.customEmojiRepaint = [=] { updateSearchResult(peer); },
.now = now,
.paused = paused,
.now = context.now,
.paused = context.paused,
});
rectForName.setWidth(rectForName.width() - badgeWidth);
QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height);
p.setFont(st::dialogsTextFont);
QString username = peer->userName();
if (!active && username.startsWith(_peerSearchQuery, Qt::CaseInsensitive)) {
if (!context.active && username.startsWith(_peerSearchQuery, Qt::CaseInsensitive)) {
auto first = '@' + username.mid(0, _peerSearchQuery.size());
auto second = username.mid(_peerSearchQuery.size());
auto w = st::dialogsTextFont->width(first);
@ -884,11 +891,11 @@ void InnerWidget::paintPeerSearchResult(
p.drawText(tr.left() + w, tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(second, tr.width() - w));
}
} else {
p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFgService);
p.setPen(context.active ? st::dialogsTextFgActive : st::dialogsTextFgService);
p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided('@' + username, tr.width()));
}
p.setPen(active ? st::dialogsTextFgActive : st::dialogsNameFg);
p.setPen(context.active ? st::dialogsTextFgActive : st::dialogsNameFg);
result->name.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
}
@ -974,7 +981,7 @@ void InnerWidget::paintSearchInPeer(
const auto paintUserpic = [&](Painter &p, int x, int y, int size) {
peer->paintUserpicLeft(p, userpic, x, y, width(), size);
};
const auto icon = Ui::ChatTypeIcon(peer, false, false);
const auto icon = Ui::ChatTypeIcon(peer);
paintSearchInFilter(p, paintUserpic, top, icon, text);
}

View file

@ -43,6 +43,7 @@ class Forum;
namespace Dialogs::Ui {
using namespace ::Ui;
class VideoUserpic;
struct PaintContext;
} // namespace Dialogs::Ui
namespace Dialogs {
@ -297,11 +298,7 @@ private:
void paintPeerSearchResult(
Painter &p,
not_null<const PeerSearchResult*> result,
int fullWidth,
bool active,
bool selected,
crl::time now,
bool paused);
const Ui::PaintContext &context);
void paintSearchInChat(Painter &p) const;
void paintSearchInPeer(
Painter &p,

View file

@ -55,15 +55,30 @@ const auto kPsaBadgePrefix = "cloud_lng_badge_psa_";
|| history->peer->asUser()->onlineTill > 0);
}
void PaintRowTopRight(QPainter &p, const QString &text, QRect &rectForName, bool active, bool selected) {
void PaintRowTopRight(
QPainter &p,
const QString &text,
QRect &rectForName,
const PaintContext &context) {
const auto width = st::dialogsDateFont->width(text);
rectForName.setWidth(rectForName.width() - width - st::dialogsDateSkip);
p.setFont(st::dialogsDateFont);
p.setPen(active ? st::dialogsDateFgActive : (selected ? st::dialogsDateFgOver : st::dialogsDateFg));
p.drawText(rectForName.left() + rectForName.width() + st::dialogsDateSkip, rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent, text);
p.setPen(context.active
? st::dialogsDateFgActive
: context.selected
? st::dialogsDateFgOver
: st::dialogsDateFg);
p.drawText(
rectForName.left() + rectForName.width() + st::dialogsDateSkip,
rectForName.top() + st::msgNameFont->height - st::msgDateFont->descent,
text);
}
void PaintRowDate(QPainter &p, QDateTime date, QRect &rectForName, bool active, bool selected) {
void PaintRowDate(
QPainter &p,
QDateTime date,
QRect &rectForName,
const PaintContext &context) {
const auto now = QDateTime::currentDateTime();
const auto &lastTime = date;
const auto nowDate = now.date();
@ -81,18 +96,17 @@ void PaintRowDate(QPainter &p, QDateTime date, QRect &rectForName, bool active,
return QLocale().toString(lastDate, cDateFormat());
}
}();
PaintRowTopRight(p, dt, rectForName, active, selected);
PaintRowTopRight(p, dt, rectForName, context);
}
void PaintNarrowCounter(
QPainter &p,
const PaintContext &context,
bool displayUnreadCounter,
bool displayUnreadMark,
bool displayMentionBadge,
bool displayReactionBadge,
int unreadCount,
bool selected,
bool active,
bool unreadMuted,
bool mentionOrReactionMuted) {
auto skipBeforeMention = 0;
@ -111,8 +125,8 @@ void PaintNarrowCounter(
- st::dialogsUnreadHeight;
UnreadBadgeStyle st;
st.active = active;
st.selected = selected;
st.active = context.active;
st.selected = context.selected;
st.muted = unreadMuted;
const auto badge = PaintUnreadBadge(
p,
@ -134,10 +148,10 @@ void PaintNarrowCounter(
UnreadBadgeStyle st;
st.sizeId = displayMentionBadge
? UnreadBadgeInDialogs
: UnreadBadgeReactionInDialogs;
st.active = active;
st.selected = selected;
? UnreadBadgeSize::Dialogs
: UnreadBadgeSize::ReactionInDialogs;
st.active = context.active;
st.selected = context.selected;
st.muted = mentionOrReactionMuted;
st.padding = 0;
st.textTop = 0;
@ -163,17 +177,15 @@ void PaintNarrowCounter(
int PaintWideCounter(
QPainter &p,
const PaintContext &context,
int texttop,
int availableWidth,
int fullWidth,
bool displayUnreadCounter,
bool displayUnreadMark,
bool displayMentionBadge,
bool displayReactionBadge,
bool displayPinnedIcon,
int unreadCount,
bool active,
bool selected,
bool unreadMuted,
bool mentionOrReactionMuted) {
const auto initial = availableWidth;
@ -181,7 +193,7 @@ int PaintWideCounter(
const auto counter = (unreadCount > 0)
? QString::number(unreadCount)
: QString();
const auto unreadRight = fullWidth
const auto unreadRight = context.width
- st::dialogsPadding.x();
const auto unreadTop = texttop
+ st::dialogsTextFont->ascent
@ -189,8 +201,8 @@ int PaintWideCounter(
- (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
UnreadBadgeStyle st;
st.active = active;
st.selected = selected;
st.active = context.active;
st.selected = context.selected;
st.muted = unreadMuted;
const auto badge = PaintUnreadBadge(
p,
@ -200,21 +212,21 @@ int PaintWideCounter(
st);
availableWidth -= badge.width() + st.padding;
} else if (displayPinnedIcon) {
const auto &icon = active
const auto &icon = context.active
? st::dialogsPinnedIconActive
: selected
: context.selected
? st::dialogsPinnedIconOver
: st::dialogsPinnedIcon;
icon.paint(
p,
fullWidth - st::dialogsPadding.x() - icon.width(),
context.width - st::dialogsPadding.x() - icon.width(),
texttop,
fullWidth);
context.width);
availableWidth -= icon.width() + st::dialogsUnreadPadding;
}
if (displayMentionBadge || displayReactionBadge) {
const auto counter = QString();
const auto unreadRight = fullWidth
const auto unreadRight = context.width
- st::dialogsPadding.x()
- (initial - availableWidth);
const auto unreadTop = texttop
@ -224,10 +236,10 @@ int PaintWideCounter(
UnreadBadgeStyle st;
st.sizeId = displayMentionBadge
? UnreadBadgeInDialogs
: UnreadBadgeReactionInDialogs;
st.active = active;
st.selected = selected;
? UnreadBadgeSize::Dialogs
: UnreadBadgeSize::ReactionInDialogs;
st.active = context.active;
st.selected = context.selected;
st.muted = mentionOrReactionMuted;
st.padding = 0;
st.textTop = 0;
@ -257,62 +269,54 @@ int PaintWideCounter(
void PaintListEntryText(
Painter &p,
QRect rect,
bool active,
bool selected,
not_null<const Row*> row,
crl::time now,
bool paused) {
const PaintContext &context,
QRect rect) {
if (rect.isEmpty()) {
return;
}
row->validateListEntryCache();
p.setFont(st::dialogsTextFont);
p.setPen(active
p.setPen(context.active
? st::dialogsTextFgActive
: selected
: context.selected
? st::dialogsTextFgOver
: st::dialogsTextFg);
row->listEntryCache().draw(p, {
.position = rect.topLeft(),
.availableWidth = rect.width(),
.palette = &(row->folder()
? (active
? (context.active
? st::dialogsTextPaletteArchiveActive
: selected
: context.selected
? st::dialogsTextPaletteArchiveOver
: st::dialogsTextPaletteArchive)
: (active
: (context.active
? st::dialogsTextPaletteActive
: selected
: context.selected
? st::dialogsTextPaletteOver
: st::dialogsTextPalette)),
.spoiler = Text::DefaultSpoilerCache(),
.now = now,
.paused = paused,
.now = context.now,
.paused = context.paused,
.elisionLines = rect.height() / st::dialogsTextFont->height,
});
}
enum class Flag {
Active = 0x01,
Selected = 0x02,
SearchResult = 0x04,
SavedMessages = 0x08,
RepliesMessages = 0x10,
AllowUserOnline = 0x20,
VideoPaused = 0x40,
};
inline constexpr bool is_flag_type(Flag) { return true; }
template <typename PaintItemCallback, typename PaintCounterCallback>
void paintRow(
void PaintRow(
Painter &p,
not_null<const BasicRow*> row,
not_null<Entry*> entry,
Dialogs::Key chat,
VideoUserpic *videoUserpic,
FilterId filterId,
PeerData *from,
Ui::PeerBadge &fromBadge,
Fn<void()> customEmojiRepaint,
@ -321,9 +325,8 @@ void paintRow(
HistoryItem *item,
const Data::Draft *draft,
QDateTime date,
int fullWidth,
const PaintContext &context,
base::flags<Flag> flags,
crl::time ms,
PaintItemCallback &&paintItemCallback,
PaintCounterCallback &&paintCounterCallback) {
const auto supportMode = entry->session().supportMode();
@ -331,19 +334,17 @@ void paintRow(
draft = nullptr;
}
auto active = (flags & Flag::Active);
auto selected = (flags & Flag::Selected);
auto fullRect = QRect(0, 0, fullWidth, st::dialogsRowHeight);
auto bg = active
auto fullRect = QRect(0, 0, context.width, st::dialogsRowHeight);
auto bg = context.active
? st::dialogsBgActive
: (selected
? st::dialogsBgOver
: st::dialogsBg);
auto ripple = active
: context.selected
? st::dialogsBgOver
: st::dialogsBg;
auto ripple = context.active
? st::dialogsRippleBgActive
: st::dialogsRippleBg;
p.fillRect(fullRect, bg);
row->paintRipple(p, 0, 0, fullWidth, &ripple->c);
row->paintRipple(p, 0, 0, context.width, &ripple->c);
const auto history = chat.history();
@ -352,14 +353,14 @@ void paintRow(
p,
st::dialogsPadding.x(),
st::dialogsPadding.y(),
fullWidth,
context.width,
st::dialogsPhotoSize);
} else if (flags & Flag::RepliesMessages) {
EmptyUserpic::PaintRepliesMessages(
p,
st::dialogsPadding.x(),
st::dialogsPadding.y(),
fullWidth,
context.width,
st::dialogsPhotoSize);
} else if (from) {
row->paintUserpic(
@ -367,16 +368,16 @@ void paintRow(
from,
videoUserpic,
(flags & Flag::AllowUserOnline) ? history : nullptr,
ms,
active,
fullWidth,
(flags & Flag::VideoPaused));
context.now,
context.active,
context.width,
context.paused);
} else if (hiddenSenderInfo) {
hiddenSenderInfo->emptyUserpic.paint(
p,
st::dialogsPadding.x(),
st::dialogsPadding.y(),
fullWidth,
context.width,
st::dialogsPhotoSize);
} else {
entry->paintUserpicLeft(
@ -384,21 +385,21 @@ void paintRow(
row->userpicView(),
st::dialogsPadding.x(),
st::dialogsPadding.y(),
fullWidth,
context.width,
st::dialogsPhotoSize);
}
auto nameleft = st::dialogsPadding.x()
+ st::dialogsPhotoSize
+ st::dialogsPhotoPadding;
if (fullWidth <= nameleft) {
if (context.width <= nameleft) {
if (!draft && item && !item->isEmpty()) {
paintCounterCallback();
}
return;
}
auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
auto namewidth = context.width - nameleft - st::dialogsPadding.x();
auto rectForName = QRect(
nameleft,
st::dialogsPadding.y() + st::dialogsNameTop,
@ -406,7 +407,7 @@ void paintRow(
st::msgNameFont->height);
const auto promoted = (history && history->useTopPromotion())
&& !(flags & Flag::SearchResult);
&& !context.search;
if (promoted) {
const auto type = history->topPromotionType();
const auto custom = type.isEmpty()
@ -417,10 +418,10 @@ void paintRow(
: custom.isEmpty()
? tr::lng_badge_psa_default(tr::now)
: custom;
PaintRowTopRight(p, text, rectForName, active, selected);
PaintRowTopRight(p, text, rectForName, context);
} else if (from) {
if (const auto chatTypeIcon = ChatTypeIcon(from, active, selected)) {
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
if (const auto chatTypeIcon = ChatTypeIcon(from, context)) {
chatTypeIcon->paint(p, rectForName.topLeft(), context.width);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}
}
@ -436,33 +437,57 @@ void paintRow(
history->topPromotionMessage(),
DialogTextOptions());
}
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg));
p.setPen(context.active
? st::dialogsTextFgActive
: context.selected
? st::dialogsTextFgOver
: st::dialogsTextFg);
history->cloudDraftTextCache.draw(p, {
.position = { nameleft, texttop },
.availableWidth = availableWidth,
.spoiler = Text::DefaultSpoilerCache(),
.now = ms,
.paused = bool(flags & Flag::VideoPaused),
.now = context.now,
.paused = context.paused,
.elisionLines = 1,
});
} else if (draft
|| (supportMode
&& entry->session().supportHelper().isOccupiedBySomeone(history))) {
if (!promoted) {
PaintRowDate(p, date, rectForName, active, selected);
PaintRowDate(p, date, rectForName, context);
}
auto availableWidth = namewidth;
if (entry->isPinnedDialog(filterId) && (filterId || !entry->fixedOnTopIndex())) {
auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon));
icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth);
if (entry->isPinnedDialog(context.filter)
&& (context.filter || !entry->fixedOnTopIndex())) {
auto &icon = context.active
? st::dialogsPinnedIconActive
: context.selected
? st::dialogsPinnedIconOver
: st::dialogsPinnedIcon;
icon.paint(
p,
context.width - st::dialogsPadding.x() - icon.width(),
texttop,
context.width);
availableWidth -= icon.width() + st::dialogsUnreadPadding;
}
p.setFont(st::dialogsTextFont);
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
auto &color = context.active
? st::dialogsTextFgServiceActive
: context.selected
? st::dialogsTextFgServiceOver
: st::dialogsTextFgService;
if (!ShowSendActionInDialogs(history)
|| !history->sendActionPainter()->paint(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) {
|| !history->sendActionPainter()->paint(
p,
nameleft,
texttop,
availableWidth,
context.width,
color,
context.paused)) {
if (history->cloudDraftTextCache.isEmpty()) {
using namespace TextUtilities;
auto draftWrapped = Text::PlainLink(
@ -494,86 +519,111 @@ void paintRow(
DialogTextOptions(),
context);
}
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg));
p.setPen(context.active
? st::dialogsTextFgActive
: context.selected
? st::dialogsTextFgOver
: st::dialogsTextFg);
history->cloudDraftTextCache.draw(p, {
.position = { nameleft, texttop },
.availableWidth = availableWidth,
.palette = &(supportMode
? (active
? (context.active
? st::dialogsTextPaletteTakenActive
: selected
: context.selected
? st::dialogsTextPaletteTakenOver
: st::dialogsTextPaletteTaken)
: (active
: (context.active
? st::dialogsTextPaletteDraftActive
: selected
: context.selected
? st::dialogsTextPaletteDraftOver
: st::dialogsTextPaletteDraft)),
.spoiler = Text::DefaultSpoilerCache(),
.now = ms,
.paused = bool(flags & Flag::VideoPaused),
.now = context.now,
.paused = context.paused,
.elisionLines = 1,
});
}
} else if (!item) {
auto availableWidth = namewidth;
if (entry->isPinnedDialog(filterId) && (filterId || !entry->fixedOnTopIndex())) {
auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon));
icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth);
if (entry->isPinnedDialog(context.filter)
&& (context.filter || !entry->fixedOnTopIndex())) {
auto &icon = context.active
? st::dialogsPinnedIconActive
: context.selected
? st::dialogsPinnedIconOver
: st::dialogsPinnedIcon;
icon.paint(p, context.width - st::dialogsPadding.x() - icon.width(), texttop, context.width);
availableWidth -= icon.width() + st::dialogsUnreadPadding;
}
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
auto &color = context.active
? st::dialogsTextFgServiceActive
: context.selected
? st::dialogsTextFgServiceOver
: st::dialogsTextFgService;
p.setFont(st::dialogsTextFont);
if (!ShowSendActionInDialogs(history)
|| !history->sendActionPainter()->paint(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) {
|| !history->sendActionPainter()->paint(
p,
nameleft,
texttop,
availableWidth,
context.width,
color,
context.now)) {
// Empty history
}
} else if (!item->isEmpty()) {
if (history && !promoted) {
PaintRowDate(p, date, rectForName, active, selected);
PaintRowDate(p, date, rectForName, context);
}
paintItemCallback(nameleft, namewidth);
} else if (entry->isPinnedDialog(filterId) && (filterId || !entry->fixedOnTopIndex())) {
auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon));
icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth);
} else if (entry->isPinnedDialog(context.filter)
&& (context.filter || !entry->fixedOnTopIndex())) {
auto &icon = context.active
? st::dialogsPinnedIconActive
: context.selected
? st::dialogsPinnedIconOver
: st::dialogsPinnedIcon;
icon.paint(p, context.width - st::dialogsPadding.x() - icon.width(), texttop, context.width);
}
auto sendStateIcon = [&]() -> const style::icon* {
if (draft) {
if (draft->saveRequestId) {
return &(active
return &(context.active
? st::dialogsSendingIconActive
: (selected
? st::dialogsSendingIconOver
: st::dialogsSendingIcon));
: context.selected
? st::dialogsSendingIconOver
: st::dialogsSendingIcon);
}
} else if (item && !item->isEmpty() && item->needCheck()) {
if (!item->isSending() && !item->hasFailed()) {
if (item->unread()) {
return &(active
return &(context.active
? st::dialogsSentIconActive
: (selected
? st::dialogsSentIconOver
: st::dialogsSentIcon));
: context.selected
? st::dialogsSentIconOver
: st::dialogsSentIcon);
}
return &(active
return &(context.active
? st::dialogsReceivedIconActive
: (selected
? st::dialogsReceivedIconOver
: st::dialogsReceivedIcon));
: context.selected
? st::dialogsReceivedIconOver
: st::dialogsReceivedIcon);
}
return &(active
return &(context.active
? st::dialogsSendingIconActive
: (selected
? st::dialogsSendingIconOver
: st::dialogsSendingIcon));
: context.selected
? st::dialogsSendingIconOver
: st::dialogsSendingIcon);
}
return nullptr;
}();
if (sendStateIcon && history) {
rectForName.setWidth(rectForName.width() - st::dialogsSendStateSkip);
sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), fullWidth);
sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), context.width);
}
p.setFont(st::msgNameFont);
@ -585,69 +635,69 @@ void paintRow(
if (textWidth > rectForName.width()) {
text = st::msgNameFont->elided(text, rectForName.width());
}
p.setPen(active
p.setPen(context.active
? st::dialogsNameFgActive
: selected
: context.selected
? st::dialogsNameFgOver
: st::dialogsNameFg);
p.drawTextLeft(rectForName.left(), rectForName.top(), fullWidth, text);
p.drawTextLeft(rectForName.left(), rectForName.top(), context.width, text);
} else if (from) {
if (history && !(flags & Flag::SearchResult)) {
if (history && !context.search) {
const auto badgeWidth = fromBadge.drawGetWidth(
p,
rectForName,
fromName.maxWidth(),
fullWidth,
context.width,
{
.peer = from,
.verified = (active
.verified = (context.active
? &st::dialogsVerifiedIconActive
: selected
: context.selected
? &st::dialogsVerifiedIconOver
: &st::dialogsVerifiedIcon),
.premium = (active
.premium = (context.active
? &st::dialogsPremiumIconActive
: selected
: context.selected
? &st::dialogsPremiumIconOver
: &st::dialogsPremiumIcon),
.scam = (active
.scam = (context.active
? &st::dialogsScamFgActive
: selected
: context.selected
? &st::dialogsScamFgOver
: &st::dialogsScamFg),
.premiumFg = (active
.premiumFg = (context.active
? &st::dialogsVerifiedIconBgActive
: selected
: context.selected
? &st::dialogsVerifiedIconBgOver
: &st::dialogsVerifiedIconBg),
.preview = (active
.preview = (context.active
? st::dialogsScamFgActive
: selected
: context.selected
? st::windowBgRipple
: st::windowBgOver)->c,
.customEmojiRepaint = customEmojiRepaint,
.now = ms,
.paused = bool(flags & Flag::VideoPaused),
.now = context.now,
.paused = context.paused,
});
rectForName.setWidth(rectForName.width() - badgeWidth);
}
p.setPen(active
p.setPen(context.active
? st::dialogsNameFgActive
: selected
: context.selected
? st::dialogsNameFgOver
: st::dialogsNameFg);
fromName.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
} else if (hiddenSenderInfo) {
p.setPen(active
p.setPen(context.active
? st::dialogsNameFgActive
: selected
: context.selected
? st::dialogsNameFgOver
: st::dialogsNameFg);
hiddenSenderInfo->nameText().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
} else {
p.setPen(active
p.setPen(context.active
? st::dialogsNameFgActive
: selected
: context.selected
? st::dialogsArchiveFgOver
: st::dialogsArchiveFg);
auto text = entry->chatListName(); // TODO feed name with emoji
@ -655,7 +705,7 @@ void paintRow(
if (textWidth > rectForName.width()) {
text = st::msgNameFont->elided(text, rectForName.width());
}
p.drawTextLeft(rectForName.left(), rectForName.top(), fullWidth, text);
p.drawTextLeft(rectForName.left(), rectForName.top(), context.width, text);
}
}
@ -667,7 +717,7 @@ class UnreadBadgeStyleData : public Data::AbstractStructure {
public:
UnreadBadgeStyleData();
UnreadBadgeSizeData sizes[UnreadBadgeSizesCount];
UnreadBadgeSizeData sizes[static_cast<int>(UnreadBadgeSize::kCount)];
style::color bg[6] = {
st::dialogsUnreadBg,
st::dialogsUnreadBgOver,
@ -722,11 +772,11 @@ void PaintUnreadBadge(QPainter &p, const QRect &rect, const UnreadBadgeStyle &st
unreadBadgeStyle.createIfNull();
auto badgeData = unreadBadgeStyle->sizes;
if (st.sizeId > 0) {
Assert(st.sizeId < UnreadBadgeSizesCount);
badgeData = &unreadBadgeStyle->sizes[st.sizeId];
if (st.sizeId > UnreadBadgeSize()) {
Assert(st.sizeId < UnreadBadgeSize::kCount);
badgeData = &unreadBadgeStyle->sizes[static_cast<int>(st.sizeId)];
}
auto bg = (st.sizeId == UnreadBadgeReactionInDialogs)
const auto bg = (st.sizeId == UnreadBadgeSize::ReactionInDialogs)
? unreadBadgeStyle->reactionBg[index]
: unreadBadgeStyle->bg[index];
if (badgeData->left[index].isNull()) {
@ -762,25 +812,26 @@ void PaintUnreadBadge(QPainter &p, const QRect &rect, const UnreadBadgeStyle &st
const style::icon *ChatTypeIcon(
not_null<PeerData*> peer,
bool active,
bool selected) {
const PaintContext &context) {
if (peer->isChat() || peer->isMegagroup()) {
return &(active
return &(context.active
? st::dialogsChatIconActive
: (selected ? st::dialogsChatIconOver : st::dialogsChatIcon));
: context.selected
? st::dialogsChatIconOver
: st::dialogsChatIcon);
} else if (peer->isChannel()) {
return &(active
return &(context.active
? st::dialogsChannelIconActive
: (selected
? st::dialogsChannelIconOver
: st::dialogsChannelIcon));
: context.selected
? st::dialogsChannelIconOver
: st::dialogsChannelIcon);
} else if (const auto user = peer->asUser()) {
if (ShowUserBotIcon(user)) {
return &(active
return &(context.active
? st::dialogsBotIconActive
: (selected
? st::dialogsBotIconOver
: st::dialogsBotIcon));
: context.selected
? st::dialogsBotIconOver
: st::dialogsBotIcon);
}
}
return nullptr;
@ -841,16 +892,11 @@ QRect PaintUnreadBadge(
return badge;
}
void RowPainter::paint(
void RowPainter::Paint(
Painter &p,
not_null<const Row*> row,
VideoUserpic *videoUserpic,
FilterId filterId,
int fullWidth,
bool active,
bool selected,
crl::time ms,
bool paused) {
const PaintContext &context) {
const auto entry = row->entry();
const auto history = row->history();
const auto topic = row->topic();
@ -907,46 +953,41 @@ void RowPainter::paint(
&& !displayMentionBadge
&& !displayReactionBadge
&& !displayUnreadMark
&& entry->isPinnedDialog(filterId)
&& (filterId || !entry->fixedOnTopIndex());
&& entry->isPinnedDialog(context.filter)
&& (context.filter || !entry->fixedOnTopIndex());
const auto from = history
? (history->peer->migrateTo()
? history->peer->migrateTo()
: history->peer.get())
: nullptr;
const auto allowUserOnline = (fullWidth >= st::columnMinimalWidthLeft)
const auto allowUserOnline = !context.narrow
|| (!displayUnreadCounter && !displayUnreadMark);
const auto flags = (active ? Flag::Active : Flag(0))
| (selected ? Flag::Selected : Flag(0))
| (allowUserOnline ? Flag::AllowUserOnline : Flag(0))
const auto flags = (allowUserOnline ? Flag::AllowUserOnline : Flag(0))
| (peer && peer->isSelf() ? Flag::SavedMessages : Flag(0))
| (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0))
| (paused ? Flag::VideoPaused : Flag(0));
| (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0));
const auto paintItemCallback = [&](int nameleft, int namewidth) {
const auto texttop = st::dialogsPadding.y()
+ st::msgNameFont->height
+ st::dialogsSkip;
const auto availableWidth = PaintWideCounter(
p,
context,
texttop,
namewidth,
fullWidth,
displayUnreadCounter,
displayUnreadMark,
displayMentionBadge,
displayReactionBadge,
displayPinnedIcon,
unreadCount,
active,
selected,
unreadMuted,
mentionOrReactionMuted);
const auto &color = active
const auto &color = context.active
? st::dialogsTextFgServiceActive
: (selected
? st::dialogsTextFgServiceOver
: st::dialogsTextFgService);
: context.selected
? st::dialogsTextFgServiceOver
: st::dialogsTextFgService;
const auto rect = QRect(
nameleft,
texttop,
@ -958,9 +999,9 @@ void RowPainter::paint(
rect.x(),
rect.y(),
rect.width(),
fullWidth,
context.width,
color,
ms)
context.now)
: false;
const auto view = actionWasPainted
? nullptr
@ -970,7 +1011,7 @@ void RowPainter::paint(
? &topic->lastItemDialogsView
: nullptr;
if (const auto folder = row->folder()) {
PaintListEntryText(p, rect, active, selected, row, ms, paused);
PaintListEntryText(p, row, context, rect);
} else if (view) {
if (!view->prepared(item)) {
view->prepare(
@ -978,29 +1019,27 @@ void RowPainter::paint(
[=] { entry->updateChatListEntry(); },
{});
}
view->paint(p, rect, active, selected, ms, paused);
view->paint(p, rect, context);
}
};
const auto paintCounterCallback = [&] {
PaintNarrowCounter(
p,
context,
displayUnreadCounter,
displayUnreadMark,
displayMentionBadge,
displayReactionBadge,
unreadCount,
selected,
active,
unreadMuted,
mentionOrReactionMuted);
};
paintRow(
PaintRow(
p,
row,
entry,
row->key(),
videoUserpic,
filterId,
from,
entry->chatListBadge(),
[=] { history->updateChatListEntry(); },
@ -1009,22 +1048,16 @@ void RowPainter::paint(
item,
cloudDraft,
displayDate,
fullWidth,
context,
flags,
ms,
paintItemCallback,
paintCounterCallback);
}
void RowPainter::paint(
void RowPainter::Paint(
Painter &p,
not_null<const FakeRow*> row,
int fullWidth,
bool active,
bool selected,
crl::time ms,
bool paused,
bool displayUnreadInfo) {
const PaintContext &context) {
auto item = row->item();
auto history = item->history();
auto cloudDraft = nullptr;
@ -1059,16 +1092,16 @@ void RowPainter::paint(
return {};
}();
const auto unreadCount = displayUnreadInfo
const auto unreadCount = context.displayUnreadInfo
? history->chatListUnreadCount()
: 0;
const auto unreadMark = displayUnreadInfo
const auto unreadMark = context.displayUnreadInfo
&& history->chatListUnreadMark();
const auto unreadMuted = history->chatListMutedBadge();
const auto mentionOrReactionMuted = (history->folder() != nullptr);
const auto displayMentionBadge = displayUnreadInfo
const auto displayMentionBadge = context.displayUnreadInfo
&& history->unreadMentions().has();
const auto displayReactionBadge = displayUnreadInfo
const auto displayReactionBadge = context.displayUnreadInfo
&& !displayMentionBadge
&& history->unreadReactions().has();
const auto displayUnreadCounter = (unreadCount > 0);
@ -1083,17 +1116,15 @@ void RowPainter::paint(
+ st::dialogsSkip;
const auto availableWidth = PaintWideCounter(
p,
context,
texttop,
namewidth,
fullWidth,
displayUnreadCounter,
displayUnreadMark,
displayMentionBadge,
displayReactionBadge,
displayPinnedIcon,
unreadCount,
active,
selected,
unreadMuted,
mentionOrReactionMuted);
@ -1106,18 +1137,17 @@ void RowPainter::paint(
if (!view.prepared(item)) {
view.prepare(item, row->repaint(), previewOptions);
}
row->itemView().paint(p, itemRect, active, selected, ms, paused);
row->itemView().paint(p, itemRect, context);
};
const auto paintCounterCallback = [&] {
PaintNarrowCounter(
p,
context,
displayUnreadCounter,
displayUnreadMark,
displayMentionBadge,
displayReactionBadge,
unreadCount,
selected,
active,
unreadMuted,
mentionOrReactionMuted);
};
@ -1125,19 +1155,14 @@ void RowPainter::paint(
&& !row->searchInChat();
const auto showRepliesMessages = history->peer->isRepliesChat()
&& !row->searchInChat();
const auto flags = (active ? Flag::Active : Flag(0))
| (selected ? Flag::Selected : Flag(0))
| Flag::SearchResult
| (showSavedMessages ? Flag::SavedMessages : Flag(0))
| (showRepliesMessages ? Flag::RepliesMessages : Flag(0))
| (paused ? Flag::VideoPaused : Flag(0));
paintRow(
const auto flags = (showSavedMessages ? Flag::SavedMessages : Flag(0))
| (showRepliesMessages ? Flag::RepliesMessages : Flag(0));
PaintRow(
p,
row,
history,
history,
nullptr,
FilterId(),
from,
row->badge(),
row->repaint(),
@ -1146,14 +1171,13 @@ void RowPainter::paint(
item,
cloudDraft,
ItemDateTime(item),
fullWidth,
context,
flags,
ms,
paintItemCallback,
paintCounterCallback);
}
QRect RowPainter::sendActionAnimationRect(
QRect RowPainter::SendActionAnimationRect(
int animationLeft,
int animationWidth,
int animationHeight,

View file

@ -10,6 +10,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui {
} // namespace Ui
namespace Data {
class Forum;
class Folder;
} // namespace Data
namespace Dialogs {
class Row;
class FakeRow;
@ -22,39 +27,41 @@ using namespace ::Ui;
class VideoUserpic;
struct PaintContext {
Data::Folder *folder = nullptr;
Data::Forum *forum = nullptr;
FilterId filter = 0;
crl::time now = 0;
int width = 0;
bool active = false;
bool selected = false;
bool paused = false;
bool search = false;
bool narrow = false;
bool displayUnreadInfo = false;
};
const style::icon *ChatTypeIcon(
not_null<PeerData*> peer,
bool active,
bool selected);
const PaintContext &context = {});
class RowPainter {
public:
static void paint(
static void Paint(
Painter &p,
not_null<const Row*> row,
VideoUserpic *videoUserpic,
FilterId filterId,
int fullWidth,
bool active,
bool selected,
crl::time ms,
bool paused);
static void paint(
const PaintContext &context);
static void Paint(
Painter &p,
not_null<const FakeRow*> row,
int fullWidth,
bool active,
bool selected,
crl::time ms,
bool paused,
bool displayUnreadInfo);
static QRect sendActionAnimationRect(
const PaintContext &context);
static QRect SendActionAnimationRect(
int animationLeft,
int animationWidth,
int animationHeight,
int fullWidth,
bool textUpdated);
};
void PaintCollapsedRow(
@ -66,16 +73,16 @@ void PaintCollapsedRow(
int fullWidth,
bool selected);
enum UnreadBadgeSize {
UnreadBadgeInDialogs = 0,
UnreadBadgeInMainMenu,
UnreadBadgeInHistoryToDown,
UnreadBadgeInStickersPanel,
UnreadBadgeInStickersBox,
UnreadBadgeInTouchBar,
UnreadBadgeReactionInDialogs,
enum class UnreadBadgeSize {
Dialogs,
MainMenu,
HistoryToDown,
StickersPanel,
StickersBox,
TouchBar,
ReactionInDialogs,
UnreadBadgeSizesCount
kCount,
};
struct UnreadBadgeStyle {
UnreadBadgeStyle();
@ -87,13 +94,15 @@ struct UnreadBadgeStyle {
int textTop = 0;
int size = 0;
int padding = 0;
UnreadBadgeSize sizeId = UnreadBadgeInDialogs;
UnreadBadgeSize sizeId = UnreadBadgeSize::Dialogs;
style::font font;
};
[[nodiscard]] QSize CountUnreadBadgeSize(
const QString &unreadCount,
const UnreadBadgeStyle &st,
int allowDigits = 0);
QRect PaintUnreadBadge(
QPainter &p,
const QString &t,
@ -102,6 +111,4 @@ QRect PaintUnreadBadge(
const UnreadBadgeStyle &st,
int allowDigits = 0);
void clearUnreadBadgesCache();
} // namespace Dialogs::Ui

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h"
#include "history/view/history_view_item_preview.h"
#include "main/main_session.h"
#include "dialogs/ui/dialogs_layout.h"
#include "ui/text/text_options.h"
#include "ui/text/text_utilities.h"
#include "ui/image/image.h"
@ -175,22 +176,19 @@ void MessageView::prepare(
void MessageView::paint(
Painter &p,
const QRect &geometry,
bool active,
bool selected,
crl::time now,
bool paused) const {
const PaintContext &context) const {
if (geometry.isEmpty()) {
return;
}
p.setFont(st::dialogsTextFont);
p.setPen(active
p.setPen(context.active
? st::dialogsTextFgActive
: selected
: context.selected
? st::dialogsTextFgOver
: st::dialogsTextFg);
const auto palette = &(active
const auto palette = &(context.active
? st::dialogsTextPaletteActive
: selected
: context.selected
? st::dialogsTextPaletteOver
: st::dialogsTextPalette);
@ -229,8 +227,8 @@ void MessageView::paint(
.availableWidth = rect.width(),
.palette = palette,
.spoiler = Text::DefaultSpoilerCache(),
.now = now,
.paused = paused,
.now = context.now,
.paused = context.paused,
.elisionLines = rect.height() / st::dialogsTextFont->height,
});
}

View file

@ -26,6 +26,8 @@ namespace Dialogs::Ui {
using namespace ::Ui;
struct PaintContext;
[[nodiscard]] TextWithEntities DialogsPreviewText(TextWithEntities text);
class MessageView final {
@ -48,10 +50,7 @@ public:
void paint(
Painter &p,
const QRect &geometry,
bool active,
bool selected,
crl::time now,
bool paused) const;
const PaintContext &context) const;
private:
struct LoadingContext;

View file

@ -99,16 +99,12 @@ void Row::elementsPaint(
bool selected,
int selectedElement) {
_outerWidth = outerWidth;
using Row = Dialogs::Ui::RowPainter;
Row::paint(
p,
_fakeRow.get(),
outerWidth,
false,
selected,
crl::now(),
p.inactive(),
false);
Dialogs::Ui::RowPainter::Paint(p, _fakeRow.get(), {
.now = crl::now(),
.width = outerWidth,
.selected = selected,
.paused = p.inactive(),
});
}
class ListController final : public PeerListController {

View file

@ -99,7 +99,7 @@ QImage UnreadBadge(not_null<PeerData*> peer) {
? QString()
: QString::number(count);
Dialogs::Ui::UnreadBadgeStyle unreadSt;
unreadSt.sizeId = Dialogs::Ui::UnreadBadgeInTouchBar;
unreadSt.sizeId = Dialogs::Ui::UnreadBadgeSize::TouchBar;
unreadSt.muted = history->mute();
// Use constant values to draw badge regardless of cConfigScale().
unreadSt.size = kUnreadBadgeSize * cRetinaFactor();

View file

@ -969,7 +969,7 @@ Dialogs::Ui::UnreadBadgeStyle Style() {
auto result = Dialogs::Ui::UnreadBadgeStyle();
result.font = st::mainMenuBadgeFont;
result.size = st::mainMenuBadgeSize;
result.sizeId = Dialogs::Ui::UnreadBadgeInMainMenu;
result.sizeId = Dialogs::Ui::UnreadBadgeSize::MainMenu;
return result;
}

View file

@ -149,7 +149,7 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) {
st.align = style::al_center;
st.font = st::historyToDownBadgeFont;
st.size = st::historyToDownBadgeSize;
st.sizeId = Dialogs::Ui::UnreadBadgeInHistoryToDown;
st.sizeId = Dialogs::Ui::UnreadBadgeSize::HistoryToDown;
Dialogs::Ui::PaintUnreadBadge(p, unreadString, width(), 0, st, 4);
}
}

View file

@ -845,7 +845,7 @@ void Notification::updateNotifyDisplay() {
Ui::Emoji::Draw(p, emoji, Ui::Emoji::GetSizeNormal(), rectForName.left(), top);
rectForName.setLeft(rectForName.left() + size + st::msgNameFont->spacew);
}
if (const auto chatTypeIcon = Dialogs::Ui::ChatTypeIcon(_history->peer, false, false)) {
if (const auto chatTypeIcon = Dialogs::Ui::ChatTypeIcon(_history->peer)) {
chatTypeIcon->paint(p, rectForName.topLeft(), w);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}