wrap.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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. #pragma once
  8. #include "ui/rp_widget.h"
  9. #include "base/object_ptr.h"
  10. namespace Ui {
  11. template <typename Widget, typename ParentType = RpWidget>
  12. class Wrap;
  13. namespace details {
  14. struct UnwrapHelper {
  15. template <
  16. typename Widget,
  17. typename = typename std::decay_t<Widget>::WrapParentType>
  18. static std::true_type Is(Widget &&widget);
  19. static std::false_type Is(...);
  20. template <typename Entity>
  21. static auto Unwrap(Entity *entity, std::true_type) {
  22. return entity
  23. ? entity->entity()
  24. : nullptr;
  25. }
  26. template <typename Entity>
  27. static Entity *Unwrap(Entity *entity, std::false_type) {
  28. return entity;
  29. }
  30. template <typename Entity>
  31. static auto Unwrap(Entity *entity) {
  32. using Selector = decltype(Is(std::declval<Entity>()));
  33. return Unwrap(
  34. entity,
  35. Selector());
  36. }
  37. };
  38. } // namespace details
  39. template <typename Widget>
  40. class Wrap<Widget, RpWidget> : public RpWidget {
  41. public:
  42. Wrap(QWidget *parent, object_ptr<Widget> &&child);
  43. Widget *wrapped() {
  44. return _wrapped;
  45. }
  46. const Widget *wrapped() const {
  47. return _wrapped;
  48. }
  49. auto entity() {
  50. return details::UnwrapHelper::Unwrap(wrapped());
  51. }
  52. auto entity() const {
  53. return details::UnwrapHelper::Unwrap(wrapped());
  54. }
  55. QMargins getMargins() const override {
  56. if (auto weak = wrapped()) {
  57. return weak->getMargins();
  58. }
  59. return RpWidget::getMargins();
  60. }
  61. int naturalWidth() const override {
  62. if (auto weak = wrapped()) {
  63. return weak->naturalWidth();
  64. }
  65. return RpWidget::naturalWidth();
  66. }
  67. using WrapParentType = RpWidget;
  68. protected:
  69. int resizeGetHeight(int newWidth) override {
  70. if (auto weak = wrapped()) {
  71. weak->resizeToWidth(newWidth);
  72. return weak->heightNoMargins();
  73. }
  74. return heightNoMargins();
  75. }
  76. void visibleTopBottomUpdated(
  77. int visibleTop,
  78. int visibleBottom) override {
  79. setChildVisibleTopBottom(
  80. wrapped(),
  81. visibleTop,
  82. visibleBottom);
  83. }
  84. virtual void wrappedSizeUpdated(QSize size) {
  85. resize(size);
  86. }
  87. private:
  88. object_ptr<Widget> _wrapped;
  89. };
  90. template <typename Widget>
  91. Wrap<Widget, RpWidget>::Wrap(
  92. QWidget *parent,
  93. object_ptr<Widget> &&child)
  94. : RpWidget(parent)
  95. , _wrapped(std::move(child)) {
  96. if (_wrapped) {
  97. _wrapped->sizeValue(
  98. ) | rpl::start_with_next([this](const QSize &value) {
  99. wrappedSizeUpdated(value);
  100. }, lifetime());
  101. _wrapped->setParent(this);
  102. _wrapped->show();
  103. _wrapped->move(0, 0);
  104. _wrapped->alive(
  105. ) | rpl::start_with_done([this] {
  106. _wrapped->setParent(nullptr);
  107. _wrapped = nullptr;
  108. delete this;
  109. }, lifetime());
  110. }
  111. }
  112. template <typename Widget, typename ParentType>
  113. class Wrap : public ParentType {
  114. public:
  115. using ParentType::ParentType;
  116. Widget *wrapped() {
  117. return static_cast<Widget*>(ParentType::wrapped());
  118. }
  119. const Widget *wrapped() const {
  120. return static_cast<const Widget*>(ParentType::wrapped());
  121. }
  122. auto entity() {
  123. return details::UnwrapHelper::Unwrap(wrapped());
  124. }
  125. auto entity() const {
  126. return details::UnwrapHelper::Unwrap(wrapped());
  127. }
  128. using WrapParentType = ParentType;
  129. };
  130. class OverrideMargins : public Wrap<RpWidget> {
  131. using Parent = Wrap<RpWidget>;
  132. public:
  133. OverrideMargins(
  134. QWidget *parent,
  135. object_ptr<RpWidget> &&child,
  136. QMargins margins = QMargins())
  137. : Parent(parent, std::move(child)), _margins(margins) {
  138. if (auto weak = wrapped()) {
  139. auto margins = weak->getMargins();
  140. resizeToWidth(weak->width()
  141. - margins.left()
  142. - margins.right());
  143. }
  144. }
  145. QMargins getMargins() const override {
  146. return _margins;
  147. }
  148. protected:
  149. int resizeGetHeight(int newWidth) override {
  150. if (auto weak = wrapped()) {
  151. weak->resizeToWidth(newWidth);
  152. weak->moveToLeft(_margins.left(), _margins.top());
  153. return weak->heightNoMargins();
  154. }
  155. return height();
  156. }
  157. private:
  158. void wrappedSizeUpdated(QSize size) override {
  159. auto margins = wrapped()->getMargins();
  160. resize(
  161. (size.width()
  162. - margins.left()
  163. - margins.right()
  164. + _margins.left()
  165. + _margins.right()),
  166. (size.height()
  167. - margins.top()
  168. - margins.bottom()
  169. + _margins.top()
  170. + _margins.bottom()));
  171. }
  172. QMargins _margins;
  173. };
  174. } // namespace Ui