slide_wrap.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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/wrap/slide_wrap.h"
  8. #include "ui/qt_weak_factory.h"
  9. #include "ui/ui_utility.h"
  10. #include "styles/style_basic.h"
  11. #include <rpl/combine.h>
  12. #include <range/v3/algorithm/find.hpp>
  13. namespace Ui {
  14. SlideWrap<RpWidget>::SlideWrap(
  15. QWidget *parent,
  16. object_ptr<RpWidget> &&child)
  17. : SlideWrap(
  18. parent,
  19. std::move(child),
  20. style::margins()) {
  21. }
  22. SlideWrap<RpWidget>::SlideWrap(
  23. QWidget *parent,
  24. const style::margins &padding)
  25. : SlideWrap(parent, nullptr, padding) {
  26. }
  27. SlideWrap<RpWidget>::SlideWrap(
  28. QWidget *parent,
  29. object_ptr<RpWidget> &&child,
  30. const style::margins &padding)
  31. : Parent(
  32. parent,
  33. object_ptr<PaddingWrap<RpWidget>>(
  34. parent,
  35. std::move(child),
  36. padding))
  37. , _duration(st::slideWrapDuration) {
  38. }
  39. SlideWrap<RpWidget> *SlideWrap<RpWidget>::setDuration(int duration) {
  40. _duration = duration;
  41. return this;
  42. }
  43. SlideWrap<RpWidget> *SlideWrap<RpWidget>::setDirectionUp(bool up) {
  44. _up = up;
  45. return this;
  46. }
  47. SlideWrap<RpWidget> *SlideWrap<RpWidget>::toggle(
  48. bool shown,
  49. anim::type animated) {
  50. auto animate = (animated == anim::type::normal) && _duration;
  51. auto changed = (_toggled != shown);
  52. if (changed) {
  53. _toggled = shown;
  54. if (animate) {
  55. _animation.start(
  56. [this] { animationStep(); },
  57. _toggled ? 0. : 1.,
  58. _toggled ? 1. : 0.,
  59. _duration,
  60. anim::linear);
  61. }
  62. }
  63. if (animate) {
  64. animationStep();
  65. } else {
  66. finishAnimating();
  67. }
  68. if (changed) {
  69. _toggledChanged.fire_copy(_toggled);
  70. }
  71. return this;
  72. }
  73. SlideWrap<RpWidget> *SlideWrap<RpWidget>::finishAnimating() {
  74. _animation.stop();
  75. animationStep();
  76. return this;
  77. }
  78. SlideWrap<RpWidget> *SlideWrap<RpWidget>::toggleOn(
  79. rpl::producer<bool> &&shown,
  80. anim::type animated) {
  81. std::move(
  82. shown
  83. ) | rpl::start_with_next([=](bool shown) {
  84. toggle(shown, animated);
  85. }, lifetime());
  86. finishAnimating();
  87. return this;
  88. }
  89. void SlideWrap<RpWidget>::setMinimalHeight(int height) {
  90. _minimalHeight = height;
  91. }
  92. void SlideWrap<RpWidget>::animationStep() {
  93. const auto weak = wrapped();
  94. if (weak && !_up) {
  95. const auto margins = getMargins();
  96. weak->moveToLeft(margins.left(), margins.top());
  97. }
  98. const auto newWidth = weak ? weak->width() : width();
  99. const auto current = _animation.value(_toggled ? 1. : 0.);
  100. const auto newHeight = weak
  101. ? (_animation.animating()
  102. ? anim::interpolate(
  103. _minimalHeight,
  104. weak->heightNoMargins(),
  105. current)
  106. : (_toggled ? weak->height() : _minimalHeight))
  107. : 0;
  108. if (weak && _up) {
  109. const auto margins = getMargins();
  110. weak->moveToLeft(
  111. margins.left(),
  112. margins.top() - (weak->height() - newHeight));
  113. }
  114. if (newWidth != width() || newHeight != height()) {
  115. resize(newWidth, newHeight);
  116. }
  117. const auto shouldBeHidden = !_toggled && !_animation.animating();
  118. if (shouldBeHidden != isHidden()) {
  119. const auto guard = MakeWeak(this);
  120. setVisible(!shouldBeHidden || _minimalHeight);
  121. if (shouldBeHidden && guard) {
  122. SendPendingMoveResizeEvents(this);
  123. }
  124. }
  125. }
  126. QMargins SlideWrap<RpWidget>::getMargins() const {
  127. auto result = wrapped()->getMargins();
  128. return (animating() || !_toggled)
  129. ? QMargins(result.left(), 0, result.right(), 0)
  130. : result;
  131. }
  132. int SlideWrap<RpWidget>::resizeGetHeight(int newWidth) {
  133. if (wrapped()) {
  134. wrapped()->resizeToWidth(newWidth);
  135. }
  136. return heightNoMargins();
  137. }
  138. void SlideWrap<RpWidget>::wrappedSizeUpdated(QSize size) {
  139. if (_animation.animating()) {
  140. animationStep();
  141. } else if (_toggled) {
  142. resize(size);
  143. }
  144. }
  145. rpl::producer<bool> MultiSlideTracker::atLeastOneShownValue() const {
  146. if (_widgets.empty()) {
  147. return rpl::single(false);
  148. }
  149. auto shown = std::vector<rpl::producer<bool>>();
  150. shown.reserve(_widgets.size());
  151. for (auto &widget : _widgets) {
  152. shown.push_back(widget->toggledValue());
  153. }
  154. return rpl::combine(
  155. std::move(shown),
  156. [](const std::vector<bool> &values) {
  157. return ranges::find(values, true) != values.end();
  158. });
  159. }
  160. } // namespace Ui