Add shadow and round corners in PiP.

This commit is contained in:
John Preston 2020-01-29 16:16:22 +03:00
parent f81f37505b
commit 0fbd263562
2 changed files with 145 additions and 62 deletions

View File

@ -16,10 +16,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/platform/ui_platform_utility.h" #include "ui/platform/ui_platform_utility.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/widgets/shadow.h"
#include "window/window_controller.h" #include "window/window_controller.h"
#include "styles/style_window.h" #include "styles/style_window.h"
#include "styles/style_mediaview.h" #include "styles/style_mediaview.h"
#include "styles/style_layers.h" // st::boxTitleClose #include "styles/style_layers.h" // st::boxTitleClose
#include "styles/style_calls.h" // st::callShadow
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <QtGui/QScreen> #include <QtGui/QScreen>
@ -123,7 +125,8 @@ constexpr auto kSaveGeometryTimeout = crl::time(1000);
QSize minimalSize, QSize minimalSize,
QSize maximalSize, QSize maximalSize,
QSize ratio, QSize ratio,
RectPart by) { RectPart by,
RectParts attached) {
if (by == RectPart::Center) { if (by == RectPart::Center) {
return original; return original;
} else if (!original.width() && !original.height()) { } else if (!original.width() && !original.height()) {
@ -174,24 +177,40 @@ constexpr auto kSaveGeometryTimeout = crl::time(1000);
return QRect( return QRect(
original.topLeft() + QPoint( original.topLeft() + QPoint(
(original.width() - newSize.width()), (original.width() - newSize.width()),
(original.height() - newSize.height()) / 2), ((attached & RectPart::Top)
? 0
: (attached & RectPart::Bottom)
? (original.height() - newSize.height())
: (original.height() - newSize.height()) / 2)),
newSize); newSize);
case RectPart::Top: case RectPart::Top:
return QRect( return QRect(
original.topLeft() + QPoint( original.topLeft() + QPoint(
(original.width() - newSize.width()) / 2, ((attached & RectPart::Left)
? 0
: (attached & RectPart::Right)
? (original.width() - newSize.width())
: (original.width() - newSize.width()) / 2),
0), 0),
newSize); newSize);
case RectPart::Right: case RectPart::Right:
return QRect( return QRect(
original.topLeft() + QPoint( original.topLeft() + QPoint(
0, 0,
(original.height() - newSize.height()) / 2), ((attached & RectPart::Top)
? 0
: (attached & RectPart::Bottom)
? (original.height() - newSize.height())
: (original.height() - newSize.height()) / 2)),
newSize); newSize);
case RectPart::Bottom: case RectPart::Bottom:
return QRect( return QRect(
original.topLeft() + QPoint( original.topLeft() + QPoint(
(original.width() - newSize.width()) / 2, ((attached & RectPart::Left)
? 0
: (attached & RectPart::Right)
? (original.width() - newSize.width())
: (original.width() - newSize.width()) / 2),
(original.height() - newSize.height())), (original.height() - newSize.height())),
newSize); newSize);
} }
@ -239,11 +258,13 @@ PipPanel::PipPanel(
| Qt::WindowDoesNotAcceptFocus); | Qt::WindowDoesNotAcceptFocus);
setAttribute(Qt::WA_ShowWithoutActivating); setAttribute(Qt::WA_ShowWithoutActivating);
setAttribute(Qt::WA_MacAlwaysShowToolWindow); setAttribute(Qt::WA_MacAlwaysShowToolWindow);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
Ui::Platform::InitOnTopPanel(this); Ui::Platform::InitOnTopPanel(this);
setMouseTracking(true); setMouseTracking(true);
resize(0, 0); resize(0, 0);
show(); show();
Ui::Platform::IgnoreAllActivation(this); //Ui::Platform::IgnoreAllActivation(this);
} }
void PipPanel::setAspectRatio(QSize ratio) { void PipPanel::setAspectRatio(QSize ratio) {
@ -271,6 +292,10 @@ void PipPanel::setPosition(Position position) {
setPositionDefault(); setPositionDefault();
} }
rpl::producer<> PipPanel::saveGeometryRequests() const {
return _saveGeometryRequests.events();
}
QScreen *PipPanel::myScreen() const { QScreen *PipPanel::myScreen() const {
return windowHandle() ? windowHandle()->screen() : nullptr; return windowHandle() ? windowHandle()->screen() : nullptr;
} }
@ -282,13 +307,14 @@ PipPanel::Position PipPanel::countPosition() const {
} }
auto result = Position(); auto result = Position();
result.screen = screen->geometry(); result.screen = screen->geometry();
result.geometry = geometry(); result.geometry = geometry().marginsRemoved(_padding);
const auto available = screen->availableGeometry(); const auto available = screen->availableGeometry();
const auto skip = st::pipBorderSkip; const auto skip = st::pipBorderSkip;
const auto left = result.geometry.x(); const auto left = result.geometry.x();
const auto right = left + result.geometry.width(); const auto right = left + result.geometry.width();
const auto top = result.geometry.y(); const auto top = result.geometry.y();
const auto bottom = top + result.geometry.height(); const auto bottom = top + result.geometry.height();
if (!_dragState || *_dragState != RectPart::Center) {
if (left == available.x()) { if (left == available.x()) {
result.attached |= RectPart::Left; result.attached |= RectPart::Left;
} else if (right == available.x() + available.width()) { } else if (right == available.x() + available.width()) {
@ -307,6 +333,7 @@ PipPanel::Position PipPanel::countPosition() const {
} else if (bottom == available.y() + available.height() - skip) { } else if (bottom == available.y() + available.height() - skip) {
result.snapped |= RectPart::Bottom; result.snapped |= RectPart::Bottom;
} }
}
return result; return result;
} }
@ -393,16 +420,21 @@ void PipPanel::setPositionOnScreen(Position position, QRect available) {
geometry.moveTop(inner.y() + inner.height() - geometry.height()); geometry.moveTop(inner.y() + inner.height() - geometry.height());
} }
setGeometry(geometry); setGeometry(geometry.marginsAdded(_padding));
_attached = position.attached; updateDecorations();
update(); update();
} }
void PipPanel::paintEvent(QPaintEvent *e) { void PipPanel::paintEvent(QPaintEvent *e) {
QPainter p(this); QPainter p(this);
if (_useTransparency) {
Ui::Platform::StartTranslucentPaint(p, e);
}
auto request = FrameRequest(); auto request = FrameRequest();
request.resize = request.outer = size(); const auto inner = rect().marginsRemoved(_padding);
request.resize = request.outer = inner.size();
request.corners = RectPart(0) request.corners = RectPart(0)
| ((_attached & (RectPart::Left | RectPart::Top)) | ((_attached & (RectPart::Left | RectPart::Top))
? RectPart(0) ? RectPart(0)
@ -416,6 +448,12 @@ void PipPanel::paintEvent(QPaintEvent *e) {
| ((_attached & (RectPart::Bottom | RectPart::Left)) | ((_attached & (RectPart::Bottom | RectPart::Left))
? RectPart(0) ? RectPart(0)
: RectPart::BottomLeft); : RectPart::BottomLeft);
request.radius = ImageRoundRadius::Large;
if (_useTransparency) {
const auto sides = RectPart::AllSides & ~_attached;
Ui::Shadow::paint(p, inner, width(), st::callShadow);
}
p.translate(_padding.left(), _padding.top());
_paint(p, request); _paint(p, request);
} }
@ -430,7 +468,7 @@ void PipPanel::mousePressEvent(QMouseEvent *e) {
void PipPanel::mouseReleaseEvent(QMouseEvent *e) { void PipPanel::mouseReleaseEvent(QMouseEvent *e) {
if (e->button() != Qt::LeftButton || !base::take(_pressState)) { if (e->button() != Qt::LeftButton || !base::take(_pressState)) {
return; return;
} else if (!base::take(_dragStartGeometry)) { } else if (!base::take(_dragState)) {
//playbackPauseResume(); //playbackPauseResume();
} else { } else {
finishDrag(e->globalPos()); finishDrag(e->globalPos());
@ -439,26 +477,34 @@ void PipPanel::mouseReleaseEvent(QMouseEvent *e) {
void PipPanel::updateOverState(QPoint point) { void PipPanel::updateOverState(QPoint point) {
const auto size = st::pipResizeArea; const auto size = st::pipResizeArea;
const auto ignore = _attached | _snapped;
const auto count = [&](RectPart side, int padding) {
return (ignore & side) ? 0 : padding ? padding : size;
};
const auto left = count(RectPart::Left, _padding.left());
const auto top = count(RectPart::Top, _padding.top());
const auto right = count(RectPart::Right, _padding.right());
const auto bottom = count(RectPart::Bottom, _padding.bottom());
const auto overState = [&] { const auto overState = [&] {
if (point.x() < size) { if (point.x() < left) {
if (point.y() < size) { if (point.y() < top) {
return RectPart::TopLeft; return RectPart::TopLeft;
} else if (point.y() >= height() - size) { } else if (point.y() >= height() - bottom) {
return RectPart::BottomLeft; return RectPart::BottomLeft;
} else { } else {
return RectPart::Left; return RectPart::Left;
} }
} else if (point.x() >= width() - size) { } else if (point.x() >= width() - right) {
if (point.y() < size) { if (point.y() < top) {
return RectPart::TopRight; return RectPart::TopRight;
} else if (point.y() >= height() - size) { } else if (point.y() >= height() - bottom) {
return RectPart::BottomRight; return RectPart::BottomRight;
} else { } else {
return RectPart::Right; return RectPart::Right;
} }
} else if (point.y() < size) { } else if (point.y() < top) {
return RectPart::Top; return RectPart::Top;
} else if (point.y() >= height() - size) { } else if (point.y() >= height() - bottom) {
return RectPart::Bottom; return RectPart::Bottom;
} else { } else {
return RectPart::Center; return RectPart::Center;
@ -495,20 +541,21 @@ void PipPanel::mouseMoveEvent(QMouseEvent *e) {
} }
const auto point = e->globalPos(); const auto point = e->globalPos();
const auto distance = QApplication::startDragDistance(); const auto distance = QApplication::startDragDistance();
if (!_dragStartGeometry if (!_dragState
&& (point - _pressPoint).manhattanLength() > distance) { && (point - _pressPoint).manhattanLength() > distance) {
_dragStartGeometry = geometry(); _dragState = _pressState;
updateDecorations();
_dragStartGeometry = geometry().marginsRemoved(_padding);
} }
if (_dragStartGeometry) { if (_dragState) {
updatePosition(point); processDrag(point);
} }
} }
void PipPanel::updatePosition(QPoint point) { void PipPanel::processDrag(QPoint point) {
Expects(_dragStartGeometry.has_value()); Expects(_dragState.has_value());
Expects(_pressState.has_value());
const auto dragPart = *_pressState; const auto dragPart = *_dragState;
const auto screen = (dragPart == RectPart::Center) const auto screen = (dragPart == RectPart::Center)
? ScreenFromPosition(point) ? ScreenFromPosition(point)
: myScreen() : myScreen()
@ -526,7 +573,7 @@ void PipPanel::updatePosition(QPoint point) {
screen.height() / 2, screen.height() / 2,
Qt::KeepAspectRatio); Qt::KeepAspectRatio);
const auto geometry = Transformed( const auto geometry = Transformed(
*_dragStartGeometry, _dragStartGeometry,
minimalSize, minimalSize,
maximalSize, maximalSize,
point - _pressPoint, point - _pressPoint,
@ -536,7 +583,8 @@ void PipPanel::updatePosition(QPoint point) {
minimalSize, minimalSize,
maximalSize, maximalSize,
_ratio, _ratio,
dragPart); dragPart,
_attached);
const auto clamped = (dragPart == RectPart::Center) const auto clamped = (dragPart == RectPart::Center)
? ClampToEdges(screen, valid) ? ClampToEdges(screen, valid)
: valid.topLeft(); : valid.topLeft();
@ -544,23 +592,24 @@ void PipPanel::updatePosition(QPoint point) {
moveAnimated(clamped); moveAnimated(clamped);
} else { } else {
_positionAnimation.stop(); _positionAnimation.stop();
setGeometry(valid); setGeometry(valid.marginsAdded(_padding));
} }
} }
void PipPanel::finishDrag(QPoint point) { void PipPanel::finishDrag(QPoint point) {
const auto screen = ScreenFromPosition(point); const auto screen = ScreenFromPosition(point);
const auto inner = geometry().marginsRemoved(_padding);
const auto position = pos(); const auto position = pos();
const auto clamped = [&] { const auto clamped = [&] {
auto result = position; auto result = position;
if (result.x() > screen.x() + screen.width() - width()) { if (result.x() > screen.x() + screen.width() - inner.width()) {
result.setX(screen.x() + screen.width() - width()); result.setX(screen.x() + screen.width() - inner.width());
} }
if (result.x() < screen.x()) { if (result.x() < screen.x()) {
result.setX(screen.x()); result.setX(screen.x());
} }
if (result.y() > screen.y() + screen.height() - height()) { if (result.y() > screen.y() + screen.height() - inner.height()) {
result.setY(screen.y() + screen.height() - height()); result.setY(screen.y() + screen.height() - inner.height());
} }
if (result.y() < screen.y()) { if (result.y() < screen.y()) {
result.setY(screen.y()); result.setY(screen.y());
@ -571,18 +620,23 @@ void PipPanel::finishDrag(QPoint point) {
moveAnimated(clamped); moveAnimated(clamped);
} else { } else {
_positionAnimation.stop(); _positionAnimation.stop();
updateDecorations();
} }
} }
void PipPanel::updatePositionAnimated() { void PipPanel::updatePositionAnimated() {
const auto progress = _positionAnimation.value(1.); const auto progress = _positionAnimation.value(1.);
if (!_positionAnimation.animating()) { if (!_positionAnimation.animating()) {
move(_positionAnimationTo); move(_positionAnimationTo - QPoint(_padding.left(), _padding.top()));
if (!_dragState) {
updateDecorations();
}
return; return;
} }
const auto from = QPointF(_positionAnimationFrom); const auto from = QPointF(_positionAnimationFrom);
const auto to = QPointF(_positionAnimationTo); const auto to = QPointF(_positionAnimationTo);
move((from + (to - from) * progress).toPoint()); move((from + (to - from) * progress).toPoint()
- QPoint(_padding.left(), _padding.top()));
} }
void PipPanel::moveAnimated(QPoint to) { void PipPanel::moveAnimated(QPoint to) {
@ -590,7 +644,7 @@ void PipPanel::moveAnimated(QPoint to) {
return; return;
} }
_positionAnimationTo = to; _positionAnimationTo = to;
_positionAnimationFrom = pos(); _positionAnimationFrom = pos() + QPoint(_padding.left(), _padding.top());
_positionAnimation.stop(); _positionAnimation.stop();
_positionAnimation.start( _positionAnimation.start(
[=] { updatePositionAnimated(); }, [=] { updatePositionAnimated(); },
@ -600,6 +654,32 @@ void PipPanel::moveAnimated(QPoint to) {
anim::easeOutCirc); anim::easeOutCirc);
} }
void PipPanel::updateDecorations() {
const auto position = countPosition();
const auto center = position.geometry.center();
const auto use = Ui::Platform::TranslucentWindowsSupported(center);
const auto full = use ? st::callShadow.extend : style::margins();
const auto padding = style::margins(
(position.attached & RectPart::Left) ? 0 : full.left(),
(position.attached & RectPart::Top) ? 0 : full.top(),
(position.attached & RectPart::Right) ? 0 : full.right(),
(position.attached & RectPart::Bottom) ? 0 : full.bottom());
_snapped = position.snapped;
if (_padding == padding || _attached == position.attached) {
return;
}
const auto newGeometry = position.geometry.marginsAdded(padding);
_attached = position.attached;
_padding = padding;
_useTransparency = use;
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
setGeometry(newGeometry);
update();
if (!_dragState) {
_saveGeometryRequests.fire({});
}
}
Pip::Pip( Pip::Pip(
not_null<Delegate*> delegate, not_null<Delegate*> delegate,
std::shared_ptr<Streaming::Document> document, std::shared_ptr<Streaming::Document> document,
@ -610,7 +690,6 @@ Pip::Pip(
, _panel( , _panel(
_delegate->pipParentWidget(), _delegate->pipParentWidget(),
[=](QPainter &p, const FrameRequest &request) { paint(p, request); }) [=](QPainter &p, const FrameRequest &request) { paint(p, request); })
, _saveGeometryTimer([=] { saveGeometry(); })
, _playPauseResume( , _playPauseResume(
std::in_place, std::in_place,
&_panel, &_panel,
@ -640,9 +719,9 @@ void Pip::setupPanel() {
_panel.setPosition(Deserialize(_delegate->pipLoadGeometry())); _panel.setPosition(Deserialize(_delegate->pipLoadGeometry()));
_panel.show(); _panel.show();
_panel.geometryValue( _panel.saveGeometryRequests(
) | rpl::skip(1) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_saveGeometryTimer.callOnce(kSaveGeometryTimeout); saveGeometry();
}, _panel.lifetime()); }, _panel.lifetime());
_panel.events( _panel.events(

View File

@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/streaming/media_streaming_instance.h" #include "media/streaming/media_streaming_instance.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "base/timer.h"
#include <QtCore/QPointer> #include <QtCore/QPointer>
@ -55,6 +54,8 @@ public:
[[nodiscard]] Position countPosition() const; [[nodiscard]] Position countPosition() const;
void setPosition(Position position); void setPosition(Position position);
[[nodiscard]] rpl::producer<> saveGeometryRequests() const;
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override;
@ -66,15 +67,17 @@ private:
void setPositionOnScreen(Position position, QRect available); void setPositionOnScreen(Position position, QRect available);
QScreen *myScreen() const; QScreen *myScreen() const;
void processDrag(QPoint point);
void finishDrag(QPoint point); void finishDrag(QPoint point);
void updatePosition(QPoint point);
void updatePositionAnimated(); void updatePositionAnimated();
void updateOverState(QPoint point); void updateOverState(QPoint point);
void moveAnimated(QPoint to); void moveAnimated(QPoint to);
void updateDecorations();
QPointer<QWidget> _parent; QPointer<QWidget> _parent;
Fn<void(QPainter&, FrameRequest)> _paint; Fn<void(QPainter&, FrameRequest)> _paint;
RectParts _attached = RectParts(); RectParts _attached = RectParts();
RectParts _snapped = RectParts();
QSize _ratio; QSize _ratio;
bool _useTransparency = true; bool _useTransparency = true;
@ -83,7 +86,9 @@ private:
RectPart _overState = RectPart(); RectPart _overState = RectPart();
std::optional<RectPart> _pressState; std::optional<RectPart> _pressState;
QPoint _pressPoint; QPoint _pressPoint;
std::optional<QRect> _dragStartGeometry; QRect _dragStartGeometry;
std::optional<RectPart> _dragState;
rpl::event_stream<> _saveGeometryRequests;
QPoint _positionAnimationFrom; QPoint _positionAnimationFrom;
QPoint _positionAnimationTo; QPoint _positionAnimationTo;
@ -132,7 +137,6 @@ private:
Streaming::Instance _instance; Streaming::Instance _instance;
PipPanel _panel; PipPanel _panel;
QSize _size; QSize _size;
base::Timer _saveGeometryTimer;
base::unique_qptr<Ui::FadeWrap<Ui::IconButton>> _playPauseResume; base::unique_qptr<Ui::FadeWrap<Ui::IconButton>> _playPauseResume;
base::unique_qptr< Ui::FadeWrap<Ui::IconButton>> _pictureInPicture; base::unique_qptr< Ui::FadeWrap<Ui::IconButton>> _pictureInPicture;