diff --git a/Telegram/SourceFiles/history/view/history_view_react_button.cpp b/Telegram/SourceFiles/history/view/history_view_react_button.cpp index f62dffbd5..188022bfb 100644 --- a/Telegram/SourceFiles/history/view/history_view_react_button.cpp +++ b/Telegram/SourceFiles/history/view/history_view_react_button.cpp @@ -112,6 +112,10 @@ int Button::scroll() const { return _scroll; } +int Button::scrollMax() const { + return _expandedInnerHeight - _expandedHeight; +} + bool Button::expandUp() const { return (_expandDirection == ExpandDirection::Up); } @@ -191,6 +195,7 @@ void Button::updateExpandDirection(const ButtonParameters ¶meters) { maxAddedHeight, st::reactionCornerAddedHeightMax); _expandedHeight = _collapsed.height() + addedHeight; + _scroll = std::clamp(_scroll, 0, scrollMax()); if (parameters.reactionsCount < 2) { return; } @@ -717,6 +722,7 @@ void Manager::paintButton( const auto q = expanded ? &layeredPainter.emplace(&_expandedBuffer) : &p; const auto shadow = context.st->shadowFg()->c; const auto background = context.st->windowBg()->c; + setBackground(background); if (expanded) { q->fillRect(QRect(QPoint(), size), context.st->windowBg()); } else { @@ -745,6 +751,9 @@ void Manager::paintButton( if (current && expanded) { _showingAll = true; } + if (expanded) { + paintInnerGradients(*q, background, button, expandRatio); + } } else { const auto source = validateEmoji(frameIndex, scale); p.drawImage(mainEmojiPosition, _cacheParts, source); @@ -766,6 +775,48 @@ void Manager::paintButton( } } +void Manager::paintInnerGradients( + Painter &p, + const QColor &background, + not_null button, + float64 expandRatio) { + const auto scroll = button->scroll(); + const auto endScroll = button->scrollMax() - scroll; + const auto size = st::reactionGradientSize; + const auto ensureGradient = [&](QImage &gradient, bool top) { + if (!gradient.isNull()) { + return; + } + const auto ratio = style::DevicePixelRatio(); + gradient = Images::GenerateShadow( + size * ratio, + top ? 255 : 0, + top ? 0 : 255, + background); + gradient.setDevicePixelRatio(ratio); + }; + ensureGradient(_topGradient, true); + ensureGradient(_bottomGradient, false); + const auto paintGradient = [&](QImage &gradient, int scrolled, int top) { + if (scrolled <= 0) { + return; + } + const auto opacity = (expandRatio * scrolled) + / st::reactionGradientFadeSize; + p.setOpacity(opacity); + p.drawImage( + QRect(0, top, _outer.width(), size), + gradient, + QRect(QPoint(), gradient.size())); + }; + const auto up = button->expandUp(); + const auto start = st::reactionGradientStart; + paintGradient(_topGradient, up ? endScroll : scroll, start); + const auto bottomStart = button->geometry().height() - start - size; + paintGradient(_bottomGradient, up ? scroll : endScroll, bottomStart); + p.setOpacity(1.); +} + void Manager::overlayExpandedBorder( Painter &p, QSize size, @@ -1091,16 +1142,22 @@ QRect Manager::validateEmoji(int frameIndex, float64 scale) { return result; } +void Manager::setBackground(const QColor &background) { + if (_background == background) { + return; + } + _background = background; + _topGradient = QImage(); + _bottomGradient = QImage(); + ranges::fill(_validBg, false); +} + QRect Manager::validateFrame( int frameIndex, float64 scale, const QColor &background, const QColor &shadow) { applyPatternedShadow(shadow); - if (_background != background) { - _background = background; - ranges::fill(_validBg, false); - } const auto result = cacheRect(frameIndex, kBgCacheIndex); if (_validBg[frameIndex]) { diff --git a/Telegram/SourceFiles/history/view/history_view_react_button.h b/Telegram/SourceFiles/history/view/history_view_react_button.h index c14ae27a9..ef2f98345 100644 --- a/Telegram/SourceFiles/history/view/history_view_react_button.h +++ b/Telegram/SourceFiles/history/view/history_view_react_button.h @@ -78,6 +78,7 @@ public: [[nodiscard]] QRect geometry() const; [[nodiscard]] int expandedHeight() const; [[nodiscard]] int scroll() const; + [[nodiscard]] int scrollMax() const; [[nodiscard]] float64 currentScale() const; [[nodiscard]] float64 currentOpacity() const; [[nodiscard]] bool consumeWheelEvent(not_null e); @@ -176,6 +177,11 @@ private: float64 scale, QPoint position, QPoint mainEmojiPosition); + void paintInnerGradients( + Painter &p, + const QColor &background, + not_null button, + float64 expandRatio); void overlayExpandedBorder( Painter &p, QSize size, @@ -202,6 +208,7 @@ private: float64 scale, const QColor &background, const QColor &shadow); + void setBackground(const QColor &background); void setSelectedIcon(int index) const; @@ -228,10 +235,13 @@ private: QImage _cacheParts; QImage _shadowBuffer; QImage _expandedBuffer; + QImage _topGradient; + QImage _bottomGradient; std::array _validBg = { { false } }; std::array _validShadow = { { false } }; std::array _validEmoji = { { false } }; QColor _background; + QColor _gradient; QColor _shadow; std::shared_ptr _mainReactionMedia;