mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Seamless switch from strip icons to custom emoji.
This commit is contained in:
parent
4762c7a4fd
commit
96805b62b2
8 changed files with 290 additions and 138 deletions
|
@ -695,9 +695,7 @@ int EmojiListWidget::countDesiredHeight(int newWidth) {
|
|||
}
|
||||
|
||||
int EmojiListWidget::defaultMinimalHeight() const {
|
||||
return (_mode != Mode::Full)
|
||||
? st::emojiPanArea.height()
|
||||
: Inner::defaultMinimalHeight();
|
||||
return Inner::defaultMinimalHeight();
|
||||
}
|
||||
|
||||
void EmojiListWidget::ensureLoaded(int section) {
|
||||
|
@ -961,10 +959,9 @@ void EmojiListWidget::drawRecent(
|
|||
} else {
|
||||
drawEmoji(p, context, position, *emoji);
|
||||
}
|
||||
} else {
|
||||
Assert(_recent[index].custom != nullptr);
|
||||
} else if (const auto custom = _recent[index].custom) {
|
||||
position += _innerPosition + _customPosition;
|
||||
_recent[index].custom->paint(p, {
|
||||
const auto paintContext = Ui::Text::CustomEmoji::Context{
|
||||
.preview = st::windowBgRipple->c,
|
||||
.size = QSize(_customSingleSize, _customSingleSize),
|
||||
.now = now,
|
||||
|
@ -972,7 +969,10 @@ void EmojiListWidget::drawRecent(
|
|||
.position = position,
|
||||
.paused = paused,
|
||||
.scaled = context.expanding,
|
||||
});
|
||||
};
|
||||
custom->paint(p, paintContext);
|
||||
} else {
|
||||
Unexpected("Empty custom emoji in EmojiListWidget::drawRecent.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1597,14 +1597,11 @@ not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
|
|||
}
|
||||
auto repaint = repaintCallback(documentId, RecentEmojiSectionSetId());
|
||||
auto custom = _customRecentFactory
|
||||
? _customRecentFactory(documentId, repaint)
|
||||
: nullptr;
|
||||
if (!custom) {
|
||||
custom = session().data().customEmojiManager().create(
|
||||
? _customRecentFactory(documentId, std::move(repaint))
|
||||
: session().data().customEmojiManager().create(
|
||||
documentId,
|
||||
std::move(repaint),
|
||||
Data::CustomEmojiManager::SizeTag::Large);
|
||||
}
|
||||
return _customEmoji.emplace(
|
||||
documentId,
|
||||
CustomEmojiInstance{ .emoji = std::move(custom), .recentOnly = true }
|
||||
|
@ -1857,7 +1854,6 @@ QPoint EmojiListWidget::buttonRippleTopLeft(int section) const {
|
|||
void EmojiListWidget::refreshEmoji() {
|
||||
refreshRecent();
|
||||
refreshCustom();
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
void EmojiListWidget::showSet(uint64 setId) {
|
||||
|
|
|
@ -41,10 +41,33 @@ public:
|
|||
QString entityData() override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
bool ready() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> _real;
|
||||
QPoint _shift;
|
||||
const std::unique_ptr<Ui::Text::CustomEmoji> _real;
|
||||
const QPoint _shift;
|
||||
|
||||
};
|
||||
|
||||
class StripEmoji final : public Ui::Text::CustomEmoji {
|
||||
public:
|
||||
StripEmoji(
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> wrapped,
|
||||
not_null<Strip*> strip,
|
||||
QPoint shift,
|
||||
int index);
|
||||
|
||||
QString entityData() override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
bool ready() override;
|
||||
|
||||
private:
|
||||
const std::unique_ptr<Ui::Text::CustomEmoji> _wrapped;
|
||||
const not_null<Strip*> _strip;
|
||||
const QPoint _shift;
|
||||
const int _index = 0;
|
||||
bool _switched = false;
|
||||
|
||||
};
|
||||
|
||||
|
@ -74,6 +97,45 @@ void ShiftedEmoji::unload() {
|
|||
_real->unload();
|
||||
}
|
||||
|
||||
bool ShiftedEmoji::ready() {
|
||||
return _real->ready();
|
||||
}
|
||||
|
||||
StripEmoji::StripEmoji(
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> wrapped,
|
||||
not_null<Strip*> strip,
|
||||
QPoint shift,
|
||||
int index)
|
||||
: _wrapped(std::move(wrapped))
|
||||
, _strip(strip)
|
||||
, _shift(shift)
|
||||
, _index(index) {
|
||||
}
|
||||
|
||||
QString StripEmoji::entityData() {
|
||||
return _wrapped->entityData();
|
||||
}
|
||||
|
||||
void StripEmoji::paint(QPainter &p, const Context &context) {
|
||||
if (_switched) {
|
||||
_wrapped->paint(p, context);
|
||||
} else if (_wrapped->ready() && _strip->inDefaultState(_index)) {
|
||||
_switched = true;
|
||||
_wrapped->paint(p, context);
|
||||
} else {
|
||||
_strip->paintOne(p, _index, context.position + _shift, 1.);
|
||||
}
|
||||
}
|
||||
|
||||
void StripEmoji::unload() {
|
||||
_wrapped->unload();
|
||||
_switched = true;
|
||||
}
|
||||
|
||||
bool StripEmoji::ready() {
|
||||
return _wrapped->ready();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Selector::Selector(
|
||||
|
@ -275,7 +337,6 @@ void Selector::paintCollapsed(QPainter &p) {
|
|||
|
||||
void Selector::paintExpanding(Painter &p, float64 progress) {
|
||||
const auto rects = paintExpandingBg(p, progress);
|
||||
//paintStripWithoutExpand(p);
|
||||
progress /= kFullDuration;
|
||||
if (_footer) {
|
||||
_footer->paintExpanding(
|
||||
|
@ -334,16 +395,6 @@ auto Selector::paintExpandingBg(QPainter &p, float64 progress)
|
|||
};
|
||||
}
|
||||
|
||||
void Selector::paintStripWithoutExpand(QPainter &p) {
|
||||
_strip.paint(
|
||||
p,
|
||||
_inner.topLeft() + QPoint(_skipx, _skipy),
|
||||
{ _size, 0 },
|
||||
_inner.marginsRemoved({ 0, 0, _skipx + _size, 0 }),
|
||||
1.,
|
||||
false);
|
||||
}
|
||||
|
||||
void Selector::paintFadingExpandIcon(QPainter &p, float64 progress) {
|
||||
if (progress >= 1.) {
|
||||
return;
|
||||
|
@ -365,7 +416,6 @@ void Selector::paintExpanded(QPainter &p) {
|
|||
finishExpand();
|
||||
}
|
||||
p.drawImage(0, 0, _paintBuffer);
|
||||
paintStripWithoutExpand(p);
|
||||
}
|
||||
|
||||
void Selector::finishExpand() {
|
||||
|
@ -429,6 +479,9 @@ int Selector::lookupSelectedIndex(QPoint position) const {
|
|||
}
|
||||
|
||||
void Selector::setSelected(int index) {
|
||||
if (index >= 0 && _expandScheduled) {
|
||||
return;
|
||||
}
|
||||
_strip.setSelected(index);
|
||||
const auto over = (index >= 0);
|
||||
if (_over != over) {
|
||||
|
@ -468,6 +521,10 @@ void Selector::mouseReleaseEvent(QMouseEvent *e) {
|
|||
}
|
||||
|
||||
void Selector::expand() {
|
||||
if (_expandScheduled) {
|
||||
return;
|
||||
}
|
||||
_expandScheduled = true;
|
||||
const auto parent = parentWidget()->geometry();
|
||||
const auto additionalBottom = parent.height() - y() - height();
|
||||
const auto additional = _specialExpandTopSkip + additionalBottom;
|
||||
|
@ -483,11 +540,12 @@ void Selector::expand() {
|
|||
cacheExpandIcon();
|
||||
|
||||
[[maybe_unused]] const auto grabbed = Ui::GrabWidget(_scroll);
|
||||
setSelected(-1);
|
||||
|
||||
base::call_delayed(kExpandDelay, this, [=] {
|
||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||
_expanded = true;
|
||||
base::call_delayed(kExpandDelay, this, [this] {
|
||||
const auto full = kExpandDuration + kScaleDuration;
|
||||
_expanded = true;
|
||||
_paintBuffer = _cachedRound.PrepareImage(size());
|
||||
_expanding.start([=] { update(); }, 0., full, full);
|
||||
});
|
||||
}
|
||||
|
@ -496,14 +554,7 @@ void Selector::cacheExpandIcon() {
|
|||
_expandIconCache = _cachedRound.PrepareImage({ _size, _size });
|
||||
_expandIconCache.fill(Qt::transparent);
|
||||
auto q = QPainter(&_expandIconCache);
|
||||
const auto count = _strip.count();
|
||||
_strip.paint(
|
||||
q,
|
||||
QPoint(-(count - 1) * _size, 0),
|
||||
{ _size, 0 },
|
||||
QRect(-(count - 1) * _size, 0, count * _size, _size),
|
||||
1.,
|
||||
false);
|
||||
_strip.paintOne(q, _strip.count() - 1, { 0, 0 }, 1.);
|
||||
}
|
||||
|
||||
void Selector::createList(not_null<Window::SessionController*> controller) {
|
||||
|
@ -511,6 +562,8 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
|
|||
auto recent = std::vector<DocumentId>();
|
||||
auto defaultReactionIds = base::flat_map<DocumentId, QString>();
|
||||
recent.reserve(_reactions.recent.size());
|
||||
auto index = 0;
|
||||
const auto inStrip = _strip.count();
|
||||
for (const auto &reaction : _reactions.recent) {
|
||||
if (const auto id = reaction->id.custom()) {
|
||||
recent.push_back(id);
|
||||
|
@ -518,9 +571,12 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
|
|||
recent.push_back(reaction->selectAnimation->id);
|
||||
defaultReactionIds.emplace(recent.back(), reaction->id.emoji());
|
||||
}
|
||||
if (index + 1 < inStrip) {
|
||||
_defaultReactionInStripMap.emplace(recent.back(), index++);
|
||||
}
|
||||
};
|
||||
const auto manager = &controller->session().data().customEmojiManager();
|
||||
const auto shift = [&] {
|
||||
_stripPaintOneShift = [&] {
|
||||
// See EmojiListWidget custom emoji position resolving.
|
||||
const auto area = st::emojiPanArea;
|
||||
const auto areaPosition = QPoint(
|
||||
|
@ -533,19 +589,34 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
|
|||
const auto customSize = Ui::Text::AdjustCustomEmojiSize(esize);
|
||||
const auto customSkip = (esize - customSize) / 2;
|
||||
const auto customPosition = QPoint(customSkip, customSkip);
|
||||
return QPoint(
|
||||
(_size - st::reactStripImage) / 2,
|
||||
(_size - st::reactStripImage) / 2
|
||||
) - areaPosition - innerPosition - customPosition;
|
||||
return areaPosition + innerPosition + customPosition;
|
||||
}();
|
||||
auto factory = [=](DocumentId id, Fn<void()> repaint) {
|
||||
return defaultReactionIds.contains(id)
|
||||
_defaultReactionShift = QPoint(
|
||||
(_size - st::reactStripImage) / 2,
|
||||
(_size - st::reactStripImage) / 2
|
||||
) - _stripPaintOneShift;
|
||||
auto factory = [=](DocumentId id, Fn<void()> repaint)
|
||||
-> std::unique_ptr<Ui::Text::CustomEmoji> {
|
||||
const auto isDefaultReaction = defaultReactionIds.contains(id);
|
||||
auto result = isDefaultReaction
|
||||
? std::make_unique<ShiftedEmoji>(
|
||||
manager,
|
||||
id,
|
||||
std::move(repaint),
|
||||
shift)
|
||||
: nullptr;
|
||||
_defaultReactionShift)
|
||||
: manager->create(
|
||||
id,
|
||||
std::move(repaint),
|
||||
Data::CustomEmojiManager::SizeTag::Large);
|
||||
const auto i = _defaultReactionInStripMap.find(id);
|
||||
if (i != end(_defaultReactionInStripMap)) {
|
||||
return std::make_unique<StripEmoji>(
|
||||
std::move(result),
|
||||
&_strip,
|
||||
-_stripPaintOneShift,
|
||||
i->second);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
_scroll = Ui::CreateChild<Ui::ScrollArea>(this, st::reactPanelScroll);
|
||||
_scroll->hide();
|
||||
|
@ -631,6 +702,7 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
|
|||
0,
|
||||
0,
|
||||
}));
|
||||
_list->setMinimalHeight(geometry.width(), _scroll->height());
|
||||
|
||||
updateVisibleTopBottom();
|
||||
}
|
||||
|
|
|
@ -83,7 +83,6 @@ private:
|
|||
void paintCollapsed(QPainter &p);
|
||||
void paintExpanding(Painter &p, float64 progress);
|
||||
ExpandingRects paintExpandingBg(QPainter &p, float64 progress);
|
||||
void paintStripWithoutExpand(QPainter &p);
|
||||
void paintFadingExpandIcon(QPainter &p, float64 progress);
|
||||
void paintExpanded(QPainter &p);
|
||||
void paintBubble(QPainter &p, int innerWidth);
|
||||
|
@ -100,7 +99,10 @@ private:
|
|||
|
||||
const base::weak_ptr<Window::SessionController> _parentController;
|
||||
const Data::PossibleItemReactions _reactions;
|
||||
base::flat_map<DocumentId, int> _defaultReactionInStripMap;
|
||||
Ui::RoundAreaWithShadow _cachedRound;
|
||||
QPoint _defaultReactionShift;
|
||||
QPoint _stripPaintOneShift;
|
||||
Strip _strip;
|
||||
|
||||
rpl::event_stream<ChosenReaction> _chosen;
|
||||
|
@ -133,6 +135,7 @@ private:
|
|||
bool _appearing = false;
|
||||
bool _toggling = false;
|
||||
bool _expanded = false;
|
||||
bool _expandScheduled = false;
|
||||
bool _expandFinished = false;
|
||||
bool _small = false;
|
||||
bool _over = false;
|
||||
|
|
|
@ -99,6 +99,28 @@ void Strip::paint(
|
|||
const auto animationRect = clip.marginsRemoved({ 0, skip, 0, skip });
|
||||
|
||||
PainterHighQualityEnabler hq(p);
|
||||
const auto countTarget = resolveCountTargetMethod(scale);
|
||||
for (auto &icon : _icons) {
|
||||
const auto target = countTarget(icon).translated(position);
|
||||
position += shift;
|
||||
if (target.intersects(clip)) {
|
||||
paintOne(
|
||||
p,
|
||||
icon,
|
||||
position - shift,
|
||||
target,
|
||||
!hiding && target.intersects(animationRect));
|
||||
} else if (!hiding) {
|
||||
clearStateForHidden(icon);
|
||||
}
|
||||
if (!hiding) {
|
||||
clearStateForSelectFinished(icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Strip::resolveCountTargetMethod(float64 scale) const
|
||||
-> Fn<QRectF(const ReactionIcons&)> {
|
||||
const auto hoveredSize = int(base::SafeRound(_finalSize * kHoverScale));
|
||||
const auto basicTargetForScale = [&](int size, float64 scale) {
|
||||
const auto remove = size * (1. - scale) / 2.;
|
||||
|
@ -110,7 +132,7 @@ void Strip::paint(
|
|||
)).marginsRemoved({ remove, remove, remove, remove });
|
||||
};
|
||||
const auto basicTarget = basicTargetForScale(_finalSize, scale);
|
||||
const auto countTarget = [&](const ReactionIcons &icon) {
|
||||
return [=](const ReactionIcons &icon) {
|
||||
const auto selectScale = icon.selectedScale.value(
|
||||
icon.selected ? kHoverScale : 1.);
|
||||
if (selectScale == 1.) {
|
||||
|
@ -121,45 +143,62 @@ void Strip::paint(
|
|||
? basicTargetForScale(_finalSize, finalScale)
|
||||
: basicTargetForScale(hoveredSize, finalScale / kHoverScale);
|
||||
};
|
||||
for (auto &icon : _icons) {
|
||||
const auto target = countTarget(icon).translated(position);
|
||||
position += shift;
|
||||
}
|
||||
|
||||
void Strip::paintOne(
|
||||
QPainter &p,
|
||||
ReactionIcons &icon,
|
||||
QPoint position,
|
||||
QRectF target,
|
||||
bool allowAppearStart) {
|
||||
if (icon.added == AddedButton::Premium) {
|
||||
paintPremiumIcon(p, position, target);
|
||||
} else if (icon.added == AddedButton::Expand) {
|
||||
paintExpandIcon(p, position, target);
|
||||
} else {
|
||||
const auto paintFrame = [&](not_null<Lottie::Icon*> animation) {
|
||||
const auto size = int(std::floor(target.width() + 0.01));
|
||||
const auto frame = animation->frame({ size, size }, _update);
|
||||
p.drawImage(target, frame.image);
|
||||
};
|
||||
|
||||
if (!target.intersects(clip)) {
|
||||
if (!hiding) {
|
||||
clearStateForHidden(icon);
|
||||
}
|
||||
} else if (icon.added == AddedButton::Premium) {
|
||||
paintPremiumIcon(p, position - shift, target);
|
||||
} else if (icon.added == AddedButton::Expand) {
|
||||
paintExpandIcon(p, position - shift, target);
|
||||
} else {
|
||||
const auto appear = icon.appear.get();
|
||||
if (!hiding
|
||||
&& appear
|
||||
&& !icon.appearAnimated
|
||||
&& target.intersects(animationRect)) {
|
||||
icon.appearAnimated = true;
|
||||
appear->animate(_update, 0, appear->framesCount() - 1);
|
||||
}
|
||||
if (appear && appear->animating()) {
|
||||
paintFrame(appear);
|
||||
} else if (const auto select = icon.select.get()) {
|
||||
paintFrame(select);
|
||||
}
|
||||
const auto appear = icon.appear.get();
|
||||
if (appear && !icon.appearAnimated && allowAppearStart) {
|
||||
icon.appearAnimated = true;
|
||||
appear->animate(_update, 0, appear->framesCount() - 1);
|
||||
}
|
||||
if (!hiding) {
|
||||
clearStateForSelectFinished(icon);
|
||||
if (appear && appear->animating()) {
|
||||
paintFrame(appear);
|
||||
} else if (const auto select = icon.select.get()) {
|
||||
paintFrame(select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Strip::paintOne(
|
||||
QPainter &p,
|
||||
int index,
|
||||
QPoint position,
|
||||
float64 scale) {
|
||||
Expects(index >= 0 && index < _icons.size());
|
||||
|
||||
auto &icon = _icons[index];
|
||||
const auto countTarget = resolveCountTargetMethod(scale);
|
||||
const auto target = countTarget(icon).translated(position);
|
||||
paintOne(p, icon, position, target, false);
|
||||
}
|
||||
|
||||
bool Strip::inDefaultState(int index) const {
|
||||
Expects(index >= 0 && index < _icons.size());
|
||||
|
||||
const auto &icon = _icons[index];
|
||||
return !icon.selected
|
||||
&& !icon.selectedScale.animating()
|
||||
&& icon.select
|
||||
&& !icon.select->animating()
|
||||
&& (!icon.appear || !icon.appear->animating());
|
||||
}
|
||||
|
||||
bool Strip::empty() const {
|
||||
return _icons.empty();
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ public:
|
|||
QRect clip,
|
||||
float64 scale,
|
||||
bool hiding);
|
||||
void paintOne(QPainter &p, int index, QPoint position, float64 scale);
|
||||
[[nodiscard]] bool inDefaultState(int index) const;
|
||||
|
||||
[[nodiscard]] bool empty() const;
|
||||
[[nodiscard]] int count() const;
|
||||
|
@ -107,6 +109,14 @@ private:
|
|||
[[nodiscard]] bool checkIconLoaded(ReactionDocument &entry) const;
|
||||
void loadIcons();
|
||||
void checkIcons();
|
||||
void paintOne(
|
||||
QPainter &p,
|
||||
ReactionIcons &icon,
|
||||
QPoint position,
|
||||
QRectF target,
|
||||
bool allowAppearStart);
|
||||
[[nodiscard]] Fn<QRectF(const ReactionIcons&)> resolveCountTargetMethod(
|
||||
float64 scale) const;
|
||||
|
||||
void resolveMainReactionIcon();
|
||||
void setMainReactionIcon();
|
||||
|
|
|
@ -520,6 +520,10 @@ std::unique_ptr<Loader> Renderer::cancel() {
|
|||
return _loader();
|
||||
}
|
||||
|
||||
bool Renderer::canMakePreview() const {
|
||||
return _cache.frames() > 0;
|
||||
}
|
||||
|
||||
Preview Renderer::makePreview() const {
|
||||
return _cache.makePreview();
|
||||
}
|
||||
|
@ -567,7 +571,7 @@ void Loading::paint(QPainter &p, const Context &context) {
|
|||
}
|
||||
|
||||
bool Loading::hasImagePreview() const {
|
||||
return _preview.isImage();
|
||||
return _preview.isImage();
|
||||
}
|
||||
|
||||
Preview Loading::imagePreview() const {
|
||||
|
@ -599,84 +603,99 @@ Instance::Instance(
|
|||
}
|
||||
|
||||
QString Instance::entityData() const {
|
||||
if (const auto loading = std::get_if<Loading>(&_state)) {
|
||||
return loading->entityData();
|
||||
} else if (const auto caching = std::get_if<Caching>(&_state)) {
|
||||
return caching->entityData;
|
||||
} else if (const auto cached = std::get_if<Cached>(&_state)) {
|
||||
return cached->entityData();
|
||||
}
|
||||
Unexpected("State in Instance::entityData.");
|
||||
return v::match(_state, [](const Loading &state) {
|
||||
return state.entityData();
|
||||
}, [](const Caching &state) {
|
||||
return state.entityData;
|
||||
}, [](const Cached &state) {
|
||||
return state.entityData();
|
||||
});
|
||||
}
|
||||
|
||||
void Instance::paint(QPainter &p, const Context &context) {
|
||||
if (const auto loading = std::get_if<Loading>(&_state)) {
|
||||
loading->paint(p, context);
|
||||
loading->load([=](Loader::LoadResult result) {
|
||||
if (auto caching = std::get_if<Caching>(&result)) {
|
||||
caching->renderer->setRepaintCallback([=] { repaint(); });
|
||||
_state = std::move(*caching);
|
||||
} else if (auto cached = std::get_if<Cached>(&result)) {
|
||||
_state = std::move(*cached);
|
||||
repaint();
|
||||
} else {
|
||||
Unexpected("Value in Loader::LoadResult.");
|
||||
}
|
||||
});
|
||||
} else if (const auto caching = std::get_if<Caching>(&_state)) {
|
||||
auto result = caching->renderer->paint(p, context);
|
||||
v::match(_state, [&](Loading &state) {
|
||||
state.paint(p, context);
|
||||
load(state);
|
||||
}, [&](Caching &state) {
|
||||
auto result = state.renderer->paint(p, context);
|
||||
if (!result.painted) {
|
||||
caching->preview.paint(p, context);
|
||||
state.preview.paint(p, context);
|
||||
} else {
|
||||
if (!caching->preview.isExactImage()) {
|
||||
caching->preview = caching->renderer->makePreview();
|
||||
if (!state.preview.isExactImage()) {
|
||||
state.preview = state.renderer->makePreview();
|
||||
}
|
||||
if (result.next > context.now) {
|
||||
_repaintLater(this, { result.next, result.duration });
|
||||
}
|
||||
}
|
||||
if (auto cached = caching->renderer->ready(caching->entityData)) {
|
||||
if (auto cached = state.renderer->ready(state.entityData)) {
|
||||
_state = std::move(*cached);
|
||||
}
|
||||
} else if (const auto cached = std::get_if<Cached>(&_state)) {
|
||||
const auto result = cached->paint(p, context);
|
||||
}, [&](Cached &state) {
|
||||
const auto result = state.paint(p, context);
|
||||
if (result.next > context.now) {
|
||||
_repaintLater(this, { result.next, result.duration });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool Instance::ready() {
|
||||
return v::match(_state, [&](Loading &state) {
|
||||
if (state.hasImagePreview()) {
|
||||
return true;
|
||||
}
|
||||
load(state);
|
||||
return false;
|
||||
}, [](Caching &state) {
|
||||
return state.renderer->canMakePreview();
|
||||
}, [](Cached &state) {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void Instance::load(Loading &state) {
|
||||
state.load([=](Loader::LoadResult result) {
|
||||
if (auto caching = std::get_if<Caching>(&result)) {
|
||||
caching->renderer->setRepaintCallback([=] { repaint(); });
|
||||
_state = std::move(*caching);
|
||||
} else if (auto cached = std::get_if<Cached>(&result)) {
|
||||
_state = std::move(*cached);
|
||||
repaint();
|
||||
} else {
|
||||
Unexpected("Value in Loader::LoadResult.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool Instance::hasImagePreview() const {
|
||||
if (const auto loading = std::get_if<Loading>(&_state)) {
|
||||
return loading->hasImagePreview();
|
||||
} else if (const auto caching = std::get_if<Caching>(&_state)) {
|
||||
return caching->preview.isImage();
|
||||
} else if (const auto cached = std::get_if<Cached>(&_state)) {
|
||||
return v::match(_state, [](const Loading &state) {
|
||||
return state.hasImagePreview();
|
||||
}, [](const Caching &state) {
|
||||
return state.preview.isImage();
|
||||
}, [](const Cached &state) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
Preview Instance::imagePreview() const {
|
||||
if (const auto loading = std::get_if<Loading>(&_state)) {
|
||||
return loading->imagePreview();
|
||||
} else if (const auto caching = std::get_if<Caching>(&_state)) {
|
||||
return caching->preview.isImage() ? caching->preview : Preview();
|
||||
} else if (const auto cached = std::get_if<Cached>(&_state)) {
|
||||
return cached->makePreview();
|
||||
}
|
||||
return {};
|
||||
return v::match(_state, [](const Loading &state) {
|
||||
return state.imagePreview();
|
||||
}, [](const Caching &state) {
|
||||
return state.preview.isImage() ? state.preview : Preview();
|
||||
}, [](const Cached &state) {
|
||||
return state.makePreview();
|
||||
});
|
||||
}
|
||||
|
||||
void Instance::updatePreview(Preview preview) {
|
||||
if (const auto loading = std::get_if<Loading>(&_state)) {
|
||||
loading->updatePreview(std::move(preview));
|
||||
} else if (const auto caching = std::get_if<Caching>(&_state)) {
|
||||
if ((!caching->preview.isImage() && preview.isImage())
|
||||
|| (!caching->preview && preview)) {
|
||||
caching->preview = std::move(preview);
|
||||
v::match(_state, [&](Loading &state) {
|
||||
state.updatePreview(std::move(preview));
|
||||
}, [&](Caching &state) {
|
||||
if ((!state.preview.isImage() && preview.isImage())
|
||||
|| (!state.preview && preview)) {
|
||||
state.preview = std::move(preview);
|
||||
}
|
||||
}
|
||||
}, [](const Cached &) {});
|
||||
}
|
||||
|
||||
void Instance::repaint() {
|
||||
|
@ -694,16 +713,16 @@ void Instance::decrementUsage(not_null<Object*> object) {
|
|||
if (!_usage.empty()) {
|
||||
return;
|
||||
}
|
||||
if (const auto loading = std::get_if<Loading>(&_state)) {
|
||||
loading->cancel();
|
||||
} else if (const auto caching = std::get_if<Caching>(&_state)) {
|
||||
v::match(_state, [](Loading &state) {
|
||||
state.cancel();
|
||||
}, [&](Caching &state) {
|
||||
_state = Loading{
|
||||
caching->renderer->cancel(),
|
||||
std::move(caching->preview),
|
||||
state.renderer->cancel(),
|
||||
std::move(state.preview),
|
||||
};
|
||||
} else if (const auto cached = std::get_if<Cached>(&_state)) {
|
||||
_state = cached->unload();
|
||||
}
|
||||
}, [&](Cached &state) {
|
||||
_state = state.unload();
|
||||
});
|
||||
_repaintLater(this, RepaintRequest());
|
||||
}
|
||||
|
||||
|
@ -735,6 +754,14 @@ void Object::unload() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Object::ready() {
|
||||
if (!_using) {
|
||||
_using = true;
|
||||
_instance->incrementUsage(this);
|
||||
}
|
||||
return _instance->ready();
|
||||
}
|
||||
|
||||
void Object::repaint() {
|
||||
_repaint();
|
||||
}
|
||||
|
|
|
@ -145,6 +145,7 @@ public:
|
|||
[[nodiscard]] std::optional<Cached> ready(const QString &entityData);
|
||||
[[nodiscard]] std::unique_ptr<Loader> cancel();
|
||||
|
||||
[[nodiscard]] bool canMakePreview() const;
|
||||
[[nodiscard]] Preview makePreview() const;
|
||||
|
||||
void setRepaintCallback(Fn<void()> repaint);
|
||||
|
@ -223,6 +224,7 @@ public:
|
|||
|
||||
[[nodiscard]] QString entityData() const;
|
||||
void paint(QPainter &p, const Context &context);
|
||||
[[nodiscard]] bool ready();
|
||||
[[nodiscard]] bool hasImagePreview() const;
|
||||
[[nodiscard]] Preview imagePreview() const;
|
||||
void updatePreview(Preview preview);
|
||||
|
@ -233,6 +235,8 @@ public:
|
|||
void repaint();
|
||||
|
||||
private:
|
||||
void load(Loading &state);
|
||||
|
||||
std::variant<Loading, Caching, Cached> _state;
|
||||
base::flat_set<not_null<Object*>> _usage;
|
||||
Fn<void(not_null<Instance*> that, RepaintRequest)> _repaintLater;
|
||||
|
@ -253,6 +257,7 @@ public:
|
|||
QString entityData() override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
bool ready() override;
|
||||
|
||||
void repaint();
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 01c4ba869a07eabc9eea2b633542a53e9ff6ff4c
|
||||
Subproject commit fc2c55367099ca7bdeacd0d52ff6007f00a6ba72
|
Loading…
Add table
Reference in a new issue