mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Nice reactions panel expanding.
This commit is contained in:
parent
20d4d00634
commit
0277d765bb
17 changed files with 253 additions and 175 deletions
|
@ -1268,13 +1268,12 @@ void StickerSetBox::Inner::paintSticker(
|
|||
(_singleSize.height() - size.height()) / 2);
|
||||
auto lottieFrame = QImage();
|
||||
if (element.emoji) {
|
||||
element.emoji->paint(
|
||||
p,
|
||||
ppos.x(),
|
||||
ppos.y(),
|
||||
now,
|
||||
st::windowBgOver->c,
|
||||
paused);
|
||||
element.emoji->paint(p, {
|
||||
.preview = st::windowBgOver->c,
|
||||
.now = now,
|
||||
.position = ppos,
|
||||
.paused = paused,
|
||||
});
|
||||
} else if (element.lottie && element.lottie->ready()) {
|
||||
lottieFrame = element.lottie->frame();
|
||||
p.drawImage(
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace ChatHelpers {
|
|||
namespace {
|
||||
|
||||
constexpr auto kCollapsedRows = 3;
|
||||
constexpr auto kAppearDuration = 0.3;
|
||||
|
||||
using Core::RecentEmojiId;
|
||||
using Core::RecentEmojiDocument;
|
||||
|
@ -486,15 +487,19 @@ auto EmojiListWidget::premiumChosen() const
|
|||
void EmojiListWidget::paintExpanding(
|
||||
QPainter &p,
|
||||
QRect clip,
|
||||
int finalBottom,
|
||||
float64 progress,
|
||||
RectPart origin) {
|
||||
const auto shift = clip.topLeft();
|
||||
const auto adjusted = clip.translated(-shift);
|
||||
const auto finalHeight = (finalBottom - clip.y());
|
||||
p.translate(shift);
|
||||
p.setClipRect(adjusted);
|
||||
const auto context = ExpandingContext{
|
||||
paint(p, ExpandingContext{
|
||||
.progress = progress,
|
||||
.finalHeight = finalHeight,
|
||||
.expanding = true,
|
||||
};
|
||||
paint(p, context, adjusted);
|
||||
}, adjusted);
|
||||
p.translate(-shift);
|
||||
}
|
||||
|
||||
|
@ -778,7 +783,7 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
|||
|
||||
void EmojiListWidget::paint(
|
||||
QPainter &p,
|
||||
const ExpandingContext &context,
|
||||
ExpandingContext context,
|
||||
QRect clip) {
|
||||
auto fromColumn = floorclamp(
|
||||
clip.x() - _rowsLeft,
|
||||
|
@ -796,6 +801,7 @@ void EmojiListWidget::paint(
|
|||
toColumn = _columnCount - toColumn;
|
||||
}
|
||||
|
||||
const auto expandProgress = context.progress;
|
||||
const auto paused = this->paused();
|
||||
const auto now = crl::now();
|
||||
auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed)
|
||||
|
@ -866,10 +872,26 @@ void EmojiListWidget::paint(
|
|||
const auto selected = (state == _selected)
|
||||
|| (!_picker->isHidden()
|
||||
&& state == _pickerSelected);
|
||||
auto w = QPoint(
|
||||
const auto position = QPoint(
|
||||
_rowsLeft + j * _singleSize.width(),
|
||||
info.rowsTop + i * _singleSize.height()
|
||||
) + _areaPosition;
|
||||
);
|
||||
const auto w = position + _areaPosition;
|
||||
if (context.expanding) {
|
||||
const auto y = (position.y() - st().padding.top());
|
||||
const auto x = (position.x() - _rowsLeft);
|
||||
const auto sum = y
|
||||
+ std::max(std::min(y, width()) - x, 0);
|
||||
const auto maxSum = context.finalHeight
|
||||
+ std::min(context.finalHeight, width());
|
||||
const auto started = (sum / float64(maxSum))
|
||||
- kAppearDuration;
|
||||
context.progress = (expandProgress <= started)
|
||||
? 0.
|
||||
: (expandProgress >= started + kAppearDuration)
|
||||
? 1.
|
||||
: ((expandProgress - started) / kAppearDuration);
|
||||
}
|
||||
if (info.collapsed
|
||||
&& index + 1 == _columnCount * kCollapsedRows) {
|
||||
drawCollapsedBadge(p, w - _areaPosition, info.count);
|
||||
|
@ -883,12 +905,12 @@ void EmojiListWidget::paint(
|
|||
_overBg.paint(p, QRect(tl, st::emojiPanArea));
|
||||
}
|
||||
if (info.section == int(Section::Recent)) {
|
||||
drawRecent(p, w, now, paused, index);
|
||||
drawRecent(p, context, w, now, paused, index);
|
||||
} else if (info.section < _staticCount) {
|
||||
drawEmoji(p, w, _emoji[info.section][index]);
|
||||
drawEmoji(p, context, w, _emoji[info.section][index]);
|
||||
} else {
|
||||
const auto set = info.section - _staticCount;
|
||||
drawCustom(p, w, now, paused, set, index);
|
||||
drawCustom(p, context, w, now, paused, set, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -919,6 +941,7 @@ void EmojiListWidget::drawCollapsedBadge(
|
|||
|
||||
void EmojiListWidget::drawRecent(
|
||||
QPainter &p,
|
||||
const ExpandingContext &context,
|
||||
QPoint position,
|
||||
crl::time now,
|
||||
bool paused,
|
||||
|
@ -932,23 +955,25 @@ void EmojiListWidget::drawRecent(
|
|||
) - _areaPosition;
|
||||
p.drawImage(position, _premiumIcon->image());
|
||||
} else {
|
||||
drawEmoji(p, position, *emoji);
|
||||
drawEmoji(p, context, position, *emoji);
|
||||
}
|
||||
} else {
|
||||
Assert(_recent[index].custom != nullptr);
|
||||
position += _innerPosition + _customPosition;
|
||||
_recent[index].custom->paint(
|
||||
p,
|
||||
position.x(),
|
||||
position.y(),
|
||||
now,
|
||||
st::windowBgRipple->c,
|
||||
paused);
|
||||
_recent[index].custom->paint(p, {
|
||||
.preview = st::windowBgRipple->c,
|
||||
.now = now,
|
||||
.scale = context.progress,
|
||||
.position = position,
|
||||
.paused = paused,
|
||||
.scaled = context.expanding,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiListWidget::drawEmoji(
|
||||
QPainter &p,
|
||||
const ExpandingContext &context,
|
||||
QPoint position,
|
||||
EmojiPtr emoji) {
|
||||
position += _innerPosition;
|
||||
|
@ -962,6 +987,7 @@ void EmojiListWidget::drawEmoji(
|
|||
|
||||
void EmojiListWidget::drawCustom(
|
||||
QPainter &p,
|
||||
const ExpandingContext &context,
|
||||
QPoint position,
|
||||
crl::time now,
|
||||
bool paused,
|
||||
|
@ -969,13 +995,14 @@ void EmojiListWidget::drawCustom(
|
|||
int index) {
|
||||
position += _innerPosition + _customPosition;
|
||||
_custom[set].painted = true;
|
||||
_custom[set].list[index].custom->paint(
|
||||
p,
|
||||
position.x(),
|
||||
position.y(),
|
||||
now,
|
||||
st::windowBgRipple->c,
|
||||
paused);
|
||||
_custom[set].list[index].custom->paint(p, {
|
||||
.preview = st::windowBgRipple->c,
|
||||
.now = now,
|
||||
.scale = context.progress,
|
||||
.position = position,
|
||||
.paused = paused,
|
||||
.scaled = context.expanding,
|
||||
});
|
||||
}
|
||||
|
||||
bool EmojiListWidget::checkPickerHide() {
|
||||
|
|
|
@ -112,7 +112,12 @@ public:
|
|||
[[nodiscard]] auto premiumChosen() const
|
||||
-> rpl::producer<not_null<DocumentData*>>;
|
||||
|
||||
void paintExpanding(QPainter &p, QRect clip, RectPart origin);
|
||||
void paintExpanding(
|
||||
QPainter &p,
|
||||
QRect clip,
|
||||
int finalBottom,
|
||||
float64 progress,
|
||||
RectPart origin);
|
||||
|
||||
protected:
|
||||
void visibleTopBottomUpdated(
|
||||
|
@ -208,6 +213,8 @@ private:
|
|||
OverSet,
|
||||
OverButton>;
|
||||
struct ExpandingContext {
|
||||
float64 progress = 0.;
|
||||
int finalHeight = 0;
|
||||
bool expanding = false;
|
||||
};
|
||||
|
||||
|
@ -235,20 +242,23 @@ private:
|
|||
[[nodiscard]] EmojiPtr lookupOverEmoji(const OverEmoji *over) const;
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
void selectCustom(not_null<DocumentData*> document);
|
||||
void paint(QPainter &p, const ExpandingContext &context, QRect clip);
|
||||
void paint(QPainter &p, ExpandingContext context, QRect clip);
|
||||
void drawCollapsedBadge(QPainter &p, QPoint position, int count);
|
||||
void drawRecent(
|
||||
QPainter &p,
|
||||
const ExpandingContext &context,
|
||||
QPoint position,
|
||||
crl::time now,
|
||||
bool paused,
|
||||
int index);
|
||||
void drawEmoji(
|
||||
QPainter &p,
|
||||
const ExpandingContext &context,
|
||||
QPoint position,
|
||||
EmojiPtr emoji);
|
||||
void drawCustom(
|
||||
QPainter &p,
|
||||
const ExpandingContext &context,
|
||||
QPoint position,
|
||||
crl::time now,
|
||||
bool paused,
|
||||
|
|
|
@ -351,7 +351,11 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
|
|||
const auto x = i * _oneWidth + (_oneWidth - size) / 2;
|
||||
const auto y = (_oneWidth - size) / 2;
|
||||
if (row.custom) {
|
||||
row.custom->paint(p, x, y, now, preview, false);
|
||||
row.custom->paint(p, {
|
||||
.preview = preview,
|
||||
.now = now,
|
||||
.position = { x, y },
|
||||
});
|
||||
} else {
|
||||
Ui::Emoji::Draw(p, emoji, esize, x, y);
|
||||
}
|
||||
|
|
|
@ -1217,19 +1217,29 @@ void StickersListFooter::paintSetIcon(
|
|||
crl::time now,
|
||||
bool paused) const {
|
||||
const auto &icon = _icons[info.index];
|
||||
if (context.expanding) {
|
||||
p.save();
|
||||
const auto center = QPoint(
|
||||
info.adjustedLeft + _singleWidth / 2,
|
||||
_iconsTop + st().footer / 2);
|
||||
const auto shift = QPoint(0, anim::interpolate(height() / 2, 0, context.progress));
|
||||
p.translate(shift + center);
|
||||
p.scale(context.progress, context.progress);
|
||||
p.translate(-center);
|
||||
}
|
||||
const auto expandingShift = context.expanding
|
||||
? QPoint(
|
||||
0,
|
||||
anim::interpolate(height() / 2, 0, context.progress))
|
||||
: QPoint();
|
||||
if (icon.sticker) {
|
||||
icon.ensureMediaCreated();
|
||||
const_cast<StickersListFooter*>(this)->validateIconAnimation(icon);
|
||||
}
|
||||
if (context.expanding) {
|
||||
if (icon.custom) {
|
||||
p.translate(expandingShift);
|
||||
} else {
|
||||
p.save();
|
||||
const auto center = QPoint(
|
||||
info.adjustedLeft + _singleWidth / 2,
|
||||
_iconsTop + st().footer / 2);
|
||||
p.translate(expandingShift + center);
|
||||
p.scale(context.progress, context.progress);
|
||||
p.translate(-center);
|
||||
}
|
||||
}
|
||||
if (icon.sticker) {
|
||||
const auto origin = icon.sticker->stickerSetOrigin();
|
||||
const auto thumb = icon.thumbnailMedia
|
||||
? icon.thumbnailMedia->image()
|
||||
|
@ -1239,7 +1249,15 @@ void StickersListFooter::paintSetIcon(
|
|||
const auto x = info.adjustedLeft + (_singleWidth - icon.pixw) / 2;
|
||||
const auto y = _iconsTop + (st().footer - icon.pixh) / 2;
|
||||
if (icon.custom) {
|
||||
icon.custom->paint(p, x, y, now, st::emojiIconFg->c, paused);
|
||||
icon.custom->paint(p, Ui::Text::CustomEmoji::Context{
|
||||
.preview = st::emojiIconFg->c,
|
||||
.size = QSize(icon.pixw, icon.pixh),
|
||||
.now = now,
|
||||
.scale = context.progress,
|
||||
.position = { x, y },
|
||||
.paused = paused,
|
||||
.scaled = context.expanding,
|
||||
});
|
||||
} else if (icon.lottie && icon.lottie->ready()) {
|
||||
const auto frame = icon.lottie->frame();
|
||||
const auto size = frame.size() / cIntRetinaFactor();
|
||||
|
@ -1368,7 +1386,11 @@ void StickersListFooter::paintSetIcon(
|
|||
}
|
||||
}
|
||||
if (context.expanding) {
|
||||
p.restore();
|
||||
if (icon.custom) {
|
||||
p.translate(-expandingShift);
|
||||
} else {
|
||||
p.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -356,12 +356,7 @@ void BottomInfo::paintReactions(
|
|||
y += st::msgDateFont->height;
|
||||
widthLeft = availableWidth;
|
||||
}
|
||||
if (!reaction.custom && reaction.image.isNull()) {
|
||||
reaction.custom = _reactionsOwner->resolveCustomFor(
|
||||
reaction.id,
|
||||
::Data::Reactions::ImageSize::BottomInfo);
|
||||
}
|
||||
if (!reaction.custom && reaction.image.isNull()) {
|
||||
if (reaction.image.isNull()) {
|
||||
reaction.image = _reactionsOwner->resolveImageFor(
|
||||
reaction.id,
|
||||
::Data::Reactions::ImageSize::BottomInfo);
|
||||
|
@ -375,9 +370,6 @@ void BottomInfo::paintReactions(
|
|||
&& (reaction.count < 2 || !reaction.animation->flying());
|
||||
if (!reaction.image.isNull() && !skipImage) {
|
||||
p.drawImage(image.topLeft(), reaction.image);
|
||||
} else if (reaction.custom && !skipImage) {
|
||||
const auto size = Ui::Text::AdjustCustomEmojiSize(st::emojiSize);
|
||||
reaction.custom->paint(p, x + (st::reactionInfoSize - size) / 2, y + (st::msgDateFont->height - size) / 2, crl::now(), Qt::white, false);
|
||||
}
|
||||
if (animating) {
|
||||
animations.push_back({
|
||||
|
|
|
@ -16,10 +16,6 @@ namespace Ui {
|
|||
struct ChatPaintContext;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Ui::Text {
|
||||
class CustomEmoji;
|
||||
} // namespace Ui::Text
|
||||
|
||||
namespace Data {
|
||||
class Reactions;
|
||||
} // namespace Data
|
||||
|
@ -105,7 +101,6 @@ private:
|
|||
struct Reaction {
|
||||
mutable std::unique_ptr<Reactions::Animation> animation;
|
||||
mutable QImage image;
|
||||
mutable std::unique_ptr<Ui::Text::CustomEmoji> custom;
|
||||
ReactionId id;
|
||||
QString countText;
|
||||
int count = 0;
|
||||
|
|
|
@ -298,16 +298,15 @@ void StickerToast::setupEmojiPreview(
|
|||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto p = QPainter(widget);
|
||||
const auto paused = false;
|
||||
const auto size = Ui::Emoji::GetSizeLarge()
|
||||
/ style::DevicePixelRatio();
|
||||
instance->object.paint(
|
||||
p,
|
||||
(widget->width() - size) / 2,
|
||||
(widget->height() - size) / 2,
|
||||
crl::now(),
|
||||
st::toastBg->c,
|
||||
paused);
|
||||
instance->object.paint(p, Ui::Text::CustomEmoji::Context{
|
||||
.preview = st::toastBg->c,
|
||||
.now = crl::now(),
|
||||
.position = QPoint(
|
||||
(widget->width() - size) / 2,
|
||||
(widget->height() - size) / 2),
|
||||
});
|
||||
}, widget->lifetime());
|
||||
}
|
||||
|
||||
|
|
|
@ -277,7 +277,11 @@ void CustomEmoji::paintCustom(
|
|||
}
|
||||
_selectedFrame.fill(Qt::transparent);
|
||||
auto q = QPainter(&_selectedFrame);
|
||||
emoji->paint(q, 0, 0, context.now, preview, paused);
|
||||
emoji->paint(q, {
|
||||
.preview = preview,
|
||||
.now = context.now,
|
||||
.paused = paused,
|
||||
});
|
||||
q.end();
|
||||
|
||||
_selectedFrame = Images::Colored(
|
||||
|
@ -285,7 +289,12 @@ void CustomEmoji::paintCustom(
|
|||
context.st->msgStickerOverlay()->c);
|
||||
p.drawImage(x, y, _selectedFrame);
|
||||
} else {
|
||||
emoji->paint(p, x, y, context.now, preview, paused);
|
||||
emoji->paint(p, {
|
||||
.preview = preview,
|
||||
.now = context.now,
|
||||
.position = { x, y },
|
||||
.paused = paused,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,11 @@ void LargeEmoji::paintCustom(
|
|||
}
|
||||
_selectedFrame.fill(Qt::transparent);
|
||||
auto q = QPainter(&_selectedFrame);
|
||||
emoji->paint(q, 0, 0, context.now, preview, paused);
|
||||
emoji->paint(q, {
|
||||
.preview = preview,
|
||||
.now = context.now,
|
||||
.paused = paused,
|
||||
});
|
||||
q.end();
|
||||
|
||||
_selectedFrame = Images::Colored(
|
||||
|
@ -156,7 +160,12 @@ void LargeEmoji::paintCustom(
|
|||
context.st->msgStickerOverlay()->c);
|
||||
p.drawImage(x + skip, y + skip, _selectedFrame);
|
||||
} else {
|
||||
emoji->paint(p, x + skip, y + skip, context.now, preview, paused);
|
||||
emoji->paint(p, {
|
||||
.preview = preview,
|
||||
.now = context.now,
|
||||
.position = { x + skip, y + skip },
|
||||
.paused = paused,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,12 +18,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/emoji_list_widget.h"
|
||||
#include "chat_helpers/stickers_list_footer.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
namespace {
|
||||
|
||||
constexpr auto kExpandDuration = crl::time(300);
|
||||
constexpr auto kScaleDuration = crl::time(120);
|
||||
constexpr auto kFullDuration = kExpandDuration + kScaleDuration;
|
||||
constexpr auto kExpandDelay = crl::time(40);
|
||||
|
||||
class ShiftedEmoji final : public Ui::Text::CustomEmoji {
|
||||
public:
|
||||
ShiftedEmoji(
|
||||
|
@ -33,13 +39,7 @@ public:
|
|||
QPoint shift);
|
||||
|
||||
QString entityData() override;
|
||||
void paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused) override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
|
||||
private:
|
||||
|
@ -64,14 +64,10 @@ QString ShiftedEmoji::entityData() {
|
|||
return _real->entityData();
|
||||
}
|
||||
|
||||
void ShiftedEmoji::paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused) {
|
||||
_real->paint(p, x + _shift.x(), y + _shift.y(), now, preview, paused);
|
||||
void ShiftedEmoji::paint(QPainter &p, const Context &context) {
|
||||
auto copy = context;
|
||||
copy.position += _shift;
|
||||
_real->paint(p, copy);
|
||||
}
|
||||
|
||||
void ShiftedEmoji::unload() {
|
||||
|
@ -270,6 +266,7 @@ void Selector::paintCollapsed(QPainter &p) {
|
|||
void Selector::paintExpanding(Painter &p, float64 progress) {
|
||||
const auto rects = paintExpandingBg(p, progress);
|
||||
//paintStripWithoutExpand(p);
|
||||
progress /= kFullDuration;
|
||||
paintFadingExpandIcon(p, progress);
|
||||
if (_footer) {
|
||||
_footer->paintExpanding(
|
||||
|
@ -281,11 +278,16 @@ void Selector::paintExpanding(Painter &p, float64 progress) {
|
|||
_list->paintExpanding(
|
||||
p,
|
||||
rects.list.marginsRemoved(st::reactPanelEmojiPan.margin),
|
||||
rects.finalBottom,
|
||||
progress,
|
||||
RectPart::TopRight);
|
||||
}
|
||||
|
||||
auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
||||
-> ExpandingRects {
|
||||
progress = (progress >= kExpandDuration)
|
||||
? 1.
|
||||
: (progress / kExpandDuration);
|
||||
constexpr auto kFramesCount = Ui::RoundAreaWithShadow::kFramesCount;
|
||||
const auto frame = int(base::SafeRound(progress * (kFramesCount - 1)));
|
||||
const auto radiusStart = st::reactStripHeight / 2.;
|
||||
|
@ -318,6 +320,7 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
|||
.categories = QRect(inner.x(), inner.y(), inner.width(), categories),
|
||||
.list = inner.marginsRemoved({ 0, categories, 0, 0 }),
|
||||
.radius = radius,
|
||||
.finalBottom = height() - extents.bottom(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -393,7 +396,8 @@ void Selector::paintEvent(QPaintEvent *e) {
|
|||
paintAppearing(p);
|
||||
} else if (!_expanded) {
|
||||
paintCollapsed(p);
|
||||
} else if (const auto progress = _expanding.value(1.); progress < 1.) {
|
||||
} else if (const auto progress = _expanding.value(kFullDuration)
|
||||
; progress < kFullDuration) {
|
||||
paintExpanding(p, progress);
|
||||
} else {
|
||||
paintExpanded(p);
|
||||
|
@ -468,9 +472,14 @@ void Selector::expand() {
|
|||
createList(strong);
|
||||
cacheExpandIcon();
|
||||
|
||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||
_expanded = true;
|
||||
_expanding.start([=] { update(); }, 0., 1., st::slideDuration);
|
||||
[[maybe_unused]] const auto grabbed = Ui::GrabWidget(_scroll);
|
||||
|
||||
base::call_delayed(kExpandDelay, this, [=] {
|
||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||
_expanded = true;
|
||||
const auto full = kExpandDuration + kScaleDuration;
|
||||
_expanding.start([=] { update(); }, 0., full, full);
|
||||
});
|
||||
}
|
||||
|
||||
void Selector::cacheExpandIcon() {
|
||||
|
|
|
@ -70,6 +70,7 @@ private:
|
|||
QRect categories;
|
||||
QRect list;
|
||||
float64 radius = 0.;
|
||||
int finalBottom = 0;
|
||||
};
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
|
|
@ -148,13 +148,11 @@ void BadgeView::setBadge(Badge badge, DocumentId emojiStatusId) {
|
|||
_view->paintRequest(
|
||||
) | rpl::start_with_next([=, check = _view.data()]{
|
||||
Painter p(check);
|
||||
_emojiStatus->paint(
|
||||
p,
|
||||
0,
|
||||
0,
|
||||
crl::now(),
|
||||
st::windowBgOver->c,
|
||||
_animationPaused && _animationPaused());
|
||||
_emojiStatus->paint(p, {
|
||||
.preview = st::windowBgOver->c,
|
||||
.now = crl::now(),
|
||||
.paused = _animationPaused && _animationPaused(),
|
||||
});
|
||||
}, _view->lifetime());
|
||||
} else {
|
||||
const auto icon = (_badge == Badge::Verified)
|
||||
|
|
|
@ -30,6 +30,32 @@ struct CacheHeader {
|
|||
int length = 0;
|
||||
};
|
||||
|
||||
void PaintScaledImage(
|
||||
QPainter &p,
|
||||
const QRect &target,
|
||||
const Cache::Frame &frame,
|
||||
const Context &context) {
|
||||
if (context.scaled) {
|
||||
const auto sx = anim::interpolate(
|
||||
target.width() / 2,
|
||||
0,
|
||||
context.scale);
|
||||
const auto sy = (target.height() == target.width())
|
||||
? sx
|
||||
: anim::interpolate(target.height() / 2, 0, context.scale);
|
||||
const auto scaled = target.marginsRemoved({ sx, sy, sx, sy });
|
||||
if (frame.source.isNull()) {
|
||||
p.drawImage(scaled, *frame.image);
|
||||
} else {
|
||||
p.drawImage(scaled, *frame.image, frame.source);
|
||||
}
|
||||
} else if (frame.source.isNull()) {
|
||||
p.drawImage(target, *frame.image);
|
||||
} else {
|
||||
p.drawImage(target, *frame.image, frame.source);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Preview::Preview(QPainterPath path, float64 scale)
|
||||
|
@ -40,15 +66,14 @@ Preview::Preview(QImage image, bool exact)
|
|||
: _data(Image{ .data = std::move(image), .exact = exact }) {
|
||||
}
|
||||
|
||||
void Preview::paint(QPainter &p, int x, int y, const QColor &preview) {
|
||||
void Preview::paint(QPainter &p, const Context &context) {
|
||||
if (const auto path = std::get_if<ScaledPath>(&_data)) {
|
||||
paintPath(p, x, y, preview, *path);
|
||||
paintPath(p, context, *path);
|
||||
} else if (const auto image = std::get_if<Image>(&_data)) {
|
||||
const auto &data = image->data;
|
||||
const auto factor = style::DevicePixelRatio();
|
||||
const auto width = data.width() / factor;
|
||||
const auto height = data.height() / factor;
|
||||
p.drawImage(QRect(x, y, width, height), data);
|
||||
const auto rect = QRect(context.position, data.size() / factor);
|
||||
PaintScaledImage(p, rect, { .image = &data }, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,27 +97,33 @@ QImage Preview::image() const {
|
|||
|
||||
void Preview::paintPath(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
const QColor &preview,
|
||||
const Context &context,
|
||||
const ScaledPath &path) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setBrush(preview);
|
||||
p.setBrush(context.preview);
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto scale = path.scale;
|
||||
const auto required = (scale != 1.);
|
||||
const auto required = (scale != 1.) || context.scaled;
|
||||
if (required) {
|
||||
p.save();
|
||||
}
|
||||
p.translate(x, y);
|
||||
p.translate(context.position);
|
||||
if (required) {
|
||||
p.scale(scale, scale);
|
||||
const auto center = QPoint(
|
||||
context.size.width() / 2,
|
||||
context.size.height() / 2);
|
||||
if (context.scaled) {
|
||||
p.translate(center);
|
||||
p.scale(context.scale, context.scale);
|
||||
p.translate(-center);
|
||||
}
|
||||
}
|
||||
p.drawPath(path.path);
|
||||
if (required) {
|
||||
p.restore();
|
||||
} else {
|
||||
p.translate(-x, -y);
|
||||
p.translate(-context.position);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,12 +337,11 @@ void Cache::finish() {
|
|||
|
||||
PaintFrameResult Cache::paintCurrentFrame(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now) {
|
||||
const Context &context) {
|
||||
if (!_frames) {
|
||||
return {};
|
||||
}
|
||||
const auto now = context.paused ? 0 : context.now;
|
||||
const auto finishes = now ? currentFrameFinishes() : 0;
|
||||
if (finishes && now >= finishes) {
|
||||
++_frame;
|
||||
|
@ -324,7 +354,8 @@ PaintFrameResult Cache::paintCurrentFrame(
|
|||
}
|
||||
const auto info = frame(std::min(_frame, _frames - 1));
|
||||
const auto size = _size / style::DevicePixelRatio();
|
||||
p.drawImage(QRect(x, y, size, size), *info.image, info.source);
|
||||
const auto rect = QRect(context.position, QSize(size, size));
|
||||
PaintScaledImage(p, rect, info, context);
|
||||
const auto next = currentFrameFinishes();
|
||||
const auto duration = next ? (next - _shown) : 0;
|
||||
return {
|
||||
|
@ -360,8 +391,8 @@ QString Cached::entityData() const {
|
|||
return _entityData;
|
||||
}
|
||||
|
||||
PaintFrameResult Cached::paint(QPainter &p, int x, int y, crl::time now) {
|
||||
return _cache.paintCurrentFrame(p, x, y, now);
|
||||
PaintFrameResult Cached::paint(QPainter &p, const Context &context) {
|
||||
return _cache.paintCurrentFrame(p, context);
|
||||
}
|
||||
|
||||
Preview Cached::makePreview() const {
|
||||
|
@ -469,8 +500,8 @@ void Renderer::finish() {
|
|||
}
|
||||
}
|
||||
|
||||
PaintFrameResult Renderer::paint(QPainter &p, int x, int y, crl::time now) {
|
||||
const auto result = _cache.paintCurrentFrame(p, x, y, now);
|
||||
PaintFrameResult Renderer::paint(QPainter &p, const Context &context) {
|
||||
const auto result = _cache.paintCurrentFrame(p, context);
|
||||
if (_generator
|
||||
&& (!result.painted
|
||||
|| _cache.currentFrame() + kPreloadFrames >= _cache.frames())) {
|
||||
|
@ -526,13 +557,13 @@ bool Loading::loading() const {
|
|||
return _loader->loading();
|
||||
}
|
||||
|
||||
void Loading::paint(QPainter &p, int x, int y, const QColor &preview) {
|
||||
void Loading::paint(QPainter &p, const Context &context) {
|
||||
if (!_preview) {
|
||||
if (auto preview = _loader->preview()) {
|
||||
_preview = std::move(preview);
|
||||
}
|
||||
}
|
||||
_preview.paint(p, x, y, preview);
|
||||
_preview.paint(p, context);
|
||||
}
|
||||
|
||||
bool Loading::hasImagePreview() const {
|
||||
|
@ -578,15 +609,9 @@ QString Instance::entityData() const {
|
|||
Unexpected("State in Instance::entityData.");
|
||||
}
|
||||
|
||||
void Instance::paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused) {
|
||||
void Instance::paint(QPainter &p, const Context &context) {
|
||||
if (const auto loading = std::get_if<Loading>(&_state)) {
|
||||
loading->paint(p, x, y, preview);
|
||||
loading->paint(p, context);
|
||||
loading->load([=](Loader::LoadResult result) {
|
||||
if (auto caching = std::get_if<Caching>(&result)) {
|
||||
caching->renderer->setRepaintCallback([=] { repaint(); });
|
||||
|
@ -599,14 +624,14 @@ void Instance::paint(
|
|||
}
|
||||
});
|
||||
} else if (const auto caching = std::get_if<Caching>(&_state)) {
|
||||
auto result = caching->renderer->paint(p, x, y, paused ? 0 : now);
|
||||
auto result = caching->renderer->paint(p, context);
|
||||
if (!result.painted) {
|
||||
caching->preview.paint(p, x, y, preview);
|
||||
caching->preview.paint(p, context);
|
||||
} else {
|
||||
if (!caching->preview.isExactImage()) {
|
||||
caching->preview = caching->renderer->makePreview();
|
||||
}
|
||||
if (result.next > now) {
|
||||
if (result.next > context.now) {
|
||||
_repaintLater(this, { result.next, result.duration });
|
||||
}
|
||||
}
|
||||
|
@ -614,8 +639,8 @@ void Instance::paint(
|
|||
_state = std::move(*cached);
|
||||
}
|
||||
} else if (const auto cached = std::get_if<Cached>(&_state)) {
|
||||
const auto result = cached->paint(p, x, y, paused ? 0 : now);
|
||||
if (result.next > now) {
|
||||
const auto result = cached->paint(p, context);
|
||||
if (result.next > context.now) {
|
||||
_repaintLater(this, { result.next, result.duration });
|
||||
}
|
||||
}
|
||||
|
@ -695,18 +720,12 @@ QString Object::entityData() {
|
|||
return _instance->entityData();
|
||||
}
|
||||
|
||||
void Object::paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused) {
|
||||
void Object::paint(QPainter &p, const Context &context) {
|
||||
if (!_using) {
|
||||
_using = true;
|
||||
_instance->incrementUsage(this);
|
||||
}
|
||||
_instance->paint(p, x, y, now, preview, paused);
|
||||
_instance->paint(p, context);
|
||||
}
|
||||
|
||||
void Object::unload() {
|
||||
|
|
|
@ -21,13 +21,15 @@ class FrameGenerator;
|
|||
|
||||
namespace Ui::CustomEmoji {
|
||||
|
||||
using Context = Ui::Text::CustomEmoji::Context;
|
||||
|
||||
class Preview final {
|
||||
public:
|
||||
Preview() = default;
|
||||
Preview(QImage image, bool exact);
|
||||
Preview(QPainterPath path, float64 scale);
|
||||
|
||||
void paint(QPainter &p, int x, int y, const QColor &preview);
|
||||
void paint(QPainter &p, const Context &context);
|
||||
[[nodiscard]] bool isImage() const;
|
||||
[[nodiscard]] bool isExactImage() const;
|
||||
[[nodiscard]] QImage image() const;
|
||||
|
@ -48,9 +50,7 @@ private:
|
|||
|
||||
void paintPath(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
const QColor &preview,
|
||||
const Context &context,
|
||||
const ScaledPath &path);
|
||||
|
||||
std::variant<v::null_t, ScaledPath, Image> _data;
|
||||
|
@ -86,11 +86,7 @@ public:
|
|||
|
||||
[[nodiscard]] Preview makePreview() const;
|
||||
|
||||
PaintFrameResult paintCurrentFrame(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now);
|
||||
PaintFrameResult paintCurrentFrame(QPainter &p, const Context &context);
|
||||
[[nodiscard]] int currentFrame() const;
|
||||
|
||||
private:
|
||||
|
@ -123,7 +119,7 @@ public:
|
|||
|
||||
[[nodiscard]] QString entityData() const;
|
||||
[[nodiscard]] Preview makePreview() const;
|
||||
PaintFrameResult paint(QPainter &p, int x, int y, crl::time now);
|
||||
PaintFrameResult paint(QPainter &p, const Context &context);
|
||||
[[nodiscard]] Loading unload();
|
||||
|
||||
private:
|
||||
|
@ -145,7 +141,7 @@ public:
|
|||
explicit Renderer(RendererDescriptor &&descriptor);
|
||||
virtual ~Renderer();
|
||||
|
||||
PaintFrameResult paint(QPainter &p, int x, int y, crl::time now);
|
||||
PaintFrameResult paint(QPainter &p, const Context &context);
|
||||
[[nodiscard]] std::optional<Cached> ready(const QString &entityData);
|
||||
[[nodiscard]] std::unique_ptr<Loader> cancel();
|
||||
|
||||
|
@ -199,7 +195,7 @@ public:
|
|||
|
||||
void load(Fn<void(Loader::LoadResult)> done);
|
||||
[[nodiscard]] bool loading() const;
|
||||
void paint(QPainter &p, int x, int y, const QColor &preview);
|
||||
void paint(QPainter &p, const Context &context);
|
||||
[[nodiscard]] bool hasImagePreview() const;
|
||||
[[nodiscard]] Preview imagePreview() const;
|
||||
void updatePreview(Preview preview);
|
||||
|
@ -226,13 +222,7 @@ public:
|
|||
Instance &operator=(const Instance&) = delete;
|
||||
|
||||
[[nodiscard]] QString entityData() const;
|
||||
void paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused);
|
||||
void paint(QPainter &p, const Context &context);
|
||||
[[nodiscard]] bool hasImagePreview() const;
|
||||
[[nodiscard]] Preview imagePreview() const;
|
||||
void updatePreview(Preview preview);
|
||||
|
@ -261,13 +251,7 @@ public:
|
|||
~Object();
|
||||
|
||||
QString entityData() override;
|
||||
void paint(
|
||||
QPainter &p,
|
||||
int x,
|
||||
int y,
|
||||
crl::time now,
|
||||
const QColor &preview,
|
||||
bool paused) override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
|
||||
void repaint();
|
||||
|
|
|
@ -180,13 +180,14 @@ int PeerBadge::drawGetWidth(
|
|||
id,
|
||||
descriptor.customEmojiRepaint);
|
||||
}
|
||||
_emojiStatus->emoji->paint(
|
||||
p,
|
||||
iconx - 2 * _emojiStatus->skip,
|
||||
icony + _emojiStatus->skip,
|
||||
descriptor.now,
|
||||
descriptor.preview,
|
||||
descriptor.paused);
|
||||
_emojiStatus->emoji->paint(p, {
|
||||
.preview = descriptor.preview,
|
||||
.now = descriptor.now,
|
||||
.position = QPoint(
|
||||
iconx - 2 * _emojiStatus->skip,
|
||||
icony + _emojiStatus->skip),
|
||||
.paused = descriptor.paused,
|
||||
});
|
||||
return iconw - 4 * _emojiStatus->skip;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8162619cb17456f31d1be378a7ed72dc928e0831
|
||||
Subproject commit 01c4ba869a07eabc9eea2b633542a53e9ff6ff4c
|
Loading…
Add table
Reference in a new issue