layer_widget.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include "ui/layers/layer_widget.h"
  8. #include "ui/cached_special_layer_shadow_corners.h"
  9. #include "ui/layers/box_layer_widget.h"
  10. #include "ui/widgets/shadow.h"
  11. #include "ui/image/image_prepare.h"
  12. #include "ui/painter.h"
  13. #include "ui/ui_utility.h"
  14. #include "ui/round_rect.h"
  15. #include "ui/qt_weak_factory.h"
  16. #include "base/qt/qt_tab_key.h"
  17. #include "base/integration.h"
  18. #include "styles/style_layers.h"
  19. #include "styles/style_widgets.h"
  20. #include "styles/palette.h"
  21. #include <QtGui/QtEvents>
  22. namespace Ui {
  23. class LayerStackWidget::BackgroundWidget : public TWidget {
  24. public:
  25. using TWidget::TWidget;
  26. void setDoneCallback(Fn<void()> callback) {
  27. _doneCallback = std::move(callback);
  28. }
  29. void setLayerBoxes(const QRect &specialLayerBox, const QRect &layerBox);
  30. void setCacheImages(
  31. QPixmap &&bodyCache,
  32. QPixmap &&mainMenuCache,
  33. QPixmap &&specialLayerCache,
  34. QPixmap &&layerCache);
  35. void removeBodyCache();
  36. [[nodiscard]] bool hasBodyCache() const;
  37. void refreshBodyCache(QPixmap &&bodyCache);
  38. void startAnimation(Action action);
  39. void skipAnimation(Action action);
  40. void finishAnimating();
  41. bool animating() const {
  42. return _a_mainMenuShown.animating() || _a_specialLayerShown.animating() || _a_layerShown.animating();
  43. }
  44. protected:
  45. void paintEvent(QPaintEvent *e) override;
  46. private:
  47. bool isShown() const {
  48. return _mainMenuShown || _specialLayerShown || _layerShown;
  49. }
  50. void checkIfDone();
  51. void setMainMenuShown(bool shown);
  52. void setSpecialLayerShown(bool shown);
  53. void setLayerShown(bool shown);
  54. void checkWasShown(bool wasShown);
  55. void animationCallback();
  56. QPixmap _bodyCache;
  57. QPixmap _mainMenuCache;
  58. int _mainMenuCacheWidth = 0;
  59. QPixmap _specialLayerCache;
  60. QPixmap _layerCache;
  61. Fn<void()> _doneCallback;
  62. bool _wasAnimating = false;
  63. bool _inPaintEvent = false;
  64. bool _repaintIssued = false;
  65. Ui::Animations::Simple _a_shown;
  66. Ui::Animations::Simple _a_mainMenuShown;
  67. Ui::Animations::Simple _a_specialLayerShown;
  68. Ui::Animations::Simple _a_layerShown;
  69. QRect _specialLayerBox, _specialLayerCacheBox;
  70. QRect _layerBox, _layerCacheBox;
  71. int _mainMenuRight = 0;
  72. bool _mainMenuShown = false;
  73. bool _specialLayerShown = false;
  74. bool _layerShown = false;
  75. };
  76. void LayerStackWidget::BackgroundWidget::setCacheImages(
  77. QPixmap &&bodyCache,
  78. QPixmap &&mainMenuCache,
  79. QPixmap &&specialLayerCache,
  80. QPixmap &&layerCache) {
  81. _bodyCache = std::move(bodyCache);
  82. _mainMenuCache = std::move(mainMenuCache);
  83. _specialLayerCache = std::move(specialLayerCache);
  84. _layerCache = std::move(layerCache);
  85. _specialLayerCacheBox = _specialLayerBox;
  86. _layerCacheBox = _layerBox;
  87. _repaintIssued = false;
  88. setAttribute(Qt::WA_OpaquePaintEvent, !_bodyCache.isNull());
  89. }
  90. void LayerStackWidget::BackgroundWidget::removeBodyCache() {
  91. if (hasBodyCache()) {
  92. _bodyCache = {};
  93. setAttribute(Qt::WA_OpaquePaintEvent, false);
  94. }
  95. }
  96. bool LayerStackWidget::BackgroundWidget::hasBodyCache() const {
  97. return !_bodyCache.isNull();
  98. }
  99. void LayerStackWidget::BackgroundWidget::refreshBodyCache(
  100. QPixmap &&bodyCache) {
  101. _bodyCache = std::move(bodyCache);
  102. setAttribute(Qt::WA_OpaquePaintEvent, !_bodyCache.isNull());
  103. }
  104. void LayerStackWidget::BackgroundWidget::startAnimation(Action action) {
  105. if (action == Action::ShowMainMenu) {
  106. setMainMenuShown(true);
  107. } else if (action != Action::HideLayer
  108. && action != Action::HideSpecialLayer) {
  109. setMainMenuShown(false);
  110. }
  111. if (action == Action::ShowSpecialLayer) {
  112. setSpecialLayerShown(true);
  113. } else if (action == Action::ShowMainMenu
  114. || action == Action::HideAll
  115. || action == Action::HideSpecialLayer) {
  116. setSpecialLayerShown(false);
  117. }
  118. if (action == Action::ShowLayer) {
  119. setLayerShown(true);
  120. } else if (action != Action::ShowSpecialLayer
  121. && action != Action::HideSpecialLayer) {
  122. setLayerShown(false);
  123. }
  124. _wasAnimating = true;
  125. checkIfDone();
  126. }
  127. void LayerStackWidget::BackgroundWidget::skipAnimation(Action action) {
  128. _repaintIssued = false;
  129. startAnimation(action);
  130. finishAnimating();
  131. }
  132. void LayerStackWidget::BackgroundWidget::checkIfDone() {
  133. if (!_wasAnimating || _inPaintEvent || animating()) {
  134. return;
  135. }
  136. _wasAnimating = false;
  137. _mainMenuCache = _specialLayerCache = _layerCache = QPixmap();
  138. removeBodyCache();
  139. if (_doneCallback) {
  140. _doneCallback();
  141. }
  142. }
  143. void LayerStackWidget::BackgroundWidget::setMainMenuShown(bool shown) {
  144. auto wasShown = isShown();
  145. if (_mainMenuShown != shown) {
  146. _mainMenuShown = shown;
  147. _a_mainMenuShown.start([this] { animationCallback(); }, _mainMenuShown ? 0. : 1., _mainMenuShown ? 1. : 0., st::boxDuration, anim::easeOutCirc);
  148. }
  149. _mainMenuCacheWidth = (_mainMenuCache.width() / style::DevicePixelRatio())
  150. - st::boxRoundShadow.extend.right();
  151. _mainMenuRight = _mainMenuShown ? _mainMenuCacheWidth : 0;
  152. checkWasShown(wasShown);
  153. }
  154. void LayerStackWidget::BackgroundWidget::setSpecialLayerShown(bool shown) {
  155. auto wasShown = isShown();
  156. if (_specialLayerShown != shown) {
  157. _specialLayerShown = shown;
  158. _a_specialLayerShown.start([this] { animationCallback(); }, _specialLayerShown ? 0. : 1., _specialLayerShown ? 1. : 0., st::boxDuration);
  159. }
  160. checkWasShown(wasShown);
  161. }
  162. void LayerStackWidget::BackgroundWidget::setLayerShown(bool shown) {
  163. auto wasShown = isShown();
  164. if (_layerShown != shown) {
  165. _layerShown = shown;
  166. _a_layerShown.start([this] { animationCallback(); }, _layerShown ? 0. : 1., _layerShown ? 1. : 0., st::boxDuration);
  167. }
  168. checkWasShown(wasShown);
  169. }
  170. void LayerStackWidget::BackgroundWidget::checkWasShown(bool wasShown) {
  171. if (isShown() != wasShown) {
  172. _a_shown.start([this] { animationCallback(); }, wasShown ? 1. : 0., wasShown ? 0. : 1., st::boxDuration, anim::easeOutCirc);
  173. }
  174. }
  175. void LayerStackWidget::BackgroundWidget::setLayerBoxes(const QRect &specialLayerBox, const QRect &layerBox) {
  176. _specialLayerBox = specialLayerBox;
  177. _layerBox = layerBox;
  178. update();
  179. }
  180. void LayerStackWidget::BackgroundWidget::paintEvent(QPaintEvent *e) {
  181. Painter p(this);
  182. _inPaintEvent = true;
  183. auto guard = gsl::finally([this] {
  184. _inPaintEvent = false;
  185. crl::on_main(this, [=] { checkIfDone(); });
  186. });
  187. if (!_bodyCache.isNull()) {
  188. p.drawPixmap(0, 0, _bodyCache);
  189. }
  190. auto specialLayerBox = _specialLayerCache.isNull() ? _specialLayerBox : _specialLayerCacheBox;
  191. auto layerBox = _layerCache.isNull() ? _layerBox : _layerCacheBox;
  192. auto mainMenuProgress = _a_mainMenuShown.value(-1);
  193. auto mainMenuRight = (_mainMenuCache.isNull() || mainMenuProgress < 0) ? _mainMenuRight : (mainMenuProgress < 0) ? _mainMenuRight : anim::interpolate(0, _mainMenuCacheWidth, mainMenuProgress);
  194. if (mainMenuRight) {
  195. // Move showing boxes to the right while main menu is hiding.
  196. if (!_specialLayerCache.isNull()) {
  197. specialLayerBox.moveLeft(specialLayerBox.left() + mainMenuRight / 2);
  198. }
  199. if (!_layerCache.isNull()) {
  200. layerBox.moveLeft(layerBox.left() + mainMenuRight / 2);
  201. }
  202. }
  203. auto bgOpacity = _a_shown.value(isShown() ? 1. : 0.);
  204. auto specialLayerOpacity = _a_specialLayerShown.value(_specialLayerShown ? 1. : 0.);
  205. auto layerOpacity = _a_layerShown.value(_layerShown ? 1. : 0.);
  206. if (bgOpacity == 0.) {
  207. return;
  208. }
  209. p.setOpacity(bgOpacity);
  210. auto overSpecialOpacity = (layerOpacity * specialLayerOpacity);
  211. auto bg = myrtlrect(mainMenuRight, 0, width() - mainMenuRight, height());
  212. if (_mainMenuCache.isNull() && mainMenuRight > 0) {
  213. // All cache images are taken together with their shadows,
  214. // so we paint shadow only when there is no cache.
  215. Ui::Shadow::paint(p, myrtlrect(0, 0, mainMenuRight, height()), width(), st::boxRoundShadow, RectPart::Right);
  216. }
  217. if (_specialLayerCache.isNull() && !specialLayerBox.isEmpty()) {
  218. // All cache images are taken together with their shadows,
  219. // so we paint shadow only when there is no cache.
  220. auto sides = RectPart::Left | RectPart::Right;
  221. auto topCorners = (specialLayerBox.y() > 0);
  222. auto bottomCorners = (specialLayerBox.y() + specialLayerBox.height() < height());
  223. if (topCorners) {
  224. sides |= RectPart::Top;
  225. }
  226. if (bottomCorners) {
  227. sides |= RectPart::Bottom;
  228. }
  229. if (topCorners || bottomCorners) {
  230. p.setClipRegion(QRegion(rect()) - specialLayerBox.marginsRemoved(QMargins(st::boxRadius, 0, st::boxRadius, 0)) - specialLayerBox.marginsRemoved(QMargins(0, st::boxRadius, 0, st::boxRadius)));
  231. }
  232. Ui::Shadow::paint(p, specialLayerBox, width(), st::boxRoundShadow, Ui::SpecialLayerShadowCorners(), sides);
  233. if (topCorners || bottomCorners) {
  234. p.setClipping(false);
  235. }
  236. }
  237. if (!layerBox.isEmpty() && !_specialLayerCache.isNull() && overSpecialOpacity < bgOpacity) {
  238. // In case of moving special layer below the background while showing a box
  239. // we need to fill special layer rect below its cache with a complex opacity
  240. // (alpha_final - alpha_current) / (1 - alpha_current) so we won't get glitches
  241. // in the transparent special layer cache corners after filling special layer
  242. // rect above its cache with alpha_current opacity.
  243. const auto region = QRegion(bg) - specialLayerBox;
  244. for (const auto &rect : region) {
  245. p.fillRect(rect, st::layerBg);
  246. }
  247. p.setOpacity((bgOpacity - overSpecialOpacity) / (1. - (overSpecialOpacity * st::layerBg->c.alphaF())));
  248. p.fillRect(specialLayerBox, st::layerBg);
  249. p.setOpacity(bgOpacity);
  250. } else {
  251. p.fillRect(bg, st::layerBg);
  252. }
  253. if (!_specialLayerCache.isNull() && specialLayerOpacity > 0) {
  254. p.setOpacity(specialLayerOpacity);
  255. auto cacheLeft = specialLayerBox.x() - st::boxRoundShadow.extend.left();
  256. auto cacheTop = specialLayerBox.y() - (specialLayerBox.y() > 0 ? st::boxRoundShadow.extend.top() : 0);
  257. p.drawPixmapLeft(cacheLeft, cacheTop, width(), _specialLayerCache);
  258. }
  259. if (!layerBox.isEmpty()) {
  260. if (!_specialLayerCache.isNull()) {
  261. p.setOpacity(overSpecialOpacity);
  262. p.fillRect(specialLayerBox, st::layerBg);
  263. }
  264. if (_layerCache.isNull()) {
  265. p.setOpacity(layerOpacity);
  266. Ui::Shadow::paint(p, layerBox, width(), st::boxRoundShadow);
  267. }
  268. }
  269. if (!_layerCache.isNull() && layerOpacity > 0) {
  270. p.setOpacity(layerOpacity);
  271. p.drawPixmapLeft(layerBox.topLeft() - QPoint(st::boxRoundShadow.extend.left(), st::boxRoundShadow.extend.top()), width(), _layerCache);
  272. }
  273. if (!_mainMenuCache.isNull() && mainMenuRight > 0) {
  274. p.setOpacity(1.);
  275. auto shownWidth = mainMenuRight + st::boxRoundShadow.extend.right();
  276. auto sourceWidth = shownWidth * style::DevicePixelRatio();
  277. auto sourceRect = style::rtlrect(_mainMenuCache.width() - sourceWidth, 0, sourceWidth, _mainMenuCache.height(), _mainMenuCache.width());
  278. p.drawPixmapLeft(0, 0, shownWidth, height(), width(), _mainMenuCache, sourceRect);
  279. }
  280. if (!_repaintIssued && !_a_shown.animating()) {
  281. _repaintIssued = true;
  282. update();
  283. }
  284. }
  285. void LayerStackWidget::BackgroundWidget::finishAnimating() {
  286. _a_shown.stop();
  287. _a_mainMenuShown.stop();
  288. _a_specialLayerShown.stop();
  289. _a_layerShown.stop();
  290. checkIfDone();
  291. }
  292. void LayerStackWidget::BackgroundWidget::animationCallback() {
  293. update();
  294. checkIfDone();
  295. }
  296. LayerStackWidget::LayerStackWidget(QWidget *parent, ShowFactory showFactory)
  297. : RpWidget(parent)
  298. , _background(this)
  299. , _showFactory(std::move(showFactory)) {
  300. setGeometry(parentWidget()->rect());
  301. hide();
  302. _background->setDoneCallback([this] { animationDone(); });
  303. }
  304. void LayerWidget::setInnerFocus() {
  305. if (!isAncestorOf(window()->focusWidget())) {
  306. doSetInnerFocus();
  307. }
  308. }
  309. bool LayerWidget::overlaps(const QRect &globalRect) {
  310. if (isHidden()) {
  311. return false;
  312. }
  313. auto testRect = QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size());
  314. if (testAttribute(Qt::WA_OpaquePaintEvent)) {
  315. return rect().contains(testRect);
  316. }
  317. if (QRect(0, st::boxRadius, width(), height() - 2 * st::boxRadius).contains(testRect)) {
  318. return true;
  319. }
  320. if (QRect(st::boxRadius, 0, width() - 2 * st::boxRadius, height()).contains(testRect)) {
  321. return true;
  322. }
  323. return false;
  324. }
  325. void LayerWidget::mousePressEvent(QMouseEvent *e) {
  326. e->accept();
  327. }
  328. void LayerWidget::resizeEvent(QResizeEvent *e) {
  329. if (_resizedCallback) {
  330. _resizedCallback();
  331. }
  332. }
  333. bool LayerWidget::focusNextPrevChild(bool next) {
  334. return base::FocusNextPrevChildBlocked(this, next);
  335. }
  336. void LayerStackWidget::setHideByBackgroundClick(bool hide) {
  337. _hideByBackgroundClick = hide;
  338. }
  339. void LayerStackWidget::keyPressEvent(QKeyEvent *e) {
  340. if (e->key() == Qt::Key_Escape) {
  341. hideCurrent(anim::type::normal);
  342. }
  343. }
  344. void LayerStackWidget::mousePressEvent(QMouseEvent *e) {
  345. Ui::PostponeCall(this, [=] { backgroundClicked(); });
  346. }
  347. void LayerStackWidget::backgroundClicked() {
  348. if (!_hideByBackgroundClick) {
  349. return;
  350. }
  351. if (const auto layer = currentLayer()) {
  352. if (!layer->closeByOutsideClick()) {
  353. return;
  354. }
  355. } else if (const auto special = _specialLayer.data()) {
  356. if (!special->closeByOutsideClick()) {
  357. return;
  358. }
  359. }
  360. hideCurrent(anim::type::normal);
  361. }
  362. void LayerStackWidget::hideCurrent(anim::type animated) {
  363. return currentLayer() ? hideLayers(animated) : hideAll(animated);
  364. }
  365. void LayerStackWidget::hideLayers(anim::type animated) {
  366. startAnimation([] {}, [&] {
  367. clearLayers();
  368. }, Action::HideLayer, animated);
  369. }
  370. void LayerStackWidget::hideAll(anim::type animated) {
  371. startAnimation([] {}, [&] {
  372. clearLayers();
  373. clearSpecialLayer();
  374. _mainMenu.destroy();
  375. }, Action::HideAll, animated);
  376. }
  377. void LayerStackWidget::hideAllAnimatedPrepare() {
  378. prepareAnimation([] {}, [&] {
  379. clearLayers();
  380. clearSpecialLayer();
  381. _mainMenu.destroy();
  382. }, Action::HideAll, anim::type::normal);
  383. }
  384. void LayerStackWidget::hideAllAnimatedRun() {
  385. if (_background->hasBodyCache()) {
  386. removeBodyCache();
  387. hideChildren();
  388. auto bodyCache = Ui::GrabWidget(parentWidget());
  389. showChildren();
  390. _background->refreshBodyCache(std::move(bodyCache));
  391. }
  392. _background->startAnimation(Action::HideAll);
  393. }
  394. void LayerStackWidget::hideTopLayer(anim::type animated) {
  395. if (_specialLayer || _mainMenu) {
  396. hideLayers(animated);
  397. } else {
  398. hideAll(animated);
  399. }
  400. }
  401. void LayerStackWidget::removeBodyCache() {
  402. _background->removeBodyCache();
  403. setAttribute(Qt::WA_OpaquePaintEvent, false);
  404. }
  405. bool LayerStackWidget::layerShown() const {
  406. return _specialLayer || currentLayer() || _mainMenu;
  407. }
  408. const LayerWidget *LayerStackWidget::topShownLayer() const {
  409. if (const auto result = currentLayer()) {
  410. return result;
  411. } else if (const auto special = _specialLayer.data()) {
  412. return special;
  413. } else if (const auto menu = _mainMenu.data()) {
  414. return menu;
  415. }
  416. return nullptr;
  417. }
  418. void LayerStackWidget::setStyleOverrides(
  419. const style::Box *boxSt,
  420. const style::Box *layerSt) {
  421. _boxSt = boxSt;
  422. _layerSt = layerSt;
  423. }
  424. void LayerStackWidget::setCacheImages() {
  425. auto bodyCache = QPixmap(), mainMenuCache = QPixmap();
  426. auto specialLayerCache = QPixmap();
  427. if (_specialLayer) {
  428. Ui::SendPendingMoveResizeEvents(_specialLayer);
  429. auto sides = RectPart::Left | RectPart::Right;
  430. if (_specialLayer->y() > 0) {
  431. sides |= RectPart::Top;
  432. }
  433. if (_specialLayer->y() + _specialLayer->height() < height()) {
  434. sides |= RectPart::Bottom;
  435. }
  436. specialLayerCache = Ui::Shadow::grab(_specialLayer, st::boxRoundShadow, sides);
  437. }
  438. auto layerCache = QPixmap();
  439. if (auto layer = currentLayer()) {
  440. layerCache = Ui::Shadow::grab(layer, st::boxRoundShadow);
  441. }
  442. if (isAncestorOf(window()->focusWidget())) {
  443. setFocus();
  444. }
  445. if (_mainMenu) {
  446. removeBodyCache();
  447. hideChildren();
  448. bodyCache = Ui::GrabWidget(parentWidget());
  449. showChildren();
  450. mainMenuCache = Ui::Shadow::grab(_mainMenu, st::boxRoundShadow, RectPart::Right);
  451. }
  452. setAttribute(Qt::WA_OpaquePaintEvent, !bodyCache.isNull());
  453. updateLayerBoxes();
  454. _background->setCacheImages(std::move(bodyCache), std::move(mainMenuCache), std::move(specialLayerCache), std::move(layerCache));
  455. }
  456. void LayerStackWidget::closeLayer(not_null<LayerWidget*> layer) {
  457. const auto weak = Ui::MakeWeak(layer.get());
  458. if (Ui::InFocusChain(layer)) {
  459. setFocus();
  460. }
  461. if (!layer->setClosing()) {
  462. // This layer is already closing.
  463. return;
  464. } else if (!weak) {
  465. // setClosing() could've killed the layer.
  466. return;
  467. }
  468. if (layer == _specialLayer || layer == _mainMenu) {
  469. hideAll(anim::type::normal);
  470. } else if (layer == currentLayer()) {
  471. if (_layers.size() == 1) {
  472. hideCurrent(anim::type::normal);
  473. } else {
  474. const auto taken = std::move(_layers.back());
  475. _layers.pop_back();
  476. layer = currentLayer();
  477. layer->parentResized();
  478. if (!_background->animating()) {
  479. layer->show();
  480. showFinished();
  481. }
  482. }
  483. } else {
  484. for (auto i = _layers.begin(), e = _layers.end(); i != e; ++i) {
  485. if (layer == i->get()) {
  486. const auto taken = std::move(*i);
  487. _layers.erase(i);
  488. break;
  489. }
  490. }
  491. }
  492. }
  493. void LayerStackWidget::updateLayerBoxes() {
  494. const auto layerBox = [&] {
  495. if (const auto layer = currentLayer()) {
  496. return layer->geometry();
  497. }
  498. return QRect();
  499. }();
  500. const auto specialLayerBox = _specialLayer
  501. ? _specialLayer->geometry()
  502. : QRect();
  503. _background->setLayerBoxes(specialLayerBox, layerBox);
  504. update();
  505. }
  506. void LayerStackWidget::finishAnimating() {
  507. _background->finishAnimating();
  508. }
  509. bool LayerStackWidget::canSetFocus() const {
  510. return (currentLayer() || _specialLayer || _mainMenu);
  511. }
  512. void LayerStackWidget::setInnerFocus() {
  513. if (_background->animating()) {
  514. setFocus();
  515. } else if (auto l = currentLayer()) {
  516. l->setInnerFocus();
  517. } else if (_specialLayer) {
  518. _specialLayer->setInnerFocus();
  519. } else if (_mainMenu) {
  520. _mainMenu->setInnerFocus();
  521. }
  522. }
  523. bool LayerStackWidget::contentOverlapped(const QRect &globalRect) {
  524. if (isHidden()) {
  525. return false;
  526. }
  527. if (_specialLayer && _specialLayer->overlaps(globalRect)) {
  528. return true;
  529. }
  530. if (auto layer = currentLayer()) {
  531. return layer->overlaps(globalRect);
  532. }
  533. return false;
  534. }
  535. template <typename SetupNew, typename ClearOld>
  536. bool LayerStackWidget::prepareAnimation(
  537. SetupNew &&setupNewWidgets,
  538. ClearOld &&clearOldWidgets,
  539. Action action,
  540. anim::type animated) {
  541. if (animated == anim::type::instant) {
  542. setupNewWidgets();
  543. clearOldWidgets();
  544. prepareForAnimation();
  545. _background->skipAnimation(action);
  546. } else {
  547. setupNewWidgets();
  548. setCacheImages();
  549. const auto weak = Ui::MakeWeak(this);
  550. clearOldWidgets();
  551. if (weak) {
  552. prepareForAnimation();
  553. return true;
  554. }
  555. }
  556. return false;
  557. }
  558. template <typename SetupNew, typename ClearOld>
  559. void LayerStackWidget::startAnimation(
  560. SetupNew &&setupNewWidgets,
  561. ClearOld &&clearOldWidgets,
  562. Action action,
  563. anim::type animated) {
  564. const auto alive = prepareAnimation(
  565. std::forward<SetupNew>(setupNewWidgets),
  566. std::forward<ClearOld>(clearOldWidgets),
  567. action,
  568. animated);
  569. if (alive) {
  570. _background->startAnimation(action);
  571. }
  572. }
  573. void LayerStackWidget::resizeEvent(QResizeEvent *e) {
  574. const auto weak = Ui::MakeWeak(this);
  575. _background->setGeometry(rect());
  576. if (!weak) {
  577. return;
  578. }
  579. if (_specialLayer) {
  580. _specialLayer->parentResized();
  581. if (!weak) {
  582. return;
  583. }
  584. }
  585. if (const auto layer = currentLayer()) {
  586. layer->parentResized();
  587. if (!weak) {
  588. return;
  589. }
  590. }
  591. if (_mainMenu) {
  592. _mainMenu->parentResized();
  593. if (!weak) {
  594. return;
  595. }
  596. }
  597. updateLayerBoxes();
  598. }
  599. void LayerStackWidget::prepareForAnimation() {
  600. if (isHidden()) {
  601. show();
  602. }
  603. if (_mainMenu) {
  604. if (Ui::InFocusChain(_mainMenu)) {
  605. setFocus();
  606. }
  607. _mainMenu->hide();
  608. }
  609. if (_specialLayer) {
  610. if (Ui::InFocusChain(_specialLayer)) {
  611. setFocus();
  612. }
  613. _specialLayer->hide();
  614. }
  615. if (const auto layer = currentLayer()) {
  616. if (Ui::InFocusChain(layer)) {
  617. setFocus();
  618. }
  619. layer->hide();
  620. }
  621. }
  622. void LayerStackWidget::animationDone() {
  623. auto &integration = base::Integration::Instance();
  624. bool hidden = true;
  625. if (_mainMenu) {
  626. integration.setCrashAnnotation("ShowingWidget", u"MainMenu"_q);
  627. _mainMenu->show();
  628. hidden = false;
  629. }
  630. if (_specialLayer) {
  631. integration.setCrashAnnotation("ShowingWidget", u"SpecialLayer"_q);
  632. _specialLayer->show();
  633. hidden = false;
  634. }
  635. if (auto layer = currentLayer()) {
  636. integration.setCrashAnnotation("ShowingWidget", u"Box"_q);
  637. layer->show();
  638. hidden = false;
  639. }
  640. setAttribute(Qt::WA_OpaquePaintEvent, false);
  641. if (hidden) {
  642. _hideFinishStream.fire({});
  643. } else {
  644. integration.setCrashAnnotation("ShowingWidget", u"Finished"_q);
  645. showFinished();
  646. integration.setCrashAnnotation("ShowingWidget", QString());
  647. }
  648. }
  649. rpl::producer<> LayerStackWidget::hideFinishEvents() const {
  650. return _hideFinishStream.events();
  651. }
  652. void LayerStackWidget::showFinished() {
  653. fixOrder();
  654. sendFakeMouseEvent();
  655. updateLayerBoxes();
  656. if (_specialLayer) {
  657. _specialLayer->showFinished();
  658. }
  659. if (_mainMenu) {
  660. _mainMenu->showFinished();
  661. }
  662. if (auto layer = currentLayer()) {
  663. layer->showFinished();
  664. }
  665. if (canSetFocus()) {
  666. setInnerFocus();
  667. }
  668. }
  669. void LayerStackWidget::showSpecialLayer(
  670. object_ptr<LayerWidget> layer,
  671. anim::type animated) {
  672. startAnimation([&] {
  673. _specialLayer.destroy();
  674. _specialLayer = std::move(layer);
  675. initChildLayer(_specialLayer);
  676. }, [&] {
  677. _mainMenu.destroy();
  678. }, Action::ShowSpecialLayer, animated);
  679. }
  680. bool LayerStackWidget::showSectionInternal(
  681. not_null<::Window::SectionMemento*> memento,
  682. const ::Window::SectionShow &params) {
  683. if (_specialLayer) {
  684. return _specialLayer->showSectionInternal(memento, params);
  685. }
  686. return false;
  687. }
  688. void LayerStackWidget::hideSpecialLayer(anim::type animated) {
  689. startAnimation([] {}, [&] {
  690. clearSpecialLayer();
  691. _mainMenu.destroy();
  692. }, Action::HideSpecialLayer, animated);
  693. }
  694. void LayerStackWidget::showMainMenu(
  695. object_ptr<LayerWidget> layer,
  696. anim::type animated) {
  697. startAnimation([&] {
  698. _mainMenu = std::move(layer);
  699. initChildLayer(_mainMenu);
  700. _mainMenu->moveToLeft(0, 0);
  701. }, [&] {
  702. clearLayers();
  703. _specialLayer.destroy();
  704. }, Action::ShowMainMenu, animated);
  705. }
  706. void LayerStackWidget::showBox(
  707. object_ptr<BoxContent> box,
  708. LayerOptions options,
  709. anim::type animated) {
  710. showLayer(
  711. std::make_unique<BoxLayerWidget>(this, std::move(box)),
  712. options,
  713. animated);
  714. }
  715. void LayerStackWidget::showLayer(
  716. std::unique_ptr<LayerWidget> layer,
  717. LayerOptions options,
  718. anim::type animated) {
  719. if (options & LayerOption::KeepOther) {
  720. if (options & LayerOption::ShowAfterOther) {
  721. prependLayer(std::move(layer), animated);
  722. } else {
  723. appendLayer(std::move(layer), animated);
  724. }
  725. } else {
  726. replaceLayer(std::move(layer), animated);
  727. }
  728. }
  729. LayerWidget *LayerStackWidget::pushLayer(
  730. std::unique_ptr<LayerWidget> layer,
  731. anim::type animated) {
  732. const auto oldLayer = currentLayer();
  733. if (oldLayer) {
  734. if (Ui::InFocusChain(oldLayer)) {
  735. setFocus();
  736. }
  737. oldLayer->hide();
  738. }
  739. _layers.push_back(std::move(layer));
  740. const auto raw = _layers.back().get();
  741. initChildLayer(raw);
  742. if (_layers.size() > 1) {
  743. if (!_background->animating()) {
  744. raw->setVisible(true);
  745. showFinished();
  746. }
  747. } else {
  748. startAnimation([] {}, [&] {
  749. _mainMenu.destroy();
  750. }, Action::ShowLayer, animated);
  751. }
  752. return raw;
  753. }
  754. void LayerStackWidget::appendLayer(
  755. std::unique_ptr<LayerWidget> layer,
  756. anim::type animated) {
  757. pushLayer(std::move(layer), animated);
  758. }
  759. void LayerStackWidget::prependLayer(
  760. std::unique_ptr<LayerWidget> layer,
  761. anim::type animated) {
  762. if (_layers.empty()) {
  763. replaceLayer(std::move(layer), animated);
  764. return;
  765. }
  766. _layers.insert(
  767. begin(_layers),
  768. std::move(layer));
  769. const auto raw = _layers.front().get();
  770. raw->hide();
  771. initChildLayer(raw);
  772. }
  773. void LayerStackWidget::replaceLayer(
  774. std::unique_ptr<LayerWidget> layer,
  775. anim::type animated) {
  776. const auto pointer = pushLayer(std::move(layer), animated);
  777. const auto removeTill = ranges::find(
  778. _layers,
  779. pointer,
  780. &std::unique_ptr<LayerWidget>::get);
  781. _closingLayers.insert(
  782. end(_closingLayers),
  783. std::make_move_iterator(begin(_layers)),
  784. std::make_move_iterator(removeTill));
  785. _layers.erase(begin(_layers), removeTill);
  786. clearClosingLayers();
  787. }
  788. bool LayerStackWidget::takeToThirdSection() {
  789. return _specialLayer
  790. ? _specialLayer->takeToThirdSection()
  791. : false;
  792. }
  793. void LayerStackWidget::clearLayers() {
  794. _closingLayers.insert(
  795. end(_closingLayers),
  796. std::make_move_iterator(begin(_layers)),
  797. std::make_move_iterator(end(_layers)));
  798. _layers.clear();
  799. clearClosingLayers();
  800. }
  801. void LayerStackWidget::clearClosingLayers() {
  802. const auto weak = Ui::MakeWeak(this);
  803. while (!_closingLayers.empty()) {
  804. const auto index = _closingLayers.size() - 1;
  805. const auto layer = _closingLayers.back().get();
  806. if (Ui::InFocusChain(layer)) {
  807. setFocus();
  808. }
  809. // This may destroy LayerStackWidget (by calling Ui::hideLayer).
  810. // So each time we check a weak pointer (if we are still alive).
  811. layer->setClosing();
  812. // setClosing() could destroy 'this' or could call clearLayers().
  813. if (weak && !_closingLayers.empty()) {
  814. // We could enqueue more closing layers, so we remove by index.
  815. Assert(index < _closingLayers.size());
  816. Assert(_closingLayers[index].get() == layer);
  817. _closingLayers.erase(begin(_closingLayers) + index);
  818. } else {
  819. // Everything was destroyed in clearLayers or ~LayerStackWidget.
  820. break;
  821. }
  822. }
  823. }
  824. void LayerStackWidget::clearSpecialLayer() {
  825. if (_specialLayer) {
  826. _specialLayer->setClosing();
  827. _specialLayer.destroy();
  828. }
  829. }
  830. void LayerStackWidget::initChildLayer(LayerWidget *layer) {
  831. layer->setParent(this);
  832. layer->setClosedCallback([=] { closeLayer(layer); });
  833. layer->setResizedCallback([=] { updateLayerBoxes(); });
  834. Ui::SendPendingMoveResizeEvents(layer);
  835. layer->parentResized();
  836. }
  837. void LayerStackWidget::fixOrder() {
  838. if (const auto layer = currentLayer()) {
  839. _background->raise();
  840. layer->raise();
  841. } else if (_specialLayer) {
  842. _specialLayer->raise();
  843. }
  844. if (_mainMenu) {
  845. _mainMenu->raise();
  846. }
  847. }
  848. void LayerStackWidget::sendFakeMouseEvent() {
  849. SendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton);
  850. }
  851. LayerStackWidget::~LayerStackWidget() {
  852. // Some layer destructors call back into LayerStackWidget.
  853. while (!_layers.empty() || !_closingLayers.empty()) {
  854. hideAll(anim::type::instant);
  855. clearClosingLayers();
  856. }
  857. }
  858. } // namespace Ui