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::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]);
if (callback) {
MessageDataRequest::CallbackPtr pcallback(callback.release());
req.callbacks.append(pcallback);
req.callbacks.append(std_::move(callback));
}
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();) {
if (i.value().req == req) {
for_const (auto &callback, i.value().callbacks) {
callback->call(channel, i.key());
callback(channel, i.key());
}
i = requests->erase(i);
} else {

View File

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

View File

@ -227,9 +227,9 @@ void ShareBox::onMustScrollTo(int top, int bottom) {
to = bottom - (scrollBottom - scrollTop);
}
if (from != to) {
START_ANIMATION(_scrollAnimation, func([this]() {
_scrollAnimation.start([this]() {
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) {
auto changeNameFg = [this](int index, style::color from, style::color to) {
if (auto chat = getChatAtIndex(index)) {
START_ANIMATION(chat->nameFg, func([this, chat] {
chat->nameFg.start([this, chat] {
repaintChat(chat->peer);
}), from->c, to->c, st::shareActivateDuration, anim::linear);
}, from->c, to->c, st::shareActivateDuration);
}
};
changeNameFg(_active, st::shareNameActiveFg, st::shareNameFg);
@ -459,16 +459,7 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
auto w = width();
auto photoLeft = (_rowWidth - (st::sharePhotoRadius * 2)) / 2;
auto photoTop = st::sharePhotoTop;
if (chat->selection.isNull()) {
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 {
if (chat->selection.animating()) {
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
auto userpicRadius = qRound(WideCacheScale * (st::sharePhotoRadius + (st::sharePhotoSmallRadius - st::sharePhotoRadius) * selectionLevel));
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());
p.drawPixmapLeft(to, w, chat->wideUserpicCache, from);
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) {
@ -516,11 +516,12 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
p.setRenderHint(QPainter::SmoothPixmapTransform, false);
p.setOpacity(1.);
if (chat->nameFg.isNull()) {
p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg);
} else {
if (chat->nameFg.animating()) {
p.setPen(chat->nameFg.current());
} else {
p.setPen((index == _active) ? st::shareNameActiveFg : st::shareNameFg);
}
auto nameWidth = (_rowWidth - st::shareColumnSkip);
auto nameLeft = st::shareColumnSkip / 2;
auto nameTop = photoTop + st::sharePhotoRadius * 2 + st::shareNameTop;
@ -670,21 +671,21 @@ void ShareInner::changeCheckState(Chat *chat) {
if (chat->selected) {
_selected.insert(chat->peer);
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);
}), 0, 1, st::shareSelectDuration, anim::linear);
}, 0, 1, st::shareSelectDuration);
} else {
_selected.remove(chat->peer);
prepareWideCheckIconCache(&chat->icons.back());
START_ANIMATION(chat->icons.back().fadeOut, func([this, chat] {
removeFadeOutedIcons(chat);
chat->icons.back().fadeOut.start([this, chat] {
repaintChat(chat->peer);
}), 1, 0, st::shareSelectDuration, anim::linear);
removeFadeOutedIcons(chat); // this call can destroy current lambda
}, 1, 0, st::shareSelectDuration);
}
prepareWideUserpicCache(chat);
START_ANIMATION(chat->selection, func([this, chat] {
chat->selection.start([this, chat] {
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) {
setActive(chatIndex(chat->peer));
}
@ -692,9 +693,9 @@ void ShareInner::changeCheckState(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) {
chat->icons.pop_front();
chat->icons.erase(chat->icons.begin());
} else {
break;
}
@ -1016,18 +1017,6 @@ void shareGameScoreFromItem(HistoryItem *item) {
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
void shareGameScoreByHash(const QString &hash) {
@ -1062,7 +1051,13 @@ void shareGameScoreByHash(const QString &hash) {
} else if (App::api()) {
auto channel = channelId ? App::channelLoaded(channelId) : nullptr;
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 "core/lambda_wrap.h"
#include "core/observer.h"
#include "core/vector_of_moveable.h"
namespace Dialogs {
class Row;
@ -163,7 +164,7 @@ private:
FloatAnimation fadeOut;
QPixmap wideCheckCache;
};
QList<Icon> icons;
std_::vector_of_moveable<Icon> icons;
};
void paintChat(Painter &p, Chat *chat, int index);
void updateChat(PeerData *peer);

View File

@ -62,8 +62,8 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
_selected = -1;
setCursor(style::cur_default);
if (set.type() == mtpc_messages_stickerSet) {
auto &d(set.c_messages_stickerSet());
auto &v(d.vdocuments.c_vector().v);
auto &d = set.c_messages_stickerSet();
auto &v = d.vdocuments.c_vector().v;
_pack.reserve(v.size());
_packOvers.reserve(v.size());
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) {
if (index >= 0 && index < _packOvers.size()) {
START_ANIMATION(_packOvers[index], func([this, index]() {
_packOvers[index].start([this, index] {
int row = index / StickerPanPerRow;
int column = index % StickerPanPerRow;
int left = st::stickersPadding.left() + column * st::stickersSize.width();
int top = st::stickersPadding.top() + row * 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
#include "abstractbox.h"
#include "core/vector_of_moveable.h"
class ConfirmBox;
@ -69,7 +70,7 @@ private:
return (_setFlags & MTPDstickerSet::Flag::f_masks);
}
QVector<FloatAnimation> _packOvers;
std_::vector_of_moveable<FloatAnimation> _packOvers;
StickerPack _pack;
StickersByEmojiMap _emoji;
bool _loaded = false;

View File

@ -20,6 +20,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
#ifndef OS_MAC_OLD
#include <memory>
#endif // OS_MAC_OLD
template <typename T>
void deleteAndMark(T *&link) {
delete link;
@ -259,13 +270,6 @@ typedef float float32;
typedef double float64;
#endif
#include <string>
#include <exception>
#include <QtCore/QReadWriteLock>
#include <ctime>
using std::string;
using std::exception;
#ifdef OS_MAC_OLD
@ -1035,13 +1039,15 @@ struct ComponentWrapStruct {
// global scope, so it will be filled by zeros from the start
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)
, Align(align)
, Construct(construct)
, Destruct(destruct)
, Move(move) {
}
int Size;
std::size_t Size;
std::size_t Align;
ComponentConstruct Construct;
ComponentDestruct Destruct;
ComponentMove Move;
@ -1058,6 +1064,7 @@ extern QAtomicInt ComponentIndexLast;
template <typename Type>
struct BaseComponent {
BaseComponent() {
static_assert(alignof(Type) <= sizeof(SmallestSizeType), "Components should align to a pointer!");
}
BaseComponent(const BaseComponent &other) = delete;
BaseComponent &operator=(const BaseComponent &other) = delete;
@ -1075,8 +1082,11 @@ struct BaseComponent {
t_assert(last < 64);
if (_index.testAndSetOrdered(0, last + 1)) {
ComponentWraps[last] = ComponentWrapStruct(
CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64),
Type::ComponentConstruct, Type::ComponentDestruct, Type::ComponentMove);
CeilDivideMinimumOne<sizeof(Type), sizeof(SmallestSizeType)>::Result * sizeof(SmallestSizeType),
alignof(Type),
Type::ComponentConstruct,
Type::ComponentDestruct,
Type::ComponentMove);
}
break;
}
@ -1088,6 +1098,8 @@ struct BaseComponent {
}
protected:
using SmallestSizeType = void*;
static void ComponentConstruct(void *location, Composer *composer) {
new (location) Type();
}
@ -1102,7 +1114,6 @@ protected:
class ComposerMetadata {
public:
ComposerMetadata(uint64 mask) : size(0), last(64), _mask(mask) {
for (int i = 0; i < 64; ++i) {
uint64 m = (1ULL << i);
@ -1147,15 +1158,13 @@ const ComposerMetadata *GetComposerMetadata(uint64 mask);
class Composer {
public:
Composer(uint64 mask = 0) : _data(zerodata()) {
if (mask) {
const ComposerMetadata *meta = GetComposerMetadata(mask);
int size = sizeof(meta) + meta->size;
void *data = operator new(size);
if (!data) { // terminate if we can't allocate memory
throw "Can't allocate memory!";
}
auto data = operator new(size);
t_assert(data != nullptr);
_data = data;
_meta() = meta;
@ -1163,7 +1172,13 @@ public:
int offset = meta->offsets[i];
if (offset >= 0) {
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 (...) {
while (i > 0) {
--i;
@ -1182,7 +1197,7 @@ public:
Composer &operator=(const Composer &other) = delete;
~Composer() {
if (_data != zerodata()) {
const ComposerMetadata *meta = _meta();
auto meta = _meta();
for (int i = 0; i < meta->last; ++i) {
int offset = meta->offsets[i];
if (offset >= 0) {
@ -1213,7 +1228,7 @@ protected:
Composer tmp(mask);
tmp.swap(*this);
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) {
int offset = meta->offsets[i], wasoffset = wasmeta->offsets[i];
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
// While we still use Function<>
// While we still use rpcDone() and rpcFail()
#include "mtproto/rpc_sender.h"
template <typename FunctionType>
struct LambdaFunctionHelper;
struct LambdaUniqueHelper;
template <typename Lambda, typename R, typename ...Args>
struct LambdaFunctionHelper<R(Lambda::*)(Args...) const> {
using FunctionType = Function<R, Args...>;
struct LambdaUniqueHelper<R(Lambda::*)(Args...) const> {
using UniqueType = base::lambda_unique<R(Args...)>;
};
template <typename FunctionType>
using LambdaGetFunction = typename LambdaFunctionHelper<FunctionType>::FunctionType;
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"
using LambdaGetUnique = typename LambdaUniqueHelper<FunctionType>::UniqueType;
template <typename Base, typename FunctionType>
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>
struct ObserversList {
struct Entry {
@ -109,8 +109,8 @@ public:
// entries list while the loop is still running.
for (int i = 0; i < entries.size(); ++i) {
auto &entry = entries[i];
if (!entry.handler.isNull() && (flags & entry.flags)) {
entry.handler.call(std_::forward<Args>(args)...);
if (entry.handler && (flags & entry.flags)) {
entry.handler(std_::forward<Args>(args)...);
}
}
}
@ -140,7 +140,7 @@ private:
if (entries.size() <= connectionIndex) return;
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();
}
} else {

View File

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

View File

@ -2644,10 +2644,12 @@ void HistoryMessageReplyMarkup::create(const MTPReplyMarkup &markup) {
}
}
void HistoryDependentItemCallback::call(ChannelData *channel, MsgId msgId) const {
if (HistoryItem *item = App::histItemById(_dependent)) {
item->updateDependencyItem();
}
ApiWrap::RequestMessageDataCallback historyDependentItemCallback(const FullMsgId &msgId) {
return [dependent = msgId](ChannelData *channel, MsgId msgId) {
if (HistoryItem *item = App::histItemById(dependent)) {
item->updateDependencyItem();
}
};
}
void HistoryMessageUnreadBar::init(int count) {
@ -4910,7 +4912,9 @@ bool HistoryGif::playInline(bool autoplay) {
if (!cAutoPlayGif()) {
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);
if (gif()) _gif->setAutoplay();
}
@ -6837,7 +6841,7 @@ void HistoryMessage::createComponents(const CreateConfig &config) {
if (auto reply = Get<HistoryMessageReply>()) {
reply->replyToMsgId = config.replyTo;
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>()) {
@ -8388,7 +8392,7 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
if (auto dependent = GetDependentData()) {
dependent->msgId = message.vreply_to_msg_id.v;
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;
};
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
// displaying the day mark above the message
struct HistoryMessageDate : public BaseComponent<HistoryMessageDate> {

View File

@ -101,6 +101,14 @@ public:
constexpr int ScrollDateHideTimeout = 1000;
ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
return [](ChannelData *channel, MsgId msgId) {
if (App::main()) {
App::main()->messageDataReceived(channel, msgId);
}
};
}
} // namespace
// 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;
auto from = _scrollDateShown ? 0. : 1.;
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() {
@ -4117,7 +4125,7 @@ void HistoryWidget::applyDraft(bool parseLinks) {
if (_editMsgId || _replyToId) {
updateReplyEditTexts();
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();
}
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) {
destroyPinnedBar();
@ -7652,12 +7660,6 @@ void HistoryWidget::destroyPinnedBar() {
_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) {
if (!_history || !doc || !canSendMessages(_peer)) {
return false;

View File

@ -908,11 +908,6 @@ private:
void destroyPinnedBar();
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);
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();
if (loaded && !gif() && _gif != Media::Clip::BadReader) {
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();
}
@ -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)) {
float64 radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1;
auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.;
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.fillRect(r, st::black);
} else {
@ -218,7 +220,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
bool wasactive = (_state & StateFlag::DeleteOver);
if (active != wasactive) {
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) {
_state |= StateFlag::DeleteOver;
} else {
@ -232,7 +234,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
if (!getShownDocument()->loaded()) {
ensureAnimation();
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) {
_state |= StateFlag::Over;
@ -385,7 +387,7 @@ void Sticker::preload() const {
void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context) const {
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) {
p.setOpacity(over);
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;
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);

View File

@ -638,7 +638,9 @@ QPixmap MediaPreviewWidget::currentImage() const {
if (_document->loaded()) {
if (!_gif && _gif != Media::Clip::BadReader) {
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();
}
}

View File

@ -4020,7 +4020,7 @@ DataIsLoadedResult allDataLoadedForMessage(const MTPMessage &msg) {
void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
switch (updates.type()) {
case mtpc_updates: {
const auto &d(updates.c_updates());
auto &d = updates.c_updates();
if (d.vseq.v) {
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
@ -4037,7 +4037,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break;
case mtpc_updatesCombined: {
const auto &d(updates.c_updatesCombined());
auto &d = updates.c_updatesCombined();
if (d.vseq_start.v) {
if (d.vseq_start.v <= updSeq) return;
if (d.vseq_start.v > updSeq + 1) {
@ -4054,15 +4054,14 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break;
case mtpc_updateShort: {
const auto &d(updates.c_updateShort());
auto &d = updates.c_updateShort();
feedUpdate(d.vupdate);
updSetState(0, d.vdate.v, updQts, updSeq);
} break;
case mtpc_updateShortMessage: {
const auto &d(updates.c_updateShortMessage());
auto &d = updates.c_updateShortMessage();
if (!App::userLoaded(d.vuser_id.v)
|| (d.has_via_bot_id() && !App::userLoaded(d.vvia_bot_id.v))
|| (d.has_entities() && !mentionUsersLoaded(d.ventities))
@ -4076,7 +4075,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
// update before applying skipped
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) {
_history->peerMessagesUpdated(item->history()->peer->id);
}
@ -4087,7 +4086,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break;
case mtpc_updateShortChatMessage: {
const auto &d(updates.c_updateShortChatMessage());
auto &d = updates.c_updateShortChatMessage();
bool noFrom = !App::userLoaded(d.vfrom_id.v);
if (!App::chatLoaded(d.vchat_id.v)
|| noFrom
@ -4104,7 +4103,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
// update before applying skipped
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) {
_history->peerMessagesUpdated(item->history()->peer->id);
}
@ -4115,7 +4114,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
} break;
case mtpc_updateShortSentMessage: {
const auto &d(updates.c_updateShortSentMessage());
auto &d = updates.c_updateShortSentMessage();
if (randomId) {
PeerId peerId = 0;
QString text;
@ -4125,7 +4124,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
if (peerId) {
if (auto item = App::histItemById(peerToChannel(peerId), d.vid.v)) {
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();
item->setText({ text, entities });

View File

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

View File

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

View File

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

View File

@ -156,7 +156,7 @@ void Playback::setOver(bool over) {
_over = over;
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

View File

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

View File

@ -100,7 +100,7 @@ void VolumeController::setOver(bool over) {
_over = over;
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

View File

@ -43,9 +43,6 @@ protected:
void leaveEvent(QEvent *e) override;
private:
void updateCallback() {
update();
}
void setOver(bool over);
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);
}
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.
_videoPaused = _videoIsSilent = _videoStopped = false;
@ -1439,7 +1441,9 @@ void MediaView::restartVideoAtSeekPosition(int64 positionMs) {
if (_current.isNull()) {
_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.
_videoPaused = _videoIsSilent = _videoStopped = false;

View File

@ -396,9 +396,10 @@ void reinitWebLoadManager();
void stopWebLoadManager();
namespace FileDownload {
namespace internal {
using ImageLoadedHandler = Function<void>;
using ImageLoadedHandler = base::lambda_unique<void()>;
Notify::ConnectionId plainRegisterImageLoadedObserver(ImageLoadedHandler &&handler);
void notifyImageLoaded();
@ -407,7 +408,9 @@ void notifyImageLoaded();
template <typename ObserverType>
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);
}

View File

@ -91,14 +91,16 @@ void peerUpdatedSendDelayed();
namespace internal {
using PeerUpdateHandler = Function<void, const PeerUpdate&>;
using PeerUpdateHandler = base::lambda_unique<void(const PeerUpdate&)>;
ConnectionId plainRegisterPeerObserver(PeerUpdate::Flags events, PeerUpdateHandler &&handler);
} // namespace internal
template <typename ObserverType>
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);
}

View File

@ -285,7 +285,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
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()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden));
_dropArea->hideAnimated([this](CoverDropArea *area) { dropAreaHidden(area); });
}
e->acceptProposedAction();

View File

@ -57,7 +57,9 @@ void CoverDropArea::paintEvent(QPaintEvent *e) {
_cache = QPixmap();
if (_hiding) {
hide();
_hideFinishCallback.call(this);
if (_hideFinishCallback) {
_hideFinishCallback(this);
}
return;
}
}
@ -93,7 +95,7 @@ void CoverDropArea::setupAnimation() {
_cache = myGrab(this);
}
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

View File

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

View File

@ -149,15 +149,13 @@ void InfoWidget::refreshAbout() {
textParseEntities(aboutText, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &aboutEntities);
_about->setMarkedText({ aboutText, aboutEntities });
_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() {
TextWithEntities phoneText;
if (auto user = peer()->asUser()) {

View File

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

View File

@ -99,19 +99,17 @@ void InviteLinkWidget::refreshLink() {
_link->setMarkedText(linkData);
_link->setSelectable(true);
_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) {
auto link = getInviteLink();
if (link.isEmpty()) {
return true;
QApplication::clipboard()->setText(link);
Ui::showLayer(new InformBox(lang(lng_group_invite_copied)));
return false;
});
}
QApplication::clipboard()->setText(link);
Ui::showLayer(new InformBox(lang(lng_group_invite_copied)));
return false;
}
} // namespace Profile

View File

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

View File

@ -315,17 +315,15 @@ void MembersWidget::refreshLimitReached() {
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);
_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) {
_limitReachedInfo.destroy();
}
}
bool MembersWidget::limitReachedHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new ConvertToSupergroupBox(peer()->asChat()));
return false;
}
void MembersWidget::checkSelfAdmin(ChatData *chat) {
if (chat->participants.isEmpty()) return;

View File

@ -45,7 +45,7 @@ void UserpicButton::showFinished() {
_notShownYet = false;
if (!_waiting) {
_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();
START_ANIMATION(_a_appearance, func(this, &UserpicButton::refreshCallback), 0, 1, st::profilePhotoDuration, anim::linear);
_a_appearance.start([this] { update(); }, 0, 1, st::profilePhotoDuration);
update();
}

View File

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

View File

@ -217,7 +217,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
void CoverWidget::dragLeaveEvent(QDragLeaveEvent *e) {
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()) {
img = qvariant_cast<QImage>(mimeData->imageData());
} else {
const auto &urls = mimeData->urls();
auto &urls = mimeData->urls();
if (urls.size() == 1) {
auto &url = urls.at(0);
if (url.isLocalFile()) {
@ -238,7 +238,7 @@ void CoverWidget::dropEvent(QDropEvent *e) {
}
if (!_dropArea->hiding()) {
_dropArea->hideAnimated(func(this, &CoverWidget::dropAreaHidden));
_dropArea->hideAnimated([this](Profile::CoverDropArea *area) { dropAreaHidden(area); });
}
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));
setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText);
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());
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()) {
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) {
if (textWithEntities.text.isEmpty()) {
row->slideUp();

View File

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

View File

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

View File

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

View File

@ -118,7 +118,7 @@ void HistoryDownButton::hideAnimated() {
void HistoryDownButton::toggleAnimated() {
_shown = !_shown;
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() {

View File

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

View File

@ -49,7 +49,7 @@ void IconButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
if (over != (oldState & StateOver)) {
auto from = over ? 0. : 1.;
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;
private:
void updateCallback() {
update();
}
const style::IconButton &_st;
const style::icon *_iconOverride = nullptr;

View File

@ -65,7 +65,9 @@ void FadeAnimation::stopAnimation() {
_cache = QPixmap();
updateCallback();
_widget->showChildren();
_finishedCallback.call();
if (_finishedCallback) {
_finishedCallback();
}
}
if (_visible == _widget->isHidden()) {
_widget->setVisible(_visible);
@ -91,7 +93,9 @@ void FadeAnimation::startAnimation(int duration) {
_cache = myGrab(_widget);
_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();
if (_widget->isHidden()) {
_widget->show();
@ -101,7 +105,9 @@ void FadeAnimation::startAnimation(int duration) {
void FadeAnimation::updateCallback() {
if (_animation.animating(getms())) {
_widget->update();
_updatedCallback.call(_animation.current());
if (_updatedCallback) {
_updatedCallback(_animation.current(_visible ? 1. : 0.));
}
} else {
stopAnimation();
}

View File

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

View File

@ -65,14 +65,16 @@ bool processQuery();
namespace internal {
using QueryUpdateHandler = Function<void, const QueryUpdate&>;
using QueryUpdateHandler = base::lambda_unique<void(const QueryUpdate&)>;
Notify::ConnectionId plainRegisterObserver(QueryUpdateHandler &&handler);
} // namespace internal
template <typename ObserverType>
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);
}

View File

@ -332,7 +332,7 @@ void EmojiButton::setLoading(bool loading) {
if (_loading != loading) {
_loading = loading;
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) {
_a_loading.start();
} else {

View File

@ -147,12 +147,9 @@ private:
void step_loading(uint64 ms, bool 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;
if (activated) {
if (_clickHandlerHook.isNull() || _clickHandlerHook.call(activated, button)) {
if (!_clickHandlerHook || _clickHandlerHook(activated, button)) {
App::activateClickHandler(activated, button);
}
}

View File

@ -47,7 +47,7 @@ public:
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);
// ClickHandlerHost interface

View File

@ -160,12 +160,12 @@ void InnerDropdown::onHideStart() {
void InnerDropdown::startAnimation() {
auto from = _hiding ? 1. : 0.;
auto to = _hiding ? 0. : 1.;
if (_a_appearance.isNull()) {
if (!_a_appearance.animating()) {
showChildren();
_cache = myGrab(this);
}
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() {
@ -186,7 +186,7 @@ void InnerDropdown::showingStarted() {
void InnerDropdown::repaintCallback() {
update();
if (!_a_appearance.animating(getms()) && _hiding) {
if (!_a_appearance.animating() && _hiding) {
_hiding = false;
hidingFinished();
}

View File

@ -35,7 +35,7 @@ public:
void setOwnedWidget(ScrolledWidget *widget);
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()));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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