Support enlarge / minimize of video.

This commit is contained in:
John Preston 2021-05-11 19:00:37 +04:00
parent 64c34b7029
commit 2a5977e97f
7 changed files with 158 additions and 9 deletions

View File

@ -1139,7 +1139,7 @@ groupCallNarrowNameTop: 65px;
groupCallNarrowIconTop: 62px;
groupCallNarrowIconLess: 5px;
groupCallWideModeWidthMin: 550px;
groupCallWideModeSize: size(720px, 480px);
groupCallWideModeSize: size(960px, 580px);
groupCallNarrowAddMemberHeight: 32px;
groupCallNarrowOutline: 2px;
groupCallNarrowShadowHeight: 36px;
@ -1184,6 +1184,7 @@ GroupCallLargeVideo {
statusPosition: point;
pinPosition: point;
iconPosition: point;
minimizePosition: point;
}
groupCallLargeVideoWide: GroupCallLargeVideo {
@ -1193,6 +1194,7 @@ groupCallLargeVideoWide: GroupCallLargeVideo {
statusPosition: point(15px, 28px);
pinPosition: point(52px, 16px);
iconPosition: point(14px, 16px);
minimizePosition: point(94px, 16px);
}
groupCallLargeVideoNarrow: GroupCallLargeVideo {
shadowHeight: 80px;
@ -1216,3 +1218,5 @@ groupCallLargeVideoPin: CrossLineAnimation {
endPosition: point(20px, 17px);
stroke: 2px;
}
groupCallVideoEnlarge: icon {{ "calls/voice_enlarge", mediaviewPipControlsFgOver }};
groupCallVideoMinimize: icon {{ "calls/voice_minimize", groupCallVideoSubTextFg }};

View File

@ -30,6 +30,9 @@ LargeVideo::LargeVideo(
, _st(st)
, _pin(st::groupCallLargeVideoPin)
, _pinButton(&_content)
, _minimizeButton((_st.controlsAlign == style::al_top)
? std::make_unique<Ui::AbstractButton>(&_content)
: nullptr)
, _controlsShown(_st.controlsAlign == style::al_top)
, _topControls(_st.controlsAlign == style::al_top)
, _controlsShownRatio(_controlsShown.current() ? 1. : 0.) {
@ -64,6 +67,12 @@ rpl::producer<bool> LargeVideo::pinToggled() const {
return _pinButton.clicks() | rpl::map([=] { return !_pinned; });
}
rpl::producer<> LargeVideo::minimizeClicks() const {
return _minimizeButton
? (_minimizeButton->clicks() | rpl::to_empty)
: (rpl::never<rpl::empty_value>() | rpl::type_erased());
}
rpl::producer<float64> LargeVideo::controlsShown() const {
return _controlsShownRatio.value();
}
@ -86,6 +95,18 @@ void LargeVideo::setup(
Ui::Integration::Instance().unregisterLeaveSubscription(
&_content);
setControlsShown(false);
} else if (e->type() == QEvent::MouseButtonPress
&& static_cast<QMouseEvent*>(
e.get())->button() == Qt::LeftButton) {
_mouseDown = true;
} else if (e->type() == QEvent::MouseButtonRelease
&& static_cast<QMouseEvent*>(
e.get())->button() == Qt::LeftButton
&& _mouseDown) {
_mouseDown = false;
if (!_content.isHidden()) {
_clicks.fire({});
}
}
}, _content.lifetime());
@ -118,6 +139,9 @@ void LargeVideo::setup(
}
_content.update();
}, _trackLifetime);
if (const auto size = track.track->frameSize(); !size.isEmpty()) {
_trackSize = size;
}
}, _content.lifetime());
setupControls(std::move(pinned));
@ -147,7 +171,7 @@ void LargeVideo::toggleControls() {
callback,
shown ? 0. : 1.,
shown ? 1. : 0.,
140);
st::slideWrapDuration);
}
}
@ -166,18 +190,26 @@ void LargeVideo::setupControls(rpl::producer<bool> pinned) {
void LargeVideo::updateControlsGeometry() {
if (_topControls) {
const auto &pin = st::groupCallLargeVideoPin.icon;
const auto pinWidth = pin.width();
const auto pinRight = (_content.width() - _st.pinPosition.x());
const auto pinLeft = pinRight - pin.width();
const auto pinTop = _st.pinPosition.y();
const auto &icon = st::groupCallLargeVideoCrossLine.icon;
const auto iconLeft = _content.width()
- _st.iconPosition.x()
- icon.width();
const auto skip = iconLeft - pinRight;
const auto skip1 = iconLeft - pinRight;
const auto &min = st::groupCallVideoMinimize;
const auto minRight = _content.width() - _st.minimizePosition.x();
const auto skip2 = pinLeft - minRight;
_pinButton.setGeometry(
pinRight - pin.width() - (skip / 2),
pinLeft - (skip2 / 2),
0,
pin.width() + skip,
pin.width() + (skip2 / 2) + (skip1 / 2),
pinTop * 2 + pin.height());
_minimizeButton->setGeometry(
minRight - min.width() - (skip2 / 2),
0,
min.width() + skip2,
pinTop * 2 + pin.height());
} else {
_pinButton.setGeometry(
@ -271,11 +303,11 @@ void LargeVideo::paintControls(Painter &p, QRect clip) {
0,
(_topControls
? anim::interpolate(-_st.shadowHeight, 0, shown)
: (height - _st.shadowHeight)),
: (height - anim::interpolate(_st.shadowHeight, 0, shown))),
width,
_st.shadowHeight);
const auto shadowFill = shadowRect.intersected(clip);
if (shadowFill.isEmpty()) {
if (shadowFill.isEmpty() && (_topControls || shown == 0.)) {
return;
}
const auto factor = style::DevicePixelRatio();
@ -287,6 +319,16 @@ void LargeVideo::paintControls(Painter &p, QRect clip) {
(shadowFill.y() - shadowRect.y()) * factor,
_shadow.width(),
shadowFill.height() * factor));
if (!_topControls && shown > 0.) {
auto color = st::radialBg->c;
color.setAlphaF(color.alphaF() * shown);
p.fillRect(clip, color);
p.setOpacity(shown);
st::groupCallVideoEnlarge.paintInCenter(p, _content.rect());
p.setOpacity(1.);
}
_track.row->lazyInitialize(st::groupCallMembersListItem);
// Name.
@ -338,6 +380,14 @@ void LargeVideo::paintControls(Painter &p, QRect clip) {
? (_st.pinPosition.y() + shift)
: (height - _st.pinPosition.y() - pin.height());
_pin.paint(p, pinLeft, pinTop, _pinned ? 1. : 0.);
// Minimize.
if (_topControls) {
const auto &min = st::groupCallVideoMinimize;
const auto minLeft = width - _st.minimizePosition.x() - min.width();
const auto minTop = _st.minimizePosition.y() + shift;
min.paint(p, minLeft, minTop, width);
}
}
QImage GenerateShadow(int height, int topAlpha, int bottomAlpha) {

View File

@ -64,8 +64,12 @@ public:
void setControlsShown(bool shown);
[[nodiscard]] rpl::producer<bool> pinToggled() const;
[[nodiscard]] rpl::producer<> minimizeClicks() const;
[[nodiscard]] rpl::producer<float64> controlsShown() const;
[[nodiscard]] rpl::producer<QSize> trackSizeValue() const;
[[nodiscard]] rpl::producer<> clicks() const {
return _clicks.events();
}
[[nodiscard]] rpl::lifetime &lifetime() {
return _content.lifetime();
@ -109,11 +113,14 @@ private:
QImage _shadow;
Ui::CrossLineAnimation _pin;
Ui::AbstractButton _pinButton;
std::unique_ptr<Ui::AbstractButton> _minimizeButton;
Ui::Animations::Simple _controlsAnimation;
rpl::variable<bool> _controlsShown = true;
rpl::event_stream<> _clicks;
const bool _topControls = true;
bool _pinned = false;
bool _mouseInside = false;
bool _mouseDown = false;
bool _toggleControlsScheduled = false;
rpl::variable<float64> _controlsShownRatio = 1.;
rpl::variable<QSize> _trackSize;

View File

@ -1605,6 +1605,10 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
}, lifetime());
}
rpl::producer<> Members::enlargeVideo() const {
return _pinnedVideo->clicks();
}
Row *Members::lookupRow(not_null<PeerData*> peer) const {
return _listController->findRow(peer);
}
@ -1681,8 +1685,8 @@ void Members::setupPinnedVideo() {
QSize(width, heightMax),
Qt::KeepAspectRatio);
const auto height = std::max(scaled.height(), heightMin);
_pinnedVideoWrap->resize(width, height);
_pinnedVideo->setGeometry(0, 0, width, height);
_pinnedVideoWrap->resize(width, height);
}, _pinnedVideo->lifetime());
}

