/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "boxes/abstract_box.h" #include "base/timer.h" #include "mtproto/sender.h" #include "chat_helpers/stickers.h" #include "ui/widgets/input_fields.h" class ConfirmBox; namespace style { struct RippleAnimation; } // namespace style namespace Ui { class PlainShadow; class RippleAnimation; class SettingsSlider; class SlideAnimation; class CrossButton; } // namespace Ui class StickersBox : public BoxContent, public RPCSender { public: enum class Section { Installed, Featured, Archived, }; StickersBox(QWidget*, Section section); StickersBox(QWidget*, not_null megagroup); void setInnerFocus() override; ~StickersBox(); protected: void prepare() override; void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; private: class Inner; class Tab { public: Tab() = default; template Tab(int index, Args&&... args); object_ptr takeWidget(); void returnWidget(object_ptr widget); Inner *widget() { return _weak; } int index() const { return _index; } void saveScrollTop(); int getScrollTop() const { return _scrollTop; } private: int _index = 0; object_ptr _widget = { nullptr }; QPointer _weak; int _scrollTop = 0; }; void handleStickersUpdated(); void refreshTabs(); void rebuildList(Tab *tab = nullptr); void updateTabsGeometry(); void switchTab(); void installSet(uint64 setId); int getTopSkip() const; void saveChanges(); QPixmap grabContentCache(); void installDone(const MTPmessages_StickerSetInstallResult &result); bool installFail(uint64 setId, const RPCError &error); void preloadArchivedSets(); void requestArchivedSets(); void loadMoreArchived(); void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); object_ptr _tabs = { nullptr }; QList
_tabIndices; class CounterWidget; object_ptr _unreadBadge = { nullptr }; Section _section; Tab _installed; Tab _featured; Tab _archived; Tab *_tab = nullptr; ChannelData *_megagroupSet = nullptr; std::unique_ptr _slideAnimation; object_ptr _titleShadow = { nullptr }; mtpRequestId _archivedRequestId = 0; bool _archivedLoaded = false; bool _allArchivedLoaded = false; bool _someArchivedLoaded = false; Stickers::Order _localOrder; Stickers::Order _localRemoved; }; int stickerPacksCount(bool includeArchivedOfficial = false); // This class is hold in header because it requires Qt preprocessing. class StickersBox::Inner : public TWidget, private base::Subscriber, private MTP::Sender { Q_OBJECT public: using Section = StickersBox::Section; Inner(QWidget *parent, Section section); Inner(QWidget *parent, not_null megagroup); base::Observable scrollToY; void setInnerFocus(); void saveGroupSet(); void rebuild(); void updateSize(int newWidth = 0); void updateRows(); // refresh only pack cover stickers bool appendSet(const Stickers::Set &set); Stickers::Order getOrder() const; Stickers::Order getFullOrder() const; Stickers::Order getRemovedSets() const; void setFullOrder(const Stickers::Order &order); void setRemovedSets(const Stickers::Order &removed); void setInstallSetCallback(Fn callback) { _installSetCallback = std::move(callback); } void setLoadMoreCallback(Fn callback) { _loadMoreCallback = std::move(callback); } void setMinHeight(int newWidth, int minHeight); int getVisibleTop() const { return _visibleTop; } ~Inner(); protected: void visibleTopBottomUpdated( int visibleTop, int visibleBottom) override; void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void leaveEventHook(QEvent *e) override; void leaveToChildEvent(QEvent *e, QWidget *child) override; signals: void draggingScrollDelta(int delta); public slots: void onUpdateSelected(); private: struct Row { Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh); bool isRecentSet() const { return (id == Stickers::CloudRecentSetId); } ~Row(); uint64 id = 0; DocumentData *sticker = nullptr; int32 count = 0; QString title; int titleWidth = 0; bool installed = false; bool official = false; bool unread = false; bool archived = false; bool removed = false; int32 pixw = 0; int32 pixh = 0; anim::value yadd; std::unique_ptr ripple; }; struct MegagroupSet { inline bool operator==(const MegagroupSet &other) const { return true; } inline bool operator!=(const MegagroupSet &other) const { return false; } }; using SelectedRow = base::optional_variant; class AddressField : public Ui::UsernameInput { public: using UsernameInput::UsernameInput; protected: void correctValue( const QString &was, int wasCursor, QString &now, int &nowCursor) override; }; template Stickers::Order collectSets(Check check) const; void checkLoadMore(); void updateScrollbarWidth(); int getRowIndex(uint64 setId) const; void setRowRemoved(int index, bool removed); void setSelected(SelectedRow selected); void setActionDown(int newActionDown); void setPressed(SelectedRow pressed); void setup(); QRect relativeButtonRect(bool removeButton) const; void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton); void step_shifting(TimeMs ms, bool timer); void paintRow(Painter &p, Row *set, int index, TimeMs ms); void paintFakeButton(Painter &p, Row *set, int index, TimeMs ms); void clear(); void setActionSel(int32 actionSel); float64 aboveShadowOpacity() const; void readVisibleSets(); void updateControlsGeometry(); void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth); void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const; int fillSetCount(const Stickers::Set &set) const; QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const; void fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived); void rebuildMegagroupSet(); void fixupMegagroupSetAddress(); void handleMegagroupSetAddressChange(); void setMegagroupSelectedSet(const MTPInputStickerSet &set); int countMaxNameWidth() const; Section _section; int32 _rowHeight; std::vector> _rows; QList _animStartTimes; TimeMs _aboveShadowFadeStart = 0; anim::value _aboveShadowFadeOpacity; BasicAnimation _a_shifting; Fn _installSetCallback; Fn _loadMoreCallback; int _visibleTop = 0; int _visibleBottom = 0; int _itemsTop = 0; int _actionSel = -1; int _actionDown = -1; QString _addText; int _addWidth = 0; QString _undoText; int _undoWidth = 0; int _buttonHeight = 0; QPoint _mouse; bool _inDragArea = false; SelectedRow _selected; SelectedRow _pressed; QPoint _dragStart; int _started = -1; int _dragging = -1; int _above = -1; int _minHeight = 0; int _scrollbar = 0; ChannelData *_megagroupSet = nullptr; MTPInputStickerSet _megagroupSetInput = MTP_inputStickerSetEmpty(); std::unique_ptr _megagroupSelectedSet; object_ptr _megagroupSetField = { nullptr }; object_ptr _megagroupSelectedShadow = { nullptr }; object_ptr _megagroupSelectedRemove = { nullptr }; object_ptr _megagroupDivider = { nullptr }; object_ptr _megagroupSubTitle = { nullptr }; base::Timer _megagroupSetAddressChangedTimer; mtpRequestId _megagroupSetRequestId = 0; };