Sticker preview done for inline bot results.

ReplyMarkupClickHandler moved to .cpp (implementation details).
This commit is contained in:
John Preston 2016-04-06 19:32:05 +04:00
parent ba7cb1abbc
commit a728dcfca8
10 changed files with 99 additions and 85 deletions

View file

@ -772,12 +772,12 @@ private:
T *_p;
};
template <typename T, class... Args>
template <typename T, typename... Args>
inline UniquePointer<T> MakeUnique(Args&&... args) {
return UniquePointer<T>(new T(std_::forward<Args>(args)...));
}
template <typename T, class... Args>
template <typename T, typename... Args>
inline QSharedPointer<T> MakeShared(Args&&... args) {
return QSharedPointer<T>(new T(std_::forward<Args>(args)...));
}
@ -832,6 +832,13 @@ private:
};
template <typename T>
using NeverFreedPointerCreator = T*(*)();
template <typename T, typename... Args>
inline NeverFreedPointerCreator<T> MakeNeverFreedCreator(Args&&... args) {
return []() -> T* { return new T(std_::forward<Args>(args)...); };
}
// This pointer is used for static non-POD variables that are allocated
// on first use by constructor and are never automatically freed.
template <typename T>

View file

@ -2172,7 +2172,9 @@ void StickerPanInner::refreshPanels(QVector<EmojiPanel*> &panels) {
}
void StickerPanInner::updateSelected() {
if (_pressedSel >= 0 && !_previewShown) return;
if (_pressedSel >= 0 && !_previewShown) {
return;
}
int32 selIndex = -1;
QPoint p(mapFromGlobal(_lastMousePos));
@ -2229,8 +2231,10 @@ void StickerPanInner::updateSelected() {
}
if (_pressedSel >= 0 && _selected >= 0 && _pressedSel != _selected) {
_pressedSel = _selected;
if (row >= 0 && col >= 0 && _inlineRows.at(row).items.at(col)->getDocument()) {
Ui::showStickerPreview(_inlineRows.at(row).items.at(col)->getDocument());
if (row >= 0 && col >= 0) {
if (DocumentData *previewDocument = _inlineRows.at(row).items.at(col)->getPreviewDocument()) {
Ui::showStickerPreview(previewDocument);
}
}
}
}
@ -2329,9 +2333,11 @@ void StickerPanInner::onPreview() {
if (_pressedSel < 0) return;
if (_showingInlineItems) {
int32 row = _pressedSel / MatrixRowShift, col = _pressedSel % MatrixRowShift;
if (row < _inlineRows.size() && col < _inlineRows.at(row).items.size() && _inlineRows.at(row).items.at(col)->getDocument() && _inlineRows.at(row).items.at(col)->getDocument()->loaded()) {
Ui::showStickerPreview(_inlineRows.at(row).items.at(col)->getDocument());
_previewShown = true;
if (row < _inlineRows.size() && col < _inlineRows.at(row).items.size()) {
if (DocumentData *previewDocument = _inlineRows.at(row).items.at(col)->getPreviewDocument()) {
Ui::showStickerPreview(previewDocument);
_previewShown = true;
}
}
} else if (_pressedSel < MatrixRowShift * _sets.size()) {
int tab = (_pressedSel / MatrixRowShift), sel = _pressedSel % MatrixRowShift;

View file

@ -61,8 +61,8 @@ ClickHandlerHost::~ClickHandlerHost() {
ClickHandler::hostDestroyed(this);
}
ClickHandlerPtr *ClickHandler::_active = nullptr;
ClickHandlerPtr *ClickHandler::_pressed = nullptr;
NeverFreedPointer<ClickHandlerPtr> ClickHandler::_active;
NeverFreedPointer<ClickHandlerPtr> ClickHandler::_pressed;
ClickHandlerHost *ClickHandler::_activeHost = nullptr;
ClickHandlerHost *ClickHandler::_pressedHost = nullptr;
@ -86,9 +86,7 @@ bool ClickHandler::setActive(const ClickHandlerPtr &p, ClickHandlerHost *host) {
}
}
if (p) {
if (!_active) {
_active = new ClickHandlerPtr(); // won't be deleted
}
_active.createIfNull(MakeNeverFreedCreator<ClickHandlerPtr>());
*_active = p;
if ((_activeHost = host)) {
bool emitClickHandlerActiveChanged = (!_pressed || !*_pressed || *_pressed == *_active);

View file

@ -366,9 +366,7 @@ public:
if (!_active || !*_active) {
return;
}
if (!_pressed) {
_pressed = new ClickHandlerPtr(); // won't be deleted
}
_pressed.createIfNull(MakeNeverFreedCreator<ClickHandlerPtr>());
*_pressed = *_active;
if ((_pressedHost = _activeHost)) {
_pressedHost->clickHandlerPressedChanged(*_pressed, true);
@ -428,8 +426,8 @@ public:
private:
static ClickHandlerPtr *_active;
static ClickHandlerPtr *_pressed;
static NeverFreedPointer<ClickHandlerPtr> _active;
static NeverFreedPointer<ClickHandlerPtr> _pressed;
static ClickHandlerHost *_activeHost;
static ClickHandlerHost *_pressedHost;

View file

@ -2740,36 +2740,57 @@ void HistoryBlock::removeItem(HistoryItem *item) {
}
}
void ReplyMarkupClickHandler::onClickImpl() const {
const HistoryItem *item = nullptr;
const HistoryMessageReplyMarkup::Button *button = nullptr;
if (getItemAndButton(&item, &button)) {
App::activateBotCommand(item->history()->peer, *button, _msgId.msg);
class ReplyMarkupClickHandler : public LeftButtonClickHandler {
public:
ReplyMarkupClickHandler(const HistoryItem *item, int row, int col) : _item(item), _row(row), _col(col) {
}
}
// We need to make sure the item still exists, so we get it by id.
// After that we check if the reply markup is still there and that
// there are enough button rows and buttons in the row.
// Note: it is possible that we will point to the different button
// than the one was used when constructing the handler, but not a big deal.
bool ReplyMarkupClickHandler::getItemAndButton(
const HistoryItem **outItem,
const HistoryMessageReplyMarkup::Button **outButton) const {
if (HistoryItem *item = App::histItemById(_msgId)) {
if (auto *markup = item->Get<HistoryMessageReplyMarkup>()) {
QString tooltip() const override {
return _fullDisplayed ? QString() : text();
}
void setFullDisplayed(bool full) {
_fullDisplayed = full;
}
protected:
void onClickImpl() const override {
if (auto button = getButton()) {
MsgId replyTo = (_item->id > 0) ? _item->id : 0;
App::activateBotCommand(_item->history()->peer, *button, replyTo);
}
}
private:
const HistoryItem *_item = nullptr;
int _row, _col;
bool _fullDisplayed = true;
// Finds the corresponding button in the items markup struct.
// If the button is not found it returns nullptr.
// Note: it is possible that we will point to the different button
// than the one was used when constructing the handler, but not a big deal.
const HistoryMessageReplyMarkup::Button *getButton() const {
if (auto *markup = _item->Get<HistoryMessageReplyMarkup>()) {
if (_row < markup->rows.size()) {
const HistoryMessageReplyMarkup::ButtonRow &row(markup->rows.at(_row));
if (_col < row.size()) {
if (outItem) *outItem = item;
if (outButton) *outButton = &row.at(_col);
return true;
return &row.at(_col);
}
}
}
return nullptr;
}
return false;
}
// Returns the full text of the corresponding button.
QString text() const {
if (auto button = getButton()) {
return button->text;
}
return QString();
}
};
ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s)
: _item(item)
@ -2785,7 +2806,7 @@ ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s)
Button &button(newRow[j]);
QString str = row.at(j).text;
button.type = row.at(j).type;
button.link.reset(new ReplyMarkupClickHandler(item->fullId(), i, j));
button.link.reset(new ReplyMarkupClickHandler(item, i, j));
button.text.setText(_st->textFont(), textOneLine(str), _textPlainOptions);
button.characters = str.isEmpty() ? 1 : str.size();
}

View file

@ -1121,45 +1121,7 @@ private:
};
class ReplyMarkupClickHandler : public LeftButtonClickHandler {
public:
ReplyMarkupClickHandler(const FullMsgId &msgId, int row, int col) : _msgId(msgId), _row(row), _col(col) {
}
QString tooltip() const override {
return _fullDisplayed ? QString() : text();
}
void setFullDisplayed(bool full) {
_fullDisplayed = full;
}
protected:
void onClickImpl() const override;
private:
FullMsgId _msgId;
int _row, _col;
bool _fullDisplayed = true;
// Finds the corresponding item and button in the items markup struct.
// If the item or the button is not found it returns false.
// Any of the two output arguments can be nullptr if its value is not needed.
bool getItemAndButton(
const HistoryItem **outItem,
const HistoryMessageReplyMarkup::Button **outButtonPointer) const;
// Returns the full text of the corresponding button.
QString text() const {
const HistoryMessageReplyMarkup::Button *button = nullptr;
if (getItemAndButton(nullptr, &button)) {
return button->text;
}
return QString();
}
};
class ReplyMarkupClickHandler;
class ReplyKeyboard {
private:
struct Button;

View file

@ -49,6 +49,24 @@ PhotoData *ItemBase::getPhoto() const {
return _photo;
}
DocumentData *ItemBase::getPreviewDocument() const {
auto previewDocument = [this]() -> DocumentData* {
if (_doc) {
return _doc;
}
if (_result) {
return _result->_document;
}
return nullptr;
};
if (DocumentData *result = previewDocument()) {
if (result->sticker() || result->loaded()) {
return result;
}
}
return nullptr;
}
void ItemBase::preload() const {
if (_result) {
if (_result->_photo) {

View file

@ -73,6 +73,10 @@ public:
DocumentData *getDocument() const;
PhotoData *getPhoto() const;
// Get document (possibly from InlineBots::Result) for
// showing sticker or GIF preview.
DocumentData *getPreviewDocument() const;
virtual void preload() const;
void update();

View file

@ -217,7 +217,7 @@ with open('scheme.tl') as f:
if funcsNow:
if (isTemplate != ''):
funcsText += '\ntemplate <class TQueryType>';
funcsText += '\ntemplate <typename TQueryType>';
funcsText += '\nclass MTP' + name + ' { // RPC method \'' + nametype.group(1) + '\'\n'; # class
funcsText += 'public:\n';

View file

@ -14423,7 +14423,7 @@ public:
}
};
template <class TQueryType>
template <typename TQueryType>
class MTPinvokeAfterMsg { // RPC method 'invokeAfterMsg'
public:
MTPlong vmsg_id;
@ -14465,7 +14465,7 @@ public:
}
};
template <class TQueryType>
template <typename TQueryType>
class MTPinvokeAfterMsgs { // RPC method 'invokeAfterMsgs'
public:
MTPVector<MTPlong> vmsg_ids;
@ -14507,7 +14507,7 @@ public:
}
};
template <class TQueryType>
template <typename TQueryType>
class MTPinitConnection { // RPC method 'initConnection'
public:
MTPint vapi_id;
@ -14561,7 +14561,7 @@ public:
}
};
template <class TQueryType>
template <typename TQueryType>
class MTPinvokeWithLayer { // RPC method 'invokeWithLayer'
public:
MTPint vlayer;
@ -14603,7 +14603,7 @@ public:
}
};
template <class TQueryType>
template <typename TQueryType>
class MTPinvokeWithoutUpdates { // RPC method 'invokeWithoutUpdates'
public:
TQueryType vquery;