diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 651d0c8da..7c8b88e0d 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -245,6 +245,7 @@ mediaviewTextTop: 26px; mediaviewControlSize: 90px; mediaviewIconSize: size(46px, 54px); +mediaviewIconOver: 36px; mediaviewWaitHide: 2000; mediaviewHideDuration: 1000; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp index a4d7c8875..35468706b 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/gl/gl_shader.h" #include "ui/painter.h" #include "media/streaming/media_streaming_common.h" +#include "platform/platform_overlay_widget.h" #include "base/platform/base_platform_info.h" #include "core/crash_reports.h" #include "styles/style_media_view.h" @@ -27,7 +28,7 @@ constexpr auto kFooterOffset = kSaveMsgOffset + 4; constexpr auto kCaptionOffset = kFooterOffset + 4; constexpr auto kGroupThumbsOffset = kCaptionOffset + 4; constexpr auto kControlsOffset = kGroupThumbsOffset + 4; -constexpr auto kControlValues = 2 * 4 + 4 * 4; +constexpr auto kControlValues = 4 * 4 + 4 * 4; // over + icon [[nodiscard]] ShaderPart FragmentApplyControlsFade() { return { @@ -557,28 +558,37 @@ void OverlayWidget::RendererGL::paintControlsStart() { void OverlayWidget::RendererGL::paintControl( OverState control, - QRect outer, - float64 outerOpacity, + QRect over, + float64 overOpacity, QRect inner, float64 innerOpacity, const style::icon &icon) { const auto meta = ControlMeta(control); Assert(meta.icon == &icon); - const auto &bg = st::mediaviewControlBg->c; - const auto bgAlpha = int(base::SafeRound(bg.alpha() * outerOpacity)); + const auto overAlpha = overOpacity * kOverBackgroundOpacity; const auto offset = kControlsOffset + (meta.index * kControlValues) / 4; - const auto fgOffset = offset + 2; - const auto bgRect = transformRect(outer); + const auto fgOffset = offset + 4; + const auto overRect = _controlsImage.texturedRect( + over, + _controlsTextures[kControlsCount]); + const auto overGeometry = transformRect(over); const auto iconRect = _controlsImage.texturedRect( inner, _controlsTextures[meta.index]); const auto iconGeometry = transformRect(iconRect.geometry); const GLfloat coords[] = { - bgRect.left(), bgRect.top(), - bgRect.right(), bgRect.top(), - bgRect.right(), bgRect.bottom(), - bgRect.left(), bgRect.bottom(), + overGeometry.left(), overGeometry.top(), + overRect.texture.left(), overRect.texture.bottom(), + + overGeometry.right(), overGeometry.top(), + overRect.texture.right(), overRect.texture.bottom(), + + overGeometry.right(), overGeometry.bottom(), + overRect.texture.right(), overRect.texture.top(), + + overGeometry.left(), overGeometry.bottom(), + overRect.texture.left(), overRect.texture.top(), iconGeometry.left(), iconGeometry.top(), iconRect.texture.left(), iconRect.texture.bottom(), @@ -592,27 +602,22 @@ void OverlayWidget::RendererGL::paintControl( iconGeometry.left(), iconGeometry.bottom(), iconRect.texture.left(), iconRect.texture.top(), }; - if (!outer.isEmpty() && bgAlpha > 0) { + _controlsProgram->bind(); + _controlsProgram->setUniformValue("viewport", _uniformViewport); + if (!over.isEmpty() && overOpacity > 0) { _contentBuffer->write( offset * 4 * sizeof(GLfloat), coords, sizeof(coords)); - _fillProgram->bind(); - _fillProgram->setUniformValue("viewport", _uniformViewport); - FillRectangle( - *_f, - &*_fillProgram, - offset, - QColor(bg.red(), bg.green(), bg.blue(), bgAlpha)); + _controlsProgram->setUniformValue("g_opacity", GLfloat(overAlpha)); + FillTexturedRectangle(*_f, &*_controlsProgram, offset); } else { _contentBuffer->write( fgOffset * 4 * sizeof(GLfloat), coords + (fgOffset - offset) * 4, sizeof(coords) - (fgOffset - offset) * 4 * sizeof(GLfloat)); } - _controlsProgram->bind(); _controlsProgram->setUniformValue("g_opacity", GLfloat(innerOpacity)); - _controlsProgram->setUniformValue("viewport", _uniformViewport); FillTexturedRectangle(*_f, &*_controlsProgram, fgOffset); } @@ -645,6 +650,8 @@ void OverlayWidget::RendererGL::validateControls() { maxWidth = std::max(meta.icon->width(), maxWidth); fullHeight += meta.icon->height(); } + maxWidth = std::max(st::mediaviewIconOver, maxWidth); + fullHeight += st::mediaviewIconOver; auto image = QImage( QSize(maxWidth, fullHeight) * _factor, QImage::Format_ARGB32_Premultiplied); @@ -661,6 +668,15 @@ void OverlayWidget::RendererGL::validateControls() { meta.icon->size() * _factor); height += meta.icon->height(); } + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(OverBackgroundColor()); + p.drawEllipse( + QRect(0, height, st::mediaviewIconOver, st::mediaviewIconOver)); + _controlsTextures[index++] = QRect( + QPoint(0, height) * _factor, + QSize(st::mediaviewIconOver, st::mediaviewIconOver) * _factor); + height += st::mediaviewIconOver; } _controlsImage.setImage(std::move(image)); } diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h index 2cf5994a2..ba04535de 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h @@ -60,8 +60,8 @@ private: void paintControlsStart() override; void paintControl( OverState control, - QRect outer, - float64 outerOpacity, + QRect over, + float64 overOpacity, QRect inner, float64 innerOpacity, const style::icon &icon) override; @@ -135,7 +135,9 @@ private: static constexpr auto kControlsCount = 5; [[nodiscard]] static Control ControlMeta(OverState control); - std::array _controlsTextures; + + // Last one is for the over circle image. + std::array _controlsTextures; QRect _shadowTopTexture; QRect _shadowBottomTexture; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp index 60707c97a..16b54a99f 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_raster.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/painter.h" #include "media/view/media_view_pip.h" +#include "platform/platform_overlay_widget.h" #include "styles/style_media_view.h" namespace Media::View { @@ -173,22 +174,20 @@ void OverlayWidget::RendererSW::paintControlsStart() { void OverlayWidget::RendererSW::paintControl( OverState control, - QRect outer, - float64 outerOpacity, + QRect over, + float64 overOpacity, QRect inner, float64 innerOpacity, const style::icon &icon) { - if (!outer.isEmpty() && !outer.intersects(_clipOuter)) { + if (!over.isEmpty() && !over.intersects(_clipOuter)) { return; } - if (!outer.isEmpty() && outerOpacity > 0) { - _p->setOpacity(outerOpacity); - for (const auto &rect : *_clip) { - const auto fill = outer.intersected(rect); - if (!fill.isEmpty()) { - _p->fillRect(fill, st::mediaviewControlBg); - } + if (!over.isEmpty() && overOpacity > 0) { + if (_overControlImage.isNull()) { + validateOverControlImage(); } + _p->setOpacity(overOpacity); + _p->drawImage(over.topLeft(), _overControlImage); } if (inner.intersects(_clipOuter)) { _p->setOpacity(innerOpacity); @@ -220,4 +219,22 @@ void OverlayWidget::RendererSW::paintRoundedCorners(int radius) { // The RpWindow rounding overlay will do the job. } +void OverlayWidget::RendererSW::validateOverControlImage() { + const auto size = QSize(st::mediaviewIconOver, st::mediaviewIconOver); + const auto alpha = base::SafeRound(kOverBackgroundOpacity * 255); + _overControlImage = QImage( + size * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); + _overControlImage.setDevicePixelRatio(style::DevicePixelRatio()); + _overControlImage.fill(Qt::transparent); + + Painter p(&_overControlImage); + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + auto color = OverBackgroundColor(); + color.setAlpha(alpha); + p.setBrush(color); + p.drawEllipse(QRect(QPoint(), size)); +} + } // namespace Media::View diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_raster.h b/Telegram/SourceFiles/media/view/media_view_overlay_raster.h index 25d3d3248..9fb6e42cb 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_raster.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_raster.h @@ -43,8 +43,8 @@ private: void paintControlsStart() override; void paintControl( OverState control, - QRect outer, - float64 outerOpacity, + QRect over, + float64 overOpacity, QRect inner, float64 innerOpacity, const style::icon &icon) override; @@ -53,6 +53,8 @@ private: void paintGroupThumbs(QRect outer, float64 opacity) override; void paintRoundedCorners(int radius) override; + void validateOverControlImage(); + [[nodiscard]] static QRect TransformRect(QRectF geometry, int rotation); const not_null _owner; @@ -62,6 +64,8 @@ private: const QRegion *_clip = nullptr; QRect _clipOuter; + QImage _overControlImage; + }; } // namespace Media::View diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h b/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h index 2ecbccf27..f4a8cb9bb 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_renderer.h @@ -30,8 +30,8 @@ public: virtual void paintControlsStart() = 0; virtual void paintControl( OverState control, - QRect outer, - float64 outerOpacity, + QRect over, + float64 overOpacity, QRect inner, float64 innerOpacity, const style::icon &icon) = 0; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index b36d7a005..5c2cd1c77 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -781,10 +781,15 @@ void OverlayWidget::updateGeometryToScreen(bool inMove) { } void OverlayWidget::updateControlsGeometry() { + const auto overRect = QRect( + QPoint(), + QSize(st::mediaviewIconOver, st::mediaviewIconOver)); const auto navSkip = st::mediaviewHeaderTop; _leftNav = QRect(0, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); + _leftNavOver = style::centerrect(_leftNav, overRect); _leftNavIcon = style::centerrect(_leftNav, st::mediaviewLeft); _rightNav = QRect(width() - st::mediaviewControlSize, navSkip, st::mediaviewControlSize, height() - 2 * navSkip); + _rightNavOver = style::centerrect(_rightNav, overRect); _rightNavIcon = style::centerrect(_rightNav, st::mediaviewRight); _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); @@ -1055,6 +1060,9 @@ void OverlayWidget::updateControls() { updateThemePreviewGeometry(); + const auto overRect = QRect( + QPoint(), + QSize(st::mediaviewIconOver, st::mediaviewIconOver)); _saveVisible = contentCanBeSaved(); _rotateVisible = !_themePreviewShown; const auto navRect = [&](int i) { @@ -1064,10 +1072,13 @@ void OverlayWidget::updateControls() { st::mediaviewIconSize.height()); }; _saveNav = navRect(_rotateVisible ? 3 : 2); + _saveNavOver = style::centerrect(_saveNav, overRect); _saveNavIcon = style::centerrect(_saveNav, st::mediaviewSave); _rotateNav = navRect(2); + _rotateNavOver = style::centerrect(_rotateNav, overRect); _rotateNavIcon = style::centerrect(_rotateNav, st::mediaviewRotate); _moreNav = navRect(1); + _moreNavOver = style::centerrect(_moreNav, overRect); _moreNavIcon = style::centerrect(_moreNav, st::mediaviewMore); const auto dNow = QDateTime::currentDateTime(); @@ -1374,11 +1385,11 @@ bool OverlayWidget::updateControlsAnimation(crl::time now) { _helper->setControlsOpacity(_controlsOpacity.current()); const auto content = finalContentRect(); const auto toUpdate = QRegion() - + (_over == OverLeftNav ? _leftNav : _leftNavIcon) - + (_over == OverRightNav ? _rightNav : _rightNavIcon) - + _saveNavIcon - + _rotateNavIcon - + _moreNavIcon + + (_over == OverLeftNav ? _leftNavOver : _leftNavIcon) + + (_over == OverRightNav ? _rightNavOver : _rightNavIcon) + + (_over == OverSave ? _saveNavOver : _saveNavIcon) + + (_over == OverRotate ? _rotateNavOver : _rotateNavIcon) + + (_over == OverMore ? _moreNavOver : _moreNavIcon) + _headerNav + _nameNav + _dateNav @@ -4159,7 +4170,7 @@ void OverlayWidget::paintControls( struct Control { OverState state = OverNone; bool visible = false; - const QRect &outer; + const QRect &over; const QRect &inner; const style::icon &icon; bool nonbright = false; @@ -4170,33 +4181,33 @@ void OverlayWidget::paintControls( { OverLeftNav, _leftNavVisible, - _leftNav, + _leftNavOver, _leftNavIcon, st::mediaviewLeft, true }, { OverRightNav, _rightNavVisible, - _rightNav, + _rightNavOver, _rightNavIcon, st::mediaviewRight, true }, { OverSave, _saveVisible, - kEmpty, + _saveNavOver, _saveNavIcon, st::mediaviewSave }, { OverRotate, _rotateVisible, - kEmpty, + _rotateNavOver, _rotateNavIcon, st::mediaviewRotate }, { OverMore, true, - kEmpty, + _moreNavOver, _moreNavIcon, st::mediaviewMore }, }; @@ -4211,7 +4222,7 @@ void OverlayWidget::paintControls( const auto icon = controlOpacity(progress, control.nonbright); renderer->paintControl( control.state, - control.outer, + control.over, bg * opacity, control.inner, icon * opacity, diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 2411089f9..f2b40976d 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -495,9 +495,12 @@ private: std::unique_ptr _collage; std::optional _collageData; - QRect _leftNav, _leftNavIcon, _rightNav, _rightNavIcon; + QRect _leftNav, _leftNavOver, _leftNavIcon; + QRect _rightNav, _rightNavOver, _rightNavIcon; QRect _headerNav, _nameNav, _dateNav; - QRect _rotateNav, _rotateNavIcon, _saveNav, _saveNavIcon, _moreNav, _moreNavIcon; + QRect _rotateNav, _rotateNavOver, _rotateNavIcon; + QRect _saveNav, _saveNavOver, _saveNavIcon; + QRect _moreNav, _moreNavOver, _moreNavIcon; bool _leftNavVisible = false; bool _rightNavVisible = false; bool _saveVisible = false; diff --git a/Telegram/SourceFiles/platform/platform_overlay_widget.cpp b/Telegram/SourceFiles/platform/platform_overlay_widget.cpp index af4a98858..39b9394cf 100644 --- a/Telegram/SourceFiles/platform/platform_overlay_widget.cpp +++ b/Telegram/SourceFiles/platform/platform_overlay_widget.cpp @@ -13,6 +13,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/abstract_button.h" #include "styles/style_media_view.h" +namespace Media::View { + +QColor OverBackgroundColor() { + auto c1 = st::mediaviewBg->c; + auto c2 = QColor(255, 255, 255); + const auto mix = [&](int a, int b) { + constexpr auto k1 = 0.15 * 0.85 / (1. - 0.85 * 0.85); + constexpr auto k2 = 0.15 / (1. - 0.85 * 0.85); + return int(a * k1 + b * k2); + }; + return QColor( + mix(c1.red(), c2.red()), + mix(c1.green(), c2.green()), + mix(c1.blue(), c2.blue())); +} + +} // namespace Media::View + namespace Platform { namespace { @@ -120,8 +138,9 @@ object_ptr DefaultOverlayWidgetHelper::Buttons::create( current = maximized ? &st::mediaviewTitleRestore : icon; } const auto alpha = progress * kOverBackgroundOpacity; - const auto ialpha = anim::interpolate(0, 255, alpha); - state->frame.fill(QColor(255, 255, 255, ialpha)); + auto color = OverBackgroundColor(); + color.setAlpha(anim::interpolate(0, 255, alpha)); + state->frame.fill(color); auto q = QPainter(&state->frame); const auto normal = maximized diff --git a/Telegram/SourceFiles/platform/platform_overlay_widget.h b/Telegram/SourceFiles/platform/platform_overlay_widget.h index 307e5282d..8ba537d84 100644 --- a/Telegram/SourceFiles/platform/platform_overlay_widget.h +++ b/Telegram/SourceFiles/platform/platform_overlay_widget.h @@ -19,7 +19,8 @@ namespace Media::View { inline constexpr auto kMaximizedIconOpacity = 0.6; inline constexpr auto kNormalIconOpacity = 0.9; -inline constexpr auto kOverBackgroundOpacity = 0.15; +inline constexpr auto kOverBackgroundOpacity = 0.2775; +[[nodiscard]] QColor OverBackgroundColor(); } // namespace Media::View