FlowLayout.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /******************************************************************************
  2. Example provided by Qt
  3. <https://doc.qt.io/qt-6/qtwidgets-layouts-flowlayout-example.html>
  4. Copyright (C) 2016 The Qt Company Ltd.
  5. SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
  6. ******************************************************************************/
  7. #include "FlowLayout.hpp"
  8. #include <QWidget>
  9. FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
  10. : QLayout(parent),
  11. m_hSpace(hSpacing),
  12. m_vSpace(vSpacing)
  13. {
  14. setContentsMargins(margin, margin, margin, margin);
  15. }
  16. FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) : m_hSpace(hSpacing), m_vSpace(vSpacing)
  17. {
  18. setContentsMargins(margin, margin, margin, margin);
  19. }
  20. FlowLayout::~FlowLayout()
  21. {
  22. QLayoutItem *item;
  23. while ((item = takeAt(0))) {
  24. delete item;
  25. }
  26. }
  27. void FlowLayout::addItem(QLayoutItem *item)
  28. {
  29. itemList.append(item);
  30. }
  31. int FlowLayout::horizontalSpacing() const
  32. {
  33. if (m_hSpace >= 0) {
  34. return m_hSpace;
  35. } else {
  36. return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
  37. }
  38. }
  39. int FlowLayout::verticalSpacing() const
  40. {
  41. if (m_vSpace >= 0) {
  42. return m_vSpace;
  43. } else {
  44. return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
  45. }
  46. }
  47. int FlowLayout::count() const
  48. {
  49. return itemList.size();
  50. }
  51. QLayoutItem *FlowLayout::itemAt(int index) const
  52. {
  53. return itemList.value(index);
  54. }
  55. QLayoutItem *FlowLayout::takeAt(int index)
  56. {
  57. if (index >= 0 && index < itemList.size()) {
  58. return itemList.takeAt(index);
  59. }
  60. return nullptr;
  61. }
  62. Qt::Orientations FlowLayout::expandingDirections() const
  63. {
  64. return {};
  65. }
  66. bool FlowLayout::hasHeightForWidth() const
  67. {
  68. return true;
  69. }
  70. int FlowLayout::heightForWidth(int width) const
  71. {
  72. int height = doLayout(QRect(0, 0, width, 0), true);
  73. return height;
  74. }
  75. void FlowLayout::setGeometry(const QRect &rect)
  76. {
  77. QLayout::setGeometry(rect);
  78. doLayout(rect, false);
  79. }
  80. QSize FlowLayout::sizeHint() const
  81. {
  82. return minimumSize();
  83. }
  84. QSize FlowLayout::minimumSize() const
  85. {
  86. QSize size;
  87. for (const QLayoutItem *item : std::as_const(itemList)) {
  88. size = size.expandedTo(item->minimumSize());
  89. }
  90. const QMargins margins = contentsMargins();
  91. size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
  92. return size;
  93. }
  94. int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
  95. {
  96. int left;
  97. int top;
  98. int right;
  99. int bottom;
  100. getContentsMargins(&left, &top, &right, &bottom);
  101. QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
  102. int x = effectiveRect.x();
  103. int y = effectiveRect.y();
  104. int lineHeight = 0;
  105. for (QLayoutItem *item : std::as_const(itemList)) {
  106. const QWidget *wid = item->widget();
  107. int spaceX = horizontalSpacing();
  108. if (spaceX == -1) {
  109. spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton,
  110. Qt::Horizontal);
  111. }
  112. int spaceY = verticalSpacing();
  113. if (spaceY == -1) {
  114. spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton,
  115. Qt::Vertical);
  116. }
  117. int nextX = x + item->sizeHint().width() + spaceX;
  118. if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
  119. x = effectiveRect.x();
  120. y = y + lineHeight + spaceY;
  121. nextX = x + item->sizeHint().width() + spaceX;
  122. lineHeight = 0;
  123. }
  124. if (!testOnly) {
  125. item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
  126. }
  127. x = nextX;
  128. lineHeight = qMax(lineHeight, item->sizeHint().height());
  129. }
  130. return y + lineHeight - rect.y() + bottom;
  131. }
  132. int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
  133. {
  134. QObject *parent = this->parent();
  135. if (!parent) {
  136. return -1;
  137. } else if (parent->isWidgetType()) {
  138. QWidget *pw = static_cast<QWidget *>(parent);
  139. return pw->style()->pixelMetric(pm, nullptr, pw);
  140. } else {
  141. return static_cast<QLayout *>(parent)->spacing();
  142. }
  143. }