Removed Function<> and SharedCallback<>, using base::lambda_unique<>.

Also removed macro START_ANIMATION(anim,) using anim.start() instead.
This commit is contained in:
John Preston 2016-09-26 15:09:59 +03:00
parent 866bc4ff8a
commit 453661d611
61 changed files with 322 additions and 502 deletions

View File

@ -42,11 +42,10 @@ ApiWrap::ApiWrap(QObject *parent) : QObject(parent)
void ApiWrap::init() { void ApiWrap::init() {
} }
void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr<RequestMessageDataCallback> callback) { void ApiWrap::requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback &&callback) {
MessageDataRequest &req(channel ? _channelMessageDataRequests[channel][msgId] : _messageDataRequests[msgId]); MessageDataRequest &req(channel ? _channelMessageDataRequests[channel][msgId] : _messageDataRequests[msgId]);
if (callback) { if (callback) {
MessageDataRequest::CallbackPtr pcallback(callback.release()); req.callbacks.append(std_::move(callback));
req.callbacks.append(pcallback);
} }
if (!req.req) _messageDataResolveDelayed->call(); if (!req.req) _messageDataResolveDelayed->call();
} }
@ -138,7 +137,7 @@ void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &
for (auto i = requests->begin(); i != requests->cend();) { for (auto i = requests->begin(); i != requests->cend();) {
if (i.value().req == req) { if (i.value().req == req) {
for_const (auto &callback, i.value().callbacks) { for_const (auto &callback, i.value().callbacks) {
callback->call(channel, i.key()); callback(channel, i.key());
} }
i = requests->erase(i); i = requests->erase(i);
} else { } else {

View File

@ -28,8 +28,8 @@ public:
ApiWrap(QObject *parent); ApiWrap(QObject *parent);
void init(); void init();
using RequestMessageDataCallback = SharedCallback<void, ChannelData*, MsgId>; using RequestMessageDataCallback = base::lambda_wrap<void(ChannelData*, MsgId)>;
void requestMessageData(ChannelData *channel, MsgId msgId, std_::unique_ptr<RequestMessageDataCallback> callback); void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback &&callback);
void requestFullPeer(PeerData *peer); void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer); void requestPeer(PeerData *peer);
@ -82,11 +82,8 @@ private:
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
struct MessageDataRequest { struct MessageDataRequest {
MessageDataRequest() : req(0) { using Callbacks = QList<RequestMessageDataCallback>;
} mtpRequestId req = 0;
typedef SharedCallback<void, ChannelData*, MsgId>::Ptr CallbackPtr;
typedef QList<CallbackPtr> Callbacks;
mtpRequestId req;
Callbacks callbacks; Callbacks callbacks;
}; };
typedef QMap<MsgId, MessageDataRequest> MessageDataRequests; typedef QMap<MsgId, MessageDataRequest> MessageDataRequests;

View File

@ -227,9 +227,9 @@ void ShareBox::onMustScrollTo(int top, int bottom) {
to = bottom - (scrollBottom - scrollTop); to = bottom - (scrollBottom - scrollTop);
} }
if (from != to) { if (from != to) {
START_ANIMATION(_scrollAnimation, func([this]() { _scrollAnimation.start([this]() {
scrollArea()->scrollToY(_scrollAnimation.current(scrollArea()->scrollTop())); scrollArea()->scrollToY(_scrollAnimation.current(scrollArea()->scrollTop()));
}), from, to, st::shareScrollDuration, anim::sineInOut); }, from, to, st::shareScrollDuration, anim::sineInOut);
} }
} }
@ -437,9 +437,9 @@ void ShareInner::setActive(int active) {
if (active != _active) { if (active != _active) {
auto changeNameFg = [this](int index, style::color from, style::color to) { auto changeNameFg = [this](int index, style::color from, style::color to) {
if (auto chat = getChatAtIndex(index)) { if (auto chat = getChatAtIndex(index)) {
START_ANIMATION(chat->nameFg, func([this, chat] { chat->nameFg.start([this, chat] {
repaintChat(chat->peer); repaintChat(chat->peer);
}), from->c, to->c, st::shareActivateDuration, anim::linear); }, from->c, to->c, st::shareActivateDuration);
} }
}; };
changeNameFg(_active, st::shareNameActiveFg, st::shareNameFg); changeNameFg(_active, st::shareNameActiveFg, st::shareNameFg);
@ -459,16 +459,7 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
auto w = width(); auto w = width();
auto photoLeft = (_rowWidth - (st::sharePhotoRadius * 2)) / 2; auto photoLeft = (_rowWidth - (st::sharePhotoRadius * 2)) / 2;
auto photoTop = st::sharePhotoTop; auto photoTop = st::sharePhotoTop;
if (chat->selection.isNull()) { if (chat->selection.animating()) {
if (!chat->wideUserpicCache.isNull()) {
chat->wideUserpicCache = QPixmap();
}
auto userpicRadius = chat->selected ? st::sharePhotoSmallRadius : st::sharePhotoRadius;
auto userpicShift = st::sharePhotoRadius - userpicRadius;
auto userpicLeft = x + photoLeft + userpicShift;
auto userpicTop = y + photoTop + userpicShift;
chat->peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, w);
} else {
p.setRenderHint(QPainter::SmoothPixmapTransform, true); p.setRenderHint(QPainter::SmoothPixmapTransform, true);
auto userpicRadius = qRound(WideCacheScale * (st::sharePhotoRadius + (st::sharePhotoSmallRadius - st::sharePhotoRadius) * selectionLevel)); auto userpicRadius = qRound(WideCacheScale * (st::sharePhotoRadius + (st::sharePhotoSmallRadius - st::sharePhotoRadius) * selectionLevel));
auto userpicShift = WideCacheScale * st::sharePhotoRadius - userpicRadius; auto userpicShift = WideCacheScale * st::sharePhotoRadius - userpicRadius;
@ -478,6 +469,15 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
auto from = QRect(QPoint(0, 0), chat->wideUserpicCache.size()); auto from = QRect(QPoint(0, 0), chat->wideUserpicCache.size());
p.drawPixmapLeft(to, w, chat->wideUserpicCache, from); p.drawPixmapLeft(to, w, chat->wideUserpicCache, from);
p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.setRenderHint(QPainter::SmoothPixmapTransform, false);
} else {
if (!chat->wideUserpicCache.isNull()) {
chat->wideUserpicCache = QPixmap();
}
auto userpicRadius = chat->selected ? st::sharePhotoSmallRadius : st::sharePhotoRadius;
auto userpicShift = st::sharePhotoRadius - userpicRadius;
auto userpicLeft = x + photoLeft + userpicShift;
auto userpicTop = y + photoTop + userpicShift;
chat->peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, w);
} }
if (selectionLevel > 0) { if (selectionLevel > 0) {
@ -516,11 +516,12 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.setRenderHint(QPainter::SmoothPixmapTransform, false);
p.setOpacity(1.); p.setOpacity(1.);
if (chat->nameFg.isNull()) { if (chat->nameFg.animating()) {
p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg);
} else {
p.setPen(chat->nameFg.current()); p.setPen(chat->nameFg.current());
} else {
p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg);
} }
auto nameWidth = (_rowWidth - st::shareColumnSkip); auto nameWidth = (_rowWidth - st::shareColumnSkip);
auto nameLeft = st::shareColumnSkip / 2; auto nameLeft = st::shareColumnSkip / 2;
auto nameTop = photoTop + st::sharePhotoRadius * 2 + st::shareNameTop; auto nameTop = photoTop + st::sharePhotoRadius * 2 + st::shareNameTop;
@ -670,21 +671,21 @@ void ShareInner::changeCheckState(Chat *chat) {
if (chat->selected) { if (chat->selected) {
_selected.insert(chat->peer); _selected.insert(chat->peer);
chat->icons.push_back(Chat::Icon()); chat->icons.push_back(Chat::Icon());
START_ANIMATION(chat->icons.back().fadeIn, func([this, chat] { chat->icons.back().fadeIn.start([this, chat] {
repaintChat(chat->peer); repaintChat(chat->peer);
}), 0, 1, st::shareSelectDuration, anim::linear); }, 0, 1, st::shareSelectDuration);
} else { } else {
_selected.remove(chat->peer); _selected.remove(chat->peer);
prepareWideCheckIconCache(&chat->icons.back()); prepareWideCheckIconCache(&chat->icons.back());
START_ANIMATION(chat->icons.back().fadeOut, func([this, chat] { chat->icons.back().fadeOut.start([this, chat] {
removeFadeOutedIcons(chat);
repaintChat(chat->peer); repaintChat(chat->peer);
}), 1, 0, st::shareSelectDuration, anim::linear); removeFadeOutedIcons(chat); // this call can destroy current lambda
}, 1, 0, st::shareSelectDuration);
} }
prepareWideUserpicCache(chat); prepareWideUserpicCache(chat);
START_ANIMATION(chat->selection, func([this, chat] { chat->selection.start([this, chat] {
repaintChat(chat->peer); repaintChat(chat->peer);
}), chat->selected ? 0 : 1, chat->selected ? 1 : 0, st::shareSelectDuration, anim_bumpy); }, chat->selected ? 0 : 1, chat->selected ? 1 : 0, st::shareSelectDuration, anim_bumpy);
if (chat->selected) { if (chat->selected) {
setActive(chatIndex(chat->peer)); setActive(chatIndex(chat->peer));
} }
@ -692,9 +693,9 @@ void ShareInner::changeCheckState(Chat *chat) {
} }
void ShareInner::removeFadeOutedIcons(Chat *chat) { void ShareInner::removeFadeOutedIcons(Chat *chat) {
while (!chat->icons.empty() && chat->icons.front().fadeIn.isNull() && chat->icons.front().fadeOut.isNull()) { while (!chat->icons.empty() && !chat->icons.front().fadeIn.animating() && !chat->icons.front().fadeOut.animating()) {
if (chat->icons.size() > 1 || !chat->selected) { if (chat->icons.size() > 1 || !chat->selected) {
chat->icons.pop_front(); chat->icons.erase(chat->icons.begin());
} else { } else {
break; break;
} }
@ -1016,18 +1017,6 @@ void shareGameScoreFromItem(HistoryItem *item) {
Ui::showLayer(new ShareBox(std_::move(copyCallback), std_::move(submitCallback))); Ui::showLayer(new ShareBox(std_::move(copyCallback), std_::move(submitCallback)));
} }
class GameMessageResolvedCallback : public SharedCallback<void, ChannelData*, MsgId> {
public:
void call(ChannelData *channel, MsgId msgId) const override {
if (auto item = App::histItemById(channel, msgId)) {
shareGameScoreFromItem(item);
} else {
Ui::showLayer(new InformBox(lang(lng_edit_deleted)));
}
}
};
} // namespace } // namespace
void shareGameScoreByHash(const QString &hash) { void shareGameScoreByHash(const QString &hash) {
@ -1062,7 +1051,13 @@ void shareGameScoreByHash(const QString &hash) {
} else if (App::api()) { } else if (App::api()) {
auto channel = channelId ? App::channelLoaded(channelId) : nullptr; auto channel = channelId ? App::channelLoaded(channelId) : nullptr;
if (channel || !channelId) { if (channel || !channelId) {
App::api()->requestMessageData(channel, msgId, std_::make_unique<GameMessageResolvedCallback>()); App::api()->requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) {
if (auto item = App::histItemById(channel, msgId)) {
shareGameScoreFromItem(item);
} else {
Ui::showLayer(new InformBox(lang(lng_edit_deleted)));
}
});
} }
} }
} }

