| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "calls/group/calls_group_viewport.h"
- #include "calls/group/calls_group_viewport_tile.h"
- #include "calls/group/calls_group_viewport_opengl.h"
- #include "calls/group/calls_group_viewport_raster.h"
- #include "calls/group/calls_group_common.h"
- #include "calls/group/calls_group_call.h"
- #include "calls/group/calls_group_members_row.h"
- #include "media/view/media_view_pip.h"
- #include "base/platform/base_platform_info.h"
- #include "webrtc/webrtc_video_track.h"
- #include "ui/integration.h"
- #include "ui/painter.h"
- #include "ui/abstract_button.h"
- #include "ui/gl/gl_surface.h"
- #include "ui/effects/animations.h"
- #include "ui/effects/cross_line.h"
- #include "data/data_group_call.h" // MuteButtonTooltip.
- #include "lang/lang_keys.h"
- #include "styles/style_calls.h"
- #include <QtGui/QtEvents>
- #include <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,
- Ui::GL::Backend backend)
- : _mode(mode)
- , _content(Ui::GL::CreateSurface(parent, chooseRenderer(backend))) {
- setup();
- }
- Viewport::~Viewport() = default;
- not_null<QWidget*> Viewport::widget() const {
- return _content->rpWidget();
- }
- not_null<Ui::RpWidgetWrap*> Viewport::rp() const {
- return _content.get();
- }
- void Viewport::setup() {
- const auto raw = widget();
- raw->resize(0, 0);
- raw->setAttribute(Qt::WA_OpaquePaintEvent);
- raw->setMouseTracking(true);
- _content->sizeValue(
- ) | rpl::filter([=] {
- return wide();
- }) | rpl::start_with_next([=] {
- updateTilesGeometry();
- }, lifetime());
- _content->events(
- ) | rpl::start_with_next([=](not_null<QEvent*> e) {
- const auto type = e->type();
- if (type == QEvent::Enter) {
- Ui::Integration::Instance().registerLeaveSubscription(raw);
- _mouseInside = true;
- } else if (type == QEvent::Leave) {
- Ui::Integration::Instance().unregisterLeaveSubscription(raw);
- setSelected({});
- _mouseInside = false;
- } else if (type == QEvent::MouseButtonPress) {
- handleMousePress(
- static_cast<QMouseEvent*>(e.get())->pos(),
- static_cast<QMouseEvent*>(e.get())->button());
- } else if (type == QEvent::MouseButtonRelease) {
- handleMouseRelease(
- static_cast<QMouseEvent*>(e.get())->pos(),
- static_cast<QMouseEvent*>(e.get())->button());
- } else if (type == QEvent::MouseMove) {
- handleMouseMove(static_cast<QMouseEvent*>(e.get())->pos());
- }
- }, lifetime());
- }
- void Viewport::setGeometry(bool fullscreen, QRect geometry) {
- Expects(wide());
- const auto changed = (_fullscreen != fullscreen);
- if (changed) {
- _fullscreen = fullscreen;
- }
- if (widget()->geometry() != geometry) {
- _geometryStaleAfterModeChange = false;
- widget()->setGeometry(geometry);
- } else if (_geometryStaleAfterModeChange || changed) {
- _geometryStaleAfterModeChange = false;
- updateTilesGeometry();
- }
- }
- void Viewport::resizeToWidth(int width) {
- Expects(!wide());
- updateTilesGeometry(width);
- }
- void Viewport::setScrollTop(int scrollTop) {
- if (_scrollTop == scrollTop) {
- return;
- }
- _scrollTop = scrollTop;
- updateTilesGeometry();
- }
- bool Viewport::wide() const {
- return (_mode == PanelMode::Wide);
- }
- void Viewport::setMode(PanelMode mode, not_null<QWidget*> parent) {
- if (_mode == mode && widget()->parent() == parent) {
- return;
- }
- _mode = mode;
- _scrollTop = 0;
- setControlsShown(1.);
- if (widget()->parent() != parent) {
- const auto hidden = widget()->isHidden();
- widget()->setParent(parent);
- if (!hidden) {
- widget()->show();
- }
- }
- if (!wide()) {
- for (const auto &tile : _tiles) {
- tile->toggleTopControlsShown(false);
- }
- } else if (_selected.tile) {
- _selected.tile->toggleTopControlsShown(true);
- }
- }
- void Viewport::handleMousePress(QPoint position, Qt::MouseButton button) {
- handleMouseMove(position);
- setPressed(_selected);
- }
- void Viewport::handleMouseRelease(QPoint position, Qt::MouseButton button) {
- handleMouseMove(position);
- const auto pressed = _pressed;
- setPressed({});
- if (const auto tile = pressed.tile) {
- if (pressed == _selected) {
- if (button == Qt::RightButton) {
- tile->row()->showContextMenu();
- } else if (!wide()
- || (_hasTwoOrMore && !_large)
- || pressed.element != Selection::Element::PinButton) {
- _clicks.fire_copy(tile->endpoint());
- } else if (pressed.element == Selection::Element::PinButton) {
- _pinToggles.fire(!tile->pinned());
- }
- }
- }
- }
- void Viewport::handleMouseMove(QPoint position) {
- updateSelected(position);
- }
- void Viewport::updateSelected(QPoint position) {
- if (!widget()->rect().contains(position)) {
- setSelected({});
- return;
- }
- for (const auto &tile : _tiles) {
- const auto geometry = tile->visible()
- ? tile->geometry()
- : QRect();
- if (geometry.contains(position)) {
- const auto pin = wide()
- && tile->pinOuter().contains(position - geometry.topLeft());
- const auto back = wide()
- && tile->backOuter().contains(position - geometry.topLeft());
- setSelected({
- .tile = tile.get(),
- .element = (pin
- ? Selection::Element::PinButton
- : back
- ? Selection::Element::BackButton
- : Selection::Element::Tile),
- });
- return;
- }
- }
- setSelected({});
- }
- void Viewport::updateSelected() {
- updateSelected(widget()->mapFromGlobal(QCursor::pos()));
- }
- void Viewport::setControlsShown(float64 shown) {
- _controlsShownRatio = shown;
- widget()->update();
- }
- void Viewport::setCursorShown(bool shown) {
- if (_cursorHidden == shown) {
- _cursorHidden = !shown;
- updateCursor();
- }
- }
- void Viewport::add(
- const VideoEndpoint &endpoint,
- VideoTileTrack track,
- rpl::producer<QSize> trackSize,
- rpl::producer<bool> pinned,
- bool self) {
- _tiles.push_back(std::make_unique<VideoTile>(
- endpoint,
- track,
- std::move(trackSize),
- std::move(pinned),
- [=] { widget()->update(); },
- self));
- _tiles.back()->trackSizeValue(
- ) | rpl::filter([](QSize size) {
- return !size.isEmpty();
- }) | rpl::start_with_next([=] {
- updateTilesGeometry();
- }, _tiles.back()->lifetime());
- _tiles.back()->track()->stateValue(
- ) | rpl::start_with_next([=] {
- updateTilesGeometry();
- }, _tiles.back()->lifetime());
- }
- void Viewport::remove(const VideoEndpoint &endpoint) {
- const auto i = ranges::find(_tiles, endpoint, &VideoTile::endpoint);
- if (i == end(_tiles)) {
- return;
- }
- const auto removing = i->get();
- const auto largeRemoved = (_large == removing);
- if (largeRemoved) {
- prepareLargeChangeAnimation();
- _large = nullptr;
- }
- if (_selected.tile == removing) {
- setSelected({});
- }
- 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();
- 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->trackOrUserpicSize();
- 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(base::SafeRound(column * sizew));
- const auto width = int(
- base::SafeRound(column * sizew + sizew - skip)) - left;
- const auto rows = int(base::SafeRound((count - index)
- / float64(columns - column)));
- const auto sizeh = (outerHeight + skip) / float64(rows);
- for (auto row = 0; row != rows; ++row) {
- const auto top = int(base::SafeRound(row * sizeh));
- const auto height = int(base::SafeRound(
- 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(base::SafeRound(row * sizeh));
- const auto height = int(
- base::SafeRound(row * sizeh + sizeh - skip)) - top;
- const auto columns = int(base::SafeRound((count - index)
- / float64(rows - row)));
- const auto sizew = (outerWidth + skip) / float64(columns);
- for (auto column = 0; column != columns; ++column) {
- const auto left = int(base::SafeRound(column * sizew));
- const auto width = int(base::SafeRound(
- 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) {
- // If a video get's switched off, GroupCall first unpins it,
- // then removes it from Large endpoint, then removes from active tracks.
- //
- // If we want to animate large video removal properly, we need to
- // delay this update and start animation directly from removing of the
- // track from the active list. Otherwise final state won't be correct.
- _updateLargeScheduled = [=] {
- 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();
- startLargeChangeAnimation();
- }
- Ensures(!_large || !_large->trackOrUserpicSize().isEmpty());
- };
- crl::on_main(widget(), [=] {
- if (!_updateLargeScheduled) {
- return;
- }
- base::take(_updateLargeScheduled)();
- });
- }
- void Viewport::updateTilesGeometry() {
- updateTilesGeometry(widget()->width());
- }
- void Viewport::updateTilesGeometry(int outerWidth) {
- const auto mouseInside = _mouseInside.current();
- const auto guard = gsl::finally([&] {
- if (mouseInside) {
- updateSelected();
- }
- widget()->update();
- });
- const auto outerHeight = widget()->height();
- if (_tiles.empty() || !outerWidth) {
- _fullHeight = 0;
- return;
- }
- if (wide()) {
- updateTilesGeometryWide(outerWidth, outerHeight);
- refreshHasTwoOrMore();
- _fullHeight = 0;
- } else {
- updateTilesGeometryNarrow(outerWidth);
- }
- }
- void Viewport::refreshHasTwoOrMore() {
- auto hasTwoOrMore = false;
- auto oneFound = false;
- for (const auto &tile : _tiles) {
- if (!tile->trackOrUserpicSize().isEmpty()) {
- if (oneFound) {
- hasTwoOrMore = true;
- break;
- }
- oneFound = true;
- }
- }
- if (_hasTwoOrMore == hasTwoOrMore) {
- return;
- }
- _hasTwoOrMore = hasTwoOrMore;
- updateCursor();
- updateTopControlsVisibility();
- }
- void Viewport::updateTopControlsVisibility() {
- if (_selected.tile) {
- _selected.tile->toggleTopControlsShown(
- _hasTwoOrMore && wide() && _large && _large == _selected.tile);
- }
- }
- void Viewport::updateTilesGeometryWide(int outerWidth, int outerHeight) {
- if (!outerHeight) {
- return;
- } else if (_largeChangeAnimation.animating()) {
- if (_startTilesLayout.outer == QSize(outerWidth, outerHeight)) {
- return;
- }
- _largeChangeAnimation.stop();
- }
- _startTilesLayout = countWide(outerWidth, outerHeight);
- if (_large && !_large->trackOrUserpicSize().isEmpty()) {
- for (const auto &geometry : _startTilesLayout.list) {
- if (geometry.tile == _large) {
- setTileGeometry(_large, { 0, 0, outerWidth, outerHeight });
- } else {
- geometry.tile->hide();
- }
- }
- } 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);
- }
- }
- }
- }
- void Viewport::updateTilesGeometryNarrow(int outerWidth) {
- if (outerWidth <= st::groupCallNarrowMembersWidth) {
- updateTilesGeometryColumn(outerWidth);
- return;
- }
- const auto y = -_scrollTop;
- auto sizes = base::flat_map<not_null<VideoTile*>, QSize>();
- sizes.reserve(_tiles.size());
- for (const auto &tile : _tiles) {
- const auto video = tile.get();
- const auto size = video->trackOrUserpicSize();
- if (size.isEmpty()) {
- video->hide();
- } else {
- sizes.emplace(video, size);
- }
- }
- if (sizes.empty()) {
- _fullHeight = 0;
- return;
- } else if (sizes.size() == 1) {
- const auto size = sizes.front().second;
- const auto heightMin = (outerWidth * 9) / 16;
- const auto heightMax = (outerWidth * 3) / 4;
- const auto scaled = size.scaled(
- QSize(outerWidth, heightMax),
- Qt::KeepAspectRatio);
- const auto height = std::max(scaled.height(), heightMin);
- const auto skip = st::groupCallVideoSmallSkip;
- setTileGeometry(sizes.front().first, { 0, y, outerWidth, height });
- _fullHeight = height + skip;
- return;
- }
- const auto min = (st::groupCallWidth
- - st::groupCallMembersMargin.left()
- - st::groupCallMembersMargin.right()
- - st::groupCallVideoSmallSkip) / 2;
- const auto square = (outerWidth - st::groupCallVideoSmallSkip) / 2;
- const auto skip = (outerWidth - 2 * square);
- const auto put = [&](not_null<VideoTile*> tile, int column, int row) {
- setTileGeometry(tile, {
- (column == 2) ? 0 : column ? (outerWidth - square) : 0,
- y + row * (min + skip),
- (column == 2) ? outerWidth : square,
- min,
- });
- };
- const auto rows = (sizes.size() + 1) / 2;
- if (sizes.size() == 3) {
- put(sizes.front().first, 2, 0);
- put((sizes.begin() + 1)->first, 0, 1);
- put((sizes.begin() + 2)->first, 1, 1);
- } else {
- auto row = 0;
- auto column = 0;
- for (const auto &[video, endpoint] : sizes) {
- put(video, column, row);
- if (column) {
- ++row;
- column = (row + 1 == rows && sizes.size() % 2) ? 2 : 0;
- } else {
- column = 1;
- }
- }
- }
- _fullHeight = rows * (min + skip);
- }
- void Viewport::updateTilesGeometryColumn(int outerWidth) {
- const auto y = -_scrollTop;
- auto top = 0;
- const auto layoutNext = [&](not_null<VideoTile*> tile) {
- const auto size = tile->trackOrUserpicSize();
- const auto shown = !size.isEmpty() && _large && tile != _large;
- const auto height = st::groupCallNarrowVideoHeight;
- if (!shown) {
- tile->hide();
- } else {
- setTileGeometry(tile, { 0, y + top, outerWidth, height });
- top += height + st::groupCallVideoSmallSkip;
- }
- };
- const auto topPeer = _large ? _large->row()->peer().get() : nullptr;
- const auto reorderNeeded = [&] {
- if (!topPeer) {
- return false;
- }
- for (const auto &tile : _tiles) {
- if (tile.get() != _large && tile->row()->peer() == topPeer) {
- return (tile.get() != _tiles.front().get())
- && !tile->trackOrUserpicSize().isEmpty();
- }
- }
- return false;
- }();
- if (reorderNeeded) {
- _tilesForOrder.clear();
- _tilesForOrder.reserve(_tiles.size());
- for (const auto &tile : _tiles) {
- _tilesForOrder.push_back(tile.get());
- }
- ranges::stable_partition(
- _tilesForOrder,
- [&](not_null<VideoTile*> tile) {
- return (tile->row()->peer() == topPeer);
- });
- for (const auto &tile : _tilesForOrder) {
- layoutNext(tile);
- }
- } else {
- for (const auto &tile : _tiles) {
- layoutNext(tile.get());
- }
- }
- _fullHeight = top;
- }
- void Viewport::setTileGeometry(not_null<VideoTile*> tile, QRect geometry) {
- tile->setGeometry(geometry);
- const auto min = std::min(geometry.width(), geometry.height());
- const auto kMedium = style::ConvertScale(540);
- const auto kSmall = style::ConvertScale(240);
- const auto &endpoint = tile->endpoint();
- const auto forceThumbnailQuality = !wide()
- && (ranges::count(_tiles, false, &VideoTile::hidden) > 1);
- const auto forceFullQuality = wide() && (tile.get() == _large);
- const auto quality = forceThumbnailQuality
- ? VideoQuality::Thumbnail
- : (forceFullQuality || min >= kMedium)
- ? VideoQuality::Full
- : (min >= kSmall)
- ? VideoQuality::Medium
- : VideoQuality::Thumbnail;
- if (tile->updateRequestedQuality(quality)) {
- _qualityRequests.fire(VideoQualityRequest{
- .endpoint = endpoint,
- .quality = quality,
- });
- }
- }
- void Viewport::setSelected(Selection value) {
- if (_selected == value) {
- return;
- }
- if (_selected.tile) {
- _selected.tile->toggleTopControlsShown(false);
- }
- _selected = value;
- updateTopControlsVisibility();
- updateCursor();
- }
- void Viewport::updateCursor() {
- const auto pointer = _selected.tile && (!wide() || _hasTwoOrMore);
- widget()->setCursor(_cursorHidden
- ? Qt::BlankCursor
- : pointer
- ? style::cur_pointer
- : style::cur_default);
- }
- void Viewport::setPressed(Selection value) {
- if (_pressed == value) {
- return;
- }
- _pressed = value;
- }
- Ui::GL::ChosenRenderer Viewport::chooseRenderer(Ui::GL::Backend backend) {
- _opengl = (backend == Ui::GL::Backend::OpenGL);
- return {
- .renderer = (_opengl
- ? std::unique_ptr<Ui::GL::Renderer>(
- std::make_unique<RendererGL>(this))
- : std::make_unique<RendererSW>(this)),
- .backend = backend,
- };
- }
- bool Viewport::requireARGB32() const {
- return !_opengl;
- }
- int Viewport::fullHeight() const {
- return _fullHeight.current();
- }
- rpl::producer<int> Viewport::fullHeightValue() const {
- return _fullHeight.value();
- }
- rpl::producer<bool> Viewport::pinToggled() const {
- return _pinToggles.events();
- }
- rpl::producer<VideoEndpoint> Viewport::clicks() const {
- return _clicks.events();
- }
- rpl::producer<VideoQualityRequest> Viewport::qualityRequests() const {
- return _qualityRequests.events();
- }
- rpl::producer<bool> Viewport::mouseInsideValue() const {
- return _mouseInside.value();
- }
- rpl::lifetime &Viewport::lifetime() {
- return _content->lifetime();
- }
- rpl::producer<QString> MuteButtonTooltip(not_null<GroupCall*> call) {
- //return rpl::single(std::make_tuple(
- // (Data::GroupCall*)nullptr,
- // call->scheduleDate()
- //)) | rpl::then(call->real(
- //) | rpl::map([](not_null<Data::GroupCall*> real) {
- // using namespace rpl::mappers;
- // return real->scheduleDateValue(
- // ) | rpl::map([=](TimeId scheduleDate) {
- // return std::make_tuple(real.get(), scheduleDate);
- // });
- //}) | rpl::flatten_latest(
- //)) | rpl::map([=](
- // Data::GroupCall *real,
- // TimeId scheduleDate) -> rpl::producer<QString> {
- // if (scheduleDate) {
- // return rpl::combine(
- // call->canManageValue(),
- // (real
- // ? real->scheduleStartSubscribedValue()
- // : rpl::single(false))
- // ) | rpl::map([](bool canManage, bool subscribed) {
- // return canManage
- // ? tr::lng_group_call_start_now()
- // : subscribed
- // ? tr::lng_group_call_cancel_reminder()
- // : tr::lng_group_call_set_reminder();
- // }) | rpl::flatten_latest();
- // }
- if (call->rtmp()) {
- return nullptr;
- }
- return call->mutedValue(
- ) | rpl::map([](MuteState muted) {
- switch (muted) {
- case MuteState::Active:
- case MuteState::PushToTalk:
- return tr::lng_group_call_you_are_live();
- case MuteState::ForceMuted:
- return tr::lng_group_call_tooltip_force_muted();
- case MuteState::RaisedHand:
- return tr::lng_group_call_tooltip_raised_hand();
- case MuteState::Muted:
- return tr::lng_group_call_tooltip_microphone();
- }
- Unexpected("Value in MuteState in showNiceTooltip.");
- }) | rpl::flatten_latest();
- //}) | rpl::flatten_latest();
- }
- } // namespace Calls::Group
|