tabbed_selector.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #pragma once
  8. #include "api/api_common.h"
  9. #include "chat_helpers/compose/compose_features.h"
  10. #include "ui/rp_widget.h"
  11. #include "ui/controls/swipe_handler_data.h"
  12. #include "ui/effects/animations.h"
  13. #include "ui/effects/message_sending_animation_common.h"
  14. #include "ui/effects/panel_animation.h"
  15. #include "ui/cached_round_corners.h"
  16. #include "mtproto/sender.h"
  17. #include "base/object_ptr.h"
  18. namespace InlineBots {
  19. struct ResultSelected;
  20. } // namespace InlineBots
  21. namespace Main {
  22. class Session;
  23. } // namespace Main
  24. namespace Ui {
  25. class PlainShadow;
  26. class PopupMenu;
  27. class ScrollArea;
  28. class SettingsSlider;
  29. class FlatLabel;
  30. class BoxContent;
  31. class TabbedSearch;
  32. } // namespace Ui
  33. namespace SendMenu {
  34. struct Details;
  35. } // namespace SendMenu
  36. namespace style {
  37. struct EmojiPan;
  38. } // namespace style
  39. namespace ChatHelpers {
  40. class Show;
  41. class EmojiListWidget;
  42. class StickersListWidget;
  43. class GifsListWidget;
  44. enum class PauseReason;
  45. enum class SelectorTab {
  46. Emoji,
  47. Stickers,
  48. Gifs,
  49. Masks,
  50. };
  51. struct FileChosen {
  52. not_null<DocumentData*> document;
  53. Api::SendOptions options;
  54. Ui::MessageSendingAnimationFrom messageSendingFrom;
  55. std::shared_ptr<Data::EmojiStatusCollectible> collectible;
  56. TextWithTags caption;
  57. };
  58. struct PhotoChosen {
  59. not_null<PhotoData*> photo;
  60. Api::SendOptions options;
  61. };
  62. struct EmojiChosen {
  63. EmojiPtr emoji;
  64. Ui::MessageSendingAnimationFrom messageSendingFrom;
  65. };
  66. using InlineChosen = InlineBots::ResultSelected;
  67. enum class TabbedSelectorMode {
  68. Full,
  69. EmojiOnly,
  70. StickersOnly,
  71. MediaEditor,
  72. EmojiStatus,
  73. ChannelStatus,
  74. BackgroundEmoji,
  75. FullReactions,
  76. RecentReactions,
  77. PeerTitle,
  78. ChatIntro,
  79. };
  80. struct TabbedSelectorDescriptor {
  81. std::shared_ptr<Show> show;
  82. const style::EmojiPan &st;
  83. PauseReason level = {};
  84. TabbedSelectorMode mode = TabbedSelectorMode::Full;
  85. Fn<QColor()> customTextColor;
  86. ComposeFeatures features;
  87. };
  88. enum class TabbedSearchType {
  89. Emoji,
  90. Status,
  91. ProfilePhoto,
  92. Stickers,
  93. Greeting,
  94. };
  95. [[nodiscard]] std::unique_ptr<Ui::TabbedSearch> MakeSearch(
  96. not_null<Ui::RpWidget*> parent,
  97. const style::EmojiPan &st,
  98. Fn<void(std::vector<QString>&&)> callback,
  99. not_null<Main::Session*> session,
  100. TabbedSearchType type);
  101. class TabbedSelector : public Ui::RpWidget {
  102. public:
  103. static constexpr auto kPickCustomTimeId = -1;
  104. using Mode = TabbedSelectorMode;
  105. enum class Action {
  106. Update,
  107. Cancel,
  108. };
  109. TabbedSelector(
  110. QWidget *parent,
  111. std::shared_ptr<Show> show,
  112. PauseReason level,
  113. Mode mode = Mode::Full);
  114. TabbedSelector(
  115. QWidget *parent,
  116. TabbedSelectorDescriptor &&descriptor);
  117. ~TabbedSelector();
  118. [[nodiscard]] const style::EmojiPan &st() const;
  119. [[nodiscard]] Main::Session &session() const;
  120. [[nodiscard]] PauseReason level() const;
  121. [[nodiscard]] rpl::producer<EmojiChosen> emojiChosen() const;
  122. [[nodiscard]] rpl::producer<FileChosen> customEmojiChosen() const;
  123. [[nodiscard]] rpl::producer<FileChosen> fileChosen() const;
  124. [[nodiscard]] rpl::producer<PhotoChosen> photoChosen() const;
  125. [[nodiscard]] rpl::producer<InlineChosen> inlineResultChosen() const;
  126. [[nodiscard]] rpl::producer<> cancelled() const;
  127. [[nodiscard]] rpl::producer<> checkForHide() const;
  128. [[nodiscard]] rpl::producer<> slideFinished() const;
  129. [[nodiscard]] rpl::producer<> contextMenuRequested() const;
  130. [[nodiscard]] rpl::producer<Action> choosingStickerUpdated() const;
  131. void setAllowEmojiWithoutPremium(bool allow);
  132. void setRoundRadius(int radius);
  133. void refreshStickers();
  134. void setCurrentPeer(PeerData *peer);
  135. void provideRecentEmoji(
  136. const std::vector<EmojiStatusId> &customRecentList);
  137. void hideFinished();
  138. void showStarted();
  139. void beforeHiding();
  140. void afterShown();
  141. [[nodiscard]] int marginTop() const;
  142. [[nodiscard]] int marginBottom() const;
  143. [[nodiscard]] int scrollTop() const;
  144. [[nodiscard]] int scrollBottom() const;
  145. bool preventAutoHide() const;
  146. bool isSliding() const {
  147. return _a_slide.animating();
  148. }
  149. bool hasMenu() const;
  150. void setAfterShownCallback(Fn<void(SelectorTab)> callback) {
  151. _afterShownCallback = std::move(callback);
  152. }
  153. void setBeforeHidingCallback(Fn<void(SelectorTab)> callback) {
  154. _beforeHidingCallback = std::move(callback);
  155. }
  156. void showMenuWithDetails(SendMenu::Details details);
  157. void setDropDown(bool dropDown);
  158. // Float player interface.
  159. bool floatPlayerHandleWheelEvent(QEvent *e);
  160. QRect floatPlayerAvailableRect() const;
  161. auto showRequests() const {
  162. return _showRequests.events();
  163. }
  164. class Inner;
  165. class InnerFooter;
  166. protected:
  167. void paintEvent(QPaintEvent *e) override;
  168. void resizeEvent(QResizeEvent *e) override;
  169. private:
  170. class Tab {
  171. public:
  172. Tab(SelectorTab type, int index, object_ptr<Inner> widget);
  173. object_ptr<Inner> takeWidget();
  174. void returnWidget(object_ptr<Inner> widget);
  175. [[nodiscard]] SelectorTab type() const {
  176. return _type;
  177. }
  178. [[nodiscard]] int index() const {
  179. return _index;
  180. }
  181. [[nodiscard]] Inner *widget() const {
  182. return _weak;
  183. }
  184. [[nodiscard]] bool hasFooter() const {
  185. return _footer != nullptr;
  186. }
  187. [[nodiscard]] not_null<InnerFooter*> footer() const {
  188. return _footer;
  189. }
  190. void saveScrollTop();
  191. void saveScrollTop(int scrollTop) {
  192. _scrollTop = scrollTop;
  193. }
  194. [[nodiscard]] int getScrollTop() const {
  195. return _scrollTop;
  196. }
  197. private:
  198. const SelectorTab _type;
  199. const int _index;
  200. object_ptr<Inner> _widget = { nullptr };
  201. QPointer<Inner> _weak;
  202. object_ptr<InnerFooter> _footer;
  203. int _scrollTop = 0;
  204. };
  205. bool full() const;
  206. bool mediaEditor() const;
  207. bool tabbed() const;
  208. bool hasEmojiTab() const;
  209. bool hasStickersTab() const;
  210. bool hasGifsTab() const;
  211. bool hasMasksTab() const;
  212. Tab createTab(SelectorTab type, int index);
  213. void paintSlideFrame(QPainter &p);
  214. void paintBgRoundedPart(QPainter &p);
  215. void paintContent(QPainter &p);
  216. void checkRestrictedPeer();
  217. bool isRestrictedView();
  218. void updateRestrictedLabelGeometry();
  219. void updateScrollGeometry(QSize oldSize);
  220. void updateFooterGeometry();
  221. void handleScroll();
  222. QImage grabForAnimation();
  223. void scrollToY(int y);
  224. void showAll();
  225. void hideForSliding();
  226. SelectorTab typeByIndex(int index) const;
  227. int indexByType(SelectorTab type) const;
  228. bool hasSectionIcons() const;
  229. void setWidgetToScrollArea();
  230. void createTabsSlider();
  231. void fillTabsSliderSections();
  232. void updateTabsSliderGeometry();
  233. void switchTab();
  234. not_null<Tab*> getTab(int index);
  235. not_null<const Tab*> getTab(int index) const;
  236. not_null<Tab*> currentTab();
  237. not_null<const Tab*> currentTab() const;
  238. not_null<EmojiListWidget*> emoji() const;
  239. not_null<StickersListWidget*> stickers() const;
  240. not_null<GifsListWidget*> gifs() const;
  241. not_null<StickersListWidget*> masks() const;
  242. void reinstallSwipe(not_null<Ui::RpWidget*> widget);
  243. const style::EmojiPan &_st;
  244. const ComposeFeatures _features;
  245. const std::shared_ptr<Show> _show;
  246. const PauseReason _level = {};
  247. const Fn<QColor()> _customTextColor;
  248. Ui::Controls::SwipeBackResult _swipeBackData;
  249. Mode _mode = Mode::Full;
  250. int _roundRadius = 0;
  251. int _footerTop = 0;
  252. bool _noFooter = false;
  253. Ui::CornersPixmaps _panelRounding;
  254. Ui::CornersPixmaps _categoriesRounding;
  255. PeerData *_currentPeer = nullptr;
  256. class SlideAnimation;
  257. std::unique_ptr<SlideAnimation> _slideAnimation;
  258. Ui::Animations::Simple _a_slide;
  259. object_ptr<Ui::SettingsSlider> _tabsSlider = { nullptr };
  260. object_ptr<Ui::PlainShadow> _topShadow;
  261. object_ptr<Ui::PlainShadow> _bottomShadow;
  262. object_ptr<Ui::ScrollArea> _scroll;
  263. object_ptr<Ui::FlatLabel> _restrictedLabel = { nullptr };
  264. QString _restrictedLabelKey;
  265. std::vector<Tab> _tabs;
  266. SelectorTab _currentTabType = SelectorTab::Emoji;
  267. const bool _hasEmojiTab;
  268. const bool _hasStickersTab;
  269. const bool _hasGifsTab;
  270. const bool _hasMasksTab;
  271. const bool _tabbed;
  272. bool _dropDown = false;
  273. base::unique_qptr<Ui::PopupMenu> _menu;
  274. Fn<void(SelectorTab)> _afterShownCallback;
  275. Fn<void(SelectorTab)> _beforeHidingCallback;
  276. rpl::event_stream<> _showRequests;
  277. rpl::event_stream<> _slideFinished;
  278. rpl::lifetime _swipeLifetime;
  279. };
  280. class TabbedSelector::Inner : public Ui::RpWidget {
  281. public:
  282. Inner(
  283. QWidget *parent,
  284. std::shared_ptr<Show> show,
  285. PauseReason level);
  286. Inner(
  287. QWidget *parent,
  288. const style::EmojiPan &st,
  289. std::shared_ptr<Show> show,
  290. Fn<bool()> paused);
  291. [[nodiscard]] Main::Session &session() const {
  292. return *_session;
  293. }
  294. [[nodiscard]] const style::EmojiPan &st() const {
  295. return _st;
  296. }
  297. [[nodiscard]] Fn<bool()> pausedMethod() const {
  298. return _paused;
  299. }
  300. [[nodiscard]] bool paused() const {
  301. return _paused();
  302. }
  303. [[nodiscard]] int getVisibleTop() const {
  304. return _visibleTop;
  305. }
  306. [[nodiscard]] int getVisibleBottom() const {
  307. return _visibleBottom;
  308. }
  309. void setMinimalHeight(int newWidth, int newMinimalHeight);
  310. [[nodiscard]] rpl::producer<> checkForHide() const {
  311. return _checkForHide.events();
  312. }
  313. [[nodiscard]] bool preventAutoHide() const {
  314. return _preventHideWithBox;
  315. }
  316. virtual void refreshRecent() = 0;
  317. virtual void preloadImages() {
  318. }
  319. void hideFinished();
  320. void panelHideFinished();
  321. virtual void clearSelection() = 0;
  322. virtual void afterShown() {
  323. }
  324. virtual void beforeHiding() {
  325. }
  326. [[nodiscard]] virtual base::unique_qptr<Ui::PopupMenu> fillContextMenu(
  327. const SendMenu::Details &details) {
  328. return nullptr;
  329. }
  330. rpl::producer<int> scrollToRequests() const;
  331. rpl::producer<bool> disableScrollRequests() const;
  332. virtual object_ptr<InnerFooter> createFooter() = 0;
  333. protected:
  334. void visibleTopBottomUpdated(
  335. int visibleTop,
  336. int visibleBottom) override;
  337. int minimalHeight() const;
  338. virtual int defaultMinimalHeight() const;
  339. int resizeGetHeight(int newWidth) override final;
  340. virtual int countDesiredHeight(int newWidth) = 0;
  341. virtual InnerFooter *getFooter() const = 0;
  342. virtual void processHideFinished() {
  343. }
  344. virtual void processPanelHideFinished() {
  345. }
  346. void scrollTo(int y);
  347. void disableScroll(bool disabled);
  348. void checkHideWithBox(object_ptr<Ui::BoxContent> box);
  349. void paintEmptySearchResults(
  350. Painter &p,
  351. const style::icon &icon,
  352. const QString &text) const;
  353. private:
  354. const style::EmojiPan &_st;
  355. const std::shared_ptr<Show> _show;
  356. const not_null<Main::Session*> _session;
  357. const Fn<bool()> _paused;
  358. int _visibleTop = 0;
  359. int _visibleBottom = 0;
  360. std::optional<int> _minimalHeight;
  361. rpl::event_stream<int> _scrollToRequests;
  362. rpl::event_stream<bool> _disableScrollRequests;
  363. rpl::event_stream<> _checkForHide;
  364. bool _preventHideWithBox = false;
  365. };
  366. class TabbedSelector::InnerFooter : public Ui::RpWidget {
  367. public:
  368. InnerFooter(QWidget *parent, const style::EmojiPan &st);
  369. [[nodiscard]] const style::EmojiPan &st() const;
  370. protected:
  371. virtual void processHideFinished() {
  372. }
  373. virtual void processPanelHideFinished() {
  374. }
  375. friend class Inner;
  376. private:
  377. const style::EmojiPan &_st;
  378. };
  379. } // namespace ChatHelpers