diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index 9456f65183..cfbd50429f 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -972,7 +972,11 @@ void GroupCall::markTrackShown(const VideoEndpoint &endpoint, bool shown) { _videoStreamShownUpdates.fire_copy({ endpoint, shown }); } if (shown && changed && endpoint.type == VideoEndpointType::Screen) { - pinVideoEndpoint(endpoint); + crl::on_main(this, [=] { + if (_shownVideoTracks.contains(endpoint)) { + pinVideoEndpoint(endpoint); + } + }); } } diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index a3d143c404..080f304147 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -1189,8 +1189,9 @@ base::unique_qptr Members::Controller::createRowContextMenu( if (const auto real = _call->lookupReal()) { auto oneFound = false; auto hasTwoOrMore = false; + const auto &shown = _call->shownVideoTracks(); for (const auto &[endpoint, track] : _call->activeVideoTracks()) { - if (_call->shownVideoTracks().contains(endpoint)) { + if (shown.contains(endpoint)) { if (oneFound) { hasTwoOrMore = true; break; @@ -1202,36 +1203,36 @@ base::unique_qptr Members::Controller::createRowContextMenu( if (participant && hasTwoOrMore) { const auto &large = _call->videoEndpointLarge(); const auto pinned = _call->videoEndpointPinned(); - const auto &camera = computeCameraEndpoint(participant); - const auto &screen = computeScreenEndpoint(participant); - if (!camera.empty()) { - if (pinned && large.id == camera) { + const auto camera = VideoEndpoint{ + VideoEndpointType::Camera, + participantPeer, + computeCameraEndpoint(participant) + }; + const auto screen = VideoEndpoint{ + VideoEndpointType::Screen, + participantPeer, + computeScreenEndpoint(participant) + }; + if (shown.contains(camera)) { + if (pinned && large == camera) { result->addAction( tr::lng_group_call_context_unpin_camera(tr::now), - [=] { _call->pinVideoEndpoint(VideoEndpoint()); }); + [=] { _call->pinVideoEndpoint({}); }); } else { result->addAction( tr::lng_group_call_context_pin_camera(tr::now), - [=] { _call->pinVideoEndpoint(VideoEndpoint{ - VideoEndpointType::Camera, - participantPeer, - camera }); - }); + [=] { _call->pinVideoEndpoint(camera); }); } } - if (!screen.empty()) { - if (pinned && large.id == screen) { + if (shown.contains(screen)) { + if (pinned && large == screen) { result->addAction( tr::lng_group_call_context_unpin_screen(tr::now), - [=] { _call->pinVideoEndpoint(VideoEndpoint()); }); + [=] { _call->pinVideoEndpoint({}); }); } else { result->addAction( tr::lng_group_call_context_pin_screen(tr::now), - [=] { _call->pinVideoEndpoint(VideoEndpoint{ - VideoEndpointType::Screen, - participantPeer, - screen }); - }); + [=] { _call->pinVideoEndpoint(screen); }); } } } diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index ab312d7865..5a0acd5a17 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -1359,7 +1359,7 @@ void Panel::chooseShareScreenSource() { } return nullptr; }(); - if (!screencastFromPeer) { + if (!screencastFromPeer || _call->isSharingScreen()) { choose(); return; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp index d4b9e53c40..0ead4b8634 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport.cpp @@ -29,6 +29,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include namespace Calls::Group { +namespace { + +[[nodiscard]] QRect InterpolateRect(QRect a, QRect b, float64 ratio) { + const auto left = anim::interpolate(a.x(), b.x(), ratio); + const auto top = anim::interpolate(a.y(), b.y(), ratio); + const auto right = anim::interpolate( + a.x() + a.width(), + b.x() + b.width(), + ratio); + const auto bottom = anim::interpolate( + a.y() + a.height(), + b.y() + b.height(), + ratio); + return { left, top, right - left, bottom - top }; +} + +} // namespace Viewport::Viewport(not_null parent, PanelMode mode) : _mode(mode) @@ -230,7 +247,9 @@ void Viewport::remove(const VideoEndpoint &endpoint) { return; } const auto removing = i->get(); - if (_large == removing) { + const auto largeRemoved = (_large == removing); + if (largeRemoved) { + prepareLargeChangeAnimation(); _large = nullptr; } if (_selected.tile == removing) { @@ -239,18 +258,278 @@ void Viewport::remove(const VideoEndpoint &endpoint) { if (_pressed.tile == removing) { setPressed({}); } + for (auto &geometry : _startTilesLayout.list) { + if (geometry.tile == removing) { + geometry.tile = nullptr; + } + } + for (auto &geometry : _finishTilesLayout.list) { + if (geometry.tile == removing) { + geometry.tile = nullptr; + } + } _tiles.erase(i); - updateTilesGeometry(); + if (largeRemoved) { + startLargeChangeAnimation(); + } else { + updateTilesGeometry(); + } +} + +void Viewport::prepareLargeChangeAnimation() { + if (!wide()) { + return; + } else if (_largeChangeAnimation.animating()) { + updateTilesAnimated(); + const auto field = _finishTilesLayout.useColumns + ? &Geometry::columns + : &Geometry::rows; + for (auto &finish : _finishTilesLayout.list) { + const auto tile = finish.tile; + if (!tile) { + continue; + } + finish.*field = tile->geometry(); + } + _startTilesLayout = std::move(_finishTilesLayout); + _largeChangeAnimation.stop(); + + _startTilesLayout.list.erase( + ranges::remove(_startTilesLayout.list, nullptr, &Geometry::tile), + end(_startTilesLayout.list)); + } else { + _startTilesLayout = applyLarge(std::move(_startTilesLayout)); + } +} + +void Viewport::startLargeChangeAnimation() { + Expects(!_largeChangeAnimation.animating()); + + if (!wide() + || anim::Disabled() + || (_startTilesLayout.list.size() < 2) + || !_opengl + || widget()->size().isEmpty()) { + updateTilesGeometry(); + return; + } + _finishTilesLayout = applyLarge( + countWide(widget()->width(), widget()->height())); + if (_finishTilesLayout.list.empty() + || _finishTilesLayout.outer != _startTilesLayout.outer) { + updateTilesGeometry(); + return; + } + _largeChangeAnimation.start( + [=] { updateTilesAnimated(); }, + 0., + 1., + st::slideDuration); +} + +Viewport::Layout Viewport::applyLarge(Layout layout) const { + auto &list = layout.list; + if (!_large) { + return layout; + } + const auto i = ranges::find(list, _large, &Geometry::tile); + if (i == end(list)) { + return layout; + } + const auto field = layout.useColumns + ? &Geometry::columns + : &Geometry::rows; + const auto fullWidth = layout.outer.width(); + const auto fullHeight = layout.outer.height(); + const auto largeRect = (*i).*field; + const auto largeLeft = largeRect.x(); + const auto largeTop = largeRect.y(); + const auto largeRight = largeLeft + largeRect.width(); + const auto largeBottom = largeTop + largeRect.height(); + const auto largeCenter = largeRect.center(); + for (auto &geometry : list) { + if (geometry.tile == _large) { + geometry.*field = { QPoint(), layout.outer }; + } else if (layout.useColumns) { + auto &rect = geometry.columns; + const auto center = rect.center(); + if (center.x() < largeLeft) { + rect = rect.translated(-largeLeft, 0); + } else if (center.x() > largeRight) { + rect = rect.translated(fullWidth - largeRight, 0); + } else if (center.y() < largeTop) { + rect = QRect( + 0, + rect.y() - largeTop, + fullWidth, + rect.height()); + } else if (center.y() > largeBottom) { + rect = QRect( + 0, + rect.y() + (fullHeight - largeBottom), + fullWidth, + rect.height()); + } + } else { + auto &rect = geometry.rows; + const auto center = rect.center(); + if (center.y() < largeTop) { + rect = rect.translated(0, -largeTop); + } else if (center.y() > largeBottom) { + rect = rect.translated(0, fullHeight - largeBottom); + } else if (center.x() < largeLeft) { + rect = QRect( + rect.x() - largeLeft, + 0, + rect.width(), + fullHeight); + } else { + rect = QRect( + rect.x() + (fullWidth - largeRight), + 0, + rect.width(), + fullHeight); + } + } + } + return layout; +} + +void Viewport::updateTilesAnimated() { + if (!_largeChangeAnimation.animating()) { + updateTilesGeometry(); + return; + } + const auto ratio = _largeChangeAnimation.value(1.); + const auto field = _finishTilesLayout.useColumns + ? &Geometry::columns + : &Geometry::rows; + for (const auto &finish : _finishTilesLayout.list) { + const auto tile = finish.tile; + if (!tile) { + continue; + } + const auto i = ranges::find( + _startTilesLayout.list, + tile, + &Geometry::tile); + if (i == end(_startTilesLayout.list)) { + LOG(("Tiles Animation Error 1!")); + _largeChangeAnimation.stop(); + updateTilesGeometry(); + return; + } + const auto from = (*i).*field; + const auto to = finish.*field; + tile->setGeometry( + InterpolateRect(from, to, ratio), + TileAnimation{ from.size(), to.size(), ratio }); + } + widget()->update(); +} + +Viewport::Layout Viewport::countWide(int outerWidth, int outerHeight) const { + auto result = Layout{ .outer = QSize(outerWidth, outerHeight) }; + auto &sizes = result.list; + sizes.reserve(_tiles.size()); + for (const auto &tile : _tiles) { + const auto video = tile.get(); + const auto size = video->trackSize(); + if (!size.isEmpty()) { + sizes.push_back(Geometry{ video, size }); + } + } + if (sizes.empty()) { + return result; + } else if (sizes.size() == 1) { + sizes.front().rows = { 0, 0, outerWidth, outerHeight }; + return result; + } + + auto columnsBlack = uint64(); + auto rowsBlack = uint64(); + const auto count = int(sizes.size()); + const auto skip = st::groupCallVideoLargeSkip; + const auto slices = int(std::ceil(std::sqrt(float64(count)))); + { + auto index = 0; + const auto columns = slices; + const auto sizew = (outerWidth + skip) / float64(columns); + for (auto column = 0; column != columns; ++column) { + const auto left = int(std::round(column * sizew)); + const auto width = int(std::round(column * sizew + sizew - skip)) + - left; + const auto rows = int(std::round((count - index) + / float64(columns - column))); + const auto sizeh = (outerHeight + skip) / float64(rows); + for (auto row = 0; row != rows; ++row) { + const auto top = int(std::round(row * sizeh)); + const auto height = int(std::round( + row * sizeh + sizeh - skip)) - top; + auto &geometry = sizes[index]; + geometry.columns = { + left, + top, + width, + height }; + const auto scaled = geometry.size.scaled( + width, + height, + Qt::KeepAspectRatio); + columnsBlack += (scaled.width() < width) + ? (width - scaled.width()) * height + : (height - scaled.height()) * width; + ++index; + } + } + } + { + auto index = 0; + const auto rows = slices; + const auto sizeh = (outerHeight + skip) / float64(rows); + for (auto row = 0; row != rows; ++row) { + const auto top = int(std::round(row * sizeh)); + const auto height = int(std::round(row * sizeh + sizeh - skip)) + - top; + const auto columns = int(std::round((count - index) + / float64(rows - row))); + const auto sizew = (outerWidth + skip) / float64(columns); + for (auto column = 0; column != columns; ++column) { + const auto left = int(std::round(column * sizew)); + const auto width = int(std::round( + column * sizew + sizew - skip)) - left; + auto &geometry = sizes[index]; + geometry.rows = { + left, + top, + width, + height }; + const auto scaled = geometry.size.scaled( + width, + height, + Qt::KeepAspectRatio); + rowsBlack += (scaled.width() < width) + ? (width - scaled.width()) * height + : (height - scaled.height()) * width; + ++index; + } + } + } + result.useColumns = (columnsBlack < rowsBlack); + return result; } void Viewport::showLarge(const VideoEndpoint &endpoint) { const auto i = ranges::find(_tiles, endpoint, &VideoTile::endpoint); const auto large = (i != end(_tiles)) ? i->get() : nullptr; if (_large != large) { + prepareLargeChangeAnimation(); _large = large; updateTopControlsVisibility(); - updateTilesGeometry(); + startLargeChangeAnimation(); } + + Ensures(!_large || !_large->trackSize().isEmpty()); } void Viewport::updateTilesGeometry() { @@ -311,111 +590,32 @@ void Viewport::updateTopControlsVisibility() { void Viewport::updateTilesGeometryWide(int outerWidth, int outerHeight) { if (!outerHeight) { return; + } else if (_largeChangeAnimation.animating()) { + if (_startTilesLayout.outer == QSize(outerWidth, outerHeight)) { + return; + } + _largeChangeAnimation.stop(); } - struct Geometry { - QSize size; - QRect columns; - QRect rows; - }; - auto sizes = base::flat_map, Geometry>(); - sizes.reserve(_tiles.size()); - for (const auto &tile : _tiles) { - const auto video = tile.get(); - const auto size = (_large && video != _large) - ? QSize() - : video->trackSize(); - if (size.isEmpty()) { - setTileGeometry(video, { 0, 0, outerWidth, 0 }); - } else { - sizes.emplace(video, Geometry{ size }); - } - } - if (sizes.size() == 1) { - setTileGeometry( - sizes.front().first, - { 0, 0, outerWidth, outerHeight }); - return; - } - if (sizes.empty()) { - return; - } - - auto columnsBlack = uint64(); - auto rowsBlack = uint64(); - const auto count = int(sizes.size()); - const auto skip = st::groupCallVideoLargeSkip; - const auto slices = int(std::ceil(std::sqrt(float64(count)))); - { - auto index = 0; - const auto columns = slices; - const auto sizew = (outerWidth + skip) / float64(columns); - for (auto column = 0; column != columns; ++column) { - const auto left = int(std::round(column * sizew)); - const auto width = int(std::round(column * sizew + sizew - skip)) - - left; - const auto rows = int(std::round((count - index) - / float64(columns - column))); - const auto sizeh = (outerHeight + skip) / float64(rows); - for (auto row = 0; row != rows; ++row) { - const auto top = int(std::round(row * sizeh)); - const auto height = int(std::round( - row * sizeh + sizeh - skip)) - top; - auto &geometry = (sizes.begin() + index)->second; - geometry.columns = { - left, - top, - width, - height }; - const auto scaled = geometry.size.scaled( - width, - height, - Qt::KeepAspectRatio); - columnsBlack += (scaled.width() < width) - ? (width - scaled.width()) * height - : (height - scaled.height()) * width; - ++index; + _startTilesLayout = countWide(outerWidth, outerHeight); + if (_large && !_large->trackSize().isEmpty()) { + for (const auto &geometry : _startTilesLayout.list) { + if (geometry.tile == _large) { + setTileGeometry(_large, { 0, 0, outerWidth, outerHeight }); + } else { + geometry.tile->hide(); } } - } - { - auto index = 0; - const auto rows = slices; - const auto sizeh = (outerHeight + skip) / float64(rows); - for (auto row = 0; row != rows; ++row) { - const auto top = int(std::round(row * sizeh)); - const auto height = int(std::round(row * sizeh + sizeh - skip)) - - top; - const auto columns = int(std::round((count - index) - / float64(rows - row))); - const auto sizew = (outerWidth + skip) / float64(columns); - for (auto column = 0; column != columns; ++column) { - const auto left = int(std::round(column * sizew)); - const auto width = int(std::round( - column * sizew + sizew - skip)) - left; - auto &geometry = (sizes.begin() + index)->second; - geometry.rows = { - left, - top, - width, - height }; - const auto scaled = geometry.size.scaled( - width, - height, - Qt::KeepAspectRatio); - rowsBlack += (scaled.width() < width) - ? (width - scaled.width()) * height - : (height - scaled.height()) * width; - ++index; + } else { + const auto field = _startTilesLayout.useColumns + ? &Geometry::columns + : &Geometry::rows; + for (const auto &geometry : _startTilesLayout.list) { + if (const auto video = geometry.tile) { + setTileGeometry(video, geometry.*field); } } } - const auto layout = (columnsBlack < rowsBlack) - ? &Geometry::columns - : &Geometry::rows; - for (const auto &[video, geometry] : sizes) { - setTileGeometry(video, geometry.*layout); - } } void Viewport::updateTilesGeometryNarrow(int outerWidth) { @@ -431,7 +631,7 @@ void Viewport::updateTilesGeometryNarrow(int outerWidth) { const auto video = tile.get(); const auto size = video->trackSize(); if (size.isEmpty()) { - setTileGeometry(video, { 0, y, outerWidth, 0 }); + video->hide(); } else { sizes.emplace(video, size); } @@ -536,7 +736,6 @@ void Viewport::updateTilesGeometryColumn(int outerWidth) { void Viewport::setTileGeometry(not_null tile, QRect geometry) { tile->setGeometry(geometry); - tile->setShown(!geometry.isEmpty()); const auto min = std::min(geometry.width(), geometry.height()); const auto kMedium = style::ConvertScale(480); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport.h b/Telegram/SourceFiles/calls/group/calls_group_viewport.h index d4250a5009..dac2fcdeec 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/rp_widget.h" +#include "ui/effects/animations.h" namespace Ui { class AbstractButton; @@ -91,6 +92,26 @@ private: class VideoTile; class Renderer; class RendererGL; + using TileId = quintptr; + + struct Geometry { + VideoTile *tile = nullptr; + QSize size; + QRect rows; + QRect columns; + }; + + struct Layout { + std::vector list; + QSize outer; + bool useColumns = false; + }; + + struct TileAnimation { + QSize from; + QSize to; + float64 ratio = -1.; + }; struct Selection { enum class Element { @@ -122,6 +143,12 @@ private: void refreshHasTwoOrMore(); void updateTopControlsVisibility(); + void prepareLargeChangeAnimation(); + void startLargeChangeAnimation(); + void updateTilesAnimated(); + [[nodiscard]] Layout countWide(int outerWidth, int outerHeight) const; + [[nodiscard]] Layout applyLarge(Layout layout) const; + void setSelected(Selection value); void setPressed(Selection value); @@ -149,6 +176,9 @@ private: rpl::event_stream _qualityRequests; float64 _controlsShownRatio = 1.; VideoTile *_large = nullptr; + Ui::Animations::Simple _largeChangeAnimation; + Layout _startTilesLayout; + Layout _finishTilesLayout; Selection _selected; Selection _pressed; rpl::variable _mouseInside = false; diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index 15008e8b07..33536a37e3 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -124,14 +124,36 @@ vec4 background() { : NonEmpty(scaled); } +[[nodiscard]] QSize InterpolateScaledSize( + QSize unscaled, + QSize size, + float64 ratio) { + if (ratio == 0.) { + return NonEmpty(unscaled.scaled( + size, + Qt::KeepAspectRatio)); + } else if (ratio == 1.) { + return NonEmpty(unscaled.scaled( + size, + Qt::KeepAspectRatioByExpanding)); + } + const auto notExpanded = NonEmpty(unscaled.scaled( + size, + Qt::KeepAspectRatio)); + const auto expanded = NonEmpty(unscaled.scaled( + size, + Qt::KeepAspectRatioByExpanding)); + return QSize( + anim::interpolate(notExpanded.width(), expanded.width(), ratio), + anim::interpolate(notExpanded.height(), expanded.height(), ratio)); +} + [[nodiscard]] std::array, 4> CountTexCoords( QSize unscaled, QSize size, - bool expand, + float64 expandRatio, bool swap = false) { - const auto scaled = NonEmpty(unscaled.scaled( - size, - expand ? Qt::KeepAspectRatioByExpanding : Qt::KeepAspectRatio)); + const auto scaled = InterpolateScaledSize(unscaled, size, expandRatio); const auto left = (size.width() - scaled.width()) / 2; const auto top = (size.height() - scaled.height()) / 2; const auto right = left + scaled.width(); @@ -457,12 +479,17 @@ void Viewport::RendererGL::paintTile( data.rotation); const auto tileSize = geometry.size(); const auto swap = (((data.rotation / 90) % 2) == 1); - const auto expand = !tile->screencast() - && (!_owner->wide() || UseExpandForCamera(unscaled, tileSize)); - auto texCoords = CountTexCoords(unscaled, tileSize, expand, swap); - auto blurTexCoords = expand + const auto expand = isExpanded(tile, unscaled, tileSize); + const auto animation = tile->animation(); + const auto expandRatio = (animation.ratio >= 0.) + ? countExpandRatio(tile, unscaled, animation) + : expand + ? 1. + : 0.; + auto texCoords = CountTexCoords(unscaled, tileSize, expandRatio, swap); + auto blurTexCoords = (expandRatio == 1.) ? texCoords - : CountTexCoords(unscaled, tileSize, true); + : CountTexCoords(unscaled, tileSize, 1.); const auto rect = transformRect(geometry); auto toBlurTexCoords = std::array, 4> { { { { 0.f, 1.f } }, @@ -763,6 +790,29 @@ void Viewport::RendererGL::prepareObjects( create(1, kFirstBlurPassTextureIndex); } +bool Viewport::RendererGL::isExpanded( + not_null tile, + QSize unscaled, + QSize tileSize) const { + return !tile->screencast() + && (!_owner->wide() || UseExpandForCamera(unscaled, tileSize)); +} + +float64 Viewport::RendererGL::countExpandRatio( + not_null tile, + QSize unscaled, + const TileAnimation &animation) const { + const auto expandedFrom = isExpanded(tile, unscaled, animation.from); + const auto expandedTo = isExpanded(tile, unscaled, animation.to); + return (expandedFrom && expandedTo) + ? 1. + : (!expandedFrom && !expandedTo) + ? 0. + : expandedFrom + ? (1. - animation.ratio) + : animation.ratio; +} + void Viewport::RendererGL::bindFrame( QOpenGLFunctions &f, const Webrtc::FrameWithInfo &data, diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h index 3a27b03989..2db68b8055 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.h @@ -102,6 +102,15 @@ private: not_null tile, TileData &data); + [[nodiscard]] bool isExpanded( + not_null tile, + QSize unscaled, + QSize tileSize) const; + [[nodiscard]] float64 countExpandRatio( + not_null tile, + QSize unscaled, + const TileAnimation &animation) const; + const not_null _owner; GLfloat _factor = 1.; diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp index 9b7a3cc2e7..485fd5ec53 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.cpp @@ -58,13 +58,18 @@ bool Viewport::VideoTile::screencast() const { return (_endpoint.type == VideoEndpointType::Screen); } -void Viewport::VideoTile::setGeometry(QRect geometry) { +void Viewport::VideoTile::setGeometry( + QRect geometry, + TileAnimation animation) { + _shown = true; _geometry = geometry; - updateTopControlsGeometry(); + _animation = animation; + updateTopControlsPosition(); } -void Viewport::VideoTile::setShown(bool shown) { - _shown = shown; +void Viewport::VideoTile::hide() { + _shown = false; + _quality = std::nullopt; } void Viewport::VideoTile::toggleTopControlsShown(bool shown) { @@ -183,27 +188,38 @@ void Viewport::VideoTile::PaintBackButton( tr::lng_create_group_back(tr::now)); } -void Viewport::VideoTile::updateTopControlsGeometry() { +void Viewport::VideoTile::updateTopControlsSize() { const auto &st = st::groupCallVideoTile; const auto pinSize = PinInnerSize(_pinned); const auto pinWidth = st.pinPosition.x() * 2 + pinSize.width(); const auto pinHeight = st.pinPosition.y() * 2 + pinSize.height(); - _pinInner = QRect(QPoint(), pinSize).translated( - _geometry.width() - st.pinPosition.x() - pinSize.width(), - st.pinPosition.y()); - _pinOuter = QRect( - _geometry.width() - pinWidth, - 0, - pinWidth, - pinHeight); + _pinInner = QRect(QPoint(), pinSize); + _pinOuter = QRect(0, 0, pinWidth, pinHeight); + const auto backSize = BackInnerSize(); const auto backWidth = st.pinPosition.x() * 2 + backSize.width(); const auto backHeight = st.pinPosition.y() * 2 + backSize.height(); - _backInner = QRect(QPoint(), backSize).translated(st.pinPosition); + _backInner = QRect(QPoint(), backSize); _backOuter = QRect(0, 0, backWidth, backHeight); } +void Viewport::VideoTile::updateTopControlsPosition() { + const auto &st = st::groupCallVideoTile; + + _pinInner = QRect( + _geometry.width() - st.pinPosition.x() - _pinInner.width(), + st.pinPosition.y(), + _pinInner.width(), + _pinInner.height()); + _pinOuter = QRect( + _geometry.width() - _pinOuter.width(), + 0, + _pinOuter.width(), + _pinOuter.height()); + _backInner = QRect(st.pinPosition, _backInner.size()); +} + void Viewport::VideoTile::setup(rpl::producer pinned) { std::move( pinned @@ -211,8 +227,11 @@ void Viewport::VideoTile::setup(rpl::producer pinned) { return (_pinned != pinned); }) | rpl::start_with_next([=](bool pinned) { _pinned = pinned; - updateTopControlsGeometry(); - _update(); + updateTopControlsSize(); + if (_shown) { + updateTopControlsPosition(); + _update(); + } }, _lifetime); _track.track->renderNextFrame( @@ -229,6 +248,8 @@ void Viewport::VideoTile::setup(rpl::producer pinned) { if (const auto size = _track.track->frameSize(); !size.isEmpty()) { _trackSize = size; } + + updateTopControlsSize(); } } // namespace Calls::Group diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h index 68501c65c2..20804cc0b2 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_tile.h @@ -38,6 +38,9 @@ public: [[nodiscard]] QRect geometry() const { return _geometry; } + [[nodiscard]] TileAnimation animation() const { + return _animation; + } [[nodiscard]] bool pinned() const { return _pinned; } @@ -59,8 +62,10 @@ public: } [[nodiscard]] bool screencast() const; - void setGeometry(QRect geometry); - void setShown(bool shown); + void setGeometry( + QRect geometry, + TileAnimation animation = TileAnimation()); + void hide(); void toggleTopControlsShown(bool shown); bool updateRequestedQuality(VideoQuality quality); @@ -89,13 +94,15 @@ public: private: void setup(rpl::producer pinned); [[nodiscard]] int topControlsSlide() const; - void updateTopControlsGeometry(); + void updateTopControlsSize(); + void updateTopControlsPosition(); const VideoEndpoint _endpoint; const Fn _update; VideoTileTrack _track; QRect _geometry; + TileAnimation _animation; rpl::variable _trackSize; QRect _pinOuter; QRect _pinInner;