show_animation.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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/effects/show_animation.h"
  8. #include "ui/effects/animations.h"
  9. #include "ui/qt_weak_factory.h"
  10. #include "ui/rp_widget.h"
  11. #include "ui/ui_utility.h"
  12. #include "styles/style_widgets.h"
  13. namespace Ui::Animations {
  14. namespace {
  15. void AnimateWidgets(const Widgets &targets, bool show) {
  16. enum class Finish {
  17. Bad,
  18. Good,
  19. };
  20. struct Object {
  21. base::unique_qptr<Ui::RpWidget> container;
  22. QPointer<Ui::RpWidget> weakTarget;
  23. };
  24. struct State {
  25. rpl::event_stream<Finish> destroy;
  26. Ui::Animations::Simple animation;
  27. std::vector<Object> objects;
  28. };
  29. auto lifetime = std::make_shared<rpl::lifetime>();
  30. const auto state = lifetime->make_state<State>();
  31. const auto from = show ? 0. : 1.;
  32. const auto to = show ? 1. : 0.;
  33. for (const auto &target : targets) {
  34. state->objects.push_back({
  35. base::make_unique_q<Ui::RpWidget>(target->parentWidget()),
  36. Ui::MakeWeak(target),
  37. });
  38. const auto pixmap = Ui::GrabWidget(target);
  39. const auto raw = state->objects.back().container.get();
  40. raw->paintRequest(
  41. ) | rpl::start_with_next([=] {
  42. QPainter p(raw);
  43. p.setOpacity(state->animation.value(to));
  44. p.drawPixmap(QPoint(), pixmap);
  45. }, raw->lifetime());
  46. target->geometryValue(
  47. ) | rpl::start_with_next([=](const QRect &r) {
  48. raw->setGeometry(r);
  49. }, raw->lifetime());
  50. raw->show();
  51. if (!show) {
  52. target->hide();
  53. }
  54. }
  55. state->destroy.events(
  56. ) | rpl::take(
  57. 1
  58. ) | rpl::start_with_next([=](Finish type) mutable {
  59. if (type == Finish::Good && show) {
  60. for (const auto &object : state->objects) {
  61. if (object.weakTarget) {
  62. object.weakTarget->show();
  63. }
  64. }
  65. }
  66. if (lifetime) {
  67. base::take(lifetime)->destroy();
  68. }
  69. }, *lifetime);
  70. state->animation.start(
  71. [=](auto value) {
  72. for (const auto &object : state->objects) {
  73. object.container->update();
  74. if (!object.weakTarget && show) {
  75. state->destroy.fire(Finish::Bad);
  76. return;
  77. }
  78. }
  79. if (value == to) {
  80. state->destroy.fire(Finish::Good);
  81. }
  82. },
  83. from,
  84. to,
  85. st::defaultToggle.duration);
  86. }
  87. } // namespace
  88. void ShowWidgets(const Widgets &targets) {
  89. AnimateWidgets(targets, true);
  90. }
  91. void HideWidgets(const Widgets &targets) {
  92. AnimateWidgets(targets, false);
  93. }
  94. } // namespace Ui::Animations