diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index aa5e8bdac..c21d75496 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -351,11 +351,7 @@ filtersRemove: IconButton(stickersRemove) { emojiPanMargins: margins(10px, 10px, 10px, 10px); -emojiTabs: SettingsSlider(defaultTabsSlider) { - height: 43px; - barTop: 40px; - labelTop: 12px; -} +emojiTabs: defaultTabsSlider; emojiCategoryIconTop: 6px; emojiPanAnimation: PanelAnimation(defaultPanelAnimation) { diff --git a/Telegram/SourceFiles/info/downloads/info_downloads_inner_widget.h b/Telegram/SourceFiles/info/downloads/info_downloads_inner_widget.h index 2d2047f5e..65b55f4d0 100644 --- a/Telegram/SourceFiles/info/downloads/info_downloads_inner_widget.h +++ b/Telegram/SourceFiles/info/downloads/info_downloads_inner_widget.h @@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unique_qptr.h" namespace Ui { -class SettingsSlider; class VerticalLayout; class SearchFieldController; } // namespace Ui diff --git a/Telegram/SourceFiles/info/info_section_widget.h b/Telegram/SourceFiles/info/info_section_widget.h index 8ff1dbcfa..f53ed505f 100644 --- a/Telegram/SourceFiles/info/info_section_widget.h +++ b/Telegram/SourceFiles/info/info_section_widget.h @@ -10,10 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include "window/section_widget.h" -namespace Ui { -class SettingsSlider; -} // namespace Ui - namespace Window { class ConnectionState; } // namespace Window diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h index 47215d340..5445185e1 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.h +++ b/Telegram/SourceFiles/info/info_wrap_widget.h @@ -15,7 +15,6 @@ enum class SharedMediaType : signed char; } // namespace Storage namespace Ui { -class SettingsSlider; class FadeShadow; class PlainShadow; class PopupMenu; diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.h b/Telegram/SourceFiles/info/media/info_media_inner_widget.h index 4e305de40..a3e485960 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.h @@ -14,7 +14,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/media/info_media_list_widget.h" namespace Ui { -class SettingsSlider; class VerticalLayout; class SearchFieldController; } // namespace Ui diff --git a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h index 3e6819af9..0aaeed54d 100644 --- a/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h +++ b/Telegram/SourceFiles/info/stories/info_stories_inner_widget.h @@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unique_qptr.h" namespace Ui { -class SettingsSlider; class VerticalLayout; } // namespace Ui diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp index ff30d88c7..174d84d29 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp @@ -13,7 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { -DiscreteSlider::DiscreteSlider(QWidget *parent) : RpWidget(parent) { +DiscreteSlider::DiscreteSlider(QWidget *parent, bool snapToLabel) +: RpWidget(parent) +, _snapToLabel(snapToLabel) { setCursor(style::cur_pointer); } @@ -80,9 +82,23 @@ void DiscreteSlider::setSections(const std::vector &labels) { resizeToWidth(width()); } -int DiscreteSlider::getCurrentActiveLeft() { - const auto left = _sections.empty() ? 0 : _sections[_selected].left; - return _a_left.value(left); +DiscreteSlider::Range DiscreteSlider::getFinalActiveRange() const { + const auto raw = _sections.empty() ? nullptr : &_sections[_selected]; + if (!raw) { + return { 0, 0 }; + } + const auto width = _snapToLabel + ? std::min(raw->width, raw->label.maxWidth()) + : raw->width; + return { raw->left + ((raw->width - width) / 2), width }; +} + +DiscreteSlider::Range DiscreteSlider::getCurrentActiveRange() const { + const auto to = getFinalActiveRange(); + return { + int(base::SafeRound(_a_left.value(to.left))), + int(base::SafeRound(_a_width.value(to.width))), + }; } template @@ -138,11 +154,13 @@ void DiscreteSlider::setSelectedSection(int index) { if (index < 0 || index >= _sections.size()) return; if (_selected != index) { - auto from = _sections[_selected].left; + const auto from = getFinalActiveRange(); _selected = index; - auto to = _sections[_selected].left; - auto duration = getAnimationDuration(); - _a_left.start([this] { update(); }, from, to, duration); + const auto to = getFinalActiveRange(); + const auto duration = getAnimationDuration(); + const auto updater = [=] { update(); }; + _a_left.start(updater, from.left, to.left, duration); + _a_width.start(updater, from.width, to.width, duration); _callbackAfterMs = crl::now() + duration; } } @@ -166,7 +184,7 @@ DiscreteSlider::Section::Section( SettingsSlider::SettingsSlider( QWidget *parent, const style::SettingsSlider &st) -: DiscreteSlider(parent) +: DiscreteSlider(parent, st.barSnapToLabel) , _st(st) { if (_st.barRadius > 0) { _bar.emplace(_st.barRadius, _st.barFg); @@ -299,7 +317,7 @@ void SettingsSlider::paintEvent(QPaintEvent *e) { Painter p(this); auto clip = e->rect(); - auto activeLeft = getCurrentActiveLeft(); + auto range = getCurrentActiveRange(); const auto drawRect = [&](QRect rect, bool active = false) { const auto &bar = active ? _barActive : _bar; @@ -310,9 +328,14 @@ void SettingsSlider::paintEvent(QPaintEvent *e) { } }; enumerateSections([&](Section §ion) { + const auto activeWidth = _st.barSnapToLabel + ? section.label.maxWidth() + : section.width; + const auto activeLeft = section.left + + (section.width - activeWidth) / 2; auto active = 1. - std::clamp( - qAbs(activeLeft - section.left) / float64(section.width), + qAbs(range.left - activeLeft) / float64(section.width), 0., 1.); if (section.ripple) { @@ -322,36 +345,47 @@ void SettingsSlider::paintEvent(QPaintEvent *e) { section.ripple.reset(); } } - auto from = section.left, tofill = section.width; - if (activeLeft > from) { - auto fill = qMin(tofill, activeLeft - from); - drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke)); - from += fill; - tofill -= fill; - } - if (activeLeft + section.width > from) { - if (auto fill = qMin(tofill, activeLeft + section.width - from)) { - drawRect( - myrtlrect(from, _st.barTop, fill, _st.barStroke), - true); + if (!_st.barSnapToLabel) { + auto from = activeLeft, tofill = activeWidth; + if (range.left > from) { + auto fill = qMin(tofill, range.left - from); + drawRect(myrtlrect(from, _st.barTop, fill, _st.barStroke)); from += fill; tofill -= fill; } + if (range.left + activeWidth > from) { + if (auto fill = qMin(tofill, range.left + activeWidth - from)) { + drawRect( + myrtlrect(from, _st.barTop, fill, _st.barStroke), + true); + from += fill; + tofill -= fill; + } + } + if (tofill) { + drawRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke)); + } } - if (tofill) { - drawRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke)); - } - if (myrtlrect(section.left, _st.labelTop, section.width, _st.labelStyle.font->height).intersects(clip)) { + const auto labelLeft = section.left + (section.width - section.label.maxWidth()) / 2; + if (myrtlrect(labelLeft, _st.labelTop, section.label.maxWidth(), _st.labelStyle.font->height).intersects(clip)) { p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active)); section.label.drawLeft( p, - section.left + (section.width - section.label.maxWidth()) / 2, + labelLeft, _st.labelTop, section.label.maxWidth(), width()); } return true; }); + if (_st.barSnapToLabel) { + const auto add = _st.barStroke / 2; + const auto from = std::max(range.left - add, 0); + const auto till = std::min(range.left + range.width + add, width()); + if (from < till) { + drawRect(myrtlrect(from, _st.barTop, till - from, _st.barStroke), true); + } + } } } // namespace Ui diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h index 017108741..e1513e693 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h @@ -18,7 +18,7 @@ class RippleAnimation; class DiscreteSlider : public RpWidget { public: - DiscreteSlider(QWidget *parent); + DiscreteSlider(QWidget *parent, bool snapToLabel); void addSection(const QString &label); void setSections(const std::vector &labels); @@ -49,10 +49,15 @@ protected: Ui::Text::String label; std::unique_ptr ripple; }; + struct Range { + int left = 0; + int width = 0; + }; - int getCurrentActiveLeft(); + [[nodiscard]] Range getFinalActiveRange() const; + [[nodiscard]] Range getCurrentActiveRange() const; - int getSectionsCount() const { + [[nodiscard]] int getSectionsCount() const { return _sections.size(); } @@ -67,6 +72,7 @@ protected: void stopAnimation() { _a_left.stop(); + _a_width.stop(); } void setSelectOnPress(bool selectOnPress); @@ -82,12 +88,14 @@ private: std::vector
_sections; int _activeIndex = 0; bool _selectOnPress = true; + bool _snapToLabel = false; rpl::event_stream _sectionActivated; int _pressed = -1; int _selected = 0; Ui::Animations::Simple _a_left; + Ui::Animations::Simple _a_width; int _timerId = -1; crl::time _callbackAfterMs = 0; diff --git a/Telegram/codegen b/Telegram/codegen index 5a11029c4..2d03abc7d 160000 --- a/Telegram/codegen +++ b/Telegram/codegen @@ -1 +1 @@ -Subproject commit 5a11029c461416407a423ac9921356fba0088ab6 +Subproject commit 2d03abc7de8558ae8862688a226b3d5a817dc466 diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 0f25a9451..5f2e0a32b 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 0f25a9451012c7fba93777a009f3b5dcc0f1ca89 +Subproject commit 5f2e0a32b12df1468419b123ac8fb4bb17cf47cc