View File

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "abstractbox.h" #include "abstractbox.h"
#include "core/lambda_wrap.h" #include "core/lambda_wrap.h"
#include "core/observer.h" #include "core/observer.h"
#include "core/vector_of_moveable.h"
namespace Dialogs { namespace Dialogs {
class Row; class Row;
@ -163,7 +164,7 @@ private:
FloatAnimation fadeOut; FloatAnimation fadeOut;
QPixmap wideCheckCache; QPixmap wideCheckCache;
}; };
QList<Icon> icons; std_::vector_of_moveable<Icon> icons;
}; };
void paintChat(Painter &p, Chat *chat, int index); void paintChat(Painter &p, Chat *chat, int index);
void updateChat(PeerData *peer); void updateChat(PeerData *peer);

View File

@ -62,8 +62,8 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_selected = -1; _selected = -1;
setCursor(style::cur_default); setCursor(style::cur_default);
if (set.type() == mtpc_messages_stickerSet) { if (set.type() == mtpc_messages_stickerSet) {
auto &d(set.c_messages_stickerSet()); auto &d = set.c_messages_stickerSet();
auto &v(d.vdocuments.c_vector().v); auto &v = d.vdocuments.c_vector().v;
_pack.reserve(v.size()); _pack.reserve(v.size());
_packOvers.reserve(v.size()); _packOvers.reserve(v.size());
for (int i = 0, l = v.size(); i < l; ++i) { for (int i = 0, l = v.size(); i < l; ++i) {
@ -247,13 +247,13 @@ void StickerSetInner::updateSelected() {
void StickerSetInner::startOverAnimation(int index, float64 from, float64 to) { void StickerSetInner::startOverAnimation(int index, float64 from, float64 to) {
if (index >= 0 && index < _packOvers.size()) { if (index >= 0 && index < _packOvers.size()) {
START_ANIMATION(_packOvers[index], func([this, index]() { _packOvers[index].start([this, index] {
int row = index / StickerPanPerRow; int row = index / StickerPanPerRow;
int column = index % StickerPanPerRow; int column = index % StickerPanPerRow;
int left = st::stickersPadding.left() + column * st::stickersSize.width(); int left = st::stickersPadding.left() + column * st::stickersSize.width();
int top = st::stickersPadding.top() + row * st::stickersSize.height(); int top = st::stickersPadding.top() + row * st::stickersSize.height();
rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height()); rtlupdate(left, top, st::stickersSize.width(), st::stickersSize.height());
}), from, to, st::emojiPanDuration, anim::linear); }, from, to, st::emojiPanDuration);
} }
} }

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "abstractbox.h" #include "abstractbox.h"
#include "core/vector_of_moveable.h"
class ConfirmBox; class ConfirmBox;
@ -69,7 +70,7 @@ private:
return (_setFlags & MTPDstickerSet::Flag::f_masks); return (_setFlags & MTPDstickerSet::Flag::f_masks);
} }
QVector<FloatAnimation> _packOvers; std_::vector_of_moveable<FloatAnimation> _packOvers;
StickerPack _pack; StickerPack _pack;
StickersByEmojiMap _emoji; StickersByEmojiMap _emoji;
bool _loaded = false; bool _loaded = false;

View File

@ -20,6 +20,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
#ifndef OS_MAC_OLD
#include <memory>
#endif // OS_MAC_OLD
template <typename T> template <typename T>
void deleteAndMark(T *&link) { void deleteAndMark(T *&link) {
delete link; delete link;
@ -259,13 +270,6 @@ typedef float float32;
typedef double float64; typedef double float64;
#endif #endif
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
using std::string; using std::string;
using std::exception; using std::exception;
#ifdef OS_MAC_OLD #ifdef OS_MAC_OLD
@ -1035,13 +1039,15 @@ struct ComponentWrapStruct {
// global scope, so it will be filled by zeros from the start // global scope, so it will be filled by zeros from the start
ComponentWrapStruct() { ComponentWrapStruct() {
} }
ComponentWrapStruct(int size, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move) ComponentWrapStruct(std::size_t size, std::size_t align, ComponentConstruct construct, ComponentDestruct destruct, ComponentMove move)
: Size(size) : Size(size)
, Align(align)
, Construct(construct) , Construct(construct)
, Destruct(destruct) , Destruct(destruct)
, Move(move) { , Move(move) {
} }
int Size; std::size_t Size;
std::size_t Align;
ComponentConstruct Construct; ComponentConstruct Construct;
ComponentDestruct Destruct; ComponentDestruct Destruct;
ComponentMove Move; ComponentMove Move;
@ -1058,6 +1064,7 @@ extern QAtomicInt ComponentIndexLast;
template <typename Type> template <typename Type>
struct BaseComponent { struct BaseComponent {
BaseComponent() { BaseComponent() {
static_assert(alignof(Type) <= sizeof(SmallestSizeType), "Components should align to a pointer!");
} }
BaseComponent(const BaseComponent &other) = delete; BaseComponent(const BaseComponent &other) = delete;
BaseComponent &operator=(const BaseComponent &other) = delete; BaseComponent &operator=(const BaseComponent &other) = delete;
@ -1075,8 +1082,11 @@ struct BaseComponent {
t_assert(last < 64); t_assert(last < 64);
if (_index.testAndSetOrdered(0, last + 1)) { if (_index.testAndSetOrdered(0, last + 1)) {
ComponentWraps[last] = ComponentWrapStruct( ComponentWraps[last] = ComponentWrapStruct(
CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64), CeilDivideMinimumOne<sizeof(Type), sizeof(SmallestSizeType)>::Result * sizeof(SmallestSizeType),
Type::ComponentConstruct, Type::ComponentDestruct, Type::ComponentMove); alignof(Type),
Type::ComponentConstruct,
Type::ComponentDestruct,
Type::ComponentMove);
} }
break; break;
} }
@ -1088,6 +1098,8 @@ struct BaseComponent {
} }
protected: protected:
using SmallestSizeType = void*;
static void ComponentConstruct(void *location, Composer *composer) { static void ComponentConstruct(void *location, Composer *composer) {
new (location) Type(); new (location) Type();
} }
@ -1102,7 +1114,6 @@ protected:
class ComposerMetadata { class ComposerMetadata {
public: public:
ComposerMetadata(uint64 mask) : size(0), last(64), _mask(mask) { ComposerMetadata(uint64 mask) : size(0), last(64), _mask(mask) {
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
uint64 m = (1ULL << i); uint64 m = (1ULL << i);
@ -1147,15 +1158,13 @@ const ComposerMetadata *GetComposerMetadata(uint64 mask);
class Composer { class Composer {
public: public:
Composer(uint64 mask = 0) : _data(zerodata()) { Composer(uint64 mask = 0) : _data(zerodata()) {
if (mask) { if (mask) {
const ComposerMetadata *meta = GetComposerMetadata(mask); const ComposerMetadata *meta = GetComposerMetadata(mask);
int size = sizeof(meta) + meta->size; int size = sizeof(meta) + meta->size;
void *data = operator new(size);
if (!data) { // terminate if we can't allocate memory auto data = operator new(size);
throw "Can't allocate memory!"; t_assert(data != nullptr);
}
_data = data; _data = data;
_meta() = meta; _meta() = meta;
@ -1163,7 +1172,13 @@ public:
int offset = meta->offsets[i]; int offset = meta->offsets[i];
if (offset >= 0) { if (offset >= 0) {
try { try {
ComponentWraps[i].Construct(_dataptrunsafe(offset), this); auto constructAt = _dataptrunsafe(offset);
#ifndef OS_MAC_OLD
auto space = ComponentWraps[i].Size;
auto alignedAt = std::align(ComponentWraps[i].Align, space, constructAt, space);
t_assert(alignedAt == constructAt);
#endif // OS_MAC_OLD
ComponentWraps[i].Construct(constructAt, this);
} catch (...) { } catch (...) {
while (i > 0) { while (i > 0) {
--i; --i;
@ -1182,7 +1197,7 @@ public:
Composer &operator=(const Composer &other) = delete; Composer &operator=(const Composer &other) = delete;
~Composer() { ~Composer() {
if (_data != zerodata()) { if (_data != zerodata()) {
const ComposerMetadata *meta = _meta(); auto meta = _meta();
for (int i = 0; i < meta->last; ++i) { for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i]; int offset = meta->offsets[i];
if (offset >= 0) { if (offset >= 0) {
@ -1213,7 +1228,7 @@ protected:
Composer tmp(mask); Composer tmp(mask);
tmp.swap(*this); tmp.swap(*this);
if (_data != zerodata() && tmp._data != zerodata()) { if (_data != zerodata() && tmp._data != zerodata()) {
const ComposerMetadata *meta = _meta(), *wasmeta = tmp._meta(); auto meta = _meta(), wasmeta = tmp._meta();
for (int i = 0; i < meta->last; ++i) { for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i]; int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i];
if (offset >= 0 && wasoffset >= 0) { if (offset >= 0 && wasoffset >= 0) {
@ -1252,103 +1267,3 @@ private:
} }
}; };
template <typename R, typename... Args>
class SharedCallback {
public:
virtual R call(Args... args) const = 0;
virtual ~SharedCallback() {
}
using Ptr = QSharedPointer<SharedCallback<R, Args...>>;
};
template <typename R, typename... Args>
class FunctionImplementation {
public:
virtual R call(Args... args) = 0;
virtual void destroy() { delete this; }
virtual ~FunctionImplementation() {}
};
template <typename R, typename... Args>
class NullFunctionImplementation : public FunctionImplementation<R, Args...> {
public:
R call(Args... args) override { return R(); }
void destroy() override {}
static NullFunctionImplementation<R, Args...> SharedInstance;
};
template <typename R, typename... Args>
NullFunctionImplementation<R, Args...> NullFunctionImplementation<R, Args...>::SharedInstance;
template <typename R, typename... Args>
class Function {
public:
Function() : _implementation(nullImpl()) {}
Function(FunctionImplementation<R, Args...> *implementation) : _implementation(implementation) {}
Function(const Function<R, Args...> &other) = delete;
Function<R, Args...> &operator=(const Function<R, Args...> &other) = delete;
Function(Function<R, Args...> &&other) : _implementation(other._implementation) {
other._implementation = nullImpl();
}
Function<R, Args...> &operator=(Function<R, Args...> &&other) {
std::swap(_implementation, other._implementation);
return *this;
}
bool isNull() const {
return (_implementation == nullImpl());
}
R call(Args... args) { return _implementation->call(args...); }
~Function() {
if (_implementation) {
_implementation->destroy();
_implementation = nullptr;
}
deleteAndMark(_implementation);
}
private:
static FunctionImplementation<R, Args...> *nullImpl() {
return &NullFunctionImplementation<R, Args...>::SharedInstance;
}
FunctionImplementation<R, Args...> *_implementation;
};
template <typename R, typename... Args>
class WrappedFunction : public FunctionImplementation<R, Args...> {
public:
using Method = R(*)(Args... args);
WrappedFunction(Method method) : _method(method) {}
R call(Args... args) override { return (*_method)(args...); }
private:
Method _method;
};
template <typename R, typename... Args>
inline Function<R, Args...> func(R(*method)(Args... args)) {
return Function<R, Args...>(new WrappedFunction<R, Args...>(method));
}
template <typename O, typename I, typename R, typename... Args>
class ObjectFunction : public FunctionImplementation<R, Args...> {
public:
using Method = R(I::*)(Args... args);
ObjectFunction(O *obj, Method method) : _obj(obj), _method(method) {}
R call(Args... args) override { return (_obj->*_method)(args...); }
private:
O *_obj;
Method _method;
};
template <typename O, typename I, typename R, typename... Args>
inline Function<R, Args...> func(O *obj, R(I::*method)(Args...)) {
return Function<R, Args...>(new ObjectFunction<O, I, R, Args...>(obj, method));
}

View File

@ -373,48 +373,20 @@ public:
} // namespace base } // namespace base
// While we still use Function<> // While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
template <typename FunctionType> template <typename FunctionType>
struct LambdaFunctionHelper; struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args> template <typename Lambda, typename R, typename ...Args>
struct LambdaFunctionHelper<R(Lambda::*)(Args...) const> { struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using FunctionType = Function<R, Args...>;
using UniqueType = base::lambda_unique<R(Args...)>; using UniqueType = base::lambda_unique<R(Args...)>;
}; };
template <typename FunctionType> template <typename FunctionType>
using LambdaGetFunction = typename LambdaFunctionHelper<FunctionType>::FunctionType; using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
template <typename FunctionType>
using LambdaGetUnique = typename LambdaFunctionHelper<FunctionType>::UniqueType;
template <typename R, typename ...Args>
class LambdaFunctionImplementation : public FunctionImplementation<R, Args...> {
public:
LambdaFunctionImplementation(base::lambda_unique<R(Args...)> &&lambda) : _lambda(std_::move(lambda)) {
}
R call(Args... args) override { return _lambda(std_::forward<Args>(args)...); }
private:
base::lambda_unique<R(Args...)> _lambda;
};
template <typename R, typename ...Args>
inline Function<R, Args...> func_lambda_wrap_helper(base::lambda_unique<R(Args...)> &&lambda) {
return Function<R, Args...>(new LambdaFunctionImplementation<R, Args...>(std_::move(lambda)));
}
template <typename Lambda, typename = std_::enable_if_t<std_::is_rvalue_reference<Lambda&&>::value>>
inline LambdaGetFunction<decltype(&Lambda::operator())> func(Lambda &&lambda) {
return func_lambda_wrap_helper(LambdaGetUnique<decltype(&Lambda::operator())>(std_::move(lambda)));
}
// While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
template <typename Base, typename FunctionType> template <typename Base, typename FunctionType>
class RPCHandlerImplementation : public Base { class RPCHandlerImplementation : public Base {

View File

@ -58,7 +58,7 @@ private:
}; };
// Handler is one of Function<> instantiations. // Handler is one of base::lambda_unique<> instantiations.
template <typename Flags, typename Handler> template <typename Flags, typename Handler>
struct ObserversList { struct ObserversList {
struct Entry { struct Entry {
@ -109,8 +109,8 @@ public:
// entries list while the loop is still running. // entries list while the loop is still running.
for (int i = 0; i < entries.size(); ++i) { for (int i = 0; i < entries.size(); ++i) {
auto &entry = entries[i]; auto &entry = entries[i];
if (!entry.handler.isNull() && (flags & entry.flags)) { if (entry.handler && (flags & entry.flags)) {
entry.handler.call(std_::forward<Args>(args)...); entry.handler(std_::forward<Args>(args)...);
} }
} }
} }
@ -140,7 +140,7 @@ private:
if (entries.size() <= connectionIndex) return; if (entries.size() <= connectionIndex) return;
if (entries.size() == connectionIndex + 1) { if (entries.size() == connectionIndex + 1) {
for (entries.pop_back(); !entries.isEmpty() && entries.back().handler.isNull();) { for (entries.pop_back(); !entries.isEmpty() && !entries.back().handler;) {
entries.pop_back(); entries.pop_back();
} }
} else { } else {

View File

@ -93,6 +93,7 @@ public:
*prev = std_::move(*next); *prev = std_::move(*next);
} }
--_size; --_size;
end()->~T();
return it; return it;
} }
@ -143,15 +144,21 @@ public:
} }
inline const T &at(int index) const { inline const T &at(int index) const {
if (index < 0 || index >= _size) { if (index < 0 || index >= _size) {
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) #ifndef OS_MAC_OLD
throw std::exception();
#else // QT_VERSION < 5.5.0
throw std::out_of_range(""); throw std::out_of_range("");
#endif // QT_VERSION < 5.5.0 #else // OS_MAC_OLD
throw std::exception();
#endif // OS_MAC_OLD
} }
return data()[index]; return data()[index];
} }
void reserve(int newCapacity) {
if (newCapacity > _capacity) {
reallocate(newCapacity);
}
}
inline ~vector_of_moveable() { inline ~vector_of_moveable() {
clear(); clear();
} }

View File

@ -2644,10 +2644,12 @@ void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) {
} }
} }
void HistoryDependentItemCallback::call(ChannelData *channel, MsgId msgId) const { ApiWrap::RequestMessageDataCallback historyDependentItemCallback(const FullMsgId &msgId) {
if (HistoryItem *item = App::histItemById(_dependent)) { return [dependent = msgId](ChannelData *channel, MsgId msgId) {
item->updateDependencyItem(); if (HistoryItem *item = App::histItemById(dependent)) {
} item->updateDependencyItem();
}
};
} }
void HistoryMessageUnreadBar::init(int count) { void HistoryMessageUnreadBar::init(int count) {
@ -4910,7 +4912,9 @@ bool HistoryGif::playInline(bool autoplay) {
if (!cAutoPlayGif()) { if (!cAutoPlayGif()) {
App::stopGifItems(); App::stopGifItems();
} }
_gif = new Media::Clip::Reader(_data->location(), _data->data(), func(_parent, &HistoryItem::clipCallback)); _gif = new Media::Clip::Reader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) {
_parent->clipCallback(notification);
});
App::regGifItem(_gif, _parent); App::regGifItem(_gif, _parent);
if (gif()) _gif->setAutoplay(); if (gif()) _gif->setAutoplay();
} }
@ -6837,7 +6841,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
if (auto reply = Get<HistoryMessageReply>()) { if (auto reply = Get<HistoryMessageReply>()) {
reply->replyToMsgId = config.replyTo; reply->replyToMsgId = config.replyTo;
if (!reply->updateData(this) && App::api()) { if (!reply->updateData(this) && App::api()) {
App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, std_::make_unique<HistoryDependentItemCallback>(fullId())); App::api()->requestMessageData(history()->peer->asChannel(), reply->replyToMsgId, historyDependentItemCallback(fullId()));
} }
} }
if (auto via = Get<HistoryMessageVia>()) { if (auto via = Get<HistoryMessageVia>()) {
@ -8388,7 +8392,7 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
if (auto dependent = GetDependentData()) { if (auto dependent = GetDependentData()) {
dependent->msgId = message.vreply_to_msg_id.v; dependent->msgId = message.vreply_to_msg_id.v;
if (!updateDependent() && App::api()) { if (!updateDependent() && App::api()) {
App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, std_::make_unique<HistoryDependentItemCallback>(fullId())); App::api()->requestMessageData(history()->peer->asChannel(), dependent->msgId, historyDependentItemCallback(fullId()));
} }
} }
} }

View File

@ -935,17 +935,6 @@ private:
StylePtr _st; StylePtr _st;
}; };
class HistoryDependentItemCallback : public SharedCallback<void, ChannelData*, MsgId> {
public:
HistoryDependentItemCallback(FullMsgId dependent) : _dependent(dependent) {
}
void call(ChannelData *channel, MsgId msgId) const override;
private:
FullMsgId _dependent;
};
// any HistoryItem can have this Interface for // any HistoryItem can have this Interface for
// displaying the day mark above the message // displaying the day mark above the message
struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> { struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> {

View File

@ -101,6 +101,14 @@ public:
constexpr int ScrollDateHideTimeout = 1000; constexpr int ScrollDateHideTimeout = 1000;
ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
return [](ChannelData *channel, MsgId msgId) {
if (App::main()) {
App::main()->messageDataReceived(channel, msgId);
}
};
}
} // namespace } // namespace
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@ -1684,7 +1692,7 @@ void HistoryInner::toggleScrollDateShown() {
_scrollDateShown = !_scrollDateShown; _scrollDateShown = !_scrollDateShown;
auto from = _scrollDateShown ? 0. : 1.; auto from = _scrollDateShown ? 0. : 1.;
auto to = _scrollDateShown ? 1. : 0.; auto to = _scrollDateShown ? 1. : 0.;
START_ANIMATION(_scrollDateOpacity, func(this, &HistoryInner::repaintScrollDateCallback), from, to, st::btnAttachEmoji.duration, anim::linear); _scrollDateOpacity.start([this] { repaintScrollDateCallback(); }, from, to, st::btnAttachEmoji.duration);
} }
void HistoryInner::repaintScrollDateCallback() { void HistoryInner::repaintScrollDateCallback() {
@ -4117,7 +4125,7 @@ void HistoryWidget::applyDraft(bool parseLinks) {
if (_editMsgId || _replyToId) { if (_editMsgId || _replyToId) {
updateReplyEditTexts(); updateReplyEditTexts();
if (!_replyEditMsg && App::api()) { if (!_replyEditMsg && App::api()) {
App::api()->requestMessageData(_peer->asChannel(), _editMsgId ? _editMsgId : _replyToId, std_::make_unique<ReplyEditMessageDataCallback>()); App::api()->requestMessageData(_peer->asChannel(), _editMsgId ? _editMsgId : _replyToId, replyEditMessageDataCallback());
} }
} }
} }
@ -7633,7 +7641,7 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
update(); update();
} }
if (!_pinnedBar->msg && App::api()) { if (!_pinnedBar->msg && App::api()) {
App::api()->requestMessageData(_peer->asChannel(), _pinnedBar->msgId, std_::make_unique<ReplyEditMessageDataCallback>()); App::api()->requestMessageData(_peer->asChannel(), _pinnedBar->msgId, replyEditMessageDataCallback());
} }
} else if (_pinnedBar) { } else if (_pinnedBar) {
destroyPinnedBar(); destroyPinnedBar();
@ -7652,12 +7660,6 @@ void HistoryWidget::destroyPinnedBar() {
_inPinnedMsg = false; _inPinnedMsg = false;
} }
void HistoryWidget::ReplyEditMessageDataCallback::call(ChannelData *channel, MsgId msgId) const {
if (App::main()) {
App::main()->messageDataReceived(channel, msgId);
}
}
bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) { bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) {
if (!_history || !doc || !canSendMessages(_peer)) { if (!_history || !doc || !canSendMessages(_peer)) {
return false; return false;

View File

@ -908,11 +908,6 @@ private:
void destroyPinnedBar(); void destroyPinnedBar();
void unpinDone(const MTPUpdates &updates); void unpinDone(const MTPUpdates &updates);
class ReplyEditMessageDataCallback : public SharedCallback<void, ChannelData*, MsgId> {
public:
void call(ChannelData *channel, MsgId msgId) const override;
};
bool sendExistingDocument(DocumentData *doc, const QString &caption); bool sendExistingDocument(DocumentData *doc, const QString &caption);
void sendExistingPhoto(PhotoData *photo, const QString &caption); void sendExistingPhoto(PhotoData *photo, const QString &caption);

View File

@ -134,7 +134,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading(); bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !gif() && _gif != Media::Clip::BadReader) { if (loaded && !gif() && _gif != Media::Clip::BadReader) {
Gif *that = const_cast<Gif*>(this); Gif *that = const_cast<Gif*>(this);
that->_gif = new Media::Clip::Reader(document->location(), document->data(), func(that, &Gif::clipCallback)); that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay(); if (gif()) _gif->setAutoplay();
} }
@ -164,9 +166,9 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
} }
if (radial || (!_gif && !loaded && !loading) || (_gif == Media::Clip::BadReader)) { if (radial || (!_gif && !loaded && !loading) || (_gif == Media::Clip::BadReader)) {
float64 radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1; auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.;
if (_animation && _animation->_a_over.animating(context->ms)) { if (_animation && _animation->_a_over.animating(context->ms)) {
float64 over = _animation->_a_over.current(); auto over = _animation->_a_over.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.fillRect(r, st::black); p.fillRect(r, st::black);
} else { } else {
@ -218,7 +220,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
bool wasactive = (_state & StateFlag::DeleteOver); bool wasactive = (_state & StateFlag::DeleteOver);
if (active != wasactive) { if (active != wasactive) {
auto from = active ? 0. : 1., to = active ? 1. : 0.; auto from = active ? 0. : 1., to = active ? 1. : 0.;
START_ANIMATION(_a_deleteOver, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear); _a_deleteOver.start([this] { update(); }, from, to, st::stickersRowDuration);
if (active) { if (active) {
_state |= StateFlag::DeleteOver; _state |= StateFlag::DeleteOver;
} else { } else {
@ -232,7 +234,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
if (!getShownDocument()->loaded()) { if (!getShownDocument()->loaded()) {
ensureAnimation(); ensureAnimation();
auto from = active ? 0. : 1., to = active ? 1. : 0.; auto from = active ? 0. : 1., to = active ? 1. : 0.;
START_ANIMATION(_animation->_a_over, func(this, &Gif::update), from, to, st::stickersRowDuration, anim::linear); _animation->_a_over.start([this] { update(); }, from, to, st::stickersRowDuration);
} }
if (active) { if (active) {
_state |= StateFlag::Over; _state |= StateFlag::Over;
@ -385,7 +387,7 @@ void Sticker::preload() const {
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const { void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
bool loaded = getShownDocument()->loaded(); bool loaded = getShownDocument()->loaded();
float64 over = _a_over.isNull() ? (_active ? 1 : 0) : _a_over.current(); auto over = _a_over.current(_active ? 1. : 0.);
if (over > 0) { if (over > 0) {
p.setOpacity(over); p.setOpacity(over);
App::roundRect(p, QRect(QPoint(0, 0), st::stickerPanSize), st::emojiPanHover, StickerHoverCorners); App::roundRect(p, QRect(QPoint(0, 0), st::stickerPanSize), st::emojiPanHover, StickerHoverCorners);
@ -414,7 +416,7 @@ void Sticker::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
_active = active; _active = active;
auto from = active ? 0. : 1., to = active ? 1. : 0.; auto from = active ? 0. : 1., to = active ? 1. : 0.;
START_ANIMATION(_a_over, func(this, &Sticker::update), from, to, st::stickersRowDuration, anim::linear); _a_over.start([this] { update(); }, from, to, st::stickersRowDuration);
} }
} }
ItemBase::clickHandlerActiveChanged(p, active); ItemBase::clickHandlerActiveChanged(p, active);

View File

@ -638,7 +638,9 @@ QPixmap MediaPreviewWidget::currentImage() const {
if (_document->loaded()) { if (_document->loaded()) {
if (!_gif && _gif != Media::Clip::BadReader) { if (!_gif && _gif != Media::Clip::BadReader) {
auto that = const_cast<MediaPreviewWidget*>(this); auto that = const_cast<MediaPreviewWidget*>(this);
that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), func(that, &MediaPreviewWidget::clipCallback)); that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), [this, that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay(); if (gif()) _gif->setAutoplay();
} }
} }

View File

@ -4020,7 +4020,7 @@ DataIsLoadedResult allDataLoadedForMessage(const MTPMessage &msg) {
void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
switch (updates.type()) { switch (updates.type()) {
case mtpc_updates: { case mtpc_updates: {
const auto &d(updates.c_updates()); auto &d = updates.c_updates();
if (d.vseq.v) { if (d.vseq.v) {
if (d.vseq.v <= updSeq) return; if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) { if (d.vseq.v > updSeq + 1) {
@ -4037,7 +4037,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updatesCombined: { case mtpc_updatesCombined: {
const auto &d(updates.c_updatesCombined()); auto &d = updates.c_updatesCombined();
if (d.vseq_start.v) { if (d.vseq_start.v) {
if (d.vseq_start.v <= updSeq) return; if (d.vseq_start.v <= updSeq) return;
if (d.vseq_start.v > updSeq + 1) { if (d.vseq_start.v > updSeq + 1) {
@ -4054,15 +4054,14 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updateShort: { case mtpc_updateShort: {
const auto &d(updates.c_updateShort()); auto &d = updates.c_updateShort();
feedUpdate(d.vupdate); feedUpdate(d.vupdate);
updSetState(0, d.vdate.v, updQts, updSeq); updSetState(0, d.vdate.v, updQts, updSeq);
} break; } break;
case mtpc_updateShortMessage: { case mtpc_updateShortMessage: {
const auto &d(updates.c_updateShortMessage()); auto &d = updates.c_updateShortMessage();
if (!App::userLoaded(d.vuser_id.v) if (!App::userLoaded(d.vuser_id.v)
|| (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v)) || (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v))
|| (d.has_entities() && !mentionUsersLoaded(d.ventities)) || (d.has_entities() && !mentionUsersLoaded(d.ventities))
@ -4076,7 +4075,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
// update before applying skipped // update before applying skipped
MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id;
HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); auto item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread);
if (item) { if (item) {
_history->peerMessagesUpdated(item->history()->peer->id); _history->peerMessagesUpdated(item->history()->peer->id);
} }
@ -4087,7 +4086,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updateShortChatMessage: { case mtpc_updateShortChatMessage: {
const auto &d(updates.c_updateShortChatMessage()); auto &d = updates.c_updateShortChatMessage();
bool noFrom = !App::userLoaded(d.vfrom_id.v); bool noFrom = !App::userLoaded(d.vfrom_id.v);
if (!App::chatLoaded(d.vchat_id.v) if (!App::chatLoaded(d.vchat_id.v)
|| noFrom || noFrom
@ -4104,7 +4103,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
// update before applying skipped // update before applying skipped
MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id;
HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); auto item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread);
if (item) { if (item) {
_history->peerMessagesUpdated(item->history()->peer->id); _history->peerMessagesUpdated(item->history()->peer->id);
} }
@ -4115,7 +4114,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break; } break;
case mtpc_updateShortSentMessage: { case mtpc_updateShortSentMessage: {
const auto &d(updates.c_updateShortSentMessage()); auto &d = updates.c_updateShortSentMessage();
if (randomId) { if (randomId) {
PeerId peerId = 0; PeerId peerId = 0;
QString text; QString text;
@ -4125,7 +4124,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
if (peerId) { if (peerId) {
if (auto item = App::histItemById(peerToChannel(peerId), d.vid.v)) { if (auto item = App::histItemById(peerToChannel(peerId), d.vid.v)) {
if (d.has_entities() && !mentionUsersLoaded(d.ventities)) { if (d.has_entities() && !mentionUsersLoaded(d.ventities)) {
api()->requestMessageData(item->history()->peer->asChannel(), item->id, nullptr); api()->requestMessageData(item->history()->peer->asChannel(), item->id, ApiWrap::RequestMessageDataCallback());
} }
auto entities = d.has_entities() ? entitiesFromMTP(d.ventities.c_vector().v) : EntitiesInText(); auto entities = d.has_entities() ? entitiesFromMTP(d.ventities.c_vector().v) : EntitiesInText();
item->setText({ text, entities }); item->setText({ text, entities });

View File

@ -180,8 +180,8 @@ void Reader::moveToNextWrite() const {
void Reader::callback(Reader *reader, int32 threadIndex, Notification notification) { void Reader::callback(Reader *reader, int32 threadIndex, Notification notification) {
// check if reader is not deleted already // check if reader is not deleted already
if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader)) { if (managers.size() > threadIndex && managers.at(threadIndex)->carries(reader) && reader->_callback) {
reader->_callback.call(notification); reader->_callback(notification);
} }
} }

View File

@ -52,7 +52,7 @@ enum ReaderSteps {
class ReaderPrivate; class ReaderPrivate;
class Reader { class Reader {
public: public:
using Callback = Function<void, Notification>; using Callback = base::lambda_unique<void(Notification)>;
enum class Mode { enum class Mode {
Gif, Gif,
Video, Video,

View File

@ -41,8 +41,8 @@ Controller::Controller(QWidget *parent) : TWidget(parent)
, _toPlayLeft(this, st::mediaviewPlayProgressLabel) , _toPlayLeft(this, st::mediaviewPlayProgressLabel)
, _fadeAnimation(std_::make_unique<Ui::FadeAnimation>(this)) { , _fadeAnimation(std_::make_unique<Ui::FadeAnimation>(this)) {
_fadeAnimation->show(); _fadeAnimation->show();
_fadeAnimation->setFinishedCallback(func(this, &Controller::fadeFinished)); _fadeAnimation->setFinishedCallback([this] { fadeFinished(); });
_fadeAnimation->setUpdatedCallback(func(this, &Controller::fadeUpdated)); _fadeAnimation->setUpdatedCallback([this](float64 opacity) { fadeUpdated(opacity); });
_volumeController->setVolume(Global::VideoVolume()); _volumeController->setVolume(Global::VideoVolume());

View File

@ -156,7 +156,7 @@ void Playback::setOver(bool over) {
_over = over; _over = over;
auto from = _over ? 0. : 1., to = _over ? 1. : 0.; auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
START_ANIMATION(_a_over, func(this, &Playback::updateCallback), from, to, st::mediaviewOverDuration, anim::linear); _a_over.start([this] { update(); }, from, to, st::mediaviewOverDuration);
} }
} // namespace Clip } // namespace Clip

View File

@ -48,9 +48,6 @@ protected:
private: private:
void step_progress(float64 ms, bool timer); void step_progress(float64 ms, bool timer);
void updateCallback() {
update();
}
void setOver(bool over); void setOver(bool over);
bool _over = false; bool _over = false;

View File

@ -100,7 +100,7 @@ void VolumeController::setOver(bool over) {
_over = over; _over = over;
auto from = _over ? 0. : 1., to = _over ? 1. : 0.; auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
START_ANIMATION(_a_over, func(this, &VolumeController::updateCallback), from, to, st::mediaviewOverDuration, anim::linear); _a_over.start([this] { update(); }, from, to, st::mediaviewOverDuration);
} }
} // namespace Clip } // namespace Clip

View File

@ -43,9 +43,6 @@ protected:
void leaveEvent(QEvent *e) override; void leaveEvent(QEvent *e) override;
private: private:
void updateCallback() {
update();
}
void setOver(bool over); void setOver(bool over);
void changeVolume(float64 newVolume); void changeVolume(float64 newVolume);

View File

@ -1368,7 +1368,9 @@ void MediaView::createClipReader() {
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixSmooth | ImagePixBlurred, st::mvDocIconSize, st::mvDocIconSize); _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixSmooth | ImagePixBlurred, st::mvDocIconSize, st::mvDocIconSize);
} }
auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif;
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), mode); _gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
clipCallback(notification);
}, mode);
// Correct values will be set when gif gets inited. // Correct values will be set when gif gets inited.
_videoPaused = _videoIsSilent = _videoStopped = false; _videoPaused = _videoIsSilent = _videoStopped = false;
@ -1439,7 +1441,9 @@ void MediaView::restartVideoAtSeekPosition(int64 positionMs) {
if (_current.isNull()) { if (_current.isNull()) {
_current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms()); _current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms());
} }
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), Media::Clip::Reader::Mode::Video, positionMs); _gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
clipCallback(notification);
}, Media::Clip::Reader::Mode::Video, positionMs);
// Correct values will be set when gif gets inited. // Correct values will be set when gif gets inited.
_videoPaused = _videoIsSilent = _videoStopped = false; _videoPaused = _videoIsSilent = _videoStopped = false;

View File

@ -396,9 +396,10 @@ void reinitWebLoadManager();
void stopWebLoadManager(); void stopWebLoadManager();
namespace FileDownload { namespace FileDownload {
namespace internal { namespace internal {
using ImageLoadedHandler = Function<void>; using ImageLoadedHandler = base::lambda_unique<void()>;
Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler); Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler);
void notifyImageLoaded(); void notifyImageLoaded();
@ -407,7 +408,9 @@ void notifyImageLoaded();
template <typename ObserverType> template <typename ObserverType>
void registerImageLoadedObserver(ObserverType *observer, void (ObserverType::*handler)()) { void registerImageLoadedObserver(ObserverType *observer, void (ObserverType::*handler)()) {
auto connection = internal::plainRegisterImageLoadedObserver(func(observer, handler)); auto connection = internal::plainRegisterImageLoadedObserver([observer, handler]() {
(observer->*handler)();
});
Notify::observerRegistered(observer, connection); Notify::observerRegistered(observer, connection);
} }

View File

@ -91,14 +91,16 @@ void peerUpdatedSendDelayed();
namespace internal { namespace internal {
using PeerUpdateHandler = Function<void, const PeerUpdate&>; using PeerUpdateHandler = base::lambda_unique<void(const PeerUpdate&)>;
ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler); ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler);
} // namespace internal } // namespace internal
template <typename ObserverType> template <typename ObserverType>
void registerPeerObserver(PeerUpdate::Flags events, ObserverType *observer, void (ObserverType::*handler)(const PeerUpdate &)) { void registerPeerObserver(PeerUpdate::Flags events, ObserverType *observer, void (ObserverType::*handler)(const PeerUpdate &)) {
auto connection = internal::plainRegisterPeerObserver(events, func(observer, handler)); auto connection = internal::plainRegisterPeerObserver(events, [observer, handler](const PeerUpdate &update) {
(observer->*handler)(update);
});
observerRegistered(observer, connection); observerRegistered(observer, connection);
} }

View File

@ -285,7 +285,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) { void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
if (_dropArea && !_dropArea->hiding()) { if (_dropArea && !_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](CoverDropArea *area) { dropAreaHidden(area); });
} }
} }
@ -306,7 +306,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
} }
if (!_dropArea->hiding()) { if (!_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](CoverDropArea *area) { dropAreaHidden(area); });
} }
e->acceptProposedAction(); e->acceptProposedAction();

View File

@ -57,7 +57,9 @@ void CoverDropArea::paintEvent(QPaintEvent *e) {
_cache = QPixmap(); _cache = QPixmap();
if (_hiding) { if (_hiding) {
hide(); hide();
_hideFinishCallback.call(this); if (_hideFinishCallback) {
_hideFinishCallback(this);
}
return; return;
} }
} }
@ -93,7 +95,7 @@ void CoverDropArea::setupAnimation() {
_cache = myGrab(this); _cache = myGrab(this);
} }
auto from = _hiding ? 1. : 0., to = _hiding ? 0. : 1.; auto from = _hiding ? 1. : 0., to = _hiding ? 0. : 1.;
START_ANIMATION(_a_appearance, func(this, &CoverDropArea::refreshCallback), from, to, st::profileDropAreaDuration, anim::linear); _a_appearance.start([this]() { update(); }, from, to, st::profileDropAreaDuration);
} }
} // namespace Profile } // namespace Profile

View File

@ -28,7 +28,7 @@ public:
void showAnimated(); void showAnimated();
using HideFinishCallback = Function<void, CoverDropArea*>; using HideFinishCallback = base::lambda_unique<void(CoverDropArea*)>;
void hideAnimated(HideFinishCallback &&callback); void hideAnimated(HideFinishCallback &&callback);
bool hiding() const { bool hiding() const {
@ -39,9 +39,6 @@ protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
private: private:
void refreshCallback() {
update();
}
void setupAnimation(); void setupAnimation();
QString _title, _subtitle; QString _title, _subtitle;

View File

@ -149,15 +149,13 @@ void InfoWidget::refreshAbout() {
textParseEntities(aboutText, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &aboutEntities); textParseEntities(aboutText, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &aboutEntities);
_about->setMarkedText({ aboutText, aboutEntities }); _about->setMarkedText({ aboutText, aboutEntities });
_about->setSelectable(true); _about->setSelectable(true);
_about->setClickHandlerHook(func(this, &InfoWidget::aboutClickHandlerHook)); _about->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) {
BotCommandClickHandler::setPeerForCommand(peer());
return true;
});
} }
} }
bool InfoWidget::aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
BotCommandClickHandler::setPeerForCommand(peer());
return true;
}
void InfoWidget::refreshMobileNumber() { void InfoWidget::refreshMobileNumber() {
TextWithEntities phoneText; TextWithEntities phoneText;
if (auto user = peer()->asUser()) { if (auto user = peer()->asUser()) {

View File

@ -51,8 +51,6 @@ private:
void refreshChannelLink(); void refreshChannelLink();
void refreshVisibility(); void refreshVisibility();
bool aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
// labelWidget may be nullptr. // labelWidget may be nullptr.
void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label, void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label,
ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText); ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText);

View File

@ -99,19 +99,17 @@ void InviteLinkWidget::refreshLink() {
_link->setMarkedText(linkData); _link->setMarkedText(linkData);
_link->setSelectable(true); _link->setSelectable(true);
_link->setContextCopyText(QString()); _link->setContextCopyText(QString());
_link->setClickHandlerHook(func(this, &InviteLinkWidget::clickHandlerHook)); _link->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) {
} auto link = getInviteLink();
} if (link.isEmpty()) {
return true;
}
bool InviteLinkWidget::clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) { QApplication::clipboard()->setText(link);
auto link = getInviteLink(); Ui::showLayer(new InformBox(lang(lng_group_invite_copied)));
if (link.isEmpty()) { return false;
return true; });
} }
QApplication::clipboard()->setText(link);
Ui::showLayer(new InformBox(lang(lng_group_invite_copied)));
return false;
} }
} // namespace Profile } // namespace Profile

View File

@ -46,8 +46,6 @@ private:
void refreshLink(); void refreshLink();
void refreshVisibility(); void refreshVisibility();
bool clickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
ChildWidget<FlatLabel> _link = { nullptr }; ChildWidget<FlatLabel> _link = { nullptr };
}; };

View File

@ -315,17 +315,15 @@ void MembersWidget::refreshLimitReached() {
QString link = textRichPrepare(lang(lng_profile_migrate_learn_more)); QString link = textRichPrepare(lang(lng_profile_migrate_learn_more));
QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link); QString text = qsl("%1%2%3\n%4 [a href=\"https://telegram.org/blog/supergroups5k\"]%5[/a]").arg(textcmdStartSemibold()).arg(title).arg(textcmdStopSemibold()).arg(body).arg(link);
_limitReachedInfo->setRichText(text); _limitReachedInfo->setRichText(text);
_limitReachedInfo->setClickHandlerHook(func(this, &MembersWidget::limitReachedHook)); _limitReachedInfo->setClickHandlerHook([this](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat()));
return false;
});
} else if (!limitReachedShown && _limitReachedInfo) { } else if (!limitReachedShown && _limitReachedInfo) {
_limitReachedInfo.destroy(); _limitReachedInfo.destroy();
} }
} }
bool MembersWidget::limitReachedHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat()));
return false;
}
void MembersWidget::checkSelfAdmin(ChatData *chat) { void MembersWidget::checkSelfAdmin(ChatData *chat) {
if (chat->participants.isEmpty()) return; if (chat->participants.isEmpty()) return;

View File

@ -45,7 +45,7 @@ void UserpicButton::showFinished() {
_notShownYet = false; _notShownYet = false;
if (!_waiting) { if (!_waiting) {
_a_appearance.finish(); _a_appearance.finish();
START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear); _a_appearance.start([this] { update(); }, 0, 1, st::profilePhotoDuration);
} }
} }
} }
@ -100,7 +100,7 @@ void UserpicButton::startNewPhotoShowing() {
} }
_a_appearance.finish(); _a_appearance.finish();
START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear); _a_appearance.start([this] { update(); }, 0, 1, st::profilePhotoDuration);
update(); update();
} }

