From 7d2b20e6243ac927b76693f32f3edfb47aeac5e0 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 15 Mar 2021 13:51:13 +0300 Subject: [PATCH] Made TabbedSelector more flexible. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/boxes/stickers_box.cpp | 2 +- .../chat_helpers/tabbed_selector.cpp | 386 +++++++++++++----- .../chat_helpers/tabbed_selector.h | 52 ++- .../ui/widgets/discrete_sliders.cpp | 4 +- .../SourceFiles/ui/widgets/discrete_sliders.h | 2 +- 6 files changed, 318 insertions(+), 129 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 49f97b1cec..84c31d5017 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1379,6 +1379,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_switch_stickers" = "Stickers"; "lng_switch_emoji" = "Emoji"; "lng_switch_gifs" = "GIFs"; +"lng_switch_masks" = "Masks"; "lng_stickers_featured_add" = "Add"; "lng_gifs_search" = "Search GIFs"; "lng_gifs_no_saved" = "You have no saved GIFs yet."; diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 27294ebc87..c4f311abcb 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -604,7 +604,7 @@ void StickersBox::refreshTabs() { if (!_tabs) return; _tabIndices.clear(); - auto sections = QStringList(); + auto sections = std::vector(); sections.push_back(tr::lng_stickers_installed_tab(tr::now).toUpper()); _tabIndices.push_back(Section::Installed); if (!session().data().stickers().featuredSetsOrder().isEmpty()) { diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index 739b9ccc44..767f32e946 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -256,8 +256,12 @@ void TabbedSelector::SlideAnimation::paintFrame(QPainter &p, float64 dt, float64 p.drawImage(outerLeft / cIntRetinaFactor(), outerTop / cIntRetinaFactor(), _frame, outerLeft, outerTop, outerRight - outerLeft, outerBottom - outerTop); } -TabbedSelector::Tab::Tab(SelectorTab type, object_ptr widget) +TabbedSelector::Tab::Tab( + SelectorTab type, + int index, + object_ptr widget) : _type(type) +, _index(index) , _widget(std::move(widget)) , _weak(_widget) , _footer(_widget ? _widget->createFooter() : nullptr) { @@ -292,33 +296,52 @@ TabbedSelector::TabbedSelector( , _topShadow(full() ? object_ptr(this) : nullptr) , _bottomShadow(this) , _scroll(this, st::emojiScroll) -, _tabs { { - createTab(SelectorTab::Emoji), - createTab(SelectorTab::Stickers), - createTab(SelectorTab::Gifs), -} } +, _tabs([&] { + std::vector tabs; + if (full()) { + tabs.reserve(3); + tabs.push_back(createTab(SelectorTab::Emoji, 0)); + tabs.push_back(createTab(SelectorTab::Stickers, 1)); + tabs.push_back(createTab(SelectorTab::Gifs, 2)); + } else if (mediaEditor()) { + tabs.reserve(2); + tabs.push_back(createTab(SelectorTab::Stickers, 0)); + tabs.push_back(createTab(SelectorTab::Masks, 1)); + } else { + tabs.reserve(1); + tabs.push_back(createTab(SelectorTab::Emoji, 0)); + } + return tabs; +}()) , _currentTabType(full() ? session().settings().selectorTab() - : SelectorTab::Emoji) { + : mediaEditor() + ? SelectorTab::Stickers + : SelectorTab::Emoji) +, _hasEmojiTab(ranges::contains(_tabs, SelectorTab::Emoji, &Tab::type)) +, _hasStickersTab(ranges::contains(_tabs, SelectorTab::Stickers, &Tab::type)) +, _hasGifsTab(ranges::contains(_tabs, SelectorTab::Gifs, &Tab::type)) +, _hasMasksTab(ranges::contains(_tabs, SelectorTab::Masks, &Tab::type)) +, _tabbed(_tabs.size() > 1) { resize(st::emojiPanWidth, st::emojiPanMaxHeight); for (auto &tab : _tabs) { - if (!tab.widget()) { - continue; - } tab.footer()->hide(); tab.widget()->hide(); } - createTabsSlider(); + if (tabbed()) { + createTabsSlider(); + } setWidgetToScrollArea(); - _bottomShadow->setGeometry(0, _scroll->y() + _scroll->height() - st::lineWidth, width(), st::lineWidth); + _bottomShadow->setGeometry( + 0, + _scroll->y() + _scroll->height() - st::lineWidth, + width(), + st::lineWidth); for (auto &tab : _tabs) { const auto widget = tab.widget(); - if (!widget) { - continue; - } widget->scrollToRequests( ) | rpl::start_with_next([=, tab = &tab](int y) { @@ -338,7 +361,7 @@ TabbedSelector::TabbedSelector( } rpl::merge( - (full() + (hasStickersTab() ? stickers()->scrollUpdated() | rpl::map_to(0) : rpl::never() | rpl::type_erased()), _scroll->scrollTopChanges() @@ -346,13 +369,15 @@ TabbedSelector::TabbedSelector( handleScroll(); }, lifetime()); - if (full()) { + if (_topShadow) { _topShadow->raise(); } _bottomShadow->raise(); - if (full()) { + if (_tabsSlider) { _tabsSlider->raise(); + } + if (hasStickersTab() || hasGifsTab()) { session().changes().peerUpdates( Data::PeerUpdate::Flag::Rights ) | rpl::filter([=](const Data::PeerUpdate &update) { @@ -360,11 +385,12 @@ TabbedSelector::TabbedSelector( }) | rpl::start_with_next([=] { checkRestrictedPeer(); }, lifetime()); + } + if (hasStickersTab()) { session().api().stickerSetInstalled( ) | rpl::start_with_next([this](uint64 setId) { - _tabsSlider->setActiveSection( - static_cast(SelectorTab::Stickers)); + _tabsSlider->setActiveSection(indexByType(SelectorTab::Stickers)); stickers()->showStickerSet(setId); _showRequests.fire({}); }, lifetime()); @@ -387,11 +413,8 @@ Main::Session &TabbedSelector::session() const { return _controller->session(); } -TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type) { +TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type, int index) { auto createWidget = [&]() -> object_ptr { - if (!full() && type != SelectorTab::Emoji) { - return { nullptr }; - } switch (type) { case SelectorTab::Emoji: return object_ptr(this, _controller); @@ -399,42 +422,74 @@ TabbedSelector::Tab TabbedSelector::createTab(SelectorTab type) { return object_ptr(this, _controller); case SelectorTab::Gifs: return object_ptr(this, _controller); + case SelectorTab::Masks: + return object_ptr(this, _controller); } Unexpected("Type in TabbedSelector::createTab."); }; - return Tab{ type, createWidget() }; + return Tab{ type, index, createWidget() }; } bool TabbedSelector::full() const { return (_mode == Mode::Full); } +bool TabbedSelector::mediaEditor() const { + return (_mode == Mode::MediaEditor); +} + +bool TabbedSelector::tabbed() const { + return _tabbed; +} + +bool TabbedSelector::hasEmojiTab() const { + return _hasEmojiTab; +} + +bool TabbedSelector::hasStickersTab() const { + return _hasStickersTab; +} + +bool TabbedSelector::hasGifsTab() const { + return _hasGifsTab; +} + +bool TabbedSelector::hasMasksTab() const { + return _hasMasksTab; +} + rpl::producer TabbedSelector::emojiChosen() const { return emoji()->chosen(); } rpl::producer TabbedSelector::fileChosen() const { - return full() - ? rpl::merge(stickers()->chosen(), gifs()->fileChosen()) - : rpl::never() | rpl::type_erased(); + auto never = rpl::never( + ) | rpl::type_erased(); + return rpl::merge( + hasStickersTab() ? stickers()->chosen() : never, + hasGifsTab() ? gifs()->fileChosen() : never, + hasMasksTab() ? masks()->chosen() : never); } auto TabbedSelector::photoChosen() const -> rpl::producer{ - return full() ? gifs()->photoChosen() : nullptr; + return hasGifsTab() ? gifs()->photoChosen() : nullptr; } auto TabbedSelector::inlineResultChosen() const -> rpl::producer { - return full() ? gifs()->inlineResultChosen() : nullptr; + return hasGifsTab() ? gifs()->inlineResultChosen() : nullptr; } rpl::producer<> TabbedSelector::cancelled() const { - return full() ? gifs()->cancelRequests() : nullptr; + return hasGifsTab() ? gifs()->cancelRequests() : nullptr; } rpl::producer<> TabbedSelector::checkForHide() const { - return full() ? stickers()->checkForHide() : nullptr; + auto never = rpl::never<>(); + return rpl::merge( + hasStickersTab() ? stickers()->checkForHide() : never, + hasMasksTab() ? masks()->checkForHide() : never); } rpl::producer<> TabbedSelector::slideFinished() const { @@ -442,9 +497,11 @@ rpl::producer<> TabbedSelector::slideFinished() const { } void TabbedSelector::resizeEvent(QResizeEvent *e) { - if (full()) { + if (_tabsSlider) { _tabsSlider->resizeToWidth(width()); _tabsSlider->moveToLeft(0, 0); + } + if (_topShadow && _tabsSlider) { _topShadow->setGeometry( _tabsSlider->x(), _tabsSlider->bottomNoMargins() - st::lineWidth, @@ -476,14 +533,15 @@ void TabbedSelector::resizeEvent(QResizeEvent *e) { updateInnerGeometry(); updateScrollGeometry(); } - _bottomShadow->setGeometry(0, _scroll->y() + _scroll->height() - st::lineWidth, width(), st::lineWidth); + _bottomShadow->setGeometry( + 0, + _scroll->y() + _scroll->height() - st::lineWidth, + width(), + st::lineWidth); updateRestrictedLabelGeometry(); _footerTop = height() - st::emojiFooterHeight; for (auto &tab : _tabs) { - if (!tab.widget()) { - continue; - } tab.footer()->resizeToWidth(width()); tab.footer()->moveToLeft(0, _footerTop); } @@ -521,14 +579,22 @@ void TabbedSelector::paintEvent(QPaintEvent *e) { void TabbedSelector::paintSlideFrame(Painter &p) { if (_roundRadius > 0) { - if (full()) { - auto topPart = QRect(0, 0, width(), _tabsSlider->height() + _roundRadius); - Ui::FillRoundRect(p, topPart, st::emojiPanBg, ImageRoundRadius::Small, RectPart::FullTop | RectPart::NoTopBottom); - } else { - auto topPart = QRect(0, 0, width(), 3 * _roundRadius); - Ui::FillRoundRect(p, topPart, st::emojiPanBg, ImageRoundRadius::Small, RectPart::FullTop); - } - } else if (full()) { + const auto topPart = QRect( + 0, + 0, + width(), + _tabsSlider + ? _tabsSlider->height() + _roundRadius + : 3 * _roundRadius); + Ui::FillRoundRect( + p, + topPart, + st::emojiPanBg, + ImageRoundRadius::Small, + tabbed() + ? RectPart::FullTop | RectPart::NoTopBottom + : RectPart::FullTop); + } else if (_tabsSlider) { p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg); } auto slideDt = _a_slide.value(1.); @@ -536,21 +602,39 @@ void TabbedSelector::paintSlideFrame(Painter &p) { } void TabbedSelector::paintContent(Painter &p) { - auto &bottomBg = hasSectionIcons() ? st::emojiPanCategories : st::emojiPanBg; + auto &bottomBg = hasSectionIcons() + ? st::emojiPanCategories + : st::emojiPanBg; if (_roundRadius > 0) { - if (full()) { - auto topPart = QRect(0, 0, width(), _tabsSlider->height() + _roundRadius); - Ui::FillRoundRect(p, topPart, st::emojiPanBg, ImageRoundRadius::Small, RectPart::FullTop | RectPart::NoTopBottom); - } else { - auto topPart = QRect(0, 0, width(), 3 * _roundRadius); - Ui::FillRoundRect(p, topPart, st::emojiPanBg, ImageRoundRadius::Small, RectPart::FullTop); - } + const auto topPart = QRect( + 0, + 0, + width(), + _tabsSlider + ? _tabsSlider->height() + _roundRadius + : 3 * _roundRadius); + Ui::FillRoundRect( + p, + topPart, + st::emojiPanBg, + ImageRoundRadius::Small, + tabbed() + ? RectPart::FullTop | RectPart::NoTopBottom + : RectPart::FullTop); - auto bottomPart = QRect(0, _footerTop - _roundRadius, width(), st::emojiFooterHeight + _roundRadius); - auto bottomParts = RectPart::NoTopBottom | RectPart::FullBottom; - Ui::FillRoundRect(p, bottomPart, bottomBg, ImageRoundRadius::Small, bottomParts); + const auto bottomPart = QRect( + 0, + _footerTop - _roundRadius, + width(), + st::emojiFooterHeight + _roundRadius); + Ui::FillRoundRect( + p, + bottomPart, + bottomBg, + ImageRoundRadius::Small, + RectPart::NoTopBottom | RectPart::FullBottom); } else { - if (full()) { + if (_tabsSlider) { p.fillRect(0, 0, width(), _tabsSlider->height(), st::emojiPanBg); } p.fillRect(0, _footerTop, width(), st::emojiFooterHeight, bottomBg); @@ -561,17 +645,27 @@ void TabbedSelector::paintContent(Painter &p) { if (_restrictedLabel) { p.fillRect(0, sidesTop, width(), sidesHeight, st::emojiPanBg); } else { - p.fillRect(myrtlrect(width() - st::emojiScroll.width, sidesTop, st::emojiScroll.width, sidesHeight), st::emojiPanBg); - p.fillRect(myrtlrect(0, sidesTop, st::roundRadiusSmall, sidesHeight), st::emojiPanBg); + p.fillRect( + myrtlrect( + width() - st::emojiScroll.width, + sidesTop, + st::emojiScroll.width, + sidesHeight), + st::emojiPanBg); + p.fillRect( + myrtlrect(0, sidesTop, st::roundRadiusSmall, sidesHeight), + st::emojiPanBg); } } int TabbedSelector::marginTop() const { - return full() ? (_tabsSlider->height() - st::lineWidth) : _roundRadius; + return _tabsSlider + ? (_tabsSlider->height() - st::lineWidth) + : _roundRadius; } int TabbedSelector::scrollTop() const { - return full() ? marginTop() : 0; + return tabbed() ? marginTop() : 0; } int TabbedSelector::marginBottom() const { @@ -579,7 +673,7 @@ int TabbedSelector::marginBottom() const { } void TabbedSelector::refreshStickers() { - if (!full()) { + if (!hasStickersTab()) { return; } stickers()->refreshStickers(); @@ -589,9 +683,9 @@ void TabbedSelector::refreshStickers() { } bool TabbedSelector::preventAutoHide() const { - return full() - ? (stickers()->preventAutoHide() || hasMenu()) - : false; + return (hasStickersTab() ? stickers()->preventAutoHide() : false) + || (hasMasksTab() ? masks()->preventAutoHide() : false) + || hasMenu(); } bool TabbedSelector::hasMenu() const { @@ -603,13 +697,17 @@ QImage TabbedSelector::grabForAnimation() { auto slideAnimation = base::take(_a_slide); showAll(); - if (full()) { + if (_topShadow) { _topShadow->hide(); + } + if (_tabsSlider) { _tabsSlider->hide(); } Ui::SendPendingMoveResizeEvents(this); - auto result = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + auto result = QImage( + size() * cIntRetinaFactor(), + QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(cRetinaFactor()); result.fill(Qt::transparent); render(&result); @@ -630,9 +728,6 @@ QRect TabbedSelector::floatPlayerAvailableRect() const { void TabbedSelector::hideFinished() { for (auto &tab : _tabs) { - if (!tab.widget()) { - continue; - } tab.widget()->panelHideFinished(); } _a_slide.stop(); @@ -640,7 +735,7 @@ void TabbedSelector::hideFinished() { } void TabbedSelector::showStarted() { - if (full()) { + if (hasStickersTab()) { session().api().updateStickers(); } currentTab()->widget()->refreshRecent(); @@ -670,13 +765,14 @@ void TabbedSelector::afterShown() { } void TabbedSelector::setCurrentPeer(PeerData *peer) { - if (!full()) { - return; + if (hasGifsTab()) { + gifs()->setInlineQueryPeer(peer); } - gifs()->setInlineQueryPeer(peer); _currentPeer = peer; checkRestrictedPeer(); - stickers()->showMegagroupSet(peer ? peer->asMegagroup() : nullptr); + if (hasStickersTab()) { + stickers()->showMegagroupSet(peer ? peer->asMegagroup() : nullptr); + } } void TabbedSelector::checkRestrictedPeer() { @@ -730,16 +826,20 @@ void TabbedSelector::showAll() { _scroll->show(); _bottomShadow->setVisible(_currentTabType == SelectorTab::Gifs); } - if (full()) { + if (_topShadow) { _topShadow->show(); + } + if (_tabsSlider) { _tabsSlider->show(); } } void TabbedSelector::hideForSliding() { hideChildren(); - if (full()) { + if (_topShadow) { _topShadow->show(); + } + if (_tabsSlider) { _tabsSlider->show(); } currentTab()->widget()->clearSelection(); @@ -753,25 +853,33 @@ void TabbedSelector::handleScroll() { void TabbedSelector::setRoundRadius(int radius) { _roundRadius = radius; - if (full()) { + if (_tabsSlider) { _tabsSlider->setRippleTopRoundRadius(_roundRadius); } } void TabbedSelector::createTabsSlider() { - if (!full()) { - return; - } - _tabsSlider.create(this, st::emojiTabs); - auto sections = QStringList(); - sections.push_back(tr::lng_switch_emoji(tr::now).toUpper()); - sections.push_back(tr::lng_switch_stickers(tr::now).toUpper()); - sections.push_back(tr::lng_switch_gifs(tr::now).toUpper()); + const auto sections = ranges::views::all( + _tabs + ) | ranges::views::transform([=](const Tab &tab) { + return [type = tab.type()] { + switch (type) { + case SelectorTab::Emoji: + return tr::lng_switch_emoji; + case SelectorTab::Stickers: + return tr::lng_switch_stickers; + case SelectorTab::Gifs: + return tr::lng_switch_gifs; + case SelectorTab::Masks: + return tr::lng_switch_masks; + } + }()(tr::now).toUpper(); + }) | ranges::to_vector; _tabsSlider->setSections(sections); - _tabsSlider->setActiveSectionFast(static_cast(_currentTabType)); + _tabsSlider->setActiveSectionFast(indexByType(_currentTabType)); _tabsSlider->sectionActivated( ) | rpl::start_with_next([=] { switchTab(); @@ -783,18 +891,19 @@ bool TabbedSelector::hasSectionIcons() const { } void TabbedSelector::switchTab() { - Expects(full()); + Expects(tabbed()); - auto tab = _tabsSlider->activeSection(); - Assert(tab >= 0 && tab < Tab::kCount); - auto newTabType = static_cast(tab); + const auto tab = _tabsSlider->activeSection(); + Assert(tab >= 0 && tab < _tabs.size()); + const auto newTabType = typeByIndex(tab); if (_currentTabType == newTabType) { _scroll->scrollToY(0); return; } - auto wasSectionIcons = hasSectionIcons(); - auto wasTab = _currentTabType; + const auto wasSectionIcons = hasSectionIcons(); + const auto wasTab = _currentTabType; + const auto wasIndex = indexByType(_currentTabType); currentTab()->saveScrollTop(); beforeHiding(); @@ -817,21 +926,38 @@ void TabbedSelector::switchTab() { auto nowCache = grabForAnimation(); - auto direction = (wasTab > _currentTabType) ? SlideAnimation::Direction::LeftToRight : SlideAnimation::Direction::RightToLeft; + auto direction = (wasIndex > indexByType(_currentTabType)) + ? SlideAnimation::Direction::LeftToRight + : SlideAnimation::Direction::RightToLeft; if (direction == SlideAnimation::Direction::LeftToRight) { std::swap(wasCache, nowCache); } _slideAnimation = std::make_unique(); - auto slidingRect = QRect(0, _scroll->y() * cIntRetinaFactor(), width() * cIntRetinaFactor(), (height() - _scroll->y()) * cIntRetinaFactor()); - _slideAnimation->setFinalImages(direction, std::move(wasCache), std::move(nowCache), slidingRect, wasSectionIcons); - _slideAnimation->setCornerMasks(Images::CornersMask(ImageRoundRadius::Small)); + const auto slidingRect = QRect( + 0, + _scroll->y() * cIntRetinaFactor(), + width() * cIntRetinaFactor(), + (height() - _scroll->y()) * cIntRetinaFactor()); + _slideAnimation->setFinalImages( + direction, + std::move(wasCache), + std::move(nowCache), + slidingRect, + wasSectionIcons); + _slideAnimation->setCornerMasks( + Images::CornersMask(ImageRoundRadius::Small)); _slideAnimation->start(); hideForSliding(); - getTab(wasTab)->widget()->hideFinished(); + getTab(wasIndex)->widget()->hideFinished(); - _a_slide.start([this] { update(); }, 0., 1., st::emojiPanSlideDuration, anim::linear); + _a_slide.start( + [=] { update(); }, + 0., + 1., + st::emojiPanSlideDuration, + anim::linear); update(); if (full()) { @@ -841,19 +967,31 @@ void TabbedSelector::switchTab() { } not_null TabbedSelector::emoji() const { - return static_cast(getTab(SelectorTab::Emoji)->widget()); + Expects(hasEmojiTab()); + + return static_cast( + getTab(indexByType(SelectorTab::Emoji))->widget()); } not_null TabbedSelector::stickers() const { - Expects(full()); + Expects(hasStickersTab()); - return static_cast(getTab(SelectorTab::Stickers)->widget()); + return static_cast( + getTab(indexByType(SelectorTab::Stickers))->widget()); } not_null TabbedSelector::gifs() const { - Expects(full()); + Expects(hasGifsTab()); - return static_cast(getTab(SelectorTab::Gifs)->widget()); + return static_cast( + getTab(indexByType(SelectorTab::Gifs))->widget()); +} + +not_null TabbedSelector::masks() const { + Expects(hasMasksTab()); + + return static_cast( + getTab(indexByType(SelectorTab::Masks))->widget()); } void TabbedSelector::setWidgetToScrollArea() { @@ -873,7 +1011,7 @@ void TabbedSelector::scrollToY(int y) { _scroll->scrollToY(y); // Qt render glitch workaround, shadow sometimes disappears if we just scroll to y. - if (full()) { + if (_topShadow) { _topShadow->update(); } } @@ -894,6 +1032,40 @@ rpl::producer<> TabbedSelector::contextMenuRequested() const { }) | rpl::to_empty; } +SelectorTab TabbedSelector::typeByIndex(int index) const { + for (const auto &tab : _tabs) { + if (tab.index() == index) { + return tab.type(); + } + } + Unexpected("Type in TabbedSelector::typeByIndex."); +} + +int TabbedSelector::indexByType(SelectorTab type) const { + for (const auto &tab : _tabs) { + if (tab.type() == type) { + return tab.index(); + } + } + Unexpected("Index in TabbedSelector::indexByType."); +} + +not_null TabbedSelector::getTab(int index) { + return &(_tabs[index]); +} + +not_null TabbedSelector::getTab(int index) const { + return &_tabs[index]; +} + +not_null TabbedSelector::currentTab() { + return &_tabs[indexByType(_currentTabType)]; +} + +not_null TabbedSelector::currentTab() const { + return &_tabs[indexByType(_currentTabType)]; +} + TabbedSelector::Inner::Inner( QWidget *parent, not_null controller) @@ -917,7 +1089,9 @@ void TabbedSelector::Inner::disableScroll(bool disabled) { _disableScrollRequests.fire_copy(disabled); } -void TabbedSelector::Inner::visibleTopBottomUpdated(int visibleTop, int visibleBottom) { +void TabbedSelector::Inner::visibleTopBottomUpdated( + int visibleTop, + int visibleBottom) { _visibleTop = visibleTop; _visibleBottom = visibleBottom; } diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index 0011fecb95..bd881cb311 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -44,6 +44,7 @@ enum class SelectorTab { Emoji, Stickers, Gifs, + Masks, }; class EmojiListWidget; @@ -63,7 +64,8 @@ public: using InlineChosen = InlineBots::ResultSelected; enum class Mode { Full, - EmojiOnly + EmojiOnly, + MediaEditor, }; TabbedSelector( @@ -130,9 +132,7 @@ protected: private: class Tab { public: - static constexpr auto kCount = 3; - - Tab(SelectorTab type, object_ptr widget); + Tab(SelectorTab type, int index, object_ptr widget); object_ptr takeWidget(); void returnWidget(object_ptr widget); @@ -140,6 +140,9 @@ private: SelectorTab type() const { return _type; } + int index() const { + return _index; + } Inner *widget() const { return _weak; } @@ -156,7 +159,8 @@ private: } private: - SelectorTab _type = SelectorTab::Emoji; + const SelectorTab _type; + const int _index; object_ptr _widget = { nullptr }; QPointer _weak; object_ptr _footer; @@ -165,7 +169,13 @@ private: }; bool full() const; - Tab createTab(SelectorTab type); + bool mediaEditor() const; + bool tabbed() const; + bool hasEmojiTab() const; + bool hasStickersTab() const; + bool hasGifsTab() const; + bool hasMasksTab() const; + Tab createTab(SelectorTab type, int index); void paintSlideFrame(Painter &p); void paintContent(Painter &p); @@ -182,25 +192,23 @@ private: void showAll(); void hideForSliding(); + SelectorTab typeByIndex(int index) const; + int indexByType(SelectorTab type) const; + bool hasSectionIcons() const; void setWidgetToScrollArea(); void createTabsSlider(); void switchTab(); - not_null getTab(SelectorTab type) { - return &_tabs[static_cast(type)]; - } - not_null getTab(SelectorTab type) const { - return &_tabs[static_cast(type)]; - } - not_null currentTab() { - return getTab(_currentTabType); - } - not_null currentTab() const { - return getTab(_currentTabType); - } + + not_null getTab(int index); + not_null getTab(int index) const; + not_null currentTab(); + not_null currentTab() const; + not_null emoji() const; not_null stickers() const; not_null gifs() const; + not_null masks() const; const not_null _controller; @@ -218,9 +226,15 @@ private: object_ptr _bottomShadow; object_ptr _scroll; object_ptr _restrictedLabel = { nullptr }; - std::array _tabs; + std::vector _tabs; SelectorTab _currentTabType = SelectorTab::Emoji; + const bool _hasEmojiTab; + const bool _hasStickersTab; + const bool _hasGifsTab; + const bool _hasMasksTab; + const bool _tabbed; + base::unique_qptr _menu; Fn _afterShownCallback; diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp index 70732c495a..a8397197ae 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp @@ -62,8 +62,8 @@ void DiscreteSlider::addSection(const QString &label) { resizeToWidth(width()); } -void DiscreteSlider::setSections(const QStringList &labels) { - Assert(!labels.isEmpty()); +void DiscreteSlider::setSections(const std::vector &labels) { + Assert(!labels.empty()); _sections.clear(); for (const auto &label : labels) { diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h index 3947cab845..44ded4450b 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h @@ -20,7 +20,7 @@ public: DiscreteSlider(QWidget *parent); void addSection(const QString &label); - void setSections(const QStringList &labels); + void setSections(const std::vector &labels); int activeSection() const { return _activeIndex; }