/* 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 #include #include #include "base/unique_qptr.h" namespace Ui { namespace details { struct ForwardTag { }; struct InPlaceTag { }; template class AttachmentOwner : public QObject { public: template AttachmentOwner(QObject *parent, const ForwardTag&, OtherValue &&value) : QObject(parent) , _value(std::forward(value)) { } template AttachmentOwner(QObject *parent, const InPlaceTag&, Args &&...args) : QObject(parent) , _value(std::forward(args)...) { } not_null value() { return &_value; } private: Value _value; }; } // namespace details class RpWidget; template inline base::unique_qptr CreateObject(Args &&...args) { return base::make_unique_q( nullptr, std::forward(args)...); } template inline Value *CreateChild( Parent *parent, Args &&...args) { Expects(parent != nullptr); if constexpr (std::is_base_of_v) { return new Value(parent, std::forward(args)...); } else { return CreateChild>( parent, details::InPlaceTag{}, std::forward(args)...)->value(); } } inline void DestroyChild(QWidget *child) { delete child; } void ResizeFitChild( not_null parent, not_null child); template inline not_null*> AttachAsChild( not_null parent, Value &&value) { return CreateChild>>( parent.get(), details::ForwardTag{}, std::forward(value))->value(); } template using RpWidgetParent = std::conditional_t< std::is_same_v, TWidget, TWidgetHelper>; template class RpWidgetWrap; class RpWidgetMethods { public: rpl::producer geometryValue() const; rpl::producer sizeValue() const; rpl::producer heightValue() const; rpl::producer widthValue() const; rpl::producer positionValue() const; rpl::producer leftValue() const; rpl::producer topValue() const; virtual rpl::producer desiredHeightValue() const; rpl::producer shownValue() const; rpl::producer paintRequest() const; rpl::producer<> alive() const; template void showOn(rpl::producer &&shown) { std::move( shown ) | rpl::start_with_next([this](bool visible) { callSetVisible(visible); }, lifetime()); } rpl::lifetime &lifetime(); virtual ~RpWidgetMethods() = default; protected: bool handleEvent(QEvent *event); virtual bool eventHook(QEvent *event) = 0; private: template friend class RpWidgetWrap; struct EventStreams { rpl::event_stream geometry; rpl::event_stream paint; rpl::event_stream shown; rpl::event_stream<> alive; }; struct Initer { Initer(QWidget *parent); }; virtual void callSetVisible(bool visible) = 0; virtual QPointer callCreateWeak() = 0; virtual QRect callGetGeometry() const = 0; virtual bool callIsHidden() const = 0; void visibilityChangedHook(bool wasVisible, bool nowVisible); EventStreams &eventStreams() const; mutable std::unique_ptr _eventStreams; rpl::lifetime _lifetime; }; template class RpWidgetWrap : public RpWidgetParent , public RpWidgetMethods { using Self = RpWidgetWrap; using Parent = RpWidgetParent; public: using Parent::Parent; void setVisible(bool visible) final override { auto wasVisible = !this->isHidden(); setVisibleHook(visible); visibilityChangedHook(wasVisible, !this->isHidden()); } ~RpWidgetWrap() { base::take(_lifetime); base::take(_eventStreams); } protected: bool event(QEvent *event) final override { return handleEvent(event); } bool eventHook(QEvent *event) override { return Parent::event(event); } virtual void setVisibleHook(bool visible) { Parent::setVisible(visible); } private: void callSetVisible(bool visible) override { Self::setVisible(visible); } QPointer callCreateWeak() override { return QPointer((QObject*)this); } QRect callGetGeometry() const override { return this->geometry(); } bool callIsHidden() const override { return this->isHidden(); } Initer _initer = { this }; }; class RpWidget : public RpWidgetWrap { public: using RpWidgetWrap::RpWidgetWrap; }; } // namespace Ui