diff --git a/ui/layers/box_content.cpp b/ui/layers/box_content.cpp index 484dffa..5034048 100644 --- a/ui/layers/box_content.cpp +++ b/ui/layers/box_content.cpp @@ -317,37 +317,65 @@ void BoxContent::paintEvent(QPaintEvent *e) { } } -BoxShow::BoxShow(not_null box) -: Show() -, _weak(Ui::MakeWeak(box.get())) { +BoxShow::BoxShow(not_null box) +: BoxShow(MakeWeak(box.get()), nullptr) { +} + +BoxShow::BoxShow(const BoxShow &other) +: BoxShow(other._weak, other._wrapped) { +} + +BoxShow::BoxShow(QPointer weak, ShowPtr wrapped) +: _weak(weak) +, _wrapped(std::move(wrapped)) { + if (!resolve()) { + if (const auto box = _weak.data()) { + box->boxClosing( + ) | rpl::start_with_next([=] { + resolve(); + _lifetime.destroy(); + }, _lifetime); + } + } } BoxShow::~BoxShow() = default; +bool BoxShow::resolve() const { + if (_wrapped) { + return true; + } else if (const auto strong = _weak.data()) { + if (strong->hasDelegate()) { + _wrapped = strong->getDelegate()->showFactory()(); + return true; + } + } + return false; +} + void BoxShow::showBox( object_ptr content, LayerOptions options) const { - if (const auto strong = _weak.data()) { - strong->getDelegate()->show(std::move(content), options); + if (resolve()) { + _wrapped->showBox(std::move(content), options); } } void BoxShow::hideLayer() const { - if (const auto strong = _weak.data()) { - strong->getDelegate()->hideLayer(); + if (resolve()) { + _wrapped->hideLayer(); } } not_null BoxShow::toastParent() const { - if (!_toastParent) { - Assert(_weak != nullptr); - _toastParent = Ui::MakeWeak(_weak->window()); // =( + if (resolve()) { + return _wrapped->toastParent(); } - return _toastParent.data(); + Unexpected("Stale BoxShow::toastParent call."); } bool BoxShow::valid() const { - return _weak; + return resolve() && _wrapped->valid(); } BoxShow::operator bool() const { diff --git a/ui/layers/box_content.h b/ui/layers/box_content.h index deeb8af..ec1ac76 100644 --- a/ui/layers/box_content.h +++ b/ui/layers/box_content.h @@ -95,6 +95,7 @@ public: return result; } + virtual ShowFactory showFactory() = 0; virtual QPointer outerContainer() = 0; }; @@ -190,6 +191,9 @@ public: prepare(); finishPrepare(); } + [[nodiscard]] bool hasDelegate() const { + return _delegate != nullptr; + } [[nodiscard]] not_null getDelegate() const { return _delegate; } @@ -352,6 +356,7 @@ private: class BoxShow : public Show { public: explicit BoxShow(not_null box); + BoxShow(const BoxShow &other); ~BoxShow(); void showBox( object_ptr content, @@ -360,9 +365,16 @@ public: [[nodiscard]] not_null toastParent() const override; [[nodiscard]] bool valid() const override; operator bool() const override; + private: - mutable QPointer _toastParent; + BoxShow(QPointer weak, ShowPtr wrapped); + + bool resolve() const; + const QPointer _weak; + mutable std::shared_ptr _wrapped; + rpl::lifetime _lifetime; + }; } // namespace Ui diff --git a/ui/layers/box_layer_widget.cpp b/ui/layers/box_layer_widget.cpp index 42333be..e0b90a4 100644 --- a/ui/layers/box_layer_widget.cpp +++ b/ui/layers/box_layer_widget.cpp @@ -238,6 +238,10 @@ void BoxLayerWidget::updateButtonsPositions() { } } +ShowFactory BoxLayerWidget::showFactory() { + return _layer->showFactory(); +} + QPointer BoxLayerWidget::outerContainer() { return parentWidget(); } diff --git a/ui/layers/box_layer_widget.h b/ui/layers/box_layer_widget.h index 8d6e182..4200ab9 100644 --- a/ui/layers/box_layer_widget.h +++ b/ui/layers/box_layer_widget.h @@ -58,6 +58,7 @@ public: void addTopButton(object_ptr button) override; void showLoading(bool show) override; void updateButtonsPositions() override; + ShowFactory showFactory() override; QPointer outerContainer() override; void setDimensions( diff --git a/ui/layers/layer_manager.cpp b/ui/layers/layer_manager.cpp index 91e3e9e..505b4f1 100644 --- a/ui/layers/layer_manager.cpp +++ b/ui/layers/layer_manager.cpp @@ -6,7 +6,67 @@ // #include "ui/layers/layer_manager.h" +#include "ui/layers/show.h" + namespace Ui { +namespace { + +class ManagerShow final : public Show { +public: + explicit ManagerShow(not_null manager); + ~ManagerShow(); + void showBox( + object_ptr content, + Ui::LayerOptions options = Ui::LayerOption::KeepOther) const override; + void hideLayer() const override; + [[nodiscard]] not_null toastParent() const override; + [[nodiscard]] bool valid() const override; + operator bool() const override; + +private: + const base::weak_ptr _manager; + +}; + +ManagerShow::ManagerShow(not_null manager) +: _manager(manager.get()) { +} + +ManagerShow::~ManagerShow() = default; + +void ManagerShow::showBox( + object_ptr content, + Ui::LayerOptions options) const { + if (const auto manager = _manager.get()) { + manager->showBox(std::move(content), options, anim::type::normal); + } +} + +void ManagerShow::hideLayer() const { + if (const auto manager = _manager.get()) { + manager->showBox( + object_ptr{ nullptr }, + Ui::LayerOption::CloseOther, + anim::type::normal); + } +} + +not_null ManagerShow::toastParent() const { + const auto manager = _manager.get(); + + Ensures(manager != nullptr); + return manager->toastParent(); +} + +bool ManagerShow::valid() const { + return (_manager.get() != nullptr); +} + +ManagerShow::operator bool() const { + return valid(); +} + +} // namespace LayerManager::LayerManager(not_null widget) : _widget(widget) { } @@ -67,7 +127,9 @@ void LayerManager::ensureLayerCreated() { if (_layer) { return; } - _layer.emplace(_widget); + _layer.emplace(_widget, crl::guard(this, [=] { + return std::make_shared(this); + })); _layer->setHideByBackgroundClick(_hideByBackgroundClick); _layer->setStyleOverrides(_boxSt, _layerSt); diff --git a/ui/layers/layer_manager.h b/ui/layers/layer_manager.h index cce68dc..ad23a22 100644 --- a/ui/layers/layer_manager.h +++ b/ui/layers/layer_manager.h @@ -6,6 +6,7 @@ // #pragma once +#include "base/weak_ptr.h" #include "ui/layers/layer_widget.h" #include @@ -19,7 +20,7 @@ namespace Ui { class BoxContent; class RpWidget; -class LayerManager final { +class LayerManager final : public base::has_weak_ptr { public: explicit LayerManager(not_null widget); @@ -36,7 +37,10 @@ public: void raise(); bool setFocus(); - const LayerWidget *topShownLayer() const; + [[nodiscard]] not_null toastParent() const { + return _widget; + } + [[nodiscard]] const LayerWidget *topShownLayer() const; private: void ensureLayerCreated(); diff --git a/ui/layers/layer_widget.cpp b/ui/layers/layer_widget.cpp index 18aa85d..5e86df3 100644 --- a/ui/layers/layer_widget.cpp +++ b/ui/layers/layer_widget.cpp @@ -324,9 +324,10 @@ void LayerStackWidget::BackgroundWidget::animationCallback() { checkIfDone(); } -LayerStackWidget::LayerStackWidget(QWidget *parent) +LayerStackWidget::LayerStackWidget(QWidget *parent, ShowFactory showFactory) : RpWidget(parent) -, _background(this) { +, _background(this) +, _showFactory(std::move(showFactory)) { setGeometry(parentWidget()->rect()); hide(); _background->setDoneCallback([this] { animationDone(); }); diff --git a/ui/layers/layer_widget.h b/ui/layers/layer_widget.h index 6c76b9e..4fab66b 100644 --- a/ui/layers/layer_widget.h +++ b/ui/layers/layer_widget.h @@ -32,7 +32,11 @@ enum class LayerOption { using LayerOptions = base::flags; inline constexpr auto is_flag_type(LayerOption) { return true; }; -class LayerWidget : public Ui::RpWidget { +class Show; +using ShowPtr = std::shared_ptr; +using ShowFactory = Fn; + +class LayerWidget : public RpWidget { public: using RpWidget::RpWidget; @@ -91,9 +95,9 @@ private: }; -class LayerStackWidget : public Ui::RpWidget { +class LayerStackWidget : public RpWidget { public: - LayerStackWidget(QWidget *parent); + LayerStackWidget(QWidget *parent, ShowFactory showFactory); void finishAnimating(); rpl::producer<> hideFinishEvents() const; @@ -107,6 +111,9 @@ public: [[nodiscard]] const style::Box *boxStyleOverride() const { return _boxSt; } + [[nodiscard]] ShowFactory showFactory() const { + return _showFactory; + } void showBox( object_ptr box, @@ -222,6 +229,8 @@ private: class BackgroundWidget; object_ptr _background; + ShowFactory _showFactory; + const style::Box *_boxSt = nullptr; const style::Box *_layerSt = nullptr; bool _hideByBackgroundClick = true; diff --git a/ui/layers/show.h b/ui/layers/show.h index c4f7a49..ba8e636 100644 --- a/ui/layers/show.h +++ b/ui/layers/show.h @@ -26,7 +26,4 @@ public: inline Show::~Show() = default; -using ShowPtr = std::shared_ptr; - - } // namespace Ui diff --git a/ui/widgets/separate_panel.cpp b/ui/widgets/separate_panel.cpp index d2acf72..c80c51d 100644 --- a/ui/widgets/separate_panel.cpp +++ b/ui/widgets/separate_panel.cpp @@ -425,7 +425,9 @@ void SeparatePanel::ensureLayerCreated() { if (_layer) { return; } - _layer = base::make_unique_q(_body); + _layer = base::make_unique_q( + _body, + crl::guard(this, [=] { return std::make_shared(this); })); _layer->setHideByBackgroundClick(false); _layer->move(0, 0); _body->sizeValue(