media_player_float.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #pragma once
  8. #include "base/object_ptr.h"
  9. #include "ui/effects/animations.h"
  10. #include "ui/rect_part.h"
  11. #include "ui/rp_widget.h"
  12. namespace Window {
  13. class SessionController;
  14. enum class Column;
  15. } // namespace Window
  16. namespace Media {
  17. namespace View {
  18. class PlaybackProgress;
  19. } // namespace View
  20. } // namespace Media
  21. namespace Media {
  22. namespace Streaming {
  23. class Instance;
  24. } // namespace Streaming
  25. } // namespace Media
  26. namespace Media {
  27. namespace Player {
  28. class RoundPainter {
  29. public:
  30. RoundPainter(not_null<HistoryItem*> item);
  31. bool fillFrame(const QSize &size);
  32. const QImage &frame() const;
  33. private:
  34. const not_null<HistoryItem*> _item;
  35. QImage _roundingMask;
  36. QImage _frame;
  37. };
  38. class Float final : public Ui::RpWidget {
  39. public:
  40. Float(
  41. QWidget *parent,
  42. not_null<HistoryItem*> item,
  43. Fn<void(bool visible)> toggleCallback,
  44. Fn<void(bool closed)> draggedCallback,
  45. Fn<void(not_null<const HistoryItem*>)> doubleClickedCallback);
  46. [[nodiscard]] HistoryItem *item() const {
  47. return _item;
  48. }
  49. void setOpacity(float64 opacity) {
  50. if (_opacity != opacity) {
  51. _opacity = opacity;
  52. update();
  53. }
  54. }
  55. [[nodiscard]] float64 countOpacityByParent() const {
  56. return outRatio();
  57. }
  58. [[nodiscard]] bool isReady() const {
  59. return (getStreamed() != nullptr);
  60. }
  61. void detach();
  62. [[nodiscard]] bool detached() const {
  63. return !_item;
  64. }
  65. [[nodiscard]] bool dragged() const {
  66. return _drag;
  67. }
  68. void resetMouseState() {
  69. _down = false;
  70. if (_drag) {
  71. finishDrag(false);
  72. }
  73. }
  74. protected:
  75. void paintEvent(QPaintEvent *e) override;
  76. void mouseMoveEvent(QMouseEvent *e) override;
  77. void mousePressEvent(QMouseEvent *e) override;
  78. void mouseReleaseEvent(QMouseEvent *e) override;
  79. void mouseDoubleClickEvent(QMouseEvent *e) override;
  80. private:
  81. [[nodiscard]] float64 outRatio() const;
  82. [[nodiscard]] Streaming::Instance *getStreamed() const;
  83. [[nodiscard]] View::PlaybackProgress *getPlayback() const;
  84. void repaintItem();
  85. void prepareShadow();
  86. bool hasFrame() const;
  87. [[nodiscard]] QRect getInnerRect() const;
  88. void finishDrag(bool closed);
  89. void pauseResume();
  90. HistoryItem *_item = nullptr;
  91. Fn<void(bool visible)> _toggleCallback;
  92. std::unique_ptr<RoundPainter> _roundPainter;
  93. float64 _opacity = 1.;
  94. QPixmap _shadow;
  95. bool _down = false;
  96. QPoint _downPoint;
  97. bool _drag = false;
  98. QPoint _dragLocalPoint;
  99. Fn<void(bool closed)> _draggedCallback;
  100. Fn<void(not_null<const HistoryItem*>)> _doubleClickedCallback;
  101. };
  102. class FloatSectionDelegate {
  103. public:
  104. virtual QRect floatPlayerAvailableRect() = 0;
  105. virtual bool floatPlayerHandleWheelEvent(QEvent *e) = 0;
  106. };
  107. class FloatDelegate {
  108. public:
  109. virtual not_null<Ui::RpWidget*> floatPlayerWidget() = 0;
  110. virtual void floatPlayerToggleGifsPaused(bool paused) = 0;
  111. virtual not_null<FloatSectionDelegate*> floatPlayerGetSection(
  112. Window::Column column) = 0;
  113. virtual void floatPlayerEnumerateSections(Fn<void(
  114. not_null<FloatSectionDelegate*> widget,
  115. Window::Column widgetColumn)> callback) = 0;
  116. virtual bool floatPlayerIsVisible(not_null<HistoryItem*> item) = 0;
  117. virtual rpl::producer<> floatPlayerCheckVisibilityRequests() {
  118. return _checkVisibility.events();
  119. }
  120. virtual rpl::producer<> floatPlayerHideAllRequests() {
  121. return _hideAll.events();
  122. }
  123. virtual rpl::producer<> floatPlayerShowVisibleRequests() {
  124. return _showVisible.events();
  125. }
  126. virtual rpl::producer<> floatPlayerRaiseAllRequests() {
  127. return _raiseAll.events();
  128. }
  129. virtual rpl::producer<> floatPlayerUpdatePositionsRequests() {
  130. return _updatePositions.events();
  131. }
  132. virtual rpl::producer<> floatPlayerAreaUpdates() {
  133. return _areaUpdates.events();
  134. }
  135. virtual void floatPlayerDoubleClickEvent(
  136. not_null<const HistoryItem*> item) {
  137. }
  138. struct FloatPlayerFilterWheelEventRequest {
  139. not_null<QObject*> object;
  140. not_null<QEvent*> event;
  141. not_null<std::optional<bool>*> result;
  142. };
  143. virtual auto floatPlayerFilterWheelEventRequests()
  144. -> rpl::producer<FloatPlayerFilterWheelEventRequest> {
  145. return _filterWheelEvent.events();
  146. }
  147. virtual ~FloatDelegate() = default;
  148. protected:
  149. void floatPlayerCheckVisibility() {
  150. _checkVisibility.fire({});
  151. }
  152. void floatPlayerHideAll() {
  153. _hideAll.fire({});
  154. }
  155. void floatPlayerShowVisible() {
  156. _showVisible.fire({});
  157. }
  158. void floatPlayerRaiseAll() {
  159. _raiseAll.fire({});
  160. }
  161. void floatPlayerUpdatePositions() {
  162. _updatePositions.fire({});
  163. }
  164. void floatPlayerAreaUpdated() {
  165. _areaUpdates.fire({});
  166. }
  167. std::optional<bool> floatPlayerFilterWheelEvent(
  168. not_null<QObject*> object,
  169. not_null<QEvent*> event) {
  170. auto result = std::optional<bool>();
  171. _filterWheelEvent.fire({ object, event, &result });
  172. return result;
  173. }
  174. private:
  175. rpl::event_stream<> _checkVisibility;
  176. rpl::event_stream<> _hideAll;
  177. rpl::event_stream<> _showVisible;
  178. rpl::event_stream<> _raiseAll;
  179. rpl::event_stream<> _updatePositions;
  180. rpl::event_stream<> _areaUpdates;
  181. rpl::event_stream<FloatPlayerFilterWheelEventRequest> _filterWheelEvent;
  182. };
  183. class FloatController final {
  184. public:
  185. explicit FloatController(not_null<FloatDelegate*> delegate);
  186. void replaceDelegate(not_null<FloatDelegate*> delegate);
  187. [[nodiscard]] rpl::producer<FullMsgId> closeEvents() const {
  188. return _closeEvents.events();
  189. }
  190. private:
  191. struct Item {
  192. template <typename ToggleCallback, typename DraggedCallback>
  193. Item(
  194. not_null<QWidget*> parent,
  195. not_null<HistoryItem*> item,
  196. ToggleCallback toggle,
  197. DraggedCallback dragged,
  198. Fn<void(not_null<const HistoryItem*>)> doubleClicked);
  199. bool hiddenByWidget = false;
  200. bool hiddenByHistory = false;
  201. bool visible = false;
  202. RectPart animationSide;
  203. Ui::Animations::Simple visibleAnimation;
  204. Window::Column column;
  205. RectPart corner;
  206. QPoint dragFrom;
  207. Ui::Animations::Simple draggedAnimation;
  208. bool hiddenByDrag = false;
  209. object_ptr<Float> widget;
  210. };
  211. void checkCurrent();
  212. void create(not_null<HistoryItem*> item);
  213. void toggle(not_null<Item*> instance);
  214. void updatePosition(not_null<Item*> instance);
  215. void remove(not_null<Item*> instance);
  216. Item *current() const {
  217. return _items.empty() ? nullptr : _items.back().get();
  218. }
  219. void finishDrag(
  220. not_null<Item*> instance,
  221. bool closed);
  222. void updateColumnCorner(QPoint center);
  223. QPoint getPosition(not_null<Item*> instance) const;
  224. QPoint getHiddenPosition(
  225. QPoint position,
  226. QSize size,
  227. RectPart side) const;
  228. RectPart getSide(QPoint center) const;
  229. void startDelegateHandling();
  230. void checkVisibility();
  231. void hideAll();
  232. void showVisible();
  233. void raiseAll();
  234. void updatePositions();
  235. std::optional<bool> filterWheelEvent(
  236. not_null<QObject*> object,
  237. not_null<QEvent*> event);
  238. not_null<FloatDelegate*> _delegate;
  239. not_null<Ui::RpWidget*> _parent;
  240. std::vector<std::unique_ptr<Item>> _items;
  241. rpl::event_stream<FullMsgId> _closeEvents;
  242. rpl::lifetime _delegateLifetime;
  243. rpl::lifetime _lifetime;
  244. };
  245. } // namespace Player
  246. } // namespace Media