Warning, file /graphics/glaxnimate/src/gui/widgets/flow_layout.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "flow_layout.hpp" 0008 #include <QtMath> 0009 0010 using namespace glaxnimate::gui; 0011 0012 0013 FlowLayout::FlowLayout(int items_per_row, int min_w, int max_w, QWidget* parent) 0014 : QLayout(parent), min_w(min_w), max_w(max_w), items_per_row(items_per_row) 0015 { 0016 } 0017 0018 FlowLayout::~FlowLayout() 0019 { 0020 for ( auto it : items ) 0021 delete it; 0022 } 0023 0024 void FlowLayout::addItem(QLayoutItem* item) 0025 { 0026 items.push_back(item); 0027 } 0028 0029 int FlowLayout::count() const 0030 { 0031 return items.size(); 0032 } 0033 0034 bool FlowLayout::valid_index(int index) const 0035 { 0036 return index >= 0 && index < int(items.size()); 0037 } 0038 0039 QLayoutItem * FlowLayout::itemAt(int index) const 0040 { 0041 if ( !valid_index(index) ) 0042 return nullptr; 0043 return items[index]; 0044 } 0045 0046 QLayoutItem * FlowLayout::takeAt(int index) 0047 { 0048 if ( valid_index(index) ) 0049 { 0050 auto p = items[index]; 0051 items.erase(items.begin() + index); 0052 return p; 0053 } 0054 0055 return nullptr; 0056 } 0057 0058 Qt::Orientations FlowLayout::expandingDirections() const 0059 { 0060 #ifdef Q_OS_ANDROID 0061 return orient; 0062 #else 0063 return QLayout::expandingDirections(); 0064 #endif 0065 } 0066 0067 0068 bool FlowLayout::hasHeightForWidth() const 0069 { 0070 return orient == Qt::Horizontal; 0071 } 0072 0073 int FlowLayout::heightForWidth(int width) const 0074 { 0075 return do_layout(QRect(0, 0, width, 0), true).height(); 0076 } 0077 0078 QSize FlowLayout::do_layout(const QRect& rect, bool test_only) const 0079 { 0080 if ( items.size() == 0 ) 0081 return QSize(0, 0); 0082 0083 int left, top, right, bottom; 0084 getContentsMargins(&left, &top, &right, &bottom); 0085 QRect effective_rect = rect.adjusted(+left, +top, -right, -bottom); 0086 0087 int vertical_spacing = spacing(); 0088 int horizontal_spacing = spacing(); 0089 0090 int ipr = items_per_row; 0091 int iw = (effective_rect.width() - horizontal_spacing * (ipr - 1)) / ipr; 0092 int nrows; 0093 int ih; 0094 0095 if ( fixed_size.isValid() ) 0096 { 0097 iw = fixed_size.width(); 0098 ih = fixed_size.height(); 0099 if ( orient == Qt::Horizontal ) 0100 { 0101 ipr = qMax(1, (effective_rect.width() + horizontal_spacing) / (iw + horizontal_spacing)); 0102 nrows = (items.size() + ipr - 1) / ipr; 0103 } 0104 else 0105 { 0106 nrows = qMax(1, (effective_rect.height() + vertical_spacing) / (ih + vertical_spacing));; 0107 ipr = (items.size() + nrows - 1) / nrows; 0108 } 0109 } 0110 else 0111 { 0112 if ( iw < min_w ) 0113 { 0114 iw = min_w; 0115 ipr = (effective_rect.width() + horizontal_spacing) / (min_w + horizontal_spacing); 0116 } 0117 else if ( iw > max_w ) 0118 { 0119 ipr = qMin<int>( 0120 items.size(), 0121 qCeil(qreal(effective_rect.width() + horizontal_spacing) / (max_w + horizontal_spacing)) 0122 ); 0123 iw = qMin(max_w, (effective_rect.width() - horizontal_spacing * (ipr - 1)) / ipr); 0124 } 0125 0126 if ( ipr == 0 ) 0127 { 0128 ipr = items_per_row; 0129 iw = (effective_rect.width() - horizontal_spacing * (ipr - 1)) / ipr; 0130 } 0131 0132 nrows = (items.size() + ipr - 1) / ipr; 0133 ih = (effective_rect.height() - vertical_spacing * (nrows - 1)) / nrows; 0134 if ( !test_only && ih < iw ) 0135 { 0136 iw = qMax(ih, min_w); 0137 ipr = (effective_rect.width() + horizontal_spacing) / (iw + horizontal_spacing); 0138 } 0139 } 0140 0141 QSize new_contents( 0142 ipr * iw + (ipr-1) * horizontal_spacing, 0143 nrows * ih + (nrows-1) * vertical_spacing 0144 ); 0145 if ( test_only ) 0146 return new_contents; 0147 0148 contents = new_contents; 0149 0150 QSize item_size(iw, ih); 0151 0152 int x = 0; 0153 int y = 0; 0154 for ( int i = 0; i < int(items.size()); i++ ) 0155 { 0156 QLayoutItem *item = items[i]; 0157 0158 if ( !test_only ) 0159 item->setGeometry(QRect(effective_rect.topLeft() + QPoint(x, y), item_size)); 0160 0161 if ( orient == Qt::Horizontal ) 0162 { 0163 if ( i % ipr == ipr-1 ) 0164 { 0165 x = 0; 0166 y += item_size.height() + vertical_spacing; 0167 } 0168 else 0169 { 0170 x += item_size.width() + horizontal_spacing; 0171 } 0172 } 0173 else 0174 { 0175 if ( i % nrows == nrows-1 ) 0176 { 0177 y = 0; 0178 x += item_size.width() + vertical_spacing; 0179 } 0180 else 0181 { 0182 y += item_size.height() + horizontal_spacing; 0183 } 0184 } 0185 } 0186 0187 return contents; 0188 } 0189 0190 void FlowLayout::setGeometry(const QRect& rect) 0191 { 0192 QLayout::setGeometry(rect); 0193 do_layout(rect, false); 0194 } 0195 0196 QSize FlowLayout::sizeHint() const 0197 { 0198 if ( contents.isValid() ) 0199 { 0200 const QMargins margins = contentsMargins(); 0201 return contents + QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); 0202 } 0203 return minimumSize(); 0204 } 0205 0206 QSize FlowLayout::minimumSize() const 0207 { 0208 QSize size; 0209 for ( const QLayoutItem *item : items ) 0210 size = size.expandedTo(item->minimumSize()); 0211 0212 const QMargins margins = contentsMargins(); 0213 size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); 0214 0215 return size; 0216 } 0217 0218 void FlowLayout::set_fixed_item_size(const QSize& size) 0219 { 0220 fixed_size = size; 0221 invalidate(); 0222 } 0223 0224 void FlowLayout::set_orientation(Qt::Orientation orientation) 0225 { 0226 orient = orientation; 0227 invalidate(); 0228 }