Remove Qt MOC dependency for tabbed selector.

This commit is contained in:
John Preston 2018-11-21 22:14:48 +04:00
parent 9f5b09c263
commit ef4f0168f8
22 changed files with 552 additions and 476 deletions

View File

@ -32,6 +32,73 @@ constexpr auto kStickersPanelPerRow = 5;
} // namespace
class StickerSetBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
public:
Inner(QWidget *parent, const MTPInputStickerSet &set);
bool loaded() const;
bool notInstalled() const;
bool official() const;
Fn<TextWithEntities()> title() const;
QString shortName() const;
void install();
rpl::producer<uint64> setInstalled() const;
rpl::producer<> updateControls() const;
~Inner();
protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void leaveEventHook(QEvent *e) override;
private:
void updateSelected();
void setSelected(int selected);
void startOverAnimation(int index, float64 from, float64 to);
int stickerFromGlobalPos(const QPoint &p) const;
void gotSet(const MTPmessages_StickerSet &set);
bool failedSet(const RPCError &error);
void installDone(const MTPmessages_StickerSetInstallResult &result);
bool installFail(const RPCError &error);
bool isMasksSet() const {
return (_setFlags & MTPDstickerSet::Flag::f_masks);
}
void showPreview();
std::vector<Animation> _packOvers;
Stickers::Pack _pack;
Stickers::ByEmojiMap _emoji;
bool _loaded = false;
uint64 _setId = 0;
uint64 _setAccess = 0;
QString _setTitle, _setShortName;
int _setCount = 0;
int32 _setHash = 0;
MTPDstickerSet::Flags _setFlags = 0;
TimeId _setInstallDate = TimeId(0);
MTPInputStickerSet _input;
mtpRequestId _installRequest = 0;
int _selected = -1;
base::Timer _previewTimer;
int _previewShown = -1;
rpl::event_stream<uint64> _setInstalled;
rpl::event_stream<> _updateControls;
};
StickerSetBox::StickerSetBox(QWidget*, const MTPInputStickerSet &set)
: _set(set) {
}
@ -41,33 +108,37 @@ void StickerSetBox::prepare() {
_inner = setInnerWidget(object_ptr<Inner>(this, _set), st::stickersScroll);
Auth().data().stickersUpdated(
) | rpl::start_with_next(
[this] { updateButtons(); },
lifetime());
) | rpl::start_with_next([=] {
updateButtons();
}, lifetime());
setDimensions(st::boxWideWidth, st::stickersMaxHeight);
onUpdateButtons();
updateTitleAndButtons();
_inner->updateControls(
) | rpl::start_with_next([=] {
updateTitleAndButtons();
}, lifetime());
connect(_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons()));
_inner->setInstalled(
) | rpl::start_with_next([this](auto &&setId) {
) | rpl::start_with_next([=](uint64 setId) {
Auth().api().stickerSetInstalled(setId);
this->closeBox();
closeBox();
}, lifetime());
}
void StickerSetBox::onAddStickers() {
void StickerSetBox::addStickers() {
_inner->install();
}
void StickerSetBox::onShareStickers() {
void StickerSetBox::shareStickers() {
auto url = Messenger::Instance().createInternalLinkFull(qsl("addstickers/") + _inner->shortName());
QApplication::clipboard()->setText(url);
Ui::show(Box<InformBox>(lang(lng_stickers_copied)));
}
void StickerSetBox::onUpdateButtons() {
void StickerSetBox::updateTitleAndButtons() {
setTitle(_inner->title());
updateButtons();
}
@ -76,16 +147,16 @@ void StickerSetBox::updateButtons() {
clearButtons();
if (_inner->loaded()) {
if (_inner->notInstalled()) {
addButton(langFactory(lng_stickers_add_pack), [this] { onAddStickers(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
addButton(langFactory(lng_stickers_add_pack), [=] { addStickers(); });
addButton(langFactory(lng_cancel), [=] { closeBox(); });
} else if (_inner->official()) {
addButton(langFactory(lng_about_done), [this] { closeBox(); });
addButton(langFactory(lng_about_done), [=] { closeBox(); });
} else {
addButton(langFactory(lng_stickers_share_pack), [this] { onShareStickers(); });
addButton(langFactory(lng_cancel), [this] { closeBox(); });
addButton(langFactory(lng_stickers_share_pack), [=] { shareStickers(); });
addButton(langFactory(lng_cancel), [=] { closeBox(); });
}
} else {
addButton(langFactory(lng_cancel), [this] { closeBox(); });
addButton(langFactory(lng_cancel), [=] { closeBox(); });
}
update();
}
@ -96,7 +167,8 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) {
}
StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) : TWidget(parent)
, _input(set) {
, _input(set)
, _previewTimer([=] { showPreview(); }) {
switch (set.type()) {
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break;
@ -107,9 +179,6 @@ StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) : TW
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
setMouseTracking(true);
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
}
void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
@ -183,8 +252,15 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
_loaded = true;
updateSelected();
_updateControls.fire({});
}
emit updateButtons();
rpl::producer<uint64> StickerSetBox::Inner::setInstalled() const {
return _setInstalled.events();
}
rpl::producer<> StickerSetBox::Inner::updateControls() const {
return _updateControls.events();
}
bool StickerSetBox::Inner::failedSet(const RPCError &error) {
@ -273,7 +349,7 @@ bool StickerSetBox::Inner::installFail(const RPCError &error) {
void StickerSetBox::Inner::mousePressEvent(QMouseEvent *e) {
int index = stickerFromGlobalPos(e->globalPos());
if (index >= 0 && index < _pack.size()) {
_previewTimer.start(QApplication::startDragTime());
_previewTimer.callOnce(QApplication::startDragTime());
}
}
@ -300,10 +376,10 @@ void StickerSetBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
return;
}
if (_previewTimer.isActive()) {
_previewTimer.stop();
int index = stickerFromGlobalPos(e->globalPos());
_previewTimer.cancel();
const auto index = stickerFromGlobalPos(e->globalPos());
if (index >= 0 && index < _pack.size() && !isMasksSet()) {
if (auto main = App::main()) {
if (const auto main = App::main()) {
if (main->onSendSticker(_pack[index])) {
Ui::hideSettingsAndLayer();
}
@ -338,7 +414,7 @@ void StickerSetBox::Inner::startOverAnimation(int index, float64 from, float64 t
}
}
void StickerSetBox::Inner::onPreview() {
void StickerSetBox::Inner::showPreview() {
int index = stickerFromGlobalPos(QCursor::pos());
if (index >= 0 && index < _pack.size()) {
_previewShown = index;

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "chat_helpers/stickers.h"
class ConfirmBox;
@ -17,8 +18,6 @@ class PlainShadow;
} // namespace Ui
class StickerSetBox : public BoxContent, public RPCSender {
Q_OBJECT
public:
StickerSetBox(QWidget*, const MTPInputStickerSet &set);
@ -27,13 +26,11 @@ protected:
void resizeEvent(QResizeEvent *e) override;
private slots:
void onAddStickers();
void onShareStickers();
void onUpdateButtons();
private:
void updateTitleAndButtons();
void updateButtons();
void addStickers();
void shareStickers();
MTPInputStickerSet _set;
@ -41,77 +38,3 @@ private:
QPointer<Inner> _inner;
};
// This class is hold in header because it requires Qt preprocessing.
class StickerSetBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
Q_OBJECT
public:
Inner(QWidget *parent, const MTPInputStickerSet &set);
bool loaded() const;
bool notInstalled() const;
bool official() const;
Fn<TextWithEntities()> title() const;
QString shortName() const;
void install();
auto setInstalled() const {
return _setInstalled.events();
}
~Inner();
protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void leaveEventHook(QEvent *e) override;
private slots:
void onPreview();
signals:
void updateButtons();
private:
void updateSelected();
void setSelected(int selected);
void startOverAnimation(int index, float64 from, float64 to);
int stickerFromGlobalPos(const QPoint &p) const;
void gotSet(const MTPmessages_StickerSet &set);
bool failedSet(const RPCError &error);
void installDone(const MTPmessages_StickerSetInstallResult &result);
bool installFail(const RPCError &error);
bool isMasksSet() const {
return (_setFlags & MTPDstickerSet::Flag::f_masks);
}
std::vector<Animation> _packOvers;
Stickers::Pack _pack;
Stickers::ByEmojiMap _emoji;
bool _loaded = false;
uint64 _setId = 0;
uint64 _setAccess = 0;
QString _setTitle, _setShortName;
int _setCount = 0;
int32 _setHash = 0;
MTPDstickerSet::Flags _setFlags = 0;
TimeId _setInstallDate = TimeId(0);
MTPInputStickerSet _input;
mtpRequestId _installRequest = 0;
int _selected = -1;
QTimer _previewTimer;
int _previewShown = -1;
rpl::event_stream<uint64> _setInstalled;
};

View File

@ -18,6 +18,57 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace ChatHelpers {
class EmojiColorPicker : public Ui::RpWidget {
public:
EmojiColorPicker(QWidget *parent);
void showEmoji(EmojiPtr emoji);
void clearSelection();
void handleMouseMove(QPoint globalPos);
void handleMouseRelease(QPoint globalPos);
void setSingleSize(QSize size);
void showAnimated();
void hideAnimated();
void hideFast();
rpl::producer<EmojiPtr> chosen() const;
rpl::producer<> hidden() const;
protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
private:
void animationCallback();
void updateSize();
void drawVariant(Painter &p, int variant);
void updateSelected();
void setSelected(int newSelected);
bool _ignoreShow = false;
QVector<EmojiPtr> _variants;
int _selected = -1;
int _pressedSel = -1;
QPoint _lastMousePos;
QSize _singleSize;
bool _hiding = false;
QPixmap _cache;
Animation _a_opacity;
rpl::event_stream<EmojiPtr> _chosen;
rpl::event_stream<> _hidden;
};
class EmojiListWidget::Footer : public TabbedSelector::InnerFooter {
public:
Footer(not_null<EmojiListWidget*> parent);
@ -95,11 +146,9 @@ void EmojiListWidget::Footer::setActiveSection(Ui::Emoji::Section section) {
_pan->showEmojiSection(section);
}
EmojiColorPicker::EmojiColorPicker(QWidget *parent) : TWidget(parent) {
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
: RpWidget(parent) {
setMouseTracking(true);
_hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideAnimated()));
}
void EmojiColorPicker::showEmoji(EmojiPtr emoji) {
@ -167,16 +216,6 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
}
}
void EmojiColorPicker::enterEventHook(QEvent *e) {
_hideTimer.stop();
if (_hiding) showAnimated();
TWidget::enterEventHook(e);
}
void EmojiColorPicker::leaveEventHook(QEvent *e) {
TWidget::leaveEventHook(e);
}
void EmojiColorPicker::mousePressEvent(QMouseEvent *e) {
if (e->button() != Qt::LeftButton) {
return;
@ -197,7 +236,7 @@ void EmojiColorPicker::handleMouseRelease(QPoint globalPos) {
updateSelected();
if (_selected >= 0 && (pressed < 0 || _selected == pressed)) {
emit emojiSelected(_variants[_selected]);
_chosen.fire_copy(_variants[_selected]);
}
_ignoreShow = true;
hideAnimated();
@ -223,7 +262,7 @@ void EmojiColorPicker::animationCallback() {
_cache = QPixmap();
if (_hiding) {
hide();
emit hidden();
_hidden.fire({});
} else {
_lastMousePos = QCursor::pos();
updateSelected();
@ -236,7 +275,15 @@ void EmojiColorPicker::hideFast() {
_a_opacity.finish();
_cache = QPixmap();
hide();
emit hidden();
_hidden.fire({});
}
rpl::producer<EmojiPtr> EmojiColorPicker::chosen() const {
return _chosen.events();
}
rpl::producer<> EmojiColorPicker::hidden() const {
return _hidden.events();
}
void EmojiColorPicker::hideAnimated() {
@ -333,7 +380,8 @@ EmojiListWidget::EmojiListWidget(
QWidget *parent,
not_null<Window::Controller*> controller)
: Inner(parent, controller)
, _picker(this) {
, _picker(this)
, _showPickerTimer([=] { showPicker(); }) {
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
@ -345,10 +393,18 @@ EmojiListWidget::EmojiListWidget(
_counts[i] = Ui::Emoji::GetSectionCount(static_cast<Section>(i));
}
_showPickerTimer.setSingleShot(true);
connect(&_showPickerTimer, SIGNAL(timeout()), this, SLOT(onShowPicker()));
connect(_picker, SIGNAL(emojiSelected(EmojiPtr)), this, SLOT(onColorSelected(EmojiPtr)));
connect(_picker, SIGNAL(hidden()), this, SLOT(onPickerHidden()));
_picker->chosen(
) | rpl::start_with_next([=](EmojiPtr emoji) {
colorChosen(emoji);
}, lifetime());
_picker->hidden(
) | rpl::start_with_next([=] {
pickerHidden();
}, lifetime());
}
rpl::producer<EmojiPtr> EmojiListWidget::chosen() const {
return _chosen.events();
}
void EmojiListWidget::visibleTopBottomUpdated(
@ -529,9 +585,9 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
_pickerSel = _selected;
setCursor(style::cur_default);
if (!cEmojiVariants().contains(_emoji[section][sel]->nonColoredId())) {
onShowPicker();
showPicker();
} else {
_showPickerTimer.start(500);
_showPickerTimer.callOnce(500);
}
}
}
@ -559,7 +615,7 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
updateSelected();
if (_showPickerTimer.isActive()) {
_showPickerTimer.stop();
_showPickerTimer.cancel();
_pickerSel = -1;
_picker->hide();
}
@ -582,10 +638,10 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
void EmojiListWidget::selectEmoji(EmojiPtr emoji) {
Ui::Emoji::AddRecent(emoji);
emit selected(emoji);
_chosen.fire_copy(emoji);
}
void EmojiListWidget::onShowPicker() {
void EmojiListWidget::showPicker() {
if (_pickerSel < 0) return;
auto section = (_pickerSel / MatrixRowShift);
@ -607,7 +663,7 @@ void EmojiListWidget::onShowPicker() {
}
}
void EmojiListWidget::onPickerHidden() {
void EmojiListWidget::pickerHidden() {
_pickerSel = -1;
update();
emit disableScroll(false);
@ -627,7 +683,7 @@ QRect EmojiListWidget::emojiRect(int section, int sel) {
return QRect(x, y, _singleSize.width(), _singleSize.height());
}
void EmojiListWidget::onColorSelected(EmojiPtr emoji) {
void EmojiListWidget::colorChosen(EmojiPtr emoji) {
if (emoji->hasVariants()) {
cRefEmojiVariants().insert(
emoji->nonColoredId(),
@ -792,7 +848,7 @@ void EmojiListWidget::showEmojiSection(Section section) {
}
return true;
});
emit scrollToY(y);
scrollTo(y);
_lastMousePos = QCursor::pos();

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/tabbed_selector.h"
#include "ui/widgets/tooltip.h"
#include "base/timer.h"
namespace Ui {
namespace Emoji {
@ -24,66 +25,11 @@ namespace ChatHelpers {
constexpr auto kEmojiSectionCount = 8;
class EmojiColorPicker : public TWidget {
Q_OBJECT
public:
EmojiColorPicker(QWidget *parent);
void showEmoji(EmojiPtr emoji);
void clearSelection();
void handleMouseMove(QPoint globalPos);
void handleMouseRelease(QPoint globalPos);
void setSingleSize(QSize size);
void hideFast();
public slots:
void showAnimated();
void hideAnimated();
signals:
void emojiSelected(EmojiPtr emoji);
void hidden();
protected:
void paintEvent(QPaintEvent *e) override;
void enterEventHook(QEvent *e) override;
void leaveEventHook(QEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
private:
void animationCallback();
void updateSize();
void drawVariant(Painter &p, int variant);
void updateSelected();
void setSelected(int newSelected);
bool _ignoreShow = false;
QVector<EmojiPtr> _variants;
int _selected = -1;
int _pressedSel = -1;
QPoint _lastMousePos;
QSize _singleSize;
bool _hiding = false;
QPixmap _cache;
Animation _a_opacity;
QTimer _hideTimer;
};
class EmojiListWidget : public TabbedSelector::Inner, public Ui::AbstractTooltipShower {
Q_OBJECT
class EmojiColorPicker;
class EmojiListWidget
: public TabbedSelector::Inner
, public Ui::AbstractTooltipShower {
public:
EmojiListWidget(QWidget *parent, not_null<Window::Controller*> controller);
@ -100,16 +46,7 @@ public:
QString tooltipText() const override;
QPoint tooltipPos() const override;
public slots:
void onShowPicker();
void onPickerHidden();
void onColorSelected(EmojiPtr emoji);
bool checkPickerHide();
signals:
void selected(EmojiPtr emoji);
void switchToStickers();
rpl::producer<EmojiPtr> chosen() const;
protected:
void visibleTopBottomUpdated(
@ -146,8 +83,12 @@ private:
SectionInfo sectionInfo(int section) const;
SectionInfo sectionInfoByOffset(int yOffset) const;
void showPicker();
void pickerHidden();
void colorChosen(EmojiPtr emoji);
bool checkPickerHide();
void ensureLoaded(int section);
int countSectionTop(int section) const;
void updateSelected();
void setSelected(int newSelected);
@ -171,7 +112,9 @@ private:
QPoint _lastMousePos;
object_ptr<EmojiColorPicker> _picker;
QTimer _showPickerTimer;
base::Timer _showPickerTimer;
rpl::event_stream<EmojiPtr> _chosen;
};

View File

@ -513,15 +513,7 @@ FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, Mentio
, _hrows(hrows)
, _brows(brows)
, _srows(srows)
, _stickersPerRow(1)
, _recentInlineBotsInRows(0)
, _sel(-1)
, _down(-1)
, _mouseSel(false)
, _overDelete(false)
, _previewShown(false) {
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
, _previewTimer([=] { showPreview(); }) {
subscribe(Auth().downloaderTaskFinished(), [this] { update(); });
}
@ -806,13 +798,13 @@ void FieldAutocompleteInner::mousePressEvent(QMouseEvent *e) {
chooseSelected(FieldAutocomplete::ChooseMethod::ByClick);
} else {
_down = _sel;
_previewTimer.start(QApplication::startDragTime());
_previewTimer.callOnce(QApplication::startDragTime());
}
}
}
void FieldAutocompleteInner::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.stop();
_previewTimer.cancel();
int32 pressed = _down;
_down = -1;
@ -915,7 +907,7 @@ void FieldAutocompleteInner::onParentGeometryChanged() {
}
}
void FieldAutocompleteInner::onPreview() {
void FieldAutocompleteInner::showPreview() {
if (_down >= 0 && _down < _srows->size()) {
Ui::showMediaPreview(
(*_srows)[_down]->stickerSetOrigin(),

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "ui/twidget.h"
#include "base/timer.h"
#include "chat_helpers/stickers.h"
namespace Ui {
@ -152,7 +153,6 @@ signals:
public slots:
void onParentGeometryChanged();
void onUpdateSelected(bool force = false);
void onPreview();
private:
void paintEvent(QPaintEvent *e) override;
@ -167,22 +167,25 @@ private:
void updateSelectedRow();
void setSel(int sel, bool scroll = false);
void showPreview();
FieldAutocomplete *_parent;
MentionRows *_mrows;
HashtagRows *_hrows;
BotCommandRows *_brows;
StickerRows *_srows;
int32 _stickersPerRow, _recentInlineBotsInRows;
int32 _sel, _down;
bool _mouseSel;
FieldAutocomplete *_parent = nullptr;
MentionRows *_mrows = nullptr;
HashtagRows *_hrows = nullptr;
BotCommandRows *_brows = nullptr;
StickerRows *_srows = nullptr;
int _stickersPerRow = 1;
int _recentInlineBotsInRows = 0;
int _sel = -1;
int _down = -1;
bool _mouseSel = false;
QPoint _mousePos;
bool _overDelete;
bool _overDelete = false;
bool _previewShown;
bool _previewShown = false;
QTimer _previewTimer;
base::Timer _previewTimer;
};

View File

@ -69,7 +69,7 @@ GifsListWidget::Footer::Footer(not_null<GifsListWidget*> parent) : InnerFooter(p
});
connect(_field, &Ui::InputField::cancelled, [=] {
if (_field->getLastText().isEmpty()) {
emit _pan->cancelled();
_pan->cancelled();
} else {
_field->setText(QString());
}
@ -125,16 +125,12 @@ GifsListWidget::GifsListWidget(
QWidget *parent,
not_null<Window::Controller*> controller)
: Inner(parent, controller)
, _section(Section::Gifs) {
, _section(Section::Gifs)
, _updateInlineItems([=] { updateInlineItems(); })
, _previewTimer([=] { showPreview(); }) {
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
_updateInlineItems.setSingleShot(true);
connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems()));
_inlineRequestTimer.setSingleShot(true);
connect(&_inlineRequestTimer, &QTimer::timeout, this, [this] { sendInlineRequest(); });
@ -152,8 +148,22 @@ GifsListWidget::GifsListWidget(
});
}
rpl::producer<not_null<DocumentData*>> GifsListWidget::fileChosen() const {
return _fileChosen.events();
}
rpl::producer<not_null<PhotoData*>> GifsListWidget::photoChosen() const {
return _photoChosen.events();
}
auto GifsListWidget::inlineResultChosen() const
-> rpl::producer<InlineChosen> {
return _inlineResultChosen.events();
}
object_ptr<TabbedSelector::InnerFooter> GifsListWidget::createFooter() {
Expects(_footer == nullptr);
auto result = object_ptr<Footer>(this);
_footer = result;
return std::move(result);
@ -305,11 +315,11 @@ void GifsListWidget::mousePressEvent(QMouseEvent *e) {
_pressed = _selected;
ClickHandler::pressed();
_previewTimer.start(QApplication::startDragTime());
_previewTimer.callOnce(QApplication::startDragTime());
}
void GifsListWidget::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.stop();
_previewTimer.cancel();
auto pressed = std::exchange(_pressed, -1);
auto activated = ClickHandler::unpressed();
@ -340,29 +350,28 @@ void GifsListWidget::selectInlineResult(int row, int column) {
}
auto item = _rows[row].items[column];
if (auto photo = item->getPhoto()) {
if (const auto photo = item->getPhoto()) {
if (photo->medium->loaded() || photo->thumb->loaded()) {
emit selected(photo);
_photoChosen.fire_copy(photo);
} else if (!photo->medium->loading()) {
photo->thumb->loadEvenCancelled(Data::FileOrigin());
photo->medium->loadEvenCancelled(Data::FileOrigin());
}
} else if (const auto document = item->getDocument()) {
if (document->loaded()) {
emit selected(document);
_fileChosen.fire_copy(document);
} else if (document->loading()) {
document->cancel();
} else {
DocumentOpenClickHandler::Open(
document->stickerOrGifOrigin(),
document,
nullptr,
ActionOnLoadNone);
}
} else if (auto inlineResult = item->getResult()) {
} else if (const auto inlineResult = item->getResult()) {
if (inlineResult->onChoose(item)) {
emit selected(inlineResult, _searchBot);
_inlineResultChosen.fire({ inlineResult, _searchBot });
}
}
}
@ -622,8 +631,7 @@ void GifsListWidget::switchToSavedGifs() {
clearInlineRows(false);
_section = Section::Gifs;
refreshSavedGifs();
emit scrollToY(0);
emit scrollUpdated();
scrollTo(0);
}
int GifsListWidget::refreshInlineRows(const InlineCacheEntry *entry, bool resultsDeleted) {
@ -747,7 +755,7 @@ void GifsListWidget::inlineItemRepaint(const InlineBots::Layout::ItemBase *layou
if (_lastScrolled + 100 <= ms) {
update();
} else {
_updateInlineItems.start(_lastScrolled + 100 - ms);
_updateInlineItems.callOnce(_lastScrolled + 100 - ms);
}
}
@ -804,7 +812,7 @@ int32 GifsListWidget::showInlineRows(bool newResults) {
auto added = 0;
auto clear = !refreshInlineRows(&added);
if (newResults) {
scrollToY(0);
scrollTo(0);
}
return added;
}
@ -847,6 +855,14 @@ void GifsListWidget::searchForGifs(const QString &query) {
}
}
void GifsListWidget::cancelled() {
_cancelled.fire({});
}
rpl::producer<> GifsListWidget::cancelRequests() const {
return _cancelled.events();
}
void GifsListWidget::sendInlineRequest() {
if (_inlineRequestId || !_inlineQueryPeer || _inlineNextQuery.isEmpty()) {
return;
@ -977,8 +993,10 @@ void GifsListWidget::updateSelected() {
}
}
void GifsListWidget::onPreview() {
if (_pressed < 0) return;
void GifsListWidget::showPreview() {
if (_pressed < 0) {
return;
}
int row = _pressed / MatrixRowShift, col = _pressed % MatrixRowShift;
if (row < _rows.size() && col < _rows[row].items.size()) {
auto layout = _rows[row].items[col];
@ -996,12 +1014,12 @@ void GifsListWidget::onPreview() {
}
}
void GifsListWidget::onUpdateInlineItems() {
void GifsListWidget::updateInlineItems() {
auto ms = getms();
if (_lastScrolled + 100 <= ms) {
update();
} else {
_updateInlineItems.start(_lastScrolled + 100 - ms);
_updateInlineItems.callOnce(_lastScrolled + 100 - ms);
}
}

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "chat_helpers/tabbed_selector.h"
#include "base/timer.h"
#include "inline_bots/inline_bot_layout_item.h"
namespace InlineBots {
@ -32,11 +33,15 @@ class GifsListWidget
, public InlineBots::Layout::Context
, private base::Subscriber
, private MTP::Sender {
Q_OBJECT
public:
using InlineChosen = TabbedSelector::InlineChosen;
GifsListWidget(QWidget *parent, not_null<Window::Controller*> controller);
rpl::producer<not_null<DocumentData*>> fileChosen() const;
rpl::producer<not_null<PhotoData*>> photoChosen() const;
rpl::producer<InlineChosen> inlineResultChosen() const;
void refreshRecent() override;
void preloadImages() override;
void clearSelection() override;
@ -56,6 +61,9 @@ public:
void searchForGifs(const QString &query);
void sendInlineRequest();
void cancelled();
rpl::producer<> cancelRequests() const;
~GifsListWidget();
protected:
@ -76,21 +84,6 @@ protected:
void processPanelHideFinished() override;
int countDesiredHeight(int newWidth) override;
private slots:
void onPreview();
void onUpdateInlineItems();
signals:
void selected(not_null<DocumentData*> sticker);
void selected(not_null<PhotoData*> photo);
void selected(
not_null<InlineBots::Result*> result,
not_null<UserData*> bot);
void cancelled();
void emptyInlineRows();
void scrollUpdated();
private:
enum class Section {
Inlines,
@ -120,9 +113,12 @@ private:
void updateSelected();
void paintInlineItems(Painter &p, QRect clip);
void updateInlineItems();
void showPreview();
Section _section = Section::Gifs;
TimeMs _lastScrolled = 0;
QTimer _updateInlineItems;
base::Timer _updateInlineItems;
bool _inlineWithThumb = false;
struct Row {
@ -156,7 +152,7 @@ private:
int _pressed = -1;
QPoint _lastMousePos;
QTimer _previewTimer;
base::Timer _previewTimer;
bool _previewShown = false;
std::map<QString, std::unique_ptr<InlineCacheEntry>> _inlineCache;
@ -168,6 +164,11 @@ private:
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
mtpRequestId _inlineRequestId = 0;
rpl::event_stream<not_null<DocumentData*>> _fileChosen;
rpl::event_stream<not_null<PhotoData*>> _photoChosen;
rpl::event_stream<InlineChosen> _inlineResultChosen;
rpl::event_stream<> _cancelled;
};
} // namespace ChatHelpers

View File

@ -682,14 +682,14 @@ StickersListWidget::StickersListWidget(QWidget *parent, not_null<Window::Control
, _addText(lang(lng_stickers_featured_add).toUpper())
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
, _settings(this, lang(lng_stickers_you_have))
, _previewTimer([=] { showPreview(); })
, _searchRequestTimer([=] { sendSearchRequest(); }) {
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
connect(_settings, SIGNAL(clicked()), this, SLOT(onSettings()));
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
_settings->addClickHandler([] {
Ui::show(Box<StickersBox>(StickersBox::Section::Installed));
});
subscribe(Auth().downloaderTaskFinished(), [=] {
if (isVisible()) {
@ -704,8 +704,21 @@ StickersListWidget::StickersListWidget(QWidget *parent, not_null<Window::Control
}));
}
rpl::producer<not_null<DocumentData*>> StickersListWidget::chosen() const {
return _chosen.events();
}
rpl::producer<> StickersListWidget::scrollUpdated() const {
return _scrollUpdated.events();
}
rpl::producer<> StickersListWidget::checkForHide() const {
return _checkForHide.events();
}
object_ptr<TabbedSelector::InnerFooter> StickersListWidget::createFooter() {
Expects(_footer == nullptr);
auto result = object_ptr<Footer>(this);
_footer = result;
return std::move(result);
@ -927,7 +940,7 @@ void StickersListWidget::cancelSetsSearch() {
void StickersListWidget::showSearchResults() {
refreshSearchRows();
scrollToY(0);
scrollTo(0);
}
void StickersListWidget::refreshSearchRows() {
@ -1418,7 +1431,7 @@ void StickersListWidget::mousePressEvent(QMouseEvent *e) {
setPressed(_selected);
ClickHandler::pressed();
_previewTimer.start(QApplication::startDragTime());
_previewTimer.callOnce(QApplication::startDragTime());
}
void StickersListWidget::setPressed(OverState newPressed) {
@ -1498,7 +1511,7 @@ QPoint StickersListWidget::buttonRippleTopLeft(int section) const {
}
void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.stop();
_previewTimer.cancel();
auto pressed = _pressed;
setPressed(std::nullopt);
@ -1531,7 +1544,7 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
}
return;
}
emit selected(set.pack[sticker->index]);
_chosen.fire_copy(set.pack[sticker->index]);
} else if (auto set = base::get_if<OverSet>(&pressed)) {
Assert(set->section >= 0 && set->section < sets.size());
displaySet(sets[set->section].id);
@ -2170,15 +2183,11 @@ void StickersListWidget::setSelected(OverState newSelected) {
}
}
void StickersListWidget::onSettings() {
Ui::show(Box<StickersBox>(StickersBox::Section::Installed));
}
void StickersListWidget::onPreview() {
if (auto sticker = base::get_if<OverSticker>(&_pressed)) {
auto &sets = shownSets();
void StickersListWidget::showPreview() {
if (const auto sticker = base::get_if<OverSticker>(&_pressed)) {
const auto &sets = shownSets();
Assert(sticker->section >= 0 && sticker->section < sets.size());
auto &set = sets[sticker->section];
const auto &set = sets[sticker->section];
Assert(sticker->index >= 0 && sticker->index < set.pack.size());
Ui::showMediaPreview(
set.pack[sticker->index]->stickerSetOrigin(),
@ -2202,8 +2211,8 @@ void StickersListWidget::showStickerSet(uint64 setId) {
update();
}
emit scrollToY(0);
emit scrollUpdated();
scrollTo(0);
_scrollUpdated.fire({});
return;
}
@ -2222,8 +2231,8 @@ void StickersListWidget::showStickerSet(uint64 setId) {
}
return true;
});
emit scrollToY(y);
emit scrollUpdated();
scrollTo(y);
_scrollUpdated.fire({});
if (needRefresh && _footer) {
_footer->refreshIcons(ValidateIconAnimations::Scroll);
@ -2281,7 +2290,7 @@ void StickersListWidget::displaySet(uint64 setId) {
auto box = Ui::show(Box<StickersBox>(_megagroupSet));
connect(box, &QObject::destroyed, this, [this] {
_displayingSetId = 0;
emit checkForHide();
_checkForHide.fire({});
});
return;
} else if (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) {
@ -2299,7 +2308,7 @@ void StickersListWidget::displaySet(uint64 setId) {
LayerOption::KeepOther);
connect(box, &QObject::destroyed, this, [this] {
_displayingSetId = 0;
emit checkForHide();
_checkForHide.fire({});
});
}
}
@ -2357,10 +2366,10 @@ void StickersListWidget::removeMegagroupSet(bool locally) {
}
Ui::hideLayer();
_removingSetId = 0;
emit checkForHide();
_checkForHide.fire({});
}), crl::guard(this, [this] {
_removingSetId = 0;
emit checkForHide();
_checkForHide.fire({});
})));
}
@ -2370,7 +2379,7 @@ void StickersListWidget::removeSet(uint64 setId) {
if (it != sets.cend()) {
_removingSetId = it->id;
auto text = lng_stickers_remove_pack(lt_sticker_pack, it->title);
Ui::show(Box<ConfirmBox>(text, lang(lng_stickers_remove_pack_confirm), crl::guard(this, [this] {
Ui::show(Box<ConfirmBox>(text, lang(lng_stickers_remove_pack_confirm), crl::guard(this, [=] {
Ui::hideLayer();
auto &sets = Auth().data().stickerSetsRef();
auto it = sets.find(_removingSetId);
@ -2406,10 +2415,10 @@ void StickersListWidget::removeSet(uint64 setId) {
if (writeRecent) Local::writeUserSettings();
}
_removingSetId = 0;
emit checkForHide();
}), crl::guard(this, [this] {
_checkForHide.fire({});
}), crl::guard(this, [=] {
_removingSetId = 0;
emit checkForHide();
_checkForHide.fire({});
})));
}
}

View File

@ -29,13 +29,15 @@ class StickersListWidget
: public TabbedSelector::Inner
, private base::Subscriber
, private MTP::Sender {
Q_OBJECT
public:
StickersListWidget(
QWidget *parent,
not_null<Window::Controller*> controller);
rpl::producer<not_null<DocumentData*>> chosen() const;
rpl::producer<> scrollUpdated() const;
rpl::producer<> checkForHide() const;
void refreshRecent() override;
void preloadImages() override;
void clearSelection() override;
@ -82,15 +84,6 @@ protected:
void processPanelHideFinished() override;
int countDesiredHeight(int newWidth) override;
private slots:
void onSettings();
void onPreview();
signals:
void selected(not_null<DocumentData*> sticker);
void scrollUpdated();
void checkForHide();
private:
class Footer;
@ -248,6 +241,8 @@ private:
void fillCloudSearchRows(const std::vector<uint64> &cloudSets);
void addSearchRow(not_null<const Stickers::Set*> set);
void showPreview();
ChannelData *_megagroupSet = nullptr;
std::vector<Set> _mySets;
std::vector<Set> _featuredSets;
@ -281,7 +276,7 @@ private:
object_ptr<Ui::LinkButton> _settings;
QTimer _previewTimer;
base::Timer _previewTimer;
bool _previewShown = false;
std::map<QString, std::vector<uint64>> _searchCache;
@ -290,6 +285,10 @@ private:
QString _searchQuery, _searchNextQuery;
mtpRequestId _searchRequestId = 0;
rpl::event_stream<not_null<DocumentData*>> _chosen;
rpl::event_stream<> _scrollUpdated;
rpl::event_stream<> _checkForHide;
};
} // namespace ChatHelpers

View File

@ -66,24 +66,31 @@ TabbedPanel::TabbedPanel(
_hideTimer.setCallback([this] { hideByTimerOrLeave(); });
connect(_selector, &TabbedSelector::checkForHide, this, [this] {
_selector->checkForHide(
) | rpl::start_with_next([=] {
if (!rect().contains(mapFromGlobal(QCursor::pos()))) {
_hideTimer.callOnce(kDelayedHideTimeoutMs);
}
});
connect(_selector, &TabbedSelector::cancelled, this, [this] {
}, lifetime());
_selector->cancelled(
) | rpl::start_with_next([=] {
hideAnimated();
});
connect(_selector, &TabbedSelector::slideFinished, this, [this] {
InvokeQueued(this, [this] {
}, lifetime());
_selector->slideFinished(
) | rpl::start_with_next([=] {
InvokeQueued(this, [=] {
if (_hideAfterSlide) {
startOpacityAnimation(true);
}
});
});
}, lifetime());
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
connect(App::wnd()->windowHandle(), &QWindow::activeChanged, this, [=] {
windowActiveChanged();
});
}
setAttribute(Qt::WA_OpaquePaintEvent, false);
@ -122,7 +129,7 @@ void TabbedPanel::updateContentHeight() {
update();
}
void TabbedPanel::onWndActiveChanged() {
void TabbedPanel::windowActiveChanged() {
if (!App::wnd()->windowHandle()->isActive() && !isHidden() && !preventAutoHide()) {
hideAnimated();
}

View File

@ -22,9 +22,7 @@ namespace ChatHelpers {
class TabbedSelector;
class TabbedPanel : public Ui::RpWidget{
Q_OBJECT
class TabbedPanel : public Ui::RpWidget {
public:
TabbedPanel(QWidget *parent, not_null<Window::Controller*> controller);
TabbedPanel(QWidget *parent, not_null<Window::Controller*> controller, object_ptr<TabbedSelector> selector);
@ -55,9 +53,6 @@ protected:
void paintEvent(QPaintEvent *e) override;
bool eventFilter(QObject *obj, QEvent *e) override;
private slots:
void onWndActiveChanged();
private:
void hideByTimerOrLeave();
void moveByBottom();
@ -65,6 +60,7 @@ private:
return !_selector;
}
void showFromSelector();
void windowActiveChanged();
style::margins innerPadding() const;

View File

@ -62,13 +62,8 @@ TabbedSection::TabbedSection(
_selector->setGeometry(rect());
_selector->showStarted();
_selector->show();
connect(_selector, &TabbedSelector::cancelled, this, [this] {
if (_cancelledCallback) {
_cancelledCallback();
}
});
_selector->setAfterShownCallback(Fn<void(SelectorTab)>());
_selector->setBeforeHidingCallback(Fn<void(SelectorTab)>());
_selector->setAfterShownCallback(nullptr);
_selector->setBeforeHidingCallback(nullptr);
setAttribute(Qt::WA_OpaquePaintEvent, true);
}

View File

@ -49,9 +49,6 @@ public:
void beforeHiding();
void afterShown();
void setCancelledCallback(Fn<void()> callback) {
_cancelledCallback = std::move(callback);
}
object_ptr<TabbedSelector> takeSelector();
QPointer<TabbedSelector> getSelector() const;
@ -77,7 +74,6 @@ protected:
private:
object_ptr<TabbedSelector> _selector;
Fn<void()> _cancelledCallback;
Fn<void(object_ptr<TabbedSelector>)> _returnMethod;
};

View File

@ -261,6 +261,7 @@ object_ptr<TabbedSelector::Inner> TabbedSelector::Tab::takeWidget() {
void TabbedSelector::Tab::returnWidget(object_ptr<Inner> widget) {
_widget = std::move(widget);
Ensures(_widget == _weak);
}
@ -293,29 +294,30 @@ TabbedSelector::TabbedSelector(QWidget *parent, not_null<Window::Controller*> co
for (auto &tab : _tabs) {
auto widget = tab.widget();
connect(widget, &Inner::scrollToY, this, [this, tab = &tab](int y) {
widget->scrollToRequests(
) | rpl::start_with_next([=, tab = &tab](int y) {
if (tab == currentTab()) {
scrollToY(y);
} else {
tab->saveScrollTop(y);
}
});
connect(widget, &Inner::disableScroll, this, [this, tab = &tab](bool disabled) {
}, widget->lifetime());
widget->disableScrollRequests(
) | rpl::start_with_next([=, tab = &tab](bool disabled) {
if (tab == currentTab()) {
_scroll->disableScroll(disabled);
}
});
}, widget->lifetime());
}
connect(stickers(), SIGNAL(scrollUpdated()), this, SLOT(onScroll()));
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(emoji(), SIGNAL(selected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr)));
connect(stickers(), SIGNAL(selected(not_null<DocumentData*>)), this, SIGNAL(stickerOrGifSelected(not_null<DocumentData*>)));
connect(stickers(), SIGNAL(checkForHide()), this, SIGNAL(checkForHide()));
connect(gifs(), SIGNAL(selected(not_null<DocumentData*>)), this, SIGNAL(stickerOrGifSelected(not_null<DocumentData*>)));
connect(gifs(), SIGNAL(selected(not_null<PhotoData*>)), this, SIGNAL(photoSelected(not_null<PhotoData*>)));
connect(gifs(), SIGNAL(selected(not_null<InlineBots::Result*>,not_null<UserData*>)), this, SIGNAL(inlineResultSelected(not_null<InlineBots::Result*>,not_null<UserData*>)));
connect(gifs(), SIGNAL(cancelled()), this, SIGNAL(cancelled()));
rpl::merge(
stickers()->scrollUpdated() | rpl::map([] { return 0; }),
_scroll->scrollTopChanges()
) | rpl::start_with_next([=] {
handleScroll();
}, lifetime());
_topShadow->raise();
_bottomShadow->raise();
@ -340,6 +342,35 @@ TabbedSelector::TabbedSelector(QWidget *parent, not_null<Window::Controller*> co
showAll();
}
rpl::producer<EmojiPtr> TabbedSelector::emojiChosen() const {
return emoji()->chosen();
}
rpl::producer<not_null<DocumentData*>> TabbedSelector::fileChosen() const {
return rpl::merge(stickers()->chosen(), gifs()->fileChosen());
}
rpl::producer<not_null<PhotoData*>> TabbedSelector::photoChosen() const {
return gifs()->photoChosen();
}
auto TabbedSelector::inlineResultChosen() const
-> rpl::producer<InlineChosen> {
return gifs()->inlineResultChosen();
}
rpl::producer<> TabbedSelector::cancelled() const {
return gifs()->cancelRequests();
}
rpl::producer<> TabbedSelector::checkForHide() const {
return stickers()->checkForHide();
}
rpl::producer<> TabbedSelector::slideFinished() const {
return _slideFinished.events();
}
void TabbedSelector::resizeEvent(QResizeEvent *e) {
_tabsSlider->resizeToWidth(width());
_tabsSlider->moveToLeft(0, 0);
@ -408,7 +439,7 @@ void TabbedSelector::paintEvent(QPaintEvent *e) {
if (!_a_slide.animating()) {
_slideAnimation.reset();
afterShown();
emit slideFinished();
_slideFinished.fire({});
}
} else {
paintContent(p);
@ -607,7 +638,7 @@ void TabbedSelector::hideForSliding() {
currentTab()->widget()->clearSelection();
}
void TabbedSelector::onScroll() {
void TabbedSelector::handleScroll() {
auto scrollTop = _scroll->scrollTop();
auto scrollBottom = scrollTop + _scroll->height();
currentTab()->widget()->setVisibleTopBottom(scrollTop, scrollBottom);
@ -712,7 +743,7 @@ void TabbedSelector::setWidgetToScrollArea() {
_scroll->disableScroll(false);
scrollToY(currentTab()->getScrollTop());
onScroll();
handleScroll();
}
void TabbedSelector::scrollToY(int y) {
@ -729,6 +760,22 @@ TabbedSelector::Inner::Inner(
, _controller(controller) {
}
rpl::producer<int> TabbedSelector::Inner::scrollToRequests() const {
return _scrollToRequests.events();
}
rpl::producer<bool> TabbedSelector::Inner::disableScrollRequests() const {
return _disableScrollRequests.events();
}
void TabbedSelector::Inner::scrollTo(int y) {
_scrollToRequests.fire_copy(y);
}
void TabbedSelector::Inner::disableScroll(bool disabled) {
_disableScrollRequests.fire_copy(disabled);
}
void TabbedSelector::Inner::visibleTopBottomUpdated(int visibleTop, int visibleBottom) {
_visibleTop = visibleTop;
_visibleBottom = visibleBottom;

View File

@ -40,11 +40,23 @@ class StickersListWidget;
class GifsListWidget;
class TabbedSelector : public Ui::RpWidget, private base::Subscriber {
Q_OBJECT
public:
struct InlineChosen {
not_null<InlineBots::Result*> result;
not_null<UserData*> bot;
};
TabbedSelector(QWidget *parent, not_null<Window::Controller*> controller);
rpl::producer<EmojiPtr> emojiChosen() const;
rpl::producer<not_null<DocumentData*>> fileChosen() const;
rpl::producer<not_null<PhotoData*>> photoChosen() const;
rpl::producer<InlineChosen> inlineResultChosen() const;
rpl::producer<> cancelled() const;
rpl::producer<> checkForHide() const;
rpl::producer<> slideFinished() const;
void setRoundRadius(int radius);
void refreshStickers();
void showMegagroupSet(ChannelData *megagroup);
@ -87,21 +99,6 @@ protected:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
private slots:
void onScroll();
signals:
void emojiSelected(EmojiPtr emoji);
void stickerOrGifSelected(not_null<DocumentData*> sticker);
void photoSelected(not_null<PhotoData*> photo);
void inlineResultSelected(
not_null<InlineBots::Result*> result,
not_null<UserData*> bot);
void cancelled();
void slideFinished();
void checkForHide();
private:
class Tab {
public:
@ -145,6 +142,7 @@ private:
void checkRestrictedPeer();
bool isRestrictedView();
void updateRestrictedLabelGeometry();
void handleScroll();
QImage grabForAnimation();
@ -193,12 +191,11 @@ private:
Fn<void(SelectorTab)> _beforeHidingCallback;
rpl::event_stream<> _showRequests;
rpl::event_stream<> _slideFinished;
};
class TabbedSelector::Inner : public Ui::RpWidget {
Q_OBJECT
public:
Inner(QWidget *parent, not_null<Window::Controller*> controller);
@ -222,11 +219,10 @@ public:
virtual void beforeHiding() {
}
virtual object_ptr<InnerFooter> createFooter() = 0;
rpl::producer<int> scrollToRequests() const;
rpl::producer<bool> disableScrollRequests() const;
signals:
void scrollToY(int y);
void disableScroll(bool disabled);
virtual object_ptr<InnerFooter> createFooter() = 0;
protected:
void visibleTopBottomUpdated(
@ -246,6 +242,9 @@ protected:
virtual void processPanelHideFinished() {
}
void scrollTo(int y);
void disableScroll(bool disabled);
private:
not_null<Window::Controller*> _controller;
@ -253,6 +252,9 @@ private:
int _visibleBottom = 0;
int _minimalHeight = 0;
rpl::event_stream<int> _scrollToRequests;
rpl::event_stream<bool> _disableScrollRequests;
};
class TabbedSelector::InnerFooter : public TWidget {

View File

@ -477,14 +477,9 @@ HistoryWidget::HistoryWidget(
connect(_field, SIGNAL(changed()), this, SLOT(onTextChange()));
connect(App::wnd()->windowHandle(), SIGNAL(visibleChanged(bool)), this, SLOT(onWindowVisibleChanged()));
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
connect(
_tabbedSelector,
&TabbedSelector::emojiSelected,
_field,
[=](EmojiPtr emoji) { InsertEmojiToField(_field, emoji); });
connect(_tabbedSelector, SIGNAL(stickerOrGifSelected(not_null<DocumentData*>)), this, SLOT(onStickerOrGifSend(not_null<DocumentData*>)));
connect(_tabbedSelector, SIGNAL(photoSelected(not_null<PhotoData*>)), this, SLOT(onPhotoSend(not_null<PhotoData*>)));
connect(_tabbedSelector, SIGNAL(inlineResultSelected(not_null<InlineBots::Result*>,not_null<UserData*>)), this, SLOT(onInlineResultSend(not_null<InlineBots::Result*>,not_null<UserData*>)));
initTabbedSelector();
connect(Media::Capture::instance(), SIGNAL(error()), this, SLOT(onRecordError()));
connect(Media::Capture::instance(), SIGNAL(updated(quint16,qint32)), this, SLOT(onRecordUpdate(quint16,qint32)));
connect(Media::Capture::instance(), SIGNAL(done(QByteArray,VoiceWaveform,qint32)), this, SLOT(onRecordDone(QByteArray,VoiceWaveform,qint32)));
@ -532,7 +527,9 @@ HistoryWidget::HistoryWidget(
connect(_fieldAutocomplete, SIGNAL(mentionChosen(UserData*,FieldAutocomplete::ChooseMethod)), this, SLOT(onMentionInsert(UserData*)));
connect(_fieldAutocomplete, SIGNAL(hashtagChosen(QString,FieldAutocomplete::ChooseMethod)), this, SLOT(onHashtagOrBotCommandInsert(QString,FieldAutocomplete::ChooseMethod)));
connect(_fieldAutocomplete, SIGNAL(botCommandChosen(QString,FieldAutocomplete::ChooseMethod)), this, SLOT(onHashtagOrBotCommandInsert(QString,FieldAutocomplete::ChooseMethod)));
connect(_fieldAutocomplete, SIGNAL(stickerChosen(not_null<DocumentData*>,FieldAutocomplete::ChooseMethod)), this, SLOT(onStickerOrGifSend(not_null<DocumentData*>)));
connect(_fieldAutocomplete, &FieldAutocomplete::stickerChosen, this, [=](not_null<DocumentData*> document) {
sendExistingDocument(document);
});
connect(_fieldAutocomplete, SIGNAL(moderateKeyActivate(int,bool*)), this, SLOT(onModerateKeyActivate(int,bool*)));
if (_supportAutocomplete) {
supportInitAutocomplete();
@ -779,6 +776,28 @@ HistoryWidget::HistoryWidget(
setupShortcuts();
}
void HistoryWidget::initTabbedSelector() {
_tabbedSelector->emojiChosen(
) | rpl::start_with_next([=](EmojiPtr emoji) {
InsertEmojiToField(_field, emoji);
}, lifetime());
_tabbedSelector->fileChosen(
) | rpl::start_with_next([=](not_null<DocumentData*> document) {
sendExistingDocument(document);
}, lifetime());
_tabbedSelector->photoChosen(
) | rpl::start_with_next([=](not_null<PhotoData*> photo) {
sendExistingPhoto(photo);
}, lifetime());
_tabbedSelector->inlineResultChosen(
) | rpl::start_with_next([=](TabbedSelector::InlineChosen data) {
sendInlineResult(data.result, data.bot);
}, lifetime());
}
void HistoryWidget::supportInitAutocomplete() {
_supportAutocomplete->hide();
@ -1148,8 +1167,10 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
}
if (!_inlineResults) {
_inlineResults.create(this, controller());
_inlineResults->setResultSelectedCallback([this](InlineBots::Result *result, UserData *bot) {
onInlineResultSend(result, bot);
_inlineResults->setResultSelectedCallback([=](
InlineBots::Result *result,
UserData *bot) {
sendInlineResult(result, bot);
});
updateControlsGeometry();
orderWidgets();
@ -5488,34 +5509,7 @@ void HistoryWidget::onFieldTabbed() {
}
}
bool HistoryWidget::onStickerOrGifSend(not_null<DocumentData*> document) {
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restricted(ChannelRestriction::f_send_stickers)) {
Ui::show(
Box<InformBox>(lang(lng_restricted_send_stickers)),
LayerOption::KeepOther);
return false;
}
}
return sendExistingDocument(
document,
document->stickerOrGifOrigin(),
TextWithEntities());
}
void HistoryWidget::onPhotoSend(not_null<PhotoData*> photo) {
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restricted(ChannelRestriction::f_send_media)) {
Ui::show(
Box<InformBox>(lang(lng_restricted_send_media)),
LayerOption::KeepOther);
return;
}
}
sendExistingPhoto(photo, TextWithEntities());
}
void HistoryWidget::onInlineResultSend(
void HistoryWidget::sendInlineResult(
not_null<InlineBots::Result*> result,
not_null<UserData*> bot) {
if (!_peer || !_peer->canWrite()) {
@ -5662,12 +5656,20 @@ void HistoryWidget::destroyPinnedBar() {
bool HistoryWidget::sendExistingDocument(
not_null<DocumentData*> document,
Data::FileOrigin origin,
TextWithEntities caption) {
if (!_peer || !_peer->canWrite()) {
if (const auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restricted(ChannelRestriction::f_send_stickers)) {
Ui::show(
Box<InformBox>(lang(lng_restricted_send_stickers)),
LayerOption::KeepOther);
return false;
}
} else if (!_peer || !_peer->canWrite()) {
return false;
}
const auto origin = document->stickerOrGifOrigin();
auto options = ApiWrap::SendOptions(_history);
options.clearDraft = false;
options.replyTo = replyToId();
@ -5688,11 +5690,18 @@ bool HistoryWidget::sendExistingDocument(
return true;
}
void HistoryWidget::sendExistingPhoto(
bool HistoryWidget::sendExistingPhoto(
not_null<PhotoData*> photo,
TextWithEntities caption) {
if (!_peer || !_peer->canWrite()) {
return;
if (const auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restricted(ChannelRestriction::f_send_media)) {
Ui::show(
Box<InformBox>(lang(lng_restricted_send_media)),
LayerOption::KeepOther);
return false;
}
} else if (!_peer || !_peer->canWrite()) {
return false;
}
auto options = ApiWrap::SendOptions(_history);
@ -5774,6 +5783,8 @@ void HistoryWidget::sendExistingPhoto(
hideSelectorControlsAnimated();
_field->setFocus();
return true;
}
void HistoryWidget::setFieldText(

View File

@ -331,6 +331,13 @@ public:
void confirmDeleteSelected();
void clearSelected();
bool sendExistingDocument(
not_null<DocumentData*> document,
TextWithEntities caption = TextWithEntities());
bool sendExistingPhoto(
not_null<PhotoData*> photo,
TextWithEntities caption = TextWithEntities());
// Float player interface.
bool wheelEventFromFloatPlayer(QEvent *e) override;
QRect rectForFloatPlayer() const override;
@ -389,11 +396,6 @@ public slots:
void onTextChange();
void onFieldTabbed();
bool onStickerOrGifSend(not_null<DocumentData*> document);
void onPhotoSend(not_null<PhotoData*> photo);
void onInlineResultSend(
not_null<InlineBots::Result*> result,
not_null<UserData*> bot);
void onWindowVisibleChanged();
@ -431,6 +433,8 @@ private:
using TabbedSelector = ChatHelpers::TabbedSelector;
using DragState = Storage::MimeDataState;
void initTabbedSelector();
void send(Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers());
void handlePendingHistoryUpdate();
void fullPeerUpdated(PeerData *peer);
@ -601,13 +605,9 @@ private:
void destroyPinnedBar();
void unpinDone(const MTPUpdates &updates);
bool sendExistingDocument(
not_null<DocumentData*> document,
Data::FileOrigin origin,
TextWithEntities caption);
void sendExistingPhoto(
not_null<PhotoData*> photo,
TextWithEntities caption);
void sendInlineResult(
not_null<InlineBots::Result*> result,
not_null<UserData*> bot);
void drawField(Painter &p, const QRect &rect);
void paintEditHeader(Painter &p, const QRect &rect, int left, int top) const;

View File

@ -40,18 +40,14 @@ constexpr auto kInlineBotRequestDelay = 400;
} // namespace
Inner::Inner(QWidget *parent, not_null<Window::Controller*> controller) : TWidget(parent)
, _controller(controller) {
, _controller(controller)
, _updateInlineItems([=] { updateInlineItems(); })
, _previewTimer([=] { showPreview(); }) {
resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, st::emojiPanMinHeight);
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
_previewTimer.setSingleShot(true);
connect(&_previewTimer, SIGNAL(timeout()), this, SLOT(onPreview()));
_updateInlineItems.setSingleShot(true);
connect(&_updateInlineItems, SIGNAL(timeout()), this, SLOT(onUpdateInlineItems()));
subscribe(Auth().downloaderTaskFinished(), [this] {
update();
});
@ -194,11 +190,11 @@ void Inner::mousePressEvent(QMouseEvent *e) {
_pressed = _selected;
ClickHandler::pressed();
_previewTimer.start(QApplication::startDragTime());
_previewTimer.callOnce(QApplication::startDragTime());
}
void Inner::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.stop();
_previewTimer.cancel();
auto pressed = std::exchange(_pressed, -1);
auto activated = ClickHandler::unpressed();
@ -572,7 +568,7 @@ void Inner::inlineItemRepaint(const ItemBase *layout) {
if (_lastScrolled + 100 <= ms) {
update();
} else {
_updateInlineItems.start(_lastScrolled + 100 - ms);
_updateInlineItems.callOnce(_lastScrolled + 100 - ms);
}
}
@ -682,7 +678,7 @@ void Inner::updateSelected() {
}
}
void Inner::onPreview() {
void Inner::showPreview() {
if (_pressed < 0) return;
int row = _pressed / MatrixRowShift, col = _pressed % MatrixRowShift;
@ -698,12 +694,12 @@ void Inner::onPreview() {
}
}
void Inner::onUpdateInlineItems() {
void Inner::updateInlineItems() {
auto ms = getms();
if (_lastScrolled + 100 <= ms) {
update();
} else {
_updateInlineItems.start(_lastScrolled + 100 - ms);
_updateInlineItems.callOnce(_lastScrolled + 100 - ms);
}
}

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/twidget.h"
#include "ui/abstract_button.h"
#include "ui/effects/panel_animation.h"
#include "base/timer.h"
#include "mtproto/sender.h"
#include "inline_bots/inline_bot_layout_item.h"
@ -90,8 +91,6 @@ protected:
void enterFromChildEvent(QEvent *e, QWidget *child) override;
private slots:
void onPreview();
void onUpdateInlineItems();
void onSwitchPm();
signals:
@ -101,6 +100,11 @@ private:
static constexpr bool kRefreshIconsScrollAnimation = true;
static constexpr bool kRefreshIconsNoAnimation = false;
struct Row {
int height = 0;
QVector<ItemBase*> items;
};
void updateSelected();
void checkRestrictedPeer();
bool isRestrictedView();
@ -109,30 +113,9 @@ private:
void refreshSwitchPmButton(const CacheEntry *entry);
not_null<Window::Controller*> _controller;
int _visibleTop = 0;
int _visibleBottom = 0;
UserData *_inlineBot = nullptr;
PeerData *_inlineQueryPeer = nullptr;
TimeMs _lastScrolled = 0;
QTimer _updateInlineItems;
bool _inlineWithThumb = false;
object_ptr<Ui::RoundButton> _switchPmButton = { nullptr };
QString _switchPmStartToken;
object_ptr<Ui::FlatLabel> _restrictedLabel = { nullptr };
struct Row {
int height = 0;
QVector<ItemBase*> items;
};
QVector<Row> _rows;
void showPreview();
void updateInlineItems();
void clearInlineRows(bool resultsDeleted);
std::map<Result*, std::unique_ptr<ItemBase>> _inlineLayouts;
ItemBase *layoutPrepareInlineResult(Result *result, int32 position);
bool inlineRowsAddItem(Result *result, Row &row, int32 &sumWidth);
@ -144,11 +127,31 @@ private:
int validateExistingInlineRows(const Results &results);
void selectInlineResult(int row, int column);
not_null<Window::Controller*> _controller;
int _visibleTop = 0;
int _visibleBottom = 0;
UserData *_inlineBot = nullptr;
PeerData *_inlineQueryPeer = nullptr;
TimeMs _lastScrolled = 0;
base::Timer _updateInlineItems;
bool _inlineWithThumb = false;
object_ptr<Ui::RoundButton> _switchPmButton = { nullptr };
QString _switchPmStartToken;
object_ptr<Ui::FlatLabel> _restrictedLabel = { nullptr };
QVector<Row> _rows;
std::map<Result*, std::unique_ptr<ItemBase>> _inlineLayouts;
int _selected = -1;
int _pressed = -1;
QPoint _lastMousePos;
QTimer _previewTimer;
base::Timer _previewTimer;
bool _previewShown = false;
Fn<void(Result *result, UserData *bot)> _resultSelectedCallback;

View File

@ -1447,7 +1447,7 @@ void MainWidget::onSendFileConfirm(
}
bool MainWidget::onSendSticker(DocumentData *document) {
return _history->onStickerOrGifSend(document);
return _history->sendExistingDocument(document);
}
void MainWidget::dialogsCancelled() {

View File

@ -204,6 +204,9 @@ public:
auto scrollTopValue() const {
return _scrollTopUpdated.events_starting_with(scrollTop());
}
auto scrollTopChanges() const {
return _scrollTopUpdated.events();
}
void scrollTo(ScrollToRequest request);
void scrollToWidget(not_null<QWidget*> widget);