layout_mosaic.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. #pragma once
  8. #include "layout/abstract_layout_item.h"
  9. #include "layout/layout_position.h"
  10. namespace Mosaic::Layout {
  11. struct FoundItem {
  12. int index = -1;
  13. bool exact = false;
  14. QPoint relative;
  15. };
  16. class AbstractMosaicLayout {
  17. public:
  18. AbstractMosaicLayout(int bigWidth);
  19. [[nodiscard]] int rowHeightAt(int row) const;
  20. [[nodiscard]] int countDesiredHeight(int newWidth);
  21. [[nodiscard]] FoundItem findByPoint(const QPoint &globalPoint) const;
  22. [[nodiscard]] QRect findRect(int index) const;
  23. void setRightSkip(int rightSkip);
  24. void setPadding(QMargins padding);
  25. void setFullWidth(int w);
  26. [[nodiscard]] bool empty() const;
  27. [[nodiscard]] int rowsCount() const;
  28. void clearRows(bool resultsDeleted);
  29. protected:
  30. void addItems(gsl::span<const not_null<AbstractLayoutItem*>> items);
  31. [[nodiscard]] not_null<AbstractLayoutItem*> itemAt(int row, int column) const;
  32. [[nodiscard]] not_null<AbstractLayoutItem*> itemAt(int index) const;
  33. [[nodiscard]] AbstractLayoutItem *maybeItemAt(int row, int column) const;
  34. [[nodiscard]] AbstractLayoutItem *maybeItemAt(int index) const;
  35. void forEach(Fn<void(not_null<const AbstractLayoutItem*>)> callback);
  36. void paint(
  37. Fn<void(not_null<AbstractLayoutItem*>, QPoint)> paintItem,
  38. const QRect &clip) const;
  39. int validateExistingRows(
  40. Fn<bool(not_null<const AbstractLayoutItem*>, int)> checkItem,
  41. int count);
  42. private:
  43. static constexpr auto kInlineItemsMaxPerRow = 5;
  44. struct Row {
  45. int maxWidth = 0;
  46. int height = 0;
  47. std::vector<AbstractLayoutItem*> items;
  48. };
  49. void addItem(not_null<AbstractLayoutItem*> item, Row &row, int &sumWidth);
  50. bool rowFinalize(Row &row, int &sumWidth, bool force);
  51. void layoutRow(Row &row, int fullWidth);
  52. int _bigWidth;
  53. int _width = 0;
  54. int _rightSkip = 0;
  55. QMargins _padding;
  56. std::vector<Row> _rows;
  57. };
  58. template <
  59. typename ItemBase,
  60. typename = std::enable_if_t<
  61. std::is_base_of_v<AbstractLayoutItem, ItemBase>>>
  62. class MosaicLayout final : public AbstractMosaicLayout {
  63. using Parent = AbstractMosaicLayout;
  64. public:
  65. using Parent::Parent;
  66. void addItems(const std::vector<not_null<ItemBase*>> &items) {
  67. Parent::addItems({
  68. reinterpret_cast<const not_null<AbstractLayoutItem*>*>(
  69. items.data()),
  70. items.size() });
  71. }
  72. [[nodiscard]] not_null<ItemBase*> itemAt(int row, int column) const {
  73. return Downcast(Parent::itemAt(row, column));
  74. }
  75. [[nodiscard]] not_null<ItemBase*> itemAt(int index) const {
  76. return Downcast(Parent::itemAt(index));
  77. }
  78. [[nodiscard]] ItemBase *maybeItemAt(int row, int column) const {
  79. return Downcast(Parent::maybeItemAt(row, column));
  80. }
  81. [[nodiscard]] ItemBase *maybeItemAt(int index) const {
  82. return Downcast(Parent::maybeItemAt(index));
  83. }
  84. void forEach(Fn<void(not_null<const ItemBase*>)> callback) {
  85. Parent::forEach([&](
  86. not_null<const AbstractLayoutItem*> item) {
  87. callback(Downcast(item));
  88. });
  89. }
  90. void paint(
  91. Fn<void(not_null<ItemBase*>, QPoint)> paintItem,
  92. const QRect &clip) const {
  93. Parent::paint([&](
  94. not_null<AbstractLayoutItem*> item,
  95. QPoint point) {
  96. paintItem(Downcast(item), point);
  97. }, clip);
  98. }
  99. int validateExistingRows(
  100. Fn<bool(not_null<const ItemBase*>, int)> checkItem,
  101. int count) {
  102. return Parent::validateExistingRows([&](
  103. not_null<const AbstractLayoutItem*> item,
  104. int until) {
  105. return checkItem(Downcast(item), until);
  106. }, count);
  107. }
  108. private:
  109. [[nodiscard]] static not_null<ItemBase*> Downcast(
  110. not_null<AbstractLayoutItem*> item) {
  111. return static_cast<ItemBase*>(item.get());
  112. }
  113. [[nodiscard]] static ItemBase *Downcast(
  114. AbstractLayoutItem *item) {
  115. return static_cast<ItemBase*>(item);
  116. }
  117. [[nodiscard]] static not_null<const ItemBase*> Downcast(
  118. not_null<const AbstractLayoutItem*> item) {
  119. return static_cast<const ItemBase*>(item.get());
  120. }
  121. [[nodiscard]] static const ItemBase *Downcast(
  122. const AbstractLayoutItem *item) {
  123. return static_cast<const ItemBase*>(item);
  124. }
  125. };
  126. } // namespace Mosaic::Layout