diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index ad1e2f7363..fa1b94a8fd 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2404,7 +2404,6 @@ void OverlayWidget::switchToPip() { _pip = std::make_unique(_streamed->instance.shared(), [=] { showDocument(_doc, Auth().data().message(msgId), {}, true); }); - _pip->move(0, 0); _pip->show(); _pip->events( ) | rpl::filter([=](not_null e) { diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index c25298079e..e2ab09fda1 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "window/window_controller.h" #include "styles/style_window.h" +#include "styles/style_mediaview.h" #include #include @@ -23,6 +24,14 @@ namespace { constexpr auto kPipLoaderPriority = 2; +[[nodiscard]] QRect ScreenFromPosition(QPoint point) { + const auto screen = QGuiApplication::screenAt(point); + const auto use = screen ? screen : QGuiApplication::primaryScreen(); + return use + ? use->availableGeometry() + : QRect(0, 0, st::windowDefaultWidth, st::windowDefaultHeight); +} + } // namespace Pip::Pip( @@ -66,11 +75,13 @@ void Pip::setupSize() { ? QSize(_size.width() * fit.height() / _size.height(), fit.height()) : QSize(fit.width(), _size.height() * fit.width() / _size.width()); } - resize(_size); - - auto policy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - policy.setHeightForWidth(true); - setSizePolicy(policy); + const auto skip = st::pipBorderSkip; + setGeometry({ + available.x() + skip, + available.y() + skip, + _size.width(), + _size.height() + }); } void Pip::setupStreaming() { @@ -166,6 +177,8 @@ void Pip::mouseReleaseEvent(QMouseEvent *e) { return; } else if (!base::take(_dragStartPosition)) { playbackPauseResume(); + } else { + finishDrag(e->globalPos()); } } @@ -207,11 +220,98 @@ void Pip::playbackPauseResume() { } } +[[nodiscard]] QPoint ClampToEdges(QRect screen, QRect inner) { + const auto skip = st::pipBorderSkip; + const auto area = st::pipBorderSnapArea; + const auto sleft = screen.x() + skip; + const auto stop = screen.y() + skip; + const auto sright = screen.x() + screen.width() - skip; + const auto sbottom = screen.y() + screen.height() - skip; + const auto ileft = inner.x(); + const auto itop = inner.y(); + const auto iright = inner.x() + inner.width(); + const auto ibottom = inner.y() + inner.height(); + auto shiftx = 0; + auto shifty = 0; + if (iright + shiftx >= sright - area && iright + shiftx < sright + area) { + shiftx += (sright - iright); + } + if (ileft + shiftx >= sleft - area && ileft + shiftx < sleft + area) { + shiftx += (sleft - ileft); + } + if (ibottom + shifty >= sbottom - area && ibottom + shifty < sbottom + area) { + shifty += (sbottom - ibottom); + } + if (itop + shifty >= stop - area && itop + shifty < stop + area) { + shifty += (stop - itop); + } + return inner.topLeft() + QPoint(shiftx, shifty); +} + void Pip::updatePosition(QPoint point) { Expects(_dragStartPosition.has_value()); const auto position = *_dragStartPosition + (point - *_pressPoint); - move(position); + const auto screen = ScreenFromPosition(point); + const auto clamped = ClampToEdges(screen, QRect(position, size())); + if (clamped != position) { + moveAnimated(clamped); + } else { + _positionAnimation.stop(); + move(position); + } +} + +void Pip::finishDrag(QPoint point) { + const auto screen = ScreenFromPosition(point); + const auto position = pos(); + const auto clamped = [&] { + auto result = position; + if (result.x() > screen.x() + screen.width() - width()) { + result.setX(screen.x() + screen.width() - width()); + } + if (result.x() < screen.x()) { + result.setX(screen.x()); + } + if (result.y() > screen.y() + screen.height() - height()) { + result.setY(screen.y() + screen.height() - height()); + } + if (result.y() < screen.y()) { + result.setY(screen.y()); + } + return result; + }(); + if (position != clamped) { + moveAnimated(clamped); + } else { + _positionAnimation.stop(); + } +} + +void Pip::updatePositionAnimated() { + const auto progress = _positionAnimation.value(1.); + if (!_positionAnimation.animating()) { + move(_positionAnimationTo); + return; + } + const auto from = QPointF(_positionAnimationFrom); + const auto to = QPointF(_positionAnimationTo); + move((from + (to - from) * progress).toPoint()); +} + +void Pip::moveAnimated(QPoint to) { + if (_positionAnimation.animating() && _positionAnimationTo == to) { + return; + } + _positionAnimationTo = to; + _positionAnimationFrom = pos(); + _positionAnimation.stop(); + _positionAnimation.start( + [=] { updatePositionAnimated(); }, + 0., + 1., + st::slideWrapDuration, + anim::easeOutCirc); } QImage Pip::videoFrame() const { diff --git a/Telegram/SourceFiles/media/view/media_view_pip.h b/Telegram/SourceFiles/media/view/media_view_pip.h index e3a71488f8..90d0ee4885 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.h +++ b/Telegram/SourceFiles/media/view/media_view_pip.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "media/streaming/media_streaming_instance.h" +#include "ui/effects/animations.h" #include "ui/rp_widget.h" namespace Media { @@ -40,10 +41,13 @@ private: void setupSize(); void setupStreaming(); void playbackPauseResume(); + void finishDrag(QPoint point); void updatePosition(QPoint point); void waitingAnimationCallback(); void handleStreamingUpdate(Streaming::Update &&update); void handleStreamingError(Streaming::Error &&error); + void updatePositionAnimated(); + void moveAnimated(QPoint to); [[nodiscard]] QImage videoFrame() const; [[nodiscard]] QImage videoFrameForDirectPaint() const; @@ -54,6 +58,10 @@ private: std::optional _dragStartPosition; FnMut _closeAndContinue; + QPoint _positionAnimationFrom; + QPoint _positionAnimationTo; + Ui::Animations::Simple _positionAnimation; + }; } // namespace View diff --git a/Telegram/SourceFiles/media/view/mediaview.style b/Telegram/SourceFiles/media/view/mediaview.style index f1a0a2a2d8..eaa5740383 100644 --- a/Telegram/SourceFiles/media/view/mediaview.style +++ b/Telegram/SourceFiles/media/view/mediaview.style @@ -209,5 +209,4 @@ themePreviewButtonsSkip: 20px; themePreviewDialogsWidth: 312px; pipBorderSkip: 20px; -pipBorderSnapArea: 10px; -pip \ No newline at end of file +pipBorderSnapArea: 16px;