info_settings_widget.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "info/settings/info_settings_widget.h"
  8. #include "info/info_memento.h"
  9. #include "settings/settings_main.h"
  10. #include "settings/settings_information.h"
  11. #include "ui/ui_utility.h"
  12. namespace Info {
  13. namespace Settings {
  14. Memento::Memento(not_null<UserData*> self, Type type)
  15. : ContentMemento(Tag{ self })
  16. , _type(type) {
  17. }
  18. Section Memento::section() const {
  19. return Section(_type);
  20. }
  21. object_ptr<ContentWidget> Memento::createWidget(
  22. QWidget *parent,
  23. not_null<Controller*> controller,
  24. const QRect &geometry) {
  25. auto result = object_ptr<Widget>(
  26. parent,
  27. controller);
  28. result->setInternalState(geometry, this);
  29. return result;
  30. }
  31. Memento::~Memento() = default;
  32. Widget::Widget(
  33. QWidget *parent,
  34. not_null<Controller*> controller)
  35. : ContentWidget(parent, controller)
  36. , _self(controller->key().settingsSelf())
  37. , _type(controller->section().settingsType())
  38. , _inner([&] {
  39. auto inner = _type->create(
  40. this,
  41. controller->parentController(),
  42. scroll(),
  43. controller->wrapValue(
  44. ) | rpl::map([](Wrap wrap) { return (wrap == Wrap::Layer)
  45. ? ::Settings::Container::Layer
  46. : ::Settings::Container::Section; }));
  47. if (inner->hasFlexibleTopBar()) {
  48. auto filler = setInnerWidget(object_ptr<Ui::RpWidget>(this));
  49. filler->resize(1, 1);
  50. _flexibleScroll.contentHeightValue.events(
  51. ) | rpl::start_with_next([=](int h) {
  52. filler->resize(filler->width(), h);
  53. }, filler->lifetime());
  54. filler->widthValue(
  55. ) | rpl::start_to_stream(
  56. _flexibleScroll.fillerWidthValue,
  57. lifetime());
  58. controller->stepDataReference() = SectionCustomTopBarData{
  59. .backButtonEnables = _flexibleScroll.backButtonEnables.events(),
  60. .wrapValue = controller->wrapValue(),
  61. };
  62. // ScrollArea -> PaddingWrap -> RpWidget.
  63. inner->setParent(filler->parentWidget()->parentWidget());
  64. inner->raise();
  65. using InnerPtr = base::unique_qptr<::Settings::AbstractSection>;
  66. auto owner = filler->lifetime().make_state<InnerPtr>(
  67. std::move(inner.release()));
  68. return owner->get();
  69. } else {
  70. return setInnerWidget(std::move(inner));
  71. }
  72. }())
  73. , _pinnedToTop(_inner->createPinnedToTop(this))
  74. , _pinnedToBottom(_inner->createPinnedToBottom(this)) {
  75. _inner->sectionShowOther(
  76. ) | rpl::start_with_next([=](Type type) {
  77. controller->showSettings(type);
  78. }, _inner->lifetime());
  79. _inner->sectionShowBack(
  80. ) | rpl::start_with_next([=] {
  81. controller->showBackFromStack();
  82. }, _inner->lifetime());
  83. _inner->setStepDataReference(controller->stepDataReference());
  84. _removesFromStack.events(
  85. ) | rpl::start_with_next([=](const std::vector<Type> &types) {
  86. const auto sections = ranges::views::all(
  87. types
  88. ) | ranges::views::transform([](Type type) {
  89. return Section(type);
  90. }) | ranges::to_vector;
  91. controller->removeFromStack(sections);
  92. }, _inner->lifetime());
  93. if (_pinnedToTop) {
  94. _inner->widthValue(
  95. ) | rpl::start_with_next([=](int w) {
  96. _pinnedToTop->resizeToWidth(w);
  97. setScrollTopSkip(_pinnedToTop->height());
  98. }, _pinnedToTop->lifetime());
  99. _pinnedToTop->heightValue(
  100. ) | rpl::start_with_next([=](int h) {
  101. setScrollTopSkip(h);
  102. }, _pinnedToTop->lifetime());
  103. }
  104. if (_pinnedToBottom) {
  105. const auto processHeight = [=] {
  106. setScrollBottomSkip(_pinnedToBottom->height());
  107. _pinnedToBottom->moveToLeft(
  108. _pinnedToBottom->x(),
  109. height() - _pinnedToBottom->height());
  110. };
  111. _inner->sizeValue(
  112. ) | rpl::start_with_next([=](const QSize &s) {
  113. _pinnedToBottom->resizeToWidth(s.width());
  114. //processHeight();
  115. }, _pinnedToBottom->lifetime());
  116. rpl::combine(
  117. _pinnedToBottom->heightValue(),
  118. heightValue()
  119. ) | rpl::start_with_next(processHeight, _pinnedToBottom->lifetime());
  120. }
  121. if (_pinnedToTop
  122. && _pinnedToTop->minimumHeight()
  123. && _inner->hasFlexibleTopBar()) {
  124. const auto heightDiff = [=] {
  125. return _pinnedToTop->maximumHeight()
  126. - _pinnedToTop->minimumHeight();
  127. };
  128. rpl::combine(
  129. _pinnedToTop->heightValue(),
  130. _inner->heightValue()
  131. ) | rpl::start_with_next([=](int, int h) {
  132. _flexibleScroll.contentHeightValue.fire(h + heightDiff());
  133. }, _pinnedToTop->lifetime());
  134. scrollTopValue(
  135. ) | rpl::start_with_next([=](int top) {
  136. if (!_pinnedToTop) {
  137. return;
  138. }
  139. const auto current = heightDiff() - top;
  140. _inner->moveToLeft(0, std::min(0, current));
  141. _pinnedToTop->resize(
  142. _pinnedToTop->width(),
  143. std::max(current + _pinnedToTop->minimumHeight(), 0));
  144. }, _inner->lifetime());
  145. _flexibleScroll.fillerWidthValue.events(
  146. ) | rpl::start_with_next([=](int w) {
  147. _inner->resizeToWidth(w);
  148. }, _inner->lifetime());
  149. setPaintPadding({ 0, _pinnedToTop->minimumHeight(), 0, 0 });
  150. setViewport(_pinnedToTop->events(
  151. ) | rpl::filter([](not_null<QEvent*> e) {
  152. return e->type() == QEvent::Wheel;
  153. }));
  154. }
  155. }
  156. Widget::~Widget() = default;
  157. not_null<UserData*> Widget::self() const {
  158. return _self;
  159. }
  160. bool Widget::showInternal(not_null<ContentMemento*> memento) {
  161. //if (const auto myMemento = dynamic_cast<Memento*>(memento.get())) {
  162. // Assert(myMemento->self() == self());
  163. // if (_inner->showInternal(myMemento)) {
  164. // return true;
  165. // }
  166. //}
  167. return false;
  168. }
  169. void Widget::setInternalState(
  170. const QRect &geometry,
  171. not_null<Memento*> memento) {
  172. setGeometry(geometry);
  173. Ui::SendPendingMoveResizeEvents(this);
  174. restoreState(memento);
  175. }
  176. void Widget::saveChanges(FnMut<void()> done) {
  177. _inner->sectionSaveChanges(std::move(done));
  178. }
  179. void Widget::showFinished() {
  180. _inner->showFinished();
  181. _inner->removeFromStack(
  182. ) | rpl::start_to_stream(_removesFromStack, lifetime());
  183. }
  184. void Widget::setInnerFocus() {
  185. _inner->setInnerFocus();
  186. }
  187. const Ui::RoundRect *Widget::bottomSkipRounding() const {
  188. return _inner->bottomSkipRounding();
  189. }
  190. rpl::producer<bool> Widget::desiredShadowVisibility() const {
  191. return (_type == ::Settings::Main::Id()
  192. || _type == ::Settings::Information::Id())
  193. ? ContentWidget::desiredShadowVisibility()
  194. : rpl::single(true);
  195. }
  196. bool Widget::closeByOutsideClick() const {
  197. return _inner->closeByOutsideClick();;
  198. }
  199. void Widget::checkBeforeClose(Fn<void()> close) {
  200. _inner->checkBeforeClose(std::move(close));
  201. }
  202. void Widget::checkBeforeCloseByEscape(Fn<void()> close) {
  203. ContentWidget::checkBeforeCloseByEscape([&] {
  204. _inner->checkBeforeClose(std::move(close));
  205. });
  206. }
  207. rpl::producer<QString> Widget::title() {
  208. return _inner->title();
  209. }
  210. void Widget::paintEvent(QPaintEvent *e) {
  211. if (!_inner->paintOuter(this, maxVisibleHeight(), e->rect())) {
  212. ContentWidget::paintEvent(e);
  213. }
  214. }
  215. std::shared_ptr<ContentMemento> Widget::doCreateMemento() {
  216. auto result = std::make_shared<Memento>(self(), _type);
  217. saveState(result.get());
  218. return result;
  219. }
  220. void Widget::enableBackButton() {
  221. _flexibleScroll.backButtonEnables.fire({});
  222. }
  223. rpl::producer<SelectedItems> Widget::selectedListValue() const {
  224. return _inner->selectedListValue();
  225. }
  226. void Widget::selectionAction(SelectionAction action) {
  227. _inner->selectionAction(action);
  228. }
  229. void Widget::fillTopBarMenu(const Ui::Menu::MenuCallback &addAction) {
  230. _inner->fillTopBarMenu(addAction);
  231. }
  232. void Widget::saveState(not_null<Memento*> memento) {
  233. memento->setScrollTop(scrollTopSave());
  234. }
  235. void Widget::restoreState(not_null<Memento*> memento) {
  236. scrollTopRestore(memento->scrollTop());
  237. }
  238. } // namespace Settings
  239. } // namespace Info