View File

@ -43,10 +43,6 @@ private:
void notifyPeerUpdated(const Notify::PeerUpdate &update); void notifyPeerUpdated(const Notify::PeerUpdate &update);
void notifyImageLoaded(); void notifyImageLoaded();
void refreshCallback() {
update();
}
void processPeerPhoto(); void processPeerPhoto();
void processNewPeerPhoto(); void processNewPeerPhoto();
void startNewPhotoShowing(); void startNewPhotoShowing();

View File

@ -217,7 +217,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) { void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
if (_dropArea && !_dropArea->hiding()) { if (_dropArea && !_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](Profile::CoverDropArea *area) { dropAreaHidden(area); });
} }
} }
@ -228,7 +228,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
if (mimeData->hasImage()) { if (mimeData->hasImage()) {
img = qvariant_cast<QImage>(mimeData->imageData()); img = qvariant_cast<QImage>(mimeData->imageData());
} else { } else {
const auto &urls = mimeData->urls(); auto &urls = mimeData->urls();
if (urls.size() == 1) { if (urls.size() == 1) {
auto &url = urls.at(0); auto &url = urls.at(0);
if (url.isLocalFile()) { if (url.isLocalFile()) {
@ -238,7 +238,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
} }
if (!_dropArea->hiding()) { if (!_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden)); _dropArea->hideAnimated([this](Profile::CoverDropArea *area) { dropAreaHidden(area); });
} }
e->acceptProposedAction(); e->acceptProposedAction();

View File

@ -81,7 +81,10 @@ void InfoWidget::refreshUsername() {
usernameText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, usernameText.text.size(), qsl("https://telegram.me/") + self()->username)); usernameText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, usernameText.text.size(), qsl("https://telegram.me/") + self()->username));
setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText); setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText);
if (auto text = _username->entity()->textLabel()) { if (auto text = _username->entity()->textLabel()) {
text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
});
} }
} }
@ -96,19 +99,20 @@ void InfoWidget::refreshLink() {
} }
setLabeledText(_link, lang(lng_profile_link), linkText, linkTextShort, QString()); setLabeledText(_link, lang(lng_profile_link), linkText, linkTextShort, QString());
if (auto text = _link->entity()->textLabel()) { if (auto text = _link->entity()->textLabel()) {
text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); text->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
});
} }
if (auto shortText = _link->entity()->shortTextLabel()) { if (auto shortText = _link->entity()->shortTextLabel()) {
shortText->setExpandLinksMode(ExpandLinksUrlOnly); shortText->setExpandLinksMode(ExpandLinksUrlOnly);
shortText->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook)); shortText->setClickHandlerHook([](const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
});
} }
} }
bool InfoWidget::usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
}
void InfoWidget::setLabeledText(ChildWidget<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) { void InfoWidget::setLabeledText(ChildWidget<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) {
if (textWithEntities.text.isEmpty()) { if (textWithEntities.text.isEmpty()) {
row->slideUp(); row->slideUp();

View File

@ -38,8 +38,6 @@ private:
// Observed notifications. // Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update); void notifyPeerUpdated(const Notify::PeerUpdate &update);
bool usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
void createControls(); void createControls();
void refreshControls(); void refreshControls();
void refreshMobileNumber(); void refreshMobileNumber();

View File

@ -120,7 +120,7 @@ AnimationManager::AnimationManager() : _timer(this), _iterating(false) {
void AnimationManager::start(Animation *obj) { void AnimationManager::start(Animation *obj) {
if (_iterating) { if (_iterating) {
_starting.insert(obj, NullType()); _starting.insert(obj);
if (!_stopping.isEmpty()) { if (!_stopping.isEmpty()) {
_stopping.remove(obj); _stopping.remove(obj);
} }
@ -128,21 +128,21 @@ void AnimationManager::start(Animation *obj) {
if (_objects.isEmpty()) { if (_objects.isEmpty()) {
_timer.start(AnimationTimerDelta); _timer.start(AnimationTimerDelta);
} }
_objects.insert(obj, NullType()); _objects.insert(obj);
} }
} }
void AnimationManager::stop(Animation *obj) { void AnimationManager::stop(Animation *obj) {
if (_iterating) { if (_iterating) {
_stopping.insert(obj, NullType()); _stopping.insert(obj);
if (!_starting.isEmpty()) { if (!_starting.isEmpty()) {
_starting.remove(obj); _starting.remove(obj);
} }
} else { } else {
AnimatingObjects::iterator i = _objects.find(obj); auto i = _objects.find(obj);
if (i != _objects.cend()) { if (i != _objects.cend()) {
_objects.erase(i); _objects.erase(i);
if (_objects.isEmpty()) { if (_objects.empty()) {
_timer.stop(); _timer.stop();
} }
} }
@ -152,26 +152,26 @@ void AnimationManager::stop(Animation *obj) {
void AnimationManager::timeout() { void AnimationManager::timeout() {
_iterating = true; _iterating = true;
uint64 ms = getms(); uint64 ms = getms();
for (AnimatingObjects::const_iterator i = _objects.begin(), e = _objects.end(); i != e; ++i) { for_const (auto object, _objects) {
if (!_stopping.contains(i.key())) { if (!_stopping.contains(object)) {
i.key()->step(ms, true); object->step(ms, true);
} }
} }
_iterating = false; _iterating = false;
if (!_starting.isEmpty()) { if (!_starting.isEmpty()) {
for (AnimatingObjects::iterator i = _starting.begin(), e = _starting.end(); i != e; ++i) { for_const (auto object, _starting) {
_objects.insert(i.key(), NullType()); _objects.insert(object);
} }
_starting.clear(); _starting.clear();
} }
if (!_stopping.isEmpty()) { if (!_stopping.isEmpty()) {
for (AnimatingObjects::iterator i = _stopping.begin(), e = _stopping.end(); i != e; ++i) { for_const (auto object, _stopping) {
_objects.remove(i.key()); _objects.remove(object);
} }
_stopping.clear(); _stopping.clear();
} }
if (!_objects.size()) { if (_objects.empty()) {
_timer.stop(); _timer.stop();
} }
} }

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "core/basic_types.h" #include "core/basic_types.h"
#include "core/lambda_wrap.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtGui/QColor> #include <QtGui/QColor>
@ -57,6 +58,7 @@ namespace anim {
class fvalue { // float animated value class fvalue { // float animated value
public: public:
using ValueType = float64;
fvalue() { fvalue() {
} }
@ -88,15 +90,14 @@ namespace anim {
_delta = 0; _delta = 0;
} }
typedef float64 Type;
private: private:
float64 _cur, _from, _delta; float64 _cur, _from, _delta;
}; };
class ivalue { // int animated value class ivalue { // int animated value
public: public:
using ValueType = int32;
ivalue() { ivalue() {
} }
@ -128,16 +129,15 @@ namespace anim {
_delta = 0; _delta = 0;
} }
typedef int32 Type;
private: private:
int32 _cur; int32 _cur;
float64 _from, _delta; float64 _from, _delta;
}; };
class cvalue { // QColor animated value class cvalue { // QColor animated value
public: public:
using ValueType = QColor;
cvalue() { cvalue() {
} }
@ -199,12 +199,10 @@ namespace anim {
_delta_r = _delta_g = _delta_b = _delta_a = 0; _delta_r = _delta_g = _delta_b = _delta_a = 0;
} }
typedef QColor Type;
private: private:
QColor _cur; QColor _cur;
float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a; float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a;
}; };
void startManager(); void startManager();
@ -380,105 +378,81 @@ AnimationCallbacks animation(Param param, Type *obj, typename AnimationCallbacks
template <typename AnimType> template <typename AnimType>
class SimpleAnimation { class SimpleAnimation {
public: public:
using Callback = Function<void>; using ValueType = typename AnimType::ValueType;
using Callback = base::lambda_unique<void()>;
SimpleAnimation() { bool animating() const {
if (_data) {
if (_data->a_animation.animating()) {
return true;
}
_data.reset();
}
return false;
} }
bool animating(uint64 ms) { bool animating(uint64 ms) {
if (_data && _data->_a.animating()) { if (animating()) {
_data->_a.step(ms); _data->a_animation.step(ms);
return _data && _data->_a.animating(); return animating();
} }
return false; return false;
} }
bool isNull() const { ValueType current() const {
return !_data; t_assert(_data != nullptr);
return _data->value.current();
} }
ValueType current(const ValueType &def) const {
typename AnimType::Type current() { return _data ? current() : def;
return _data ? _data->a.current() : typename AnimType::Type();
} }
ValueType current(uint64 ms, const ValueType &def) {
typename AnimType::Type current(const typename AnimType::Type &def) {
return _data ? _data->a.current() : def;
}
typename AnimType::Type current(uint64 ms, const typename AnimType::Type &def) {
return animating(ms) ? current() : def; return animating(ms) ? current() : def;
} }
void setup(const typename AnimType::Type &from, Callback &&update) { template <typename Lambda>
void start(Lambda &&updateCallback, const ValueType &from, const ValueType &to, float64 duration, anim::transition transition = anim::linear) {
if (!_data) { if (!_data) {
_data = new Data(from, std_::move(update), animation(this, &SimpleAnimation<AnimType>::step)); _data = std_::make_unique<Data>(from, std_::move(updateCallback));
} else {
_data->a = AnimType(from, from);
}
}
void start(const typename AnimType::Type &to, float64 duration, anim::transition transition = anim::linear) {
if (_data) {
_data->a.start(to);
_data->_a.start();
_data->duration = duration;
_data->transition = transition;
} }
_data->value.start(to);
_data->duration = duration;
_data->transition = transition;
_data->a_animation.start();
} }
void finish() { void finish() {
if (isNull()) { if (_data) {
return; _data->value.finish();
_data->a_animation.stop();
_data.reset();
} }
_data->a.finish();
_data->_a.stop();
delete _data;
_data = nullptr;
}
~SimpleAnimation() {
deleteAndMark(_data);
} }
private: private:
struct Data { struct Data {
Data(const typename AnimType::Type &from, Callback &&update, AnimationCallbacks &&acb) Data(const ValueType &from, Callback &&updateCallback)
: a(from, from) : value(from, from)
, _a(std_::move(acb)) , a_animation(animation(this, &Data::step))
, update(std_::move(update)) , updateCallback(std_::move(updateCallback)) {
, duration(0)
, transition(anim::linear) {
} }
AnimType a; void step(float64 ms, bool timer) {
Animation _a; auto dt = (ms >= duration) ? 1. : (ms / duration);
Callback update; if (dt >= 1) {
float64 duration; value.finish();
anim::transition transition; a_animation.stop();
} else {
value.update(dt, transition);
}
updateCallback();
}
AnimType value;
Animation a_animation;
Callback updateCallback;
float64 duration = 0.;
anim::transition transition = anim::linear;
}; };
Data *_data = nullptr; mutable std_::unique_ptr<Data> _data;
void step(float64 ms, bool timer) {
float64 dt = (ms >= _data->duration) ? 1 : (ms / _data->duration);
if (dt >= 1) {
_data->a.finish();
_data->_a.stop();
} else {
_data->a.update(dt, _data->transition);
}
Callback callbackCache, *toCall = &_data->update;
if (!_data->_a.animating()) {
callbackCache = std_::move(_data->update);
toCall = &callbackCache;
delete _data;
_data = nullptr;
}
if (timer) {
toCall->call();
}
}
}; };
@ -486,18 +460,8 @@ using FloatAnimation = SimpleAnimation<anim::fvalue>;
using IntAnimation = SimpleAnimation<anim::ivalue>; using IntAnimation = SimpleAnimation<anim::ivalue>;
using ColorAnimation = SimpleAnimation<anim::cvalue>; using ColorAnimation = SimpleAnimation<anim::cvalue>;
// Macro allows us to lazily create updateCallback.
#define ENSURE_ANIMATION(animation, updateCallback, from) \
if ((animation).isNull()) { \
(animation).setup((from), (updateCallback)); \
}
#define START_ANIMATION(animation, updateCallback, from, to, duration, transition) \
ENSURE_ANIMATION(animation, updateCallback, from); \
(animation).start((to), (duration), (transition))
class AnimationManager : public QObject { class AnimationManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
AnimationManager(); AnimationManager();
@ -511,7 +475,7 @@ public slots:
void clipCallback(Media::Clip::Reader *reader, qint32 threadIndex, qint32 notification); void clipCallback(Media::Clip::Reader *reader, qint32 threadIndex, qint32 notification);
private: private:
typedef QMap<Animation*, NullType> AnimatingObjects; using AnimatingObjects = OrderedSet<Animation*>;
AnimatingObjects _objects, _starting, _stopping; AnimatingObjects _objects, _starting, _stopping;
QTimer _timer; QTimer _timer;
bool _iterating; bool _iterating;

View File

@ -118,7 +118,7 @@ void HistoryDownButton::hideAnimated() {
void HistoryDownButton::toggleAnimated() { void HistoryDownButton::toggleAnimated() {
_shown = !_shown; _shown = !_shown;
float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.; float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.;
START_ANIMATION(_a_show, func(this, &HistoryDownButton::repaintCallback), from, to, st::btnAttachEmoji.duration, anim::linear); _a_show.start([this] { update(); }, from, to, st::btnAttachEmoji.duration);
} }
void HistoryDownButton::finishAnimation() { void HistoryDownButton::finishAnimation() {

View File

@ -47,9 +47,6 @@ protected:
private: private:
void toggleAnimated(); void toggleAnimated();
void repaintCallback() {
update();
}
void step_arrowOver(float64 ms, bool timer); void step_arrowOver(float64 ms, bool timer);
QPixmap _cache; QPixmap _cache;

View File

@ -49,7 +49,7 @@ void IconButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
if (over != (oldState & StateOver)) { if (over != (oldState & StateOver)) {
auto from = over ? 0. : 1.; auto from = over ? 0. : 1.;
auto to = over ? 1. : 0.; auto to = over ? 1. : 0.;
START_ANIMATION(_a_over, func(this, &IconButton::updateCallback), from, to, _st.duration, anim::linear); _a_over.start([this] { update(); }, from, to, _st.duration);
} }
} }

View File

@ -37,10 +37,6 @@ protected:
void onStateChanged(int oldState, ButtonStateChangeSource source) override; void onStateChanged(int oldState, ButtonStateChangeSource source) override;
private: private:
void updateCallback() {
update();
}
const style::IconButton &_st; const style::IconButton &_st;
const style::icon *_iconOverride = nullptr; const style::icon *_iconOverride = nullptr;

View File

@ -65,7 +65,9 @@ void FadeAnimation::stopAnimation() {
_cache = QPixmap(); _cache = QPixmap();
updateCallback(); updateCallback();
_widget->showChildren(); _widget->showChildren();
_finishedCallback.call(); if (_finishedCallback) {
_finishedCallback();
}
} }
if (_visible == _widget->isHidden()) { if (_visible == _widget->isHidden()) {
_widget->setVisible(_visible); _widget->setVisible(_visible);
@ -91,7 +93,9 @@ void FadeAnimation::startAnimation(int duration) {
_cache = myGrab(_widget); _cache = myGrab(_widget);
_widget->hideChildren(); _widget->hideChildren();
} }
START_ANIMATION(_animation, func(this, &FadeAnimation::updateCallback), _visible ? 0. : 1., _visible ? 1. : 0., duration, anim::linear); auto from = _visible ? 0. : 1.;
auto to = _visible ? 1. : 0.;
_animation.start([this]() { updateCallback(); }, from, to, duration);
updateCallback(); updateCallback();
if (_widget->isHidden()) { if (_widget->isHidden()) {
_widget->show(); _widget->show();
@ -101,7 +105,9 @@ void FadeAnimation::startAnimation(int duration) {
void FadeAnimation::updateCallback() { void FadeAnimation::updateCallback() {
if (_animation.animating(getms())) { if (_animation.animating(getms())) {
_widget->update(); _widget->update();
_updatedCallback.call(_animation.current()); if (_updatedCallback) {
_updatedCallback(_animation.current(_visible ? 1. : 0.));
}
} else { } else {
stopAnimation(); stopAnimation();
} }

View File

@ -31,10 +31,10 @@ public:
bool paint(Painter &p); bool paint(Painter &p);
void refreshCache(); void refreshCache();
using FinishedCallback = Function<void>; using FinishedCallback = base::lambda_unique<void()>;
void setFinishedCallback(FinishedCallback &&callback); void setFinishedCallback(FinishedCallback &&callback);
using UpdatedCallback = Function<void, float64>; using UpdatedCallback = base::lambda_unique<void(float64)>;
void setUpdatedCallback(UpdatedCallback &&callback); void setUpdatedCallback(UpdatedCallback &&callback);
void show(); void show();

View File

@ -65,14 +65,16 @@ bool processQuery();
namespace internal { namespace internal {
using QueryUpdateHandler = Function<void, const QueryUpdate&>; using QueryUpdateHandler = base::lambda_unique<void(const QueryUpdate&)>;
Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler); Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler);
} // namespace internal } // namespace internal
template <typename ObserverType> template <typename ObserverType>
void registerObserver(ObserverType *observer, void (ObserverType::*handler)(const QueryUpdate &)) { void registerObserver(ObserverType *observer, void (ObserverType::*handler)(const QueryUpdate &)) {
auto connection = internal::plainRegisterObserver(func(observer, handler)); auto connection = internal::plainRegisterObserver([observer, handler](const QueryUpdate &update) {
(observer->*handler)(update);
});
Notify::observerRegistered(observer, connection); Notify::observerRegistered(observer, connection);
} }

View File

@ -332,7 +332,7 @@ void EmojiButton::setLoading(bool loading) {
if (_loading != loading) { if (_loading != loading) {
_loading = loading; _loading = loading;
auto from = loading ? 0. : 1., to = loading ? 1. : 0.; auto from = loading ? 0. : 1., to = loading ? 1. : 0.;
START_ANIMATION(a_loading, func(this, &EmojiButton::updateCallback), from, to, st::emojiCircleDuration, anim::linear); a_loading.start([this] { update(); }, from, to, st::emojiCircleDuration);
if (loading) { if (loading) {
_a_loading.start(); _a_loading.start();
} else { } else {

View File

@ -147,12 +147,9 @@ private:
void step_loading(uint64 ms, bool timer) { void step_loading(uint64 ms, bool timer) {
if (timer) { if (timer) {
updateCallback(); update();
} }
} }
void updateCallback() {
update();
}
}; };

View File

@ -232,7 +232,7 @@ Text::StateResult FlatLabel::dragActionFinish(const QPoint &p, Qt::MouseButton b
_selectionType = TextSelectType::Letters; _selectionType = TextSelectType::Letters;
if (activated) { if (activated) {
if (_clickHandlerHook.isNull() || _clickHandlerHook.call(activated, button)) { if (!_clickHandlerHook || _clickHandlerHook(activated, button)) {
App::activateClickHandler(activated, button); App::activateClickHandler(activated, button);
} }
} }

View File

@ -47,7 +47,7 @@ public:
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk); void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
using ClickHandlerHook = Function<bool, const ClickHandlerPtr &, Qt::MouseButton>; using ClickHandlerHook = base::lambda_unique<bool(const ClickHandlerPtr&,Qt::MouseButton)>;
void setClickHandlerHook(ClickHandlerHook &&hook); void setClickHandlerHook(ClickHandlerHook &&hook);
// ClickHandlerHost interface // ClickHandlerHost interface

View File

@ -160,12 +160,12 @@ void InnerDropdown::onHideStart() {
void InnerDropdown::startAnimation() { void InnerDropdown::startAnimation() {
auto from = _hiding ? 1. : 0.; auto from = _hiding ? 1. : 0.;
auto to = _hiding ? 0. : 1.; auto to = _hiding ? 0. : 1.;
if (_a_appearance.isNull()) { if (!_a_appearance.animating()) {
showChildren(); showChildren();
_cache = myGrab(this); _cache = myGrab(this);
} }
hideChildren(); hideChildren();
START_ANIMATION(_a_appearance, func(this, &InnerDropdown::repaintCallback), from, to, _st.duration, anim::linear); _a_appearance.start([this] { repaintCallback(); }, from, to, _st.duration);
} }
void InnerDropdown::hidingFinished() { void InnerDropdown::hidingFinished() {
@ -186,7 +186,7 @@ void InnerDropdown::showingStarted() {
void InnerDropdown::repaintCallback() { void InnerDropdown::repaintCallback() {
update(); update();
if (!_a_appearance.animating(getms()) && _hiding) { if (!_a_appearance.animating() && _hiding) {
_hiding = false; _hiding = false;
hidingFinished(); hidingFinished();
} }

View File

@ -35,7 +35,7 @@ public:
void setOwnedWidget(ScrolledWidget *widget); void setOwnedWidget(ScrolledWidget *widget);
bool overlaps(const QRect &globalRect) { bool overlaps(const QRect &globalRect) {
if (isHidden() || !_a_appearance.isNull()) return false; if (isHidden() || _a_appearance.animating()) return false;
return rect().marginsRemoved(_st.padding).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); return rect().marginsRemoved(_st.padding).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
} }

View File

@ -86,7 +86,7 @@ enum class Mode {
}; };
void ToggleableShadow::setMode(Mode mode) { void ToggleableShadow::setMode(Mode mode) {
if (mode == Mode::ShownFast || mode == Mode::HiddenFast) { if (mode == Mode::ShownFast || mode == Mode::HiddenFast) {
if (!_a_opacity.isNull()) { if (!_a_opacity.animating()) {
_a_opacity.finish(); _a_opacity.finish();
update(); update();
} }
@ -94,18 +94,12 @@ void ToggleableShadow::setMode(Mode mode) {
if (_shown && (mode == Mode::Hidden || mode == Mode::HiddenFast)) { if (_shown && (mode == Mode::Hidden || mode == Mode::HiddenFast)) {
_shown = false; _shown = false;
if (mode == Mode::Hidden) { if (mode == Mode::Hidden) {
if (_a_opacity.isNull()) { _a_opacity.start([this] { update(); }, 1., 0., st::shadowToggleDuration);
_a_opacity.setup(1., func(this, &ToggleableShadow::repaintCallback));
}
_a_opacity.start(0., st::shadowToggleDuration);
} }
} else if (!_shown && (mode == Mode::Shown || mode == Mode::ShownFast)) { } else if (!_shown && (mode == Mode::Shown || mode == Mode::ShownFast)) {
_shown = true; _shown = true;
if (mode == Mode::Shown) { if (mode == Mode::Shown) {
if (_a_opacity.isNull()) { _a_opacity.start([this] { update(); }, 0., 1., st::shadowToggleDuration);
_a_opacity.setup(0., func(this, &ToggleableShadow::repaintCallback));
}
_a_opacity.start(1., st::shadowToggleDuration);
} }
} }
} }

View File

@ -268,17 +268,13 @@ public:
void setMode(Mode mode); void setMode(Mode mode);
bool isFullyShown() const { bool isFullyShown() const {
return _shown && _a_opacity.isNull(); return _shown && !_a_opacity.animating();
} }
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
private: private:
void repaintCallback() {
update();
}
const style::color &_color; const style::color &_color;
FloatAnimation _a_opacity; FloatAnimation _a_opacity;
bool _shown = true; bool _shown = true;

View File

@ -50,8 +50,8 @@ void SectionWidget::showAnimated(SlideDirection direction, const SectionSlidePar
_showAnimation = std_::make_unique<SlideAnimation>(); _showAnimation = std_::make_unique<SlideAnimation>();
_showAnimation->setDirection(direction); _showAnimation->setDirection(direction);
_showAnimation->setRepaintCallback(func(this, &SectionWidget::repaintCallback)); _showAnimation->setRepaintCallback([this] { update(); });
_showAnimation->setFinishedCallback(func(this, &SectionWidget::showFinished)); _showAnimation->setFinishedCallback([this] { showFinished(); });
_showAnimation->setPixmaps(params.oldContentCache, myContentCache); _showAnimation->setPixmaps(params.oldContentCache, myContentCache);
_showAnimation->setTopBarShadow(params.withTopBarShadow); _showAnimation->setTopBarShadow(params.withTopBarShadow);
_showAnimation->start(); _showAnimation->start();

View File

@ -89,10 +89,6 @@ protected:
} }
private: private:
// QWidget::update() method is overloaded and we need template deduction.
void repaintCallback() {
update();
}
void showFinished(); void showFinished();
std_::unique_ptr<SlideAnimation> _showAnimation; std_::unique_ptr<SlideAnimation> _showAnimation;

View File

@ -92,7 +92,9 @@ void SlideAnimation::step(float64 ms, bool timer) {
a_coordUnder.finish(); a_coordUnder.finish();
a_coordOver.finish(); a_coordOver.finish();
_finishedCallback.call(); if (_finishedCallback) {
_finishedCallback();
}
return; return;
} }
} }
@ -100,8 +102,8 @@ void SlideAnimation::step(float64 ms, bool timer) {
a_coordUnder.update(dt, st::slideFunction); a_coordUnder.update(dt, st::slideFunction);
a_coordOver.update(dt, st::slideFunction); a_coordOver.update(dt, st::slideFunction);
a_progress.update(dt, st::slideFunction); a_progress.update(dt, st::slideFunction);
if (timer) { if (timer && _repaintCallback) {
_repaintCallback.call(); _repaintCallback();
} }
} }

View File

@ -37,10 +37,10 @@ public:
void setPixmaps(const QPixmap &oldContentCache, const QPixmap &newContentCache); void setPixmaps(const QPixmap &oldContentCache, const QPixmap &newContentCache);
void setTopBarShadow(bool enabled); void setTopBarShadow(bool enabled);
using RepaintCallback = Function<void>; using RepaintCallback = base::lambda_unique<void()>;
void setRepaintCallback(RepaintCallback &&callback); void setRepaintCallback(RepaintCallback &&callback);
using FinishedCallback = Function<void>; using FinishedCallback = base::lambda_unique<void()>;
void setFinishedCallback(FinishedCallback &&callback); void setFinishedCallback(FinishedCallback &&callback);
void start(); void start();