mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 21:27:07 +02:00
Play effects in a separate layer over MainWidget.
This commit is contained in:
parent
f7ab8a2174
commit
cde70b9807
4 changed files with 92 additions and 27 deletions
|
@ -63,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/call_delayed.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "mainwidget.h"
|
||||
#include "menu/menu_item_download_files.h"
|
||||
#include "core/application.h"
|
||||
#include "apiwrap.h"
|
||||
|
@ -340,6 +341,8 @@ HistoryInner::HistoryInner(
|
|||
, _history(history)
|
||||
, _elementDelegate(_history->delegateMixin()->delegate())
|
||||
, _emojiInteractions(std::make_unique<HistoryView::EmojiInteractions>(
|
||||
this,
|
||||
controller->content(),
|
||||
&controller->session(),
|
||||
[=](not_null<const Element*> view) { return itemTop(view); }))
|
||||
, _migrated(history->migrateFrom())
|
||||
|
@ -393,10 +396,6 @@ HistoryInner::HistoryInner(
|
|||
_emojiInteractions->play(std::move(request), view);
|
||||
}
|
||||
}, lifetime());
|
||||
_emojiInteractions->updateRequests(
|
||||
) | rpl::start_with_next([=](QRect rect) {
|
||||
update(rect);
|
||||
}, lifetime());
|
||||
_emojiInteractions->playStarted(
|
||||
) | rpl::start_with_next([=](QString &&emoji) {
|
||||
_controller->emojiInteractions().playStarted(_peer, std::move(emoji));
|
||||
|
@ -1238,7 +1237,6 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
|||
p.setOpacity(1.);
|
||||
|
||||
_reactionsManager->paint(p, context);
|
||||
_emojiInteractions->paint(p);
|
||||
}
|
||||
|
||||
bool HistoryInner::eventHook(QEvent *e) {
|
||||
|
|
|
@ -45,9 +45,13 @@ constexpr auto kDropDelayedAfterDelay = crl::time(2000);
|
|||
} // namespace
|
||||
|
||||
EmojiInteractions::EmojiInteractions(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<QWidget*> layerParent,
|
||||
not_null<Main::Session*> session,
|
||||
Fn<int(not_null<const Element*>)> itemTop)
|
||||
: _session(session)
|
||||
: _parent(parent)
|
||||
, _layerParent(layerParent)
|
||||
, _session(session)
|
||||
, _itemTop(std::move(itemTop)) {
|
||||
_session->data().viewRemoved(
|
||||
) | rpl::filter([=] {
|
||||
|
@ -282,6 +286,18 @@ void EmojiInteractions::play(
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_layer) {
|
||||
_layer = base::make_unique_q<Ui::RpWidget>(_layerParent);
|
||||
const auto raw = _layer.get();
|
||||
raw->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
raw->show();
|
||||
raw->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
paint(raw, clip);
|
||||
}, raw->lifetime());
|
||||
}
|
||||
refreshLayerShift();
|
||||
_layer->setGeometry(_layerParent->rect());
|
||||
|
||||
auto lottie = document->session().emojiStickersPack().effectPlayer(
|
||||
document,
|
||||
data,
|
||||
|
@ -302,11 +318,12 @@ void EmojiInteractions::play(
|
|||
const auto i = ranges::find(_plays, raw, [](const Play &p) {
|
||||
return p.lottie.get();
|
||||
});
|
||||
const auto rect = computeRect(*i).translated(shift);
|
||||
if (rect.y() + rect.height() >= _visibleTop
|
||||
&& rect.y() <= _visibleBottom) {
|
||||
_updateRequests.fire_copy(rect);
|
||||
auto update = computeRect(*i).translated(shift + _layerShift);
|
||||
if (!i->lastTarget.isEmpty()) {
|
||||
update = i->lastTarget.united(update);
|
||||
}
|
||||
_layer->update(update);
|
||||
i->lastTarget = QRect();
|
||||
});
|
||||
}, lottie->lifetime());
|
||||
_plays.push_back({
|
||||
|
@ -331,6 +348,16 @@ void EmojiInteractions::play(
|
|||
}
|
||||
}
|
||||
|
||||
void EmojiInteractions::refreshLayerShift() {
|
||||
_layerShift = Ui::MapFrom(_layerParent, _parent, QPoint(0, 0));
|
||||
}
|
||||
|
||||
void EmojiInteractions::refreshLayerGeometryAndUpdate(QRect rect) {
|
||||
if (!rect.isEmpty()) {
|
||||
_layer->update(rect.translated(_layerShift));
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiInteractions::visibleAreaUpdated(
|
||||
int visibleTop,
|
||||
int visibleBottom) {
|
||||
|
@ -375,12 +402,34 @@ QRect EmojiInteractions::computeRect(const Play &play) const {
|
|||
return QRect(QPoint(left, top), size).translated(play.shift);
|
||||
}
|
||||
|
||||
void EmojiInteractions::paint(QPainter &p) {
|
||||
void EmojiInteractions::paint(not_null<QWidget*> layer, QRect clip) {
|
||||
refreshLayerShift();
|
||||
|
||||
const auto factor = style::DevicePixelRatio();
|
||||
const auto whole = layer->rect();
|
||||
|
||||
auto p = QPainter(layer);
|
||||
|
||||
auto updated = QRect();
|
||||
const auto addRect = [&](QRect rect) {
|
||||
if (updated.isEmpty()) {
|
||||
updated = rect;
|
||||
} else {
|
||||
updated = rect.united(updated);
|
||||
}
|
||||
};
|
||||
for (auto &play : _plays) {
|
||||
if (!play.lottie->ready()) {
|
||||
continue;
|
||||
}
|
||||
const auto target = computeRect(play).translated(_layerShift);
|
||||
if (!target.intersects(whole)) {
|
||||
play.finished = true;
|
||||
addRect(target);
|
||||
continue;
|
||||
} else if (!target.intersects(clip)) {
|
||||
continue;
|
||||
}
|
||||
auto request = Lottie::FrameRequest();
|
||||
request.box = play.outer * factor;
|
||||
const auto rightAligned = play.view->hasRightLayout();
|
||||
|
@ -394,18 +443,18 @@ void EmojiInteractions::paint(QPainter &p) {
|
|||
play.framesCount = information.framesCount;
|
||||
play.frameRate = information.frameRate;
|
||||
}
|
||||
const auto rect = computeRect(play);
|
||||
if (play.started && !play.frame) {
|
||||
play.finished = true;
|
||||
_updateRequests.fire_copy(rect);
|
||||
addRect(target);
|
||||
continue;
|
||||
} else if (play.frame > 0) {
|
||||
play.started = true;
|
||||
}
|
||||
p.drawImage(
|
||||
QRect(rect.topLeft(), frame.image.size() / factor),
|
||||
QRect(target.topLeft(), frame.image.size() / factor),
|
||||
frame.image);
|
||||
play.lottie->markFrameShown();
|
||||
play.lastTarget = target.translated(_layerShift);
|
||||
}
|
||||
_plays.erase(ranges::remove_if(_plays, [](const Play &play) {
|
||||
if (!play.finished) {
|
||||
|
@ -414,6 +463,18 @@ void EmojiInteractions::paint(QPainter &p) {
|
|||
return true;
|
||||
}), end(_plays));
|
||||
checkDelayed();
|
||||
|
||||
if (_plays.empty()) {
|
||||
layer->hide();
|
||||
if (_layer.get() == layer) {
|
||||
crl::on_main([moved = std::move(_layer)] {});
|
||||
}
|
||||
} else if (!updated.isEmpty()) {
|
||||
const auto translated = updated.translated(_layerShift);
|
||||
if (translated.intersects(whole)) {
|
||||
_layer->update(translated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiInteractions::checkDelayed() {
|
||||
|
@ -456,10 +517,6 @@ void EmojiInteractions::checkDelayed() {
|
|||
good.incoming);
|
||||
}
|
||||
|
||||
rpl::producer<QRect> EmojiInteractions::updateRequests() const {
|
||||
return _updateRequests.events();
|
||||
}
|
||||
|
||||
rpl::producer<QString> EmojiInteractions::playStarted() const {
|
||||
return _playStarted.events();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/unique_qptr.h"
|
||||
|
||||
namespace Data {
|
||||
class DocumentMedia;
|
||||
} // namespace Data
|
||||
|
@ -27,6 +29,10 @@ namespace Stickers {
|
|||
enum class EffectType : uint8;
|
||||
} // namespace Stickers
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
class Element;
|
||||
|
@ -34,6 +40,8 @@ class Element;
|
|||
class EmojiInteractions final {
|
||||
public:
|
||||
EmojiInteractions(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<QWidget*> layerParent,
|
||||
not_null<Main::Session*> session,
|
||||
Fn<int(not_null<const Element*>)> itemTop);
|
||||
~EmojiInteractions();
|
||||
|
@ -50,14 +58,14 @@ public:
|
|||
void playEffectOnRead(not_null<const Element*> view);
|
||||
void playEffect(not_null<const Element*> view);
|
||||
|
||||
void paint(QPainter &p);
|
||||
[[nodiscard]] rpl::producer<QRect> updateRequests() const;
|
||||
void paint(not_null<QWidget*> layer, QRect clip);
|
||||
[[nodiscard]] rpl::producer<QString> playStarted() const;
|
||||
|
||||
private:
|
||||
struct Play {
|
||||
not_null<const Element*> view;
|
||||
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||
mutable QRect lastTarget;
|
||||
QPoint shift;
|
||||
QSize inner;
|
||||
QSize outer;
|
||||
|
@ -111,15 +119,21 @@ private:
|
|||
const ResolvedEffect &resolved);
|
||||
void checkPendingEffects();
|
||||
|
||||
void refreshLayerShift();
|
||||
void refreshLayerGeometryAndUpdate(QRect rect);
|
||||
|
||||
const not_null<QWidget*> _parent;
|
||||
const not_null<QWidget*> _layerParent;
|
||||
const not_null<Main::Session*> _session;
|
||||
const Fn<int(not_null<const Element*>)> _itemTop;
|
||||
|
||||
base::unique_qptr<Ui::RpWidget> _layer;
|
||||
QPoint _layerShift;
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
|
||||
std::vector<Play> _plays;
|
||||
std::vector<Delayed> _delayed;
|
||||
rpl::event_stream<QRect> _updateRequests;
|
||||
rpl::event_stream<QString> _playStarted;
|
||||
|
||||
std::vector<base::weak_ptr<const Element>> _pendingEffects;
|
||||
|
|
|
@ -375,6 +375,8 @@ ListWidget::ListWidget(
|
|||
, _delegate(delegate)
|
||||
, _session(session)
|
||||
, _emojiInteractions(std::make_unique<EmojiInteractions>(
|
||||
this,
|
||||
_delegate->listWindow()->content(),
|
||||
session,
|
||||
[=](not_null<const Element*> view) { return itemTop(view); }))
|
||||
, _context(_delegate->listContext())
|
||||
|
@ -501,11 +503,6 @@ ListWidget::ListWidget(
|
|||
_isChatWide = wide;
|
||||
}, lifetime());
|
||||
|
||||
_emojiInteractions->updateRequests(
|
||||
) | rpl::start_with_next([=](QRect rect) {
|
||||
update(rect);
|
||||
}, lifetime());
|
||||
|
||||
_selectScroll.scrolls(
|
||||
) | rpl::start_with_next([=](int d) {
|
||||
delegate->listScrollTo(_visibleTop + d, false);
|
||||
|
@ -2278,7 +2275,6 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
|||
if (_reactionsManager) {
|
||||
_reactionsManager->paint(p, context);
|
||||
}
|
||||
_emojiInteractions->paint(p);
|
||||
}
|
||||
|
||||
void ListWidget::paintUserpics(
|
||||
|
|
Loading…
Add table
Reference in a new issue