/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "ui/rp_widget.h" #include "ui/rect_part.h" #include "ui/effects/animations.h" #include "base/object_ptr.h" namespace Window { class SessionController; enum class Column; } // namespace Window namespace Media { namespace View { class PlaybackProgress; } // namespace View } // namespace Media namespace Media { namespace Streaming { class Instance; } // namespace Streaming } // namespace Media namespace Media { namespace Player { class Float : public Ui::RpWidget, private base::Subscriber { public: Float( QWidget *parent, not_null item, Fn toggleCallback, Fn draggedCallback, Fn)> doubleClickedCallback); [[nodiscard]] HistoryItem *item() const { return _item; } void setOpacity(float64 opacity) { if (_opacity != opacity) { _opacity = opacity; update(); } } [[nodiscard]] float64 countOpacityByParent() const { return outRatio(); } [[nodiscard]] bool isReady() const { return (getStreamed() != nullptr); } void detach(); [[nodiscard]] bool detached() const { return !_item; } [[nodiscard]] bool dragged() const { return _drag; } void resetMouseState() { _down = false; if (_drag) { finishDrag(false); } } protected: void paintEvent(QPaintEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void mouseDoubleClickEvent(QMouseEvent *e) override; private: [[nodiscard]] float64 outRatio() const; [[nodiscard]] Streaming::Instance *getStreamed() const; [[nodiscard]] View::PlaybackProgress *getPlayback() const; void repaintItem(); void prepareShadow(); bool hasFrame() const; bool fillFrame(); [[nodiscard]] QRect getInnerRect() const; void finishDrag(bool closed); void pauseResume(); HistoryItem *_item = nullptr; Fn _toggleCallback; float64 _opacity = 1.; QPixmap _shadow; QImage _frame; bool _down = false; QPoint _downPoint; bool _drag = false; QPoint _dragLocalPoint; Fn _draggedCallback; Fn)> _doubleClickedCallback; }; class FloatSectionDelegate { public: virtual QRect floatPlayerAvailableRect() = 0; virtual bool floatPlayerHandleWheelEvent(QEvent *e) = 0; }; class FloatDelegate { public: virtual not_null floatPlayerWidget() = 0; virtual not_null floatPlayerGetSection( Window::Column column) = 0; virtual void floatPlayerEnumerateSections(Fn widget, Window::Column widgetColumn)> callback) = 0; virtual bool floatPlayerIsVisible(not_null item) = 0; virtual rpl::producer<> floatPlayerCheckVisibilityRequests() { return _checkVisibility.events(); } virtual rpl::producer<> floatPlayerHideAllRequests() { return _hideAll.events(); } virtual rpl::producer<> floatPlayerShowVisibleRequests() { return _showVisible.events(); } virtual rpl::producer<> floatPlayerRaiseAllRequests() { return _raiseAll.events(); } virtual rpl::producer<> floatPlayerUpdatePositionsRequests() { return _updatePositions.events(); } virtual rpl::producer<> floatPlayerAreaUpdates() { return _areaUpdates.events(); } virtual void floatPlayerDoubleClickEvent( not_null item) { } struct FloatPlayerFilterWheelEventRequest { not_null object; not_null event; not_null*> result; }; virtual auto floatPlayerFilterWheelEventRequests() -> rpl::producer { return _filterWheelEvent.events(); } virtual ~FloatDelegate() = default; protected: void floatPlayerCheckVisibility() { _checkVisibility.fire({}); } void floatPlayerHideAll() { _hideAll.fire({}); } void floatPlayerShowVisible() { _showVisible.fire({}); } void floatPlayerRaiseAll() { _raiseAll.fire({}); } void floatPlayerUpdatePositions() { _updatePositions.fire({}); } void floatPlayerAreaUpdated() { _areaUpdates.fire({}); } std::optional floatPlayerFilterWheelEvent( not_null object, not_null event) { auto result = std::optional(); _filterWheelEvent.fire({ object, event, &result }); return result; } private: rpl::event_stream<> _checkVisibility; rpl::event_stream<> _hideAll; rpl::event_stream<> _showVisible; rpl::event_stream<> _raiseAll; rpl::event_stream<> _updatePositions; rpl::event_stream<> _areaUpdates; rpl::event_stream _filterWheelEvent; }; class FloatController : private base::Subscriber { public: explicit FloatController(not_null delegate); void replaceDelegate(not_null delegate); rpl::producer closeEvents() const { return _closeEvents.events(); } private: struct Item { template Item( not_null parent, not_null item, ToggleCallback toggle, DraggedCallback dragged, Fn)> doubleClicked); bool hiddenByWidget = false; bool hiddenByHistory = false; bool visible = false; RectPart animationSide; Ui::Animations::Simple visibleAnimation; Window::Column column; RectPart corner; QPoint dragFrom; Ui::Animations::Simple draggedAnimation; bool hiddenByDrag = false; object_ptr widget; }; void checkCurrent(); void create(not_null item); void toggle(not_null instance); void updatePosition(not_null instance); void remove(not_null instance); Item *current() const { return _items.empty() ? nullptr : _items.back().get(); } void finishDrag( not_null instance, bool closed); void updateColumnCorner(QPoint center); QPoint getPosition(not_null instance) const; QPoint getHiddenPosition( QPoint position, QSize size, RectPart side) const; RectPart getSide(QPoint center) const; void startDelegateHandling(); void checkVisibility(); void hideAll(); void showVisible(); void raiseAll(); void updatePositions(); std::optional filterWheelEvent( not_null object, not_null event); not_null _delegate; not_null _parent; std::vector> _items; rpl::event_stream _closeEvents; rpl::lifetime _delegateLifetime; }; } // namespace Player } // namespace Media