| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #include "ui/layers/layer_widget.h"
- #include "ui/cached_special_layer_shadow_corners.h"
- #include "ui/layers/box_layer_widget.h"
- #include "ui/widgets/shadow.h"
- #include "ui/image/image_prepare.h"
- #include "ui/painter.h"
- #include "ui/ui_utility.h"
- #include "ui/round_rect.h"
- #include "ui/qt_weak_factory.h"
- #include "base/qt/qt_tab_key.h"
- #include "base/integration.h"
- #include "styles/style_layers.h"
- #include "styles/style_widgets.h"
- #include "styles/palette.h"
- #include <QtGui/QtEvents>
- namespace Ui {
- class LayerStackWidget::BackgroundWidget : public TWidget {
- public:
- using TWidget::TWidget;
- void setDoneCallback(Fn<void()> callback) {
- _doneCallback = std::move(callback);
- }
- void setLayerBoxes(const QRect &specialLayerBox, const QRect &layerBox);
- void setCacheImages(
- QPixmap &&bodyCache,
- QPixmap &&mainMenuCache,
- QPixmap &&specialLayerCache,
- QPixmap &&layerCache);
- void removeBodyCache();
- [[nodiscard]] bool hasBodyCache() const;
- void refreshBodyCache(QPixmap &&bodyCache);
- void startAnimation(Action action);
- void skipAnimation(Action action);
- void finishAnimating();
- bool animating() const {
- return _a_mainMenuShown.animating() || _a_specialLayerShown.animating() || _a_layerShown.animating();
- }
- protected:
- void paintEvent(QPaintEvent *e) override;
- private:
- bool isShown() const {
- return _mainMenuShown || _specialLayerShown || _layerShown;
- }
- void checkIfDone();
- void setMainMenuShown(bool shown);
- void setSpecialLayerShown(bool shown);
- void setLayerShown(bool shown);
- void checkWasShown(bool wasShown);
- void animationCallback();
- QPixmap _bodyCache;
- QPixmap _mainMenuCache;
- int _mainMenuCacheWidth = 0;
- QPixmap _specialLayerCache;
- QPixmap _layerCache;
- Fn<void()> _doneCallback;
- bool _wasAnimating = false;
- bool _inPaintEvent = false;
- bool _repaintIssued = false;
- Ui::Animations::Simple _a_shown;
- Ui::Animations::Simple _a_mainMenuShown;
- Ui::Animations::Simple _a_specialLayerShown;
- Ui::Animations::Simple _a_layerShown;
- QRect _specialLayerBox, _specialLayerCacheBox;
- QRect _layerBox, _layerCacheBox;
- int _mainMenuRight = 0;
- bool _mainMenuShown = false;
- bool _specialLayerShown = false;
- bool _layerShown = false;
- };
- void LayerStackWidget::BackgroundWidget::setCacheImages(
- QPixmap &&bodyCache,
- QPixmap &&mainMenuCache,
- QPixmap &&specialLayerCache,
- QPixmap &&layerCache) {
- _bodyCache = std::move(bodyCache);
- _mainMenuCache = std::move(mainMenuCache);
- _specialLayerCache = std::move(specialLayerCache);
- _layerCache = std::move(layerCache);
- _specialLayerCacheBox = _specialLayerBox;
- _layerCacheBox = _layerBox;
- _repaintIssued = false;
- setAttribute(Qt::WA_OpaquePaintEvent, !_bodyCache.isNull());
- }
- void LayerStackWidget::BackgroundWidget::removeBodyCache() {
- if (hasBodyCache()) {
- _bodyCache = {};
- setAttribute(Qt::WA_OpaquePaintEvent, false);
- }
- }
- bool LayerStackWidget::BackgroundWidget::hasBodyCache() const {
- return !_bodyCache.isNull();
- }
- void LayerStackWidget::BackgroundWidget::refreshBodyCache(
- QPixmap &&bodyCache) {
- _bodyCache = std::move(bodyCache);
- setAttribute(Qt::WA_OpaquePaintEvent, !_bodyCache.isNull());
- }
- void LayerStackWidget::BackgroundWidget::startAnimation(Action action) {
- if (action == Action::ShowMainMenu) {
- setMainMenuShown(true);
- } else if (action != Action::HideLayer
- && action != Action::HideSpecialLayer) {
- setMainMenuShown(false);
- }
- if (action == Action::ShowSpecialLayer) {
- setSpecialLayerShown(true);
- } else if (action == Action::ShowMainMenu
- || action == Action::HideAll
- || action == Action::HideSpecialLayer) {
- setSpecialLayerShown(false);
- }
- if (action == Action::ShowLayer) {
- setLayerShown(true);
- } else if (action != Action::ShowSpecialLayer
- && action != Action::HideSpecialLayer) {
- setLayerShown(false);
- }
- _wasAnimating = true;
- checkIfDone();
- }
- void LayerStackWidget::BackgroundWidget::skipAnimation(Action action) {
- _repaintIssued = false;
- startAnimation(action);
- finishAnimating();
- }
- void LayerStackWidget::BackgroundWidget::checkIfDone() {
- if (!_wasAnimating || _inPaintEvent || animating()) {
- return;
- }
- _wasAnimating = false;
- _mainMenuCache = _specialLayerCache = _layerCache = QPixmap();
- removeBodyCache();
- if (_doneCallback) {
- _doneCallback();
- }
- }
- void LayerStackWidget::BackgroundWidget::setMainMenuShown(bool shown) {
- auto wasShown = isShown();
- if (_mainMenuShown != shown) {
- _mainMenuShown = shown;
- _a_mainMenuShown.start([this] { animationCallback(); }, _mainMenuShown ? 0. : 1., _mainMenuShown ? 1. : 0., st::boxDuration, anim::easeOutCirc);
- }
- _mainMenuCacheWidth = (_mainMenuCache.width() / style::DevicePixelRatio())
- - st::boxRoundShadow.extend.right();
- _mainMenuRight = _mainMenuShown ? _mainMenuCacheWidth : 0;
- checkWasShown(wasShown);
- }
- void LayerStackWidget::BackgroundWidget::setSpecialLayerShown(bool shown) {
- auto wasShown = isShown();
- if (_specialLayerShown != shown) {
- _specialLayerShown = shown;
- _a_specialLayerShown.start([this] { animationCallback(); }, _specialLayerShown ? 0. : 1., _specialLayerShown ? 1. : 0., st::boxDuration);
- }
- checkWasShown(wasShown);
- }
- void LayerStackWidget::BackgroundWidget::setLayerShown(bool shown) {
- auto wasShown = isShown();
- if (_layerShown != shown) {
- _layerShown = shown;
- _a_layerShown.start([this] { animationCallback(); }, _layerShown ? 0. : 1., _layerShown ? 1. : 0., st::boxDuration);
- }
- checkWasShown(wasShown);
- }
- void LayerStackWidget::BackgroundWidget::checkWasShown(bool wasShown) {
- if (isShown() != wasShown) {
- _a_shown.start([this] { animationCallback(); }, wasShown ? 1. : 0., wasShown ? 0. : 1., st::boxDuration, anim::easeOutCirc);
- }
- }
- void LayerStackWidget::BackgroundWidget::setLayerBoxes(const QRect &specialLayerBox, const QRect &layerBox) {
- _specialLayerBox = specialLayerBox;
- _layerBox = layerBox;
- update();
- }
- void LayerStackWidget::BackgroundWidget::paintEvent(QPaintEvent *e) {
- Painter p(this);
- _inPaintEvent = true;
- auto guard = gsl::finally([this] {
- _inPaintEvent = false;
- crl::on_main(this, [=] { checkIfDone(); });
- });
- if (!_bodyCache.isNull()) {
- p.drawPixmap(0, 0, _bodyCache);
- }
- auto specialLayerBox = _specialLayerCache.isNull() ? _specialLayerBox : _specialLayerCacheBox;
- auto layerBox = _layerCache.isNull() ? _layerBox : _layerCacheBox;
- auto mainMenuProgress = _a_mainMenuShown.value(-1);
- auto mainMenuRight = (_mainMenuCache.isNull() || mainMenuProgress < 0) ? _mainMenuRight : (mainMenuProgress < 0) ? _mainMenuRight : anim::interpolate(0, _mainMenuCacheWidth, mainMenuProgress);
- if (mainMenuRight) {
- // Move showing boxes to the right while main menu is hiding.
- if (!_specialLayerCache.isNull()) {
- specialLayerBox.moveLeft(specialLayerBox.left() + mainMenuRight / 2);
- }
- if (!_layerCache.isNull()) {
- layerBox.moveLeft(layerBox.left() + mainMenuRight / 2);
- }
- }
- auto bgOpacity = _a_shown.value(isShown() ? 1. : 0.);
- auto specialLayerOpacity = _a_specialLayerShown.value(_specialLayerShown ? 1. : 0.);
- auto layerOpacity = _a_layerShown.value(_layerShown ? 1. : 0.);
- if (bgOpacity == 0.) {
- return;
- }
- p.setOpacity(bgOpacity);
- auto overSpecialOpacity = (layerOpacity * specialLayerOpacity);
- auto bg = myrtlrect(mainMenuRight, 0, width() - mainMenuRight, height());
- if (_mainMenuCache.isNull() && mainMenuRight > 0) {
- // All cache images are taken together with their shadows,
- // so we paint shadow only when there is no cache.
- Ui::Shadow::paint(p, myrtlrect(0, 0, mainMenuRight, height()), width(), st::boxRoundShadow, RectPart::Right);
- }
- if (_specialLayerCache.isNull() && !specialLayerBox.isEmpty()) {
- // All cache images are taken together with their shadows,
- // so we paint shadow only when there is no cache.
- auto sides = RectPart::Left | RectPart::Right;
- auto topCorners = (specialLayerBox.y() > 0);
- auto bottomCorners = (specialLayerBox.y() + specialLayerBox.height() < height());
- if (topCorners) {
- sides |= RectPart::Top;
- }
- if (bottomCorners) {
- sides |= RectPart::Bottom;
- }
- if (topCorners || bottomCorners) {
- p.setClipRegion(QRegion(rect()) - specialLayerBox.marginsRemoved(QMargins(st::boxRadius, 0, st::boxRadius, 0)) - specialLayerBox.marginsRemoved(QMargins(0, st::boxRadius, 0, st::boxRadius)));
- }
- Ui::Shadow::paint(p, specialLayerBox, width(), st::boxRoundShadow, Ui::SpecialLayerShadowCorners(), sides);
- if (topCorners || bottomCorners) {
- p.setClipping(false);
- }
- }
- if (!layerBox.isEmpty() && !_specialLayerCache.isNull() && overSpecialOpacity < bgOpacity) {
- // In case of moving special layer below the background while showing a box
- // we need to fill special layer rect below its cache with a complex opacity
- // (alpha_final - alpha_current) / (1 - alpha_current) so we won't get glitches
- // in the transparent special layer cache corners after filling special layer
- // rect above its cache with alpha_current opacity.
- const auto region = QRegion(bg) - specialLayerBox;
- for (const auto &rect : region) {
- p.fillRect(rect, st::layerBg);
- }
- p.setOpacity((bgOpacity - overSpecialOpacity) / (1. - (overSpecialOpacity * st::layerBg->c.alphaF())));
- p.fillRect(specialLayerBox, st::layerBg);
- p.setOpacity(bgOpacity);
- } else {
- p.fillRect(bg, st::layerBg);
- }
- if (!_specialLayerCache.isNull() && specialLayerOpacity > 0) {
- p.setOpacity(specialLayerOpacity);
- auto cacheLeft = specialLayerBox.x() - st::boxRoundShadow.extend.left();
- auto cacheTop = specialLayerBox.y() - (specialLayerBox.y() > 0 ? st::boxRoundShadow.extend.top() : 0);
- p.drawPixmapLeft(cacheLeft, cacheTop, width(), _specialLayerCache);
- }
- if (!layerBox.isEmpty()) {
- if (!_specialLayerCache.isNull()) {
- p.setOpacity(overSpecialOpacity);
- p.fillRect(specialLayerBox, st::layerBg);
- }
- if (_layerCache.isNull()) {
- p.setOpacity(layerOpacity);
- Ui::Shadow::paint(p, layerBox, width(), st::boxRoundShadow);
- }
- }
- if (!_layerCache.isNull() && layerOpacity > 0) {
- p.setOpacity(layerOpacity);
- p.drawPixmapLeft(layerBox.topLeft() - QPoint(st::boxRoundShadow.extend.left(), st::boxRoundShadow.extend.top()), width(), _layerCache);
- }
- if (!_mainMenuCache.isNull() && mainMenuRight > 0) {
- p.setOpacity(1.);
- auto shownWidth = mainMenuRight + st::boxRoundShadow.extend.right();
- auto sourceWidth = shownWidth * style::DevicePixelRatio();
- auto sourceRect = style::rtlrect(_mainMenuCache.width() - sourceWidth, 0, sourceWidth, _mainMenuCache.height(), _mainMenuCache.width());
- p.drawPixmapLeft(0, 0, shownWidth, height(), width(), _mainMenuCache, sourceRect);
- }
- if (!_repaintIssued && !_a_shown.animating()) {
- _repaintIssued = true;
- update();
- }
- }
- void LayerStackWidget::BackgroundWidget::finishAnimating() {
- _a_shown.stop();
- _a_mainMenuShown.stop();
- _a_specialLayerShown.stop();
- _a_layerShown.stop();
- checkIfDone();
- }
- void LayerStackWidget::BackgroundWidget::animationCallback() {
- update();
- checkIfDone();
- }
- LayerStackWidget::LayerStackWidget(QWidget *parent, ShowFactory showFactory)
- : RpWidget(parent)
- , _background(this)
- , _showFactory(std::move(showFactory)) {
- setGeometry(parentWidget()->rect());
- hide();
- _background->setDoneCallback([this] { animationDone(); });
- }
- void LayerWidget::setInnerFocus() {
- if (!isAncestorOf(window()->focusWidget())) {
- doSetInnerFocus();
- }
- }
- bool LayerWidget::overlaps(const QRect &globalRect) {
- if (isHidden()) {
- return false;
- }
- auto testRect = QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size());
- if (testAttribute(Qt::WA_OpaquePaintEvent)) {
- return rect().contains(testRect);
- }
- if (QRect(0, st::boxRadius, width(), height() - 2 * st::boxRadius).contains(testRect)) {
- return true;
- }
- if (QRect(st::boxRadius, 0, width() - 2 * st::boxRadius, height()).contains(testRect)) {
- return true;
- }
- return false;
- }
- void LayerWidget::mousePressEvent(QMouseEvent *e) {
- e->accept();
- }
- void LayerWidget::resizeEvent(QResizeEvent *e) {
- if (_resizedCallback) {
- _resizedCallback();
- }
- }
- bool LayerWidget::focusNextPrevChild(bool next) {
- return base::FocusNextPrevChildBlocked(this, next);
- }
- void LayerStackWidget::setHideByBackgroundClick(bool hide) {
- _hideByBackgroundClick = hide;
- }
- void LayerStackWidget::keyPressEvent(QKeyEvent *e) {
- if (e->key() == Qt::Key_Escape) {
- hideCurrent(anim::type::normal);
- }
- }
- void LayerStackWidget::mousePressEvent(QMouseEvent *e) {
- Ui::PostponeCall(this, [=] { backgroundClicked(); });
- }
- void LayerStackWidget::backgroundClicked() {
- if (!_hideByBackgroundClick) {
- return;
- }
- if (const auto layer = currentLayer()) {
- if (!layer->closeByOutsideClick()) {
- return;
- }
- } else if (const auto special = _specialLayer.data()) {
- if (!special->closeByOutsideClick()) {
- return;
- }
- }
- hideCurrent(anim::type::normal);
- }
- void LayerStackWidget::hideCurrent(anim::type animated) {
- return currentLayer() ? hideLayers(animated) : hideAll(animated);
- }
- void LayerStackWidget::hideLayers(anim::type animated) {
- startAnimation([] {}, [&] {
- clearLayers();
- }, Action::HideLayer, animated);
- }
- void LayerStackWidget::hideAll(anim::type animated) {
- startAnimation([] {}, [&] {
- clearLayers();
- clearSpecialLayer();
- _mainMenu.destroy();
- }, Action::HideAll, animated);
- }
- void LayerStackWidget::hideAllAnimatedPrepare() {
- prepareAnimation([] {}, [&] {
- clearLayers();
- clearSpecialLayer();
- _mainMenu.destroy();
- }, Action::HideAll, anim::type::normal);
- }
- void LayerStackWidget::hideAllAnimatedRun() {
- if (_background->hasBodyCache()) {
- removeBodyCache();
- hideChildren();
- auto bodyCache = Ui::GrabWidget(parentWidget());
- showChildren();
- _background->refreshBodyCache(std::move(bodyCache));
- }
- _background->startAnimation(Action::HideAll);
- }
- void LayerStackWidget::hideTopLayer(anim::type animated) {
- if (_specialLayer || _mainMenu) {
- hideLayers(animated);
- } else {
- hideAll(animated);
- }
- }
- void LayerStackWidget::removeBodyCache() {
- _background->removeBodyCache();
- setAttribute(Qt::WA_OpaquePaintEvent, false);
- }
- bool LayerStackWidget::layerShown() const {
- return _specialLayer || currentLayer() || _mainMenu;
- }
- const LayerWidget *LayerStackWidget::topShownLayer() const {
- if (const auto result = currentLayer()) {
- return result;
- } else if (const auto special = _specialLayer.data()) {
- return special;
- } else if (const auto menu = _mainMenu.data()) {
- return menu;
- }
- return nullptr;
- }
- void LayerStackWidget::setStyleOverrides(
- const style::Box *boxSt,
- const style::Box *layerSt) {
- _boxSt = boxSt;
- _layerSt = layerSt;
- }
- void LayerStackWidget::setCacheImages() {
- auto bodyCache = QPixmap(), mainMenuCache = QPixmap();
- auto specialLayerCache = QPixmap();
- if (_specialLayer) {
- Ui::SendPendingMoveResizeEvents(_specialLayer);
- auto sides = RectPart::Left | RectPart::Right;
- if (_specialLayer->y() > 0) {
- sides |= RectPart::Top;
- }
- if (_specialLayer->y() + _specialLayer->height() < height()) {
- sides |= RectPart::Bottom;
- }
- specialLayerCache = Ui::Shadow::grab(_specialLayer, st::boxRoundShadow, sides);
- }
- auto layerCache = QPixmap();
- if (auto layer = currentLayer()) {
- layerCache = Ui::Shadow::grab(layer, st::boxRoundShadow);
- }
- if (isAncestorOf(window()->focusWidget())) {
- setFocus();
- }
- if (_mainMenu) {
- removeBodyCache();
- hideChildren();
- bodyCache = Ui::GrabWidget(parentWidget());
- showChildren();
- mainMenuCache = Ui::Shadow::grab(_mainMenu, st::boxRoundShadow, RectPart::Right);
- }
- setAttribute(Qt::WA_OpaquePaintEvent, !bodyCache.isNull());
- updateLayerBoxes();
- _background->setCacheImages(std::move(bodyCache), std::move(mainMenuCache), std::move(specialLayerCache), std::move(layerCache));
- }
- void LayerStackWidget::closeLayer(not_null<LayerWidget*> layer) {
- const auto weak = Ui::MakeWeak(layer.get());
- if (Ui::InFocusChain(layer)) {
- setFocus();
- }
- if (!layer->setClosing()) {
- // This layer is already closing.
- return;
- } else if (!weak) {
- // setClosing() could've killed the layer.
- return;
- }
- if (layer == _specialLayer || layer == _mainMenu) {
- hideAll(anim::type::normal);
- } else if (layer == currentLayer()) {
- if (_layers.size() == 1) {
- hideCurrent(anim::type::normal);
- } else {
- const auto taken = std::move(_layers.back());
- _layers.pop_back();
- layer = currentLayer();
- layer->parentResized();
- if (!_background->animating()) {
- layer->show();
- showFinished();
- }
- }
- } else {
- for (auto i = _layers.begin(), e = _layers.end(); i != e; ++i) {
- if (layer == i->get()) {
- const auto taken = std::move(*i);
- _layers.erase(i);
- break;
- }
- }
- }
- }
- void LayerStackWidget::updateLayerBoxes() {
- const auto layerBox = [&] {
- if (const auto layer = currentLayer()) {
- return layer->geometry();
- }
- return QRect();
- }();
- const auto specialLayerBox = _specialLayer
- ? _specialLayer->geometry()
- : QRect();
- _background->setLayerBoxes(specialLayerBox, layerBox);
- update();
- }
- void LayerStackWidget::finishAnimating() {
- _background->finishAnimating();
- }
- bool LayerStackWidget::canSetFocus() const {
- return (currentLayer() || _specialLayer || _mainMenu);
- }
- void LayerStackWidget::setInnerFocus() {
- if (_background->animating()) {
- setFocus();
- } else if (auto l = currentLayer()) {
- l->setInnerFocus();
- } else if (_specialLayer) {
- _specialLayer->setInnerFocus();
- } else if (_mainMenu) {
- _mainMenu->setInnerFocus();
- }
- }
- bool LayerStackWidget::contentOverlapped(const QRect &globalRect) {
- if (isHidden()) {
- return false;
- }
- if (_specialLayer && _specialLayer->overlaps(globalRect)) {
- return true;
- }
- if (auto layer = currentLayer()) {
- return layer->overlaps(globalRect);
- }
- return false;
- }
- template <typename SetupNew, typename ClearOld>
- bool LayerStackWidget::prepareAnimation(
- SetupNew &&setupNewWidgets,
- ClearOld &&clearOldWidgets,
- Action action,
- anim::type animated) {
- if (animated == anim::type::instant) {
- setupNewWidgets();
- clearOldWidgets();
- prepareForAnimation();
- _background->skipAnimation(action);
- } else {
- setupNewWidgets();
- setCacheImages();
- const auto weak = Ui::MakeWeak(this);
- clearOldWidgets();
- if (weak) {
- prepareForAnimation();
- return true;
- }
- }
- return false;
- }
- template <typename SetupNew, typename ClearOld>
- void LayerStackWidget::startAnimation(
- SetupNew &&setupNewWidgets,
- ClearOld &&clearOldWidgets,
- Action action,
- anim::type animated) {
- const auto alive = prepareAnimation(
- std::forward<SetupNew>(setupNewWidgets),
- std::forward<ClearOld>(clearOldWidgets),
- action,
- animated);
- if (alive) {
- _background->startAnimation(action);
- }
- }
- void LayerStackWidget::resizeEvent(QResizeEvent *e) {
- const auto weak = Ui::MakeWeak(this);
- _background->setGeometry(rect());
- if (!weak) {
- return;
- }
- if (_specialLayer) {
- _specialLayer->parentResized();
- if (!weak) {
- return;
- }
- }
- if (const auto layer = currentLayer()) {
- layer->parentResized();
- if (!weak) {
- return;
- }
- }
- if (_mainMenu) {
- _mainMenu->parentResized();
- if (!weak) {
- return;
- }
- }
- updateLayerBoxes();
- }
- void LayerStackWidget::prepareForAnimation() {
- if (isHidden()) {
- show();
- }
- if (_mainMenu) {
- if (Ui::InFocusChain(_mainMenu)) {
- setFocus();
- }
- _mainMenu->hide();
- }
- if (_specialLayer) {
- if (Ui::InFocusChain(_specialLayer)) {
- setFocus();
- }
- _specialLayer->hide();
- }
- if (const auto layer = currentLayer()) {
- if (Ui::InFocusChain(layer)) {
- setFocus();
- }
- layer->hide();
- }
- }
- void LayerStackWidget::animationDone() {
- auto &integration = base::Integration::Instance();
- bool hidden = true;
- if (_mainMenu) {
- integration.setCrashAnnotation("ShowingWidget", u"MainMenu"_q);
- _mainMenu->show();
- hidden = false;
- }
- if (_specialLayer) {
- integration.setCrashAnnotation("ShowingWidget", u"SpecialLayer"_q);
- _specialLayer->show();
- hidden = false;
- }
- if (auto layer = currentLayer()) {
- integration.setCrashAnnotation("ShowingWidget", u"Box"_q);
- layer->show();
- hidden = false;
- }
- setAttribute(Qt::WA_OpaquePaintEvent, false);
- if (hidden) {
- _hideFinishStream.fire({});
- } else {
- integration.setCrashAnnotation("ShowingWidget", u"Finished"_q);
- showFinished();
- integration.setCrashAnnotation("ShowingWidget", QString());
- }
- }
- rpl::producer<> LayerStackWidget::hideFinishEvents() const {
- return _hideFinishStream.events();
- }
- void LayerStackWidget::showFinished() {
- fixOrder();
- sendFakeMouseEvent();
- updateLayerBoxes();
- if (_specialLayer) {
- _specialLayer->showFinished();
- }
- if (_mainMenu) {
- _mainMenu->showFinished();
- }
- if (auto layer = currentLayer()) {
- layer->showFinished();
- }
- if (canSetFocus()) {
- setInnerFocus();
- }
- }
- void LayerStackWidget::showSpecialLayer(
- object_ptr<LayerWidget> layer,
- anim::type animated) {
- startAnimation([&] {
- _specialLayer.destroy();
- _specialLayer = std::move(layer);
- initChildLayer(_specialLayer);
- }, [&] {
- _mainMenu.destroy();
- }, Action::ShowSpecialLayer, animated);
- }
- bool LayerStackWidget::showSectionInternal(
- not_null<::Window::SectionMemento*> memento,
- const ::Window::SectionShow ¶ms) {
- if (_specialLayer) {
- return _specialLayer->showSectionInternal(memento, params);
- }
- return false;
- }
- void LayerStackWidget::hideSpecialLayer(anim::type animated) {
- startAnimation([] {}, [&] {
- clearSpecialLayer();
- _mainMenu.destroy();
- }, Action::HideSpecialLayer, animated);
- }
- void LayerStackWidget::showMainMenu(
- object_ptr<LayerWidget> layer,
- anim::type animated) {
- startAnimation([&] {
- _mainMenu = std::move(layer);
- initChildLayer(_mainMenu);
- _mainMenu->moveToLeft(0, 0);
- }, [&] {
- clearLayers();
- _specialLayer.destroy();
- }, Action::ShowMainMenu, animated);
- }
- void LayerStackWidget::showBox(
- object_ptr<BoxContent> box,
- LayerOptions options,
- anim::type animated) {
- showLayer(
- std::make_unique<BoxLayerWidget>(this, std::move(box)),
- options,
- animated);
- }
- void LayerStackWidget::showLayer(
- std::unique_ptr<LayerWidget> layer,
- LayerOptions options,
- anim::type animated) {
- if (options & LayerOption::KeepOther) {
- if (options & LayerOption::ShowAfterOther) {
- prependLayer(std::move(layer), animated);
- } else {
- appendLayer(std::move(layer), animated);
- }
- } else {
- replaceLayer(std::move(layer), animated);
- }
- }
- LayerWidget *LayerStackWidget::pushLayer(
- std::unique_ptr<LayerWidget> layer,
- anim::type animated) {
- const auto oldLayer = currentLayer();
- if (oldLayer) {
- if (Ui::InFocusChain(oldLayer)) {
- setFocus();
- }
- oldLayer->hide();
- }
- _layers.push_back(std::move(layer));
- const auto raw = _layers.back().get();
- initChildLayer(raw);
- if (_layers.size() > 1) {
- if (!_background->animating()) {
- raw->setVisible(true);
- showFinished();
- }
- } else {
- startAnimation([] {}, [&] {
- _mainMenu.destroy();
- }, Action::ShowLayer, animated);
- }
- return raw;
- }
- void LayerStackWidget::appendLayer(
- std::unique_ptr<LayerWidget> layer,
- anim::type animated) {
- pushLayer(std::move(layer), animated);
- }
- void LayerStackWidget::prependLayer(
- std::unique_ptr<LayerWidget> layer,
- anim::type animated) {
- if (_layers.empty()) {
- replaceLayer(std::move(layer), animated);
- return;
- }
- _layers.insert(
- begin(_layers),
- std::move(layer));
- const auto raw = _layers.front().get();
- raw->hide();
- initChildLayer(raw);
- }
- void LayerStackWidget::replaceLayer(
- std::unique_ptr<LayerWidget> layer,
- anim::type animated) {
- const auto pointer = pushLayer(std::move(layer), animated);
- const auto removeTill = ranges::find(
- _layers,
- pointer,
- &std::unique_ptr<LayerWidget>::get);
- _closingLayers.insert(
- end(_closingLayers),
- std::make_move_iterator(begin(_layers)),
- std::make_move_iterator(removeTill));
- _layers.erase(begin(_layers), removeTill);
- clearClosingLayers();
- }
- bool LayerStackWidget::takeToThirdSection() {
- return _specialLayer
- ? _specialLayer->takeToThirdSection()
- : false;
- }
- void LayerStackWidget::clearLayers() {
- _closingLayers.insert(
- end(_closingLayers),
- std::make_move_iterator(begin(_layers)),
- std::make_move_iterator(end(_layers)));
- _layers.clear();
- clearClosingLayers();
- }
- void LayerStackWidget::clearClosingLayers() {
- const auto weak = Ui::MakeWeak(this);
- while (!_closingLayers.empty()) {
- const auto index = _closingLayers.size() - 1;
- const auto layer = _closingLayers.back().get();
- if (Ui::InFocusChain(layer)) {
- setFocus();
- }
- // This may destroy LayerStackWidget (by calling Ui::hideLayer).
- // So each time we check a weak pointer (if we are still alive).
- layer->setClosing();
- // setClosing() could destroy 'this' or could call clearLayers().
- if (weak && !_closingLayers.empty()) {
- // We could enqueue more closing layers, so we remove by index.
- Assert(index < _closingLayers.size());
- Assert(_closingLayers[index].get() == layer);
- _closingLayers.erase(begin(_closingLayers) + index);
- } else {
- // Everything was destroyed in clearLayers or ~LayerStackWidget.
- break;
- }
- }
- }
- void LayerStackWidget::clearSpecialLayer() {
- if (_specialLayer) {
- _specialLayer->setClosing();
- _specialLayer.destroy();
- }
- }
- void LayerStackWidget::initChildLayer(LayerWidget *layer) {
- layer->setParent(this);
- layer->setClosedCallback([=] { closeLayer(layer); });
- layer->setResizedCallback([=] { updateLayerBoxes(); });
- Ui::SendPendingMoveResizeEvents(layer);
- layer->parentResized();
- }
- void LayerStackWidget::fixOrder() {
- if (const auto layer = currentLayer()) {
- _background->raise();
- layer->raise();
- } else if (_specialLayer) {
- _specialLayer->raise();
- }
- if (_mainMenu) {
- _mainMenu->raise();
- }
- }
- void LayerStackWidget::sendFakeMouseEvent() {
- SendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton);
- }
- LayerStackWidget::~LayerStackWidget() {
- // Some layer destructors call back into LayerStackWidget.
- while (!_layers.empty() || !_closingLayers.empty()) {
- hideAll(anim::type::instant);
- clearClosingLayers();
- }
- }
- } // namespace Ui
|