From 7cc81393d6e43a4c71c84e632597beca2e63e250 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 5 Nov 2024 12:16:11 +0300 Subject: [PATCH] Adapted chats filters tabs slider for reorder feature. --- .../ui/widgets/chat_filters_tabs_slider.cpp | 153 ++++++++++++++++-- .../ui/widgets/chat_filters_tabs_slider.h | 22 +++ .../window/window_filters_menu.cpp | 2 +- 3 files changed, 160 insertions(+), 17 deletions(-) diff --git a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp index ab5a2089e..c93b61453 100644 --- a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp +++ b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.cpp @@ -41,6 +41,7 @@ ChatsFiltersTabs::ChatsFiltersTabs( }; _cachedBadgeHeight = one.height(); } + Ui::DiscreteSlider::setSelectOnPress(false); } int ChatsFiltersTabs::centerOfSection(int section) const { @@ -59,6 +60,14 @@ void ChatsFiltersTabs::fitWidthToSections() { const auto widths = countSectionsWidths(0); resizeToWidth(ranges::accumulate(widths, .0)); _lockedFromX = calculateLockedFromX(); + + { + _sections.clear(); + enumerateSections([&](Section §ion) { + _sections.emplace_back(not_null{ §ion }, 0, false); + return true; + }); + } } void ChatsFiltersTabs::setUnreadCount(int index, int unreadCount) { @@ -146,30 +155,44 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) { const auto clip = e->rect(); const auto range = getCurrentActiveRange(); + const auto activeIndex = activeSection(); auto index = 0; - enumerateSections([&](Section §ion) { - const auto activeWidth = _st.barSnapToLabel - ? section.contentWidth - : section.width; - const auto activeLeft = section.left - + (section.width - activeWidth) / 2; - const auto active = 1. - - std::clamp( - std::abs(range.left - activeLeft) / float64(range.width), - 0., - 1.); + auto raisedIndex = -1; + auto activeHorizontalShift = 0; + const auto drawSection = [&](Section §ion) { + // const auto activeWidth = _st.barSnapToLabel + // ? section.contentWidth + // : section.width; + + const auto horizontalShift = _sections[index].horizontalShift; + const auto shiftedLeft = section.left + horizontalShift; + if (_sections[index].raise) { + raisedIndex = index; + } + if (index == activeIndex) { + activeHorizontalShift = horizontalShift; + } + + // const auto activeLeft = shiftedLeft + // + (section.width - activeWidth) / 2; + // const auto active = 1. + // - std::clamp( + // std::abs(range.left - activeLeft) / float64(range.width), + // 0., + // 1.); + const auto active = (index == activeIndex) ? 1. : 0.; if (section.ripple) { const auto color = anim::color( _st.rippleBg, _st.rippleBgActive, active); - section.ripple->paint(p, section.left, 0, width(), &color); + section.ripple->paint(p, shiftedLeft, 0, width(), &color); if (section.ripple->empty()) { section.ripple.reset(); } } - const auto labelLeft = section.left + const auto labelLeft = shiftedLeft + (section.width - section.contentWidth) / 2; const auto rect = myrtlrect( labelLeft, @@ -214,7 +237,12 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) { } index++; return true; - }); + }; + enumerateSections(drawSection); + if (raisedIndex >= 0) { + index = raisedIndex; + drawSection(*_sections[raisedIndex].section); + } if (_st.barSnapToLabel) { const auto drawRect = [&](QRect rect, bool active) { const auto &bar = active ? _barActive : _bar; @@ -229,7 +257,11 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) { const auto till = std::min(range.left + range.width + add, width()); if (from < till) { drawRect( - myrtlrect(from, _st.barTop, till - from, _st.barStroke), + myrtlrect( + from, + _st.barTop, + till - from, + _st.barStroke).translated(activeHorizontalShift, 0), true); } } @@ -249,6 +281,14 @@ void ChatsFiltersTabs::mousePressEvent(QMouseEvent *e) { } } +void ChatsFiltersTabs::mouseMoveEvent(QMouseEvent *e) { + if (_reordering) { + Ui::RpWidget::mouseMoveEvent(e); + } else { + Ui::SettingsSlider::mouseMoveEvent(e); + } +} + void ChatsFiltersTabs::mouseReleaseEvent(QMouseEvent *e) { const auto mouseButton = e->button(); if (mouseButton == Qt::MouseButton::LeftButton) { @@ -256,7 +296,15 @@ void ChatsFiltersTabs::mouseReleaseEvent(QMouseEvent *e) { _lockedPressed = false; _lockedClicked.fire({}); } else { - Ui::SettingsSlider::mouseReleaseEvent(e); + if (_reordering) { + for (const auto §ion : _sections) { + if (section.section->ripple) { + section.section->ripple->lastStop(); + } + } + } else { + Ui::SettingsSlider::mouseReleaseEvent(e); + } } } else { Ui::RpWidget::mouseReleaseEvent(e); @@ -290,4 +338,77 @@ rpl::producer<> ChatsFiltersTabs::lockedClicked() const { return _lockedClicked.events(); } +int ChatsFiltersTabs::count() const { + return _sections.size(); +} + +void ChatsFiltersTabs::setHorizontalShift(int index, int shift) { + Expects(index >= 0 && index < _sections.size()); + + auto §ion = _sections[index]; + if (const auto delta = shift - section.horizontalShift) { + section.horizontalShift = shift; + update(); + } +} + +void ChatsFiltersTabs::setRaised(int index) { + _sections[index].raise = true; + update(); +} + +void ChatsFiltersTabs::reorderSections(int oldIndex, int newIndex) { + Expects(oldIndex >= 0 && oldIndex < _sections.size()); + Expects(newIndex >= 0 && newIndex < _sections.size()); + // Expects(!_inResize); + auto lefts = std::vector(); + enumerateSections([&](Section §ion) { + lefts.emplace_back(section.left); + return true; + }); + const auto wasActive = activeSection(); + + { + auto unreadCounts = base::flat_map(); + for (auto &[index, unread] : _unreadCounts) { + unreadCounts.emplace( + base::reorder_index(index, oldIndex, newIndex), + std::move(unread)); + } + _unreadCounts = std::move(unreadCounts); + } + + base::reorder(sectionsRef(), oldIndex, newIndex); + Ui::DiscreteSlider::setActiveSectionFast( + base::reorder_index(wasActive, oldIndex, newIndex)); + Ui::DiscreteSlider::stopAnimation(); + + { + _sections.clear(); + auto left = 0; + enumerateSections([&](Section §ion) { + _sections.emplace_back(not_null{ §ion }, 0, false); + section.left = left; + left += section.width; + return true; + }); + } + update(); +} + +not_null ChatsFiltersTabs::widgetAt( + int index) const { + Expects(index >= 0 && index < count()); + + return _sections[index].section; +} + +void ChatsFiltersTabs::setReordering(int value) { + _reordering = value; +} + +int ChatsFiltersTabs::reordering() const { + return _reordering; +} + } // namespace Ui diff --git a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h index ca311c7fe..3a027d278 100644 --- a/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h +++ b/Telegram/SourceFiles/ui/widgets/chat_filters_tabs_slider.h @@ -19,6 +19,8 @@ namespace Ui { class RpWidget; class SettingsSlider; +class ChatsFiltersTabsReorder; + class ChatsFiltersTabs final : public Ui::SettingsSlider { public: ChatsFiltersTabs( @@ -33,12 +35,30 @@ public: [[nodiscard]] rpl::producer contextMenuRequested() const; [[nodiscard]] rpl::producer<> lockedClicked() const; + void setHorizontalShift(int index, int shift); + void setRaised(int index); + [[nodiscard]] int count() const; + void reorderSections(int oldIndex, int newIndex); + [[nodiscard]] not_null widgetAt(int i) const; + void setReordering(int value); + [[nodiscard]] int reordering() const; + protected: + struct ShiftedSection { + not_null section; + int horizontalShift = 0; + bool raise = false; + }; + friend class ChatsFiltersTabsReorder; + void paintEvent(QPaintEvent *e) override; void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override; + std::vector _sections; + private: [[nodiscard]] QImage cacheUnreadCount(int count) const; [[nodiscard]] int calculateLockedFromX() const; @@ -62,6 +82,8 @@ private: std::optional _barActive; std::optional _lockCache; + int _reordering = 0; + rpl::lifetime _paletteLifetime; rpl::event_stream _contextMenuRequested; rpl::event_stream<> _lockedClicked; diff --git a/Telegram/SourceFiles/window/window_filters_menu.cpp b/Telegram/SourceFiles/window/window_filters_menu.cpp index db6e05c4a..1502db36b 100644 --- a/Telegram/SourceFiles/window/window_filters_menu.cpp +++ b/Telegram/SourceFiles/window/window_filters_menu.cpp @@ -220,7 +220,7 @@ void FiltersMenu::setupList() { _reorder = std::make_unique(_list, &_scroll); _reorder->updates( - ) | rpl::start_with_next([=](Ui::VerticalLayoutReorder::Single data) { + ) | rpl::start_with_next([=](Ui::VerticalLayoutReorder::Single data) { using State = Ui::VerticalLayoutReorder::State; if (data.state == State::Started) { ++_reordering;