View File

@ -53,6 +53,7 @@ public:
[[nodiscard]] rpl::producer<> addMembersRequests() const {
return _addMemberRequests.events();
}
[[nodiscard]] rpl::producer<> enlargeVideo() const;
[[nodiscard]] MembersRow *lookupRow(not_null<PeerData*> peer) const;

View File

@ -56,6 +56,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QApplication>
#include <QtGui/QWindow>
#include <QtGui/QScreen>
namespace Calls::Group {
namespace {
@ -970,6 +971,79 @@ void Panel::setupMembers() {
addMembers();
}
}, _callLifetime);
_members->enlargeVideo(
) | rpl::start_with_next([=] {
enlargeVideo();
}, _callLifetime);
}
void Panel::enlargeVideo() {
_lastSmallGeometry = _window->geometry();
const auto available = _window->screen()->availableGeometry();
const auto width = std::max(
_window->width(),
std::max(
std::min(available.width(), st::groupCallWideModeSize.width()),
st::groupCallWideModeWidthMin));
const auto height = std::max(
_window->height(),
std::min(available.height(), st::groupCallWideModeSize.height()));
auto geometry = QRect(
_window->x() - (width - _window->width()) / 2,
_window->y() - (height - _window->height()) / 2,
width,
height);
if (geometry.x() < available.x()) {
geometry.setX(std::min(available.x(), _window->x()));
}
if (geometry.x() + geometry.width()
> available.x() + available.width()) {
geometry.setX(std::max(
available.x() + available.width(),
_window->x() + _window->width()) - geometry.width());
}
if (geometry.y() < available.y()) {
geometry.setY(std::min(available.y(), _window->y()));
}
if (geometry.y() + geometry.height() > available.y() + available.height()) {
geometry.setY(std::max(
available.y() + available.height(),
_window->y() + _window->height()) - geometry.height());
}
if (_lastLargeMaximized) {
_window->setWindowState(
_window->windowState() | Qt::WindowMaximized);
} else {
_window->setGeometry((_lastLargeGeometry
&& available.intersects(*_lastLargeGeometry))
? *_lastLargeGeometry
: geometry);
}
}
void Panel::minimizeVideo() {
if (_window->windowState() & Qt::WindowMaximized) {
_lastLargeMaximized = true;
_window->setWindowState(
_window->windowState() & ~Qt::WindowMaximized);
} else {
_lastLargeMaximized = false;
_lastLargeGeometry = _window->geometry();
}
const auto available = _window->screen()->availableGeometry();
const auto width = st::groupCallWidth;
const auto height = st::groupCallHeight;
auto geometry = QRect(
_window->x() + (_window->width() - width) / 2,
_window->y() + (_window->height() - height) / 2,
width,
height);
_window->setGeometry((_lastSmallGeometry
&& available.intersects(*_lastSmallGeometry))
? *_lastSmallGeometry
: geometry);
}
void Panel::raiseControls() {
@ -1008,6 +1082,10 @@ void Panel::setupPinnedVideo() {
visible,
std::move(track),
_call->videoEndpointPinnedValue());
_pinnedVideo->minimizeClicks(
) | rpl::start_with_next([=] {
minimizeVideo();
}, _pinnedVideo->lifetime());
_pinnedVideo->pinToggled(
) | rpl::start_with_next([=](bool pinned) {
if (!pinned) {

View File

@ -93,6 +93,8 @@ private:
void startScheduledNow();
void trackControls();
void raiseControls();
void enlargeVideo();
void minimizeVideo();
bool updateMode();
void updateControlsGeometry();
@ -153,6 +155,9 @@ private:
object_ptr<Ui::FlatLabel> _startsWhen = { nullptr };
ChooseJoinAsProcess _joinAsProcess;
rpl::variable<bool> _videoMode;
std::optional<QRect> _lastSmallGeometry;
std::optional<QRect> _lastLargeGeometry;
bool _lastLargeMaximized = false;
object_ptr<Ui::RpWidget> _controlsBackground = { nullptr };
object_ptr<Ui::CallButton> _settings = { nullptr };