1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "media/streaming/media_streaming_instance.h"
11 #include "ui/effects/animations.h"
12 #include "ui/round_rect.h"
13 #include "ui/rp_widget.h"
14 
15 #include <QtCore/QPointer>
16 
17 namespace Data {
18 class DocumentMedia;
19 } // namespace Data
20 
21 namespace Ui {
22 class IconButton;
23 template <typename Widget>
24 class FadeWrap;
25 namespace GL {
26 struct ChosenRenderer;
27 struct Capabilities;
28 } // namespace GL
29 } // namespace Ui
30 
31 namespace Media {
32 namespace Player {
33 struct TrackState;
34 } // namespace Player
35 
36 namespace View {
37 
38 class PlaybackProgress;
39 
40 [[nodiscard]] QRect RotatedRect(QRect rect, int rotation);
41 [[nodiscard]] bool UsePainterRotation(int rotation);
42 [[nodiscard]] QSize FlipSizeByRotation(QSize size, int rotation);
43 [[nodiscard]] QImage RotateFrameImage(QImage image, int rotation);
44 
45 class PipPanel final {
46 public:
47 	struct Position {
48 		RectParts attached = RectPart(0);
49 		RectParts snapped = RectPart(0);
50 		QRect geometry;
51 		QRect screen;
52 	};
53 
54 	PipPanel(
55 		QWidget *parent,
56 		Fn<Ui::GL::ChosenRenderer(Ui::GL::Capabilities)> renderer);
57 	void init();
58 
59 	[[nodiscard]] not_null<QWidget*> widget() const;
60 	[[nodiscard]] not_null<Ui::RpWidgetWrap*> rp() const;
61 
62 	void update();
63 	void setGeometry(QRect geometry);
64 
65 	void setAspectRatio(QSize ratio);
66 	[[nodiscard]] Position countPosition() const;
67 	void setPosition(Position position);
68 	[[nodiscard]] QRect inner() const;
69 	[[nodiscard]] RectParts attached() const;
70 	[[nodiscard]] bool useTransparency() const;
71 
72 	void setDragDisabled(bool disabled);
73 	[[nodiscard]] bool dragging() const;
74 
75 	void handleMousePress(QPoint position, Qt::MouseButton button);
76 	void handleMouseRelease(QPoint position, Qt::MouseButton button);
77 	void handleMouseMove(QPoint position);
78 
79 	[[nodiscard]] rpl::producer<> saveGeometryRequests() const;
80 
81 private:
82 	void setPositionDefault();
83 	void setPositionOnScreen(Position position, QRect available);
84 
85 	QScreen *myScreen() const;
86 	void startSystemDrag();
87 	void processDrag(QPoint point);
88 	void finishDrag(QPoint point);
89 	void updatePositionAnimated();
90 	void updateOverState(QPoint point);
91 	void moveAnimated(QPoint to);
92 	void updateDecorations();
93 
94 	const std::unique_ptr<Ui::RpWidgetWrap> _content;
95 	const QPointer<QWidget> _parent;
96 	RectParts _attached = RectParts();
97 	RectParts _snapped = RectParts();
98 	QSize _ratio;
99 
100 	bool _useTransparency = true;
101 	bool _dragDisabled = false;
102 	style::margins _padding;
103 
104 	RectPart _overState = RectPart();
105 	std::optional<RectPart> _pressState;
106 	QPoint _pressPoint;
107 	QRect _dragStartGeometry;
108 	std::optional<RectPart> _dragState;
109 	rpl::event_stream<> _saveGeometryRequests;
110 
111 	QPoint _positionAnimationFrom;
112 	QPoint _positionAnimationTo;
113 	Ui::Animations::Simple _positionAnimation;
114 
115 };
116 
117 class Pip final {
118 public:
119 	class Delegate {
120 	public:
121 		virtual void pipSaveGeometry(QByteArray geometry) = 0;
122 		[[nodiscard]] virtual QByteArray pipLoadGeometry() = 0;
123 		[[nodiscard]] virtual float64 pipPlaybackSpeed() = 0;
124 		[[nodiscard]] virtual QWidget *pipParentWidget() = 0;
125 	};
126 
127 	Pip(
128 		not_null<Delegate*> delegate,
129 		not_null<DocumentData*> data,
130 		FullMsgId contextId,
131 		std::shared_ptr<Streaming::Document> shared,
132 		FnMut<void()> closeAndContinue,
133 		FnMut<void()> destroy);
134 	~Pip();
135 
136 private:
137 	enum class OverState {
138 		None,
139 		Close,
140 		Enlarge,
141 		Playback,
142 		VolumeToggle,
143 		VolumeController,
144 		Other,
145 	};
146 	enum class ThumbState {
147 		Empty,
148 		Inline,
149 		Thumb,
150 		Good,
151 		Cover,
152 	};
153 	struct Button {
154 		QRect area;
155 		QRect icon;
156 		OverState state = OverState::None;
157 		Ui::Animations::Simple active;
158 	};
159 	struct ContentGeometry {
160 		QRect inner;
161 		RectParts attached = RectParts();
162 		float64 fade = 0.;
163 		QSize outer;
164 		int rotation = 0;
165 		int videoRotation = 0;
166 		bool useTransparency = false;
167 	};
168 	struct StaticContent {
169 		QImage image;
170 		bool blurred = false;
171 	};
172 	using FrameRequest = Streaming::FrameRequest;
173 	class Renderer;
174 	class RendererGL;
175 	class RendererSW;
176 
177 	void setupPanel();
178 	void setupButtons();
179 	void setupStreaming();
180 	void playbackPauseResume();
181 	void volumeChanged(float64 volume);
182 	void volumeToggled();
183 	void volumeControllerUpdate(QPoint position);
184 	void waitingAnimationCallback();
185 	void handleStreamingUpdate(Streaming::Update &&update);
186 	void handleStreamingError(Streaming::Error &&error);
187 	void saveGeometry();
188 
189 	void updatePlaybackState();
190 	void updatePlayPauseResumeState(const Player::TrackState &state);
191 	void restartAtSeekPosition(crl::time position);
192 
193 	[[nodiscard]] bool canUseVideoFrame() const;
194 	[[nodiscard]] QImage videoFrame(const FrameRequest &request) const;
195 	[[nodiscard]] Streaming::FrameWithInfo videoFrameWithInfo() const; // YUV
196 	[[nodiscard]] QImage staticContent() const;
197 	[[nodiscard]] OverState computeState(QPoint position) const;
198 	void setOverState(OverState state);
199 	void setPressedState(std::optional<OverState> state);
200 	[[nodiscard]] OverState shownActiveState() const;
201 	[[nodiscard]] float64 activeValue(const Button &button) const;
202 	void updateActiveState(OverState was);
203 	void updatePlaybackTexts(int64 position, int64 length, int64 frequency);
204 
205 	[[nodiscard]] static OverState ResolveShownOver(OverState state);
206 
207 	[[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer(
208 		Ui::GL::Capabilities capabilities);
209 	void paint(not_null<Renderer*> renderer) const;
210 
211 	void handleMouseMove(QPoint position);
212 	void handleMousePress(QPoint position, Qt::MouseButton button);
213 	void handleMouseRelease(QPoint position, Qt::MouseButton button);
214 	void handleDoubleClick(Qt::MouseButton button);
215 	void handleLeave();
216 	void handleClose();
217 
218 	void paintRadialLoadingContent(
219 		QPainter &p,
220 		const QRect &inner,
221 		QColor fg) const;
222 	void paintButtons(not_null<Renderer*> renderer, float64 shown) const;
223 	void paintPlayback(not_null<Renderer*> renderer, float64 shown) const;
224 	void paintPlaybackContent(QPainter &p, QRect outer, float64 shown) const;
225 	void paintPlaybackProgress(QPainter &p, QRect outer) const;
226 	void paintProgressBar(
227 		QPainter &p,
228 		const QRect &rect,
229 		float64 progress,
230 		int radius,
231 		float64 active) const;
232 	void paintPlaybackTexts(QPainter &p, QRect outer) const;
233 	void paintVolumeController(
234 		not_null<Renderer*> renderer,
235 		float64 shown) const;
236 	void paintVolumeControllerContent(
237 		QPainter &p,
238 		QRect outer,
239 		float64 shown) const;
240 	[[nodiscard]] QRect countRadialRect() const;
241 
242 	void seekUpdate(QPoint position);
243 	void seekProgress(float64 value);
244 	void seekFinish(float64 value);
245 
246 	const not_null<Delegate*> _delegate;
247 	not_null<DocumentData*> _data;
248 	FullMsgId _contextId;
249 	Streaming::Instance _instance;
250 	bool _opengl = false;
251 	PipPanel _panel;
252 	QSize _size;
253 	std::unique_ptr<PlaybackProgress> _playbackProgress;
254 	std::shared_ptr<Data::DocumentMedia> _dataMedia;
255 
256 	bool _showPause = false;
257 	bool _startPaused = false;
258 	bool _pausedBySeek = false;
259 	QString _timeAlready, _timeLeft;
260 	int _timeLeftWidth = 0;
261 	int _rotation = 0;
262 	float64 _lastPositiveVolume = 1.;
263 	crl::time _seekPositionMs = -1;
264 	crl::time _lastDurationMs = 0;
265 	OverState _over = OverState::None;
266 	std::optional<OverState> _pressed;
267 	std::optional<OverState> _lastHandledPress;
268 	Button _close;
269 	Button _enlarge;
270 	Button _playback;
271 	Button _play;
272 	Button _volumeToggle;
273 	Button _volumeController;
274 	Ui::Animations::Simple _controlsShown;
275 
276 	FnMut<void()> _closeAndContinue;
277 	FnMut<void()> _destroy;
278 
279 	mutable QImage _preparedCoverStorage;
280 	mutable ThumbState _preparedCoverState = ThumbState::Empty;
281 
282 };
283 
284 } // namespace View
285 } // namespace Media
286