/* 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 "api/api_common.h" #include "ui/effects/animations.h" #include "ui/effects/message_sending_animation_common.h" #include "ui/rp_widget.h" #include "base/timer.h" #include "base/object_ptr.h" namespace style { struct EmojiPan; } // namespace style namespace Ui { class PopupMenu; class ScrollArea; class InputField; } // namespace Ui namespace Lottie { class SinglePlayer; class FrameRenderer; } // namespace Lottie; namespace Main { class Session; } // namespace Main namespace Window { class SessionController; } // namespace Window namespace Data { class DocumentMedia; } // namespace Data namespace SendMenu { struct Details; } // namespace SendMenu namespace ChatHelpers { struct ComposeFeatures; struct FileChosen; class Show; enum class FieldAutocompleteChooseMethod { ByEnter, ByTab, ByClick, }; class FieldAutocomplete final : public Ui::RpWidget { public: FieldAutocomplete( QWidget *parent, std::shared_ptr show, const style::EmojiPan *stOverride = nullptr); ~FieldAutocomplete(); [[nodiscard]] std::shared_ptr uiShow() const; bool clearFilteredBotCommands(); void showFiltered( not_null peer, QString query, bool addInlineBots); void showStickers(EmojiPtr emoji); [[nodiscard]] EmojiPtr stickersEmoji() const; void setBoundings(QRect boundings); [[nodiscard]] const QString &filter() const; [[nodiscard]] ChatData *chat() const; [[nodiscard]] ChannelData *channel() const; [[nodiscard]] UserData *user() const; [[nodiscard]] int32 innerTop(); [[nodiscard]] int32 innerBottom(); bool eventFilter(QObject *obj, QEvent *e) override; using ChooseMethod = FieldAutocompleteChooseMethod; struct MentionChosen { not_null user; QString mention; ChooseMethod method = ChooseMethod::ByEnter; }; struct HashtagChosen { QString hashtag; ChooseMethod method = ChooseMethod::ByEnter; }; struct BotCommandChosen { not_null user; QString command; ChooseMethod method = ChooseMethod::ByEnter; }; using StickerChosen = FileChosen; enum class Type { Mentions, Hashtags, BotCommands, Stickers, }; bool chooseSelected(ChooseMethod method) const; [[nodiscard]] bool stickersShown() const { return !_srows.empty(); } [[nodiscard]] bool overlaps(const QRect &globalRect) { if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) { return false; } return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); } void setModerateKeyActivateCallback(Fn callback) { _moderateKeyActivateCallback = std::move(callback); } void setSendMenuDetails(Fn &&callback); void hideFast(); void showAnimated(); void hideAnimated(); void requestRefresh(); [[nodiscard]] rpl::producer<> refreshRequests() const; void requestStickersUpdate(); [[nodiscard]] rpl::producer<> stickersUpdateRequests() const; [[nodiscard]] rpl::producer mentionChosen() const; [[nodiscard]] rpl::producer hashtagChosen() const; [[nodiscard]] rpl::producer botCommandChosen() const; [[nodiscard]] rpl::producer stickerChosen() const; [[nodiscard]] rpl::producer choosingProcesses() const; protected: void paintEvent(QPaintEvent *e) override; private: class Inner; friend class Inner; struct StickerSuggestion; struct MentionRow; struct BotCommandRow; using HashtagRows = std::vector; using BotCommandRows = std::vector; using StickerRows = std::vector; using MentionRows = std::vector; void animationCallback(); void hideFinish(); void updateFiltered(bool resetScroll = false); void recount(bool resetScroll = false); StickerRows getStickerSuggestions(); const std::shared_ptr _show; const not_null _session; const style::EmojiPan &_st; QPixmap _cache; MentionRows _mrows; HashtagRows _hrows; BotCommandRows _brows; StickerRows _srows; void rowsUpdated( MentionRows &&mrows, HashtagRows &&hrows, BotCommandRows &&brows, StickerRows &&srows, bool resetScroll); object_ptr _scroll; QPointer _inner; ChatData *_chat = nullptr; UserData *_user = nullptr; ChannelData *_channel = nullptr; EmojiPtr _emoji; uint64 _stickersSeed = 0; Type _type = Type::Mentions; QString _filter; QRect _boundings; bool _addInlineBots; bool _hiding = false; Ui::Animations::Simple _a_opacity; rpl::event_stream<> _refreshRequests; rpl::event_stream<> _stickersUpdateRequests; Fn _moderateKeyActivateCallback; }; struct FieldAutocompleteDescriptor { not_null parent; std::shared_ptr show; not_null field; const style::EmojiPan *stOverride = nullptr; not_null peer; Fn features; Fn sendMenuDetails; Fn stickerChoosing; Fn stickerChosen; Fn setText; Fn sendBotCommand; Fn processShortcut; Fn moderateKeyActivateCallback; }; void InitFieldAutocomplete( std::unique_ptr &autocomplete, FieldAutocompleteDescriptor &&descriptor); } // namespace ChatHelpers