Add large / small video animation.

This commit is contained in:
John Preston 2021-05-31 21:25:15 +04:00
parent b22363224f
commit 2fe75f8296
9 changed files with 473 additions and 152 deletions

View file

@ -972,8 +972,12 @@ void GroupCall::markTrackShown(const VideoEndpoint &endpoint, bool shown) {
_videoStreamShownUpdates.fire_copy({ endpoint, shown });
}
if (shown && changed && endpoint.type == VideoEndpointType::Screen) {
crl::on_main(this, [=] {
if (_shownVideoTracks.contains(endpoint)) {
pinVideoEndpoint(endpoint);
}
});
}
}
void GroupCall::rejoin() {

View file

@ -1189,8 +1189,9 @@ base::unique_qptr<Ui::PopupMenu> 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<Ui::PopupMenu> 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); });
}
}
}

View file

@ -1359,7 +1359,7 @@ void Panel::chooseShareScreenSource() {
}
return nullptr;
}();
if (!screencastFromPeer) {
if (!screencastFromPeer || _call->isSharingScreen()) {
choose();
return;
}

View file

@ -29,6 +29,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QOpenGLShader>
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<QWidget*> 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);
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,110 +590,31 @@ 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<not_null<VideoTile*>, 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 });
_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 {
sizes.emplace(video, Geometry{ size });
geometry.tile->hide();
}
}
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;
}
}
}
{
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;
}
}
}
const auto layout = (columnsBlack < rowsBlack)
} else {
const auto field = _startTilesLayout.useColumns
? &Geometry::columns
: &Geometry::rows;
for (const auto &[video, geometry] : sizes) {
setTileGeometry(video, geometry.*layout);
for (const auto &geometry : _startTilesLayout.list) {
if (const auto video = geometry.tile) {
setTileGeometry(video, geometry.*field);
}
}
}
}
@ -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<VideoTile*> 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);

View file

@ -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<Geometry> 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<VideoQualityRequest> _qualityRequests;
float64 _controlsShownRatio = 1.;
VideoTile *_large = nullptr;
Ui::Animations::Simple _largeChangeAnimation;
Layout _startTilesLayout;
Layout _finishTilesLayout;
Selection _selected;
Selection _pressed;
rpl::variable<bool> _mouseInside = false;

View file

@ -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<std::array<GLfloat, 2>, 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<std::array<GLfloat, 2>, 4> { {
{ { 0.f, 1.f } },
@ -763,6 +790,29 @@ void Viewport::RendererGL::prepareObjects(
create(1, kFirstBlurPassTextureIndex);
}
bool Viewport::RendererGL::isExpanded(
not_null<VideoTile*> tile,
QSize unscaled,
QSize tileSize) const {
return !tile->screencast()
&& (!_owner->wide() || UseExpandForCamera(unscaled, tileSize));
}
float64 Viewport::RendererGL::countExpandRatio(
not_null<VideoTile*> 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,

View file

@ -102,6 +102,15 @@ private:
not_null<VideoTile*> tile,
TileData &data);
[[nodiscard]] bool isExpanded(
not_null<VideoTile*> tile,
QSize unscaled,
QSize tileSize) const;
[[nodiscard]] float64 countExpandRatio(
not_null<VideoTile*> tile,
QSize unscaled,
const TileAnimation &animation) const;
const not_null<Viewport*> _owner;
GLfloat _factor = 1.;

View file

@ -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<bool> pinned) {
std::move(
pinned
@ -211,8 +227,11 @@ void Viewport::VideoTile::setup(rpl::producer<bool> pinned) {
return (_pinned != pinned);
}) | rpl::start_with_next([=](bool pinned) {
_pinned = pinned;
updateTopControlsGeometry();
updateTopControlsSize();
if (_shown) {
updateTopControlsPosition();
_update();
}
}, _lifetime);
_track.track->renderNextFrame(
@ -229,6 +248,8 @@ void Viewport::VideoTile::setup(rpl::producer<bool> pinned) {
if (const auto size = _track.track->frameSize(); !size.isEmpty()) {
_trackSize = size;
}
updateTopControlsSize();
}
} // namespace Calls::Group

View file

@ -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<bool> pinned);
[[nodiscard]] int topControlsSlide() const;
void updateTopControlsGeometry();
void updateTopControlsSize();
void updateTopControlsPosition();
const VideoEndpoint _endpoint;
const Fn<void()> _update;
VideoTileTrack _track;
QRect _geometry;
TileAnimation _animation;
rpl::variable<QSize> _trackSize;
QRect _pinOuter;
QRect _pinInner;