FlowLayout.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include "FlowLayout.h"
  2. #include <QWidget>
  3. #include <QVariant>
  4. FlowLayout::FlowLayout(QWidget *parent, bool needAni, bool isTight)
  5. : QLayout(parent),
  6. m_aniGroup(new QParallelAnimationGroup(this)),
  7. m_verticalSpacing(10),
  8. m_horizontalSpacing(10),
  9. m_needAni(needAni),
  10. m_isTight(isTight)
  11. {
  12. }
  13. FlowLayout::~FlowLayout()
  14. {
  15. removeAllItems();
  16. }
  17. QSize FlowLayout::sizeHint() const
  18. {
  19. return minimumSize();
  20. }
  21. void FlowLayout::addItem(QLayoutItem *item)
  22. {
  23. m_items.append(item);
  24. }
  25. QLayoutItem *FlowLayout::itemAt(int index) const
  26. {
  27. if (index >= 0 && index < m_items.count()) {
  28. return m_items[index];
  29. }
  30. return nullptr;
  31. }
  32. QLayoutItem *FlowLayout::takeAt(int index)
  33. {
  34. if (index >= 0 && index < m_items.count()) {
  35. QLayoutItem *item = m_items[index];
  36. QPropertyAnimation *ani = item->widget()->property("flowAni").value<QPropertyAnimation *>();
  37. if (ani) {
  38. m_anis.removeAll(ani);
  39. m_aniGroup->removeAnimation(ani);
  40. ani->deleteLater();
  41. }
  42. return m_items.takeAt(index);
  43. }
  44. return nullptr;
  45. }
  46. int FlowLayout::count() const
  47. {
  48. return m_items.count();
  49. }
  50. QSize FlowLayout::minimumSize() const
  51. {
  52. QSize size;
  53. for (auto item : m_items) {
  54. size = size.expandedTo(item->minimumSize());
  55. }
  56. QMargins m = contentsMargins();
  57. size += QSize(m.left() + m.right(), m.top() + m.bottom());
  58. return size;
  59. }
  60. Qt::Orientations FlowLayout::expandingDirections() const
  61. {
  62. return Qt::Orientation(0);
  63. }
  64. void FlowLayout::setGeometry(const QRect &rect)
  65. {
  66. QLayout::setGeometry(rect);
  67. doLayout(rect, true);
  68. }
  69. bool FlowLayout::hasHeightForWidth() const
  70. {
  71. return true;
  72. }
  73. int FlowLayout::heightForWidth(int width) const
  74. {
  75. return doLayout(QRect(0, 0, width, 0), false);
  76. }
  77. void FlowLayout::addWidget(QWidget *w)
  78. {
  79. QLayout::addWidget(w);
  80. if (!m_needAni) {
  81. return;
  82. }
  83. QPropertyAnimation *ani = new QPropertyAnimation(w, "geometry");
  84. ani->setEndValue(QRect(QPoint(0, 0), w->size()));
  85. ani->setDuration(300);
  86. w->setProperty("flowAni", QVariant::fromValue<QPropertyAnimation *>(ani));
  87. m_anis.append(ani);
  88. m_aniGroup->addAnimation(ani);
  89. }
  90. void FlowLayout::setAnimation(int duration /*msec*/, QEasingCurve ease)
  91. {
  92. if (!m_needAni) {
  93. return;
  94. }
  95. for (auto a : m_anis) {
  96. a->setDuration(duration);
  97. a->setEasingCurve(ease);
  98. }
  99. }
  100. void FlowLayout::removeAllItems()
  101. {
  102. QLayoutItem *item;
  103. while ((item = takeAt(0)))
  104. delete item;
  105. }
  106. void FlowLayout::takeAllWidgets()
  107. {
  108. QLayoutItem *item;
  109. while ((item = takeAt(0))) {
  110. QWidget *w = item->widget();
  111. if (w) {
  112. w->deleteLater();
  113. }
  114. delete item;
  115. }
  116. }
  117. int FlowLayout::doLayout(const QRect &rect, bool move) const
  118. {
  119. QMargins margin = contentsMargins();
  120. int x = rect.x() + margin.left();
  121. int y = rect.y() + margin.top();
  122. int rowHeight = 0;
  123. int spaceX = m_horizontalSpacing;
  124. int spaceY = m_verticalSpacing;
  125. for (int i = 0; i < m_items.count(); ++i) {
  126. QLayoutItem *item = m_items.at(i);
  127. if (item->widget() && !item->widget()->isVisible() && m_isTight) {
  128. continue;
  129. }
  130. int nextX = x + item->sizeHint().width() + spaceX;
  131. if (nextX - spaceX > rect.right() && rowHeight > 0) {
  132. x = rect.x() + margin.left();
  133. y = y + rowHeight + spaceY;
  134. nextX = x + item->sizeHint().width() + spaceX;
  135. rowHeight = 0;
  136. }
  137. if (move) {
  138. if (!m_needAni) {
  139. item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
  140. } else {
  141. m_anis[i]->stop();
  142. m_anis[i]->setEndValue(QRect(QPoint(x, y), item->sizeHint()));
  143. }
  144. }
  145. x = nextX;
  146. rowHeight = qMax(rowHeight, item->sizeHint().height());
  147. }
  148. if (m_needAni) {
  149. m_aniGroup->stop();
  150. m_aniGroup->start();
  151. }
  152. return y + rowHeight - rect.y();
  153. }
  154. int FlowLayout::horizontalSpacing() const
  155. {
  156. return m_horizontalSpacing;
  157. }
  158. void FlowLayout::setHorizontalSpacing(int horizontalSpacing)
  159. {
  160. m_horizontalSpacing = horizontalSpacing;
  161. }
  162. int FlowLayout::verticalSpacing() const
  163. {
  164. return m_verticalSpacing;
  165. }
  166. void FlowLayout::setVerticalSpacing(int verticalSpacing)
  167. {
  168. m_verticalSpacing = verticalSpacing;
  169. }