generic_box.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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/layers/box_content.h"
  9. #include "ui/wrap/vertical_layout.h"
  10. #include <tuple>
  11. namespace st {
  12. extern const style::margins &boxRowPadding;
  13. } // namespace st
  14. namespace Ui {
  15. class GenericBox final : public BoxContent {
  16. public:
  17. // InitMethod::operator()(not_null<GenericBox*> box, InitArgs...)
  18. // init(box, args...)
  19. template <
  20. typename InitMethod,
  21. typename ...InitArgs,
  22. typename = decltype(std::declval<std::decay_t<InitMethod>>()(
  23. std::declval<not_null<GenericBox*>>(),
  24. std::declval<std::decay_t<InitArgs>>()...))>
  25. GenericBox(
  26. QWidget*,
  27. InitMethod &&init,
  28. InitArgs &&...args);
  29. void setWidth(int width) {
  30. _width = width;
  31. }
  32. void setFocusCallback(Fn<void()> callback) {
  33. _focus = callback;
  34. }
  35. void setInitScrollCallback(Fn<void()> callback) {
  36. _initScroll = callback;
  37. }
  38. void setShowFinishedCallback(Fn<void()> callback) {
  39. _showFinished = callback;
  40. }
  41. [[nodiscard]] rpl::producer<> showFinishes() const {
  42. return _showFinishes.events();
  43. }
  44. [[nodiscard]] int rowsCount() const;
  45. [[nodiscard]] int width() const;
  46. template <
  47. typename Widget,
  48. typename = std::enable_if_t<
  49. std::is_base_of_v<RpWidget, Widget>>>
  50. Widget *insertRow(
  51. int atPosition,
  52. object_ptr<Widget> &&child,
  53. const style::margins &margin = st::boxRowPadding) {
  54. return _content->insert(
  55. atPosition,
  56. std::move(child),
  57. margin);
  58. }
  59. template <
  60. typename Widget,
  61. typename = std::enable_if_t<
  62. std::is_base_of_v<RpWidget, Widget>>>
  63. Widget *addRow(
  64. object_ptr<Widget> &&child,
  65. const style::margins &margin = st::boxRowPadding) {
  66. return _content->add(std::move(child), margin);
  67. }
  68. void addSkip(int height);
  69. void setMaxHeight(int maxHeight) {
  70. _maxHeight = maxHeight;
  71. }
  72. void setMinHeight(int minHeight) {
  73. _minHeight = minHeight;
  74. }
  75. void setScrollStyle(const style::ScrollArea &st) {
  76. _scrollSt = &st;
  77. }
  78. void setInnerFocus() override;
  79. void showFinished() override;
  80. template <typename Widget>
  81. not_null<Widget*> setPinnedToTopContent(object_ptr<Widget> content) {
  82. return static_cast<Widget*>(
  83. doSetPinnedToTopContent(std::move(content)).get());
  84. }
  85. template <typename Widget>
  86. not_null<Widget*> setPinnedToBottomContent(object_ptr<Widget> content) {
  87. return static_cast<Widget*>(
  88. doSetPinnedToBottomContent(std::move(content)).get());
  89. }
  90. [[nodiscard]] not_null<Ui::VerticalLayout*> verticalLayout();
  91. using BoxContent::setNoContentMargin;
  92. private:
  93. template <typename InitMethod, typename ...InitArgs>
  94. struct Initer {
  95. template <
  96. typename OtherMethod,
  97. typename ...OtherArgs,
  98. typename = std::enable_if_t<
  99. std::is_constructible_v<InitMethod, OtherMethod&&>>>
  100. Initer(OtherMethod &&method, OtherArgs &&...args);
  101. void operator()(not_null<GenericBox*> box);
  102. template <std::size_t... I>
  103. void call(
  104. not_null<GenericBox*> box,
  105. std::index_sequence<I...>);
  106. InitMethod method;
  107. std::tuple<InitArgs...> args;
  108. };
  109. template <typename InitMethod, typename ...InitArgs>
  110. auto MakeIniter(InitMethod &&method, InitArgs &&...args)
  111. -> Initer<std::decay_t<InitMethod>, std::decay_t<InitArgs>...>;
  112. void prepare() override;
  113. not_null<Ui::RpWidget*> doSetPinnedToTopContent(
  114. object_ptr<Ui::RpWidget> content);
  115. not_null<Ui::RpWidget*> doSetPinnedToBottomContent(
  116. object_ptr<Ui::RpWidget> content);
  117. FnMut<void(not_null<GenericBox*>)> _init;
  118. Fn<void()> _focus;
  119. Fn<void()> _initScroll;
  120. Fn<void()> _showFinished;
  121. rpl::event_stream<> _showFinishes;
  122. object_ptr<Ui::VerticalLayout> _owned;
  123. not_null<Ui::VerticalLayout*> _content;
  124. const style::ScrollArea *_scrollSt = nullptr;
  125. int _width = 0;
  126. int _minHeight = 0;
  127. int _maxHeight = 0;
  128. object_ptr<Ui::RpWidget> _pinnedToTopContent = { nullptr };
  129. object_ptr<Ui::RpWidget> _pinnedToBottomContent = { nullptr };
  130. };
  131. template <typename InitMethod, typename ...InitArgs>
  132. template <typename OtherMethod, typename ...OtherArgs, typename>
  133. GenericBox::Initer<InitMethod, InitArgs...>::Initer(
  134. OtherMethod &&method,
  135. OtherArgs &&...args)
  136. : method(std::forward<OtherMethod>(method))
  137. , args(std::forward<OtherArgs>(args)...) {
  138. }
  139. template <typename InitMethod, typename ...InitArgs>
  140. inline void GenericBox::Initer<InitMethod, InitArgs...>::operator()(
  141. not_null<GenericBox*> box) {
  142. call(box, std::make_index_sequence<sizeof...(InitArgs)>());
  143. }
  144. template <typename InitMethod, typename ...InitArgs>
  145. template <std::size_t... I>
  146. inline void GenericBox::Initer<InitMethod, InitArgs...>::call(
  147. not_null<GenericBox*> box,
  148. std::index_sequence<I...>) {
  149. std::invoke(method, box, std::get<I>(std::move(args))...);
  150. }
  151. template <typename InitMethod, typename ...InitArgs>
  152. inline auto GenericBox::MakeIniter(InitMethod &&method, InitArgs &&...args)
  153. -> Initer<std::decay_t<InitMethod>, std::decay_t<InitArgs>...> {
  154. return {
  155. std::forward<InitMethod>(method),
  156. std::forward<InitArgs>(args)...
  157. };
  158. }
  159. template <typename InitMethod, typename ...InitArgs, typename>
  160. inline GenericBox::GenericBox(
  161. QWidget*,
  162. InitMethod &&init,
  163. InitArgs &&...args)
  164. : _init(
  165. MakeIniter(
  166. std::forward<InitMethod>(init),
  167. std::forward<InitArgs>(args)...))
  168. , _owned(this)
  169. , _content(_owned.data()) {
  170. }
  171. [[nodiscard]] rpl::producer<> BoxShowFinishes(not_null<GenericBox*> box);
  172. } // namespace Ui