X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/a3d883e73b75bdf654268c53811a2b4ac42b97e7..e29e1cda15973969164d7b7fa805544189a5e172:/src/kitemviews/kitemlistviewlayouter.cpp diff --git a/src/kitemviews/kitemlistviewlayouter.cpp b/src/kitemviews/kitemlistviewlayouter.cpp index cb0e9cf55..2d02b6725 100644 --- a/src/kitemviews/kitemlistviewlayouter.cpp +++ b/src/kitemviews/kitemlistviewlayouter.cpp @@ -24,7 +24,7 @@ #include -#define KITEMLISTVIEWLAYOUTER_DEBUG +// #define KITEMLISTVIEWLAYOUTER_DEBUG KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : QObject(parent), @@ -33,6 +33,7 @@ KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : m_scrollOrientation(Qt::Vertical), m_size(), m_itemSize(128, 128), + m_itemMargin(), m_headerHeight(0), m_model(0), m_sizeHintResolver(0), @@ -94,6 +95,19 @@ QSizeF KItemListViewLayouter::itemSize() const return m_itemSize; } +void KItemListViewLayouter::setItemMargin(const QSizeF& margin) +{ + if (m_itemMargin != margin) { + m_itemMargin = margin; + m_dirty = true; + } +} + +QSizeF KItemListViewLayouter::itemMargin() const +{ + return m_itemMargin; +} + void KItemListViewLayouter::setHeaderHeight(qreal height) { if (m_headerHeight != height) { @@ -221,6 +235,8 @@ QRectF KItemListViewLayouter::itemRect(int index) const QRectF KItemListViewLayouter::groupHeaderRect(int index) const { + const_cast(this)->doLayout(); + const QRectF firstItemRect = itemRect(index); QPointF pos = firstItemRect.topLeft(); if (pos.isNull()) { @@ -234,7 +250,7 @@ QRectF KItemListViewLayouter::groupHeaderRect(int index) const pos.rx() = 0; size = QSizeF(m_size.width(), m_groupHeaderHeight); } else { - size = QSizeF(firstItemRect.width(), m_groupHeaderHeight); + size = QSizeF(minimumGroupHeaderWidth(), m_groupHeaderHeight); } return QRectF(pos, size); } @@ -253,13 +269,9 @@ int KItemListViewLayouter::maximumVisibleItems() const return rows * m_columnCount; } -int KItemListViewLayouter::itemsPerOffset() const -{ - return m_columnCount; -} - bool KItemListViewLayouter::isFirstGroupItem(int itemIndex) const { + const_cast(this)->doLayout(); return m_groupItemIndexes.contains(itemIndex); } @@ -278,29 +290,41 @@ void KItemListViewLayouter::doLayout() m_visibleIndexesDirty = true; QSizeF itemSize = m_itemSize; + QSizeF itemMargin = m_itemMargin; QSizeF size = m_size; + + const bool grouped = createGroupHeaders(); const bool horizontalScrolling = (m_scrollOrientation == Qt::Horizontal); if (horizontalScrolling) { + // Flip everything so that the layout logically can work like having + // a vertical scrolling itemSize.setWidth(m_itemSize.height()); itemSize.setHeight(m_itemSize.width()); + itemMargin.setWidth(m_itemMargin.height()); + itemMargin.setHeight(m_itemMargin.width()); size.setWidth(m_size.height()); size.setHeight(m_size.width()); + + if (grouped) { + // In the horizontal scrolling case all groups are aligned + // at the top, which decreases the available height. For the + // flipped data this means that the width must be decreased. + size.rwidth() -= m_groupHeaderHeight; + } } - m_columnWidth = itemSize.width(); - m_columnCount = qMax(1, int(size.width() / m_columnWidth)); - m_xPosInc = 0; + m_columnWidth = itemSize.width() + itemMargin.width(); + const qreal widthForColumns = size.width() - itemMargin.width(); + m_columnCount = qMax(1, int(widthForColumns / m_columnWidth)); + m_xPosInc = itemMargin.width(); const int itemCount = m_model->count(); - if (itemCount > m_columnCount) { + if (itemCount > m_columnCount && m_columnWidth >= 32) { // Apply the unused width equally to each column const qreal unusedWidth = size.width() - m_columnCount * m_columnWidth; if (unusedWidth > 0) { - // [Comment #1] A cast to int is done on purpose to prevent rounding issues when - // drawing pixmaps and drawing text or other graphic primitives: Qt uses a different - // rastering algorithm for the upper/left of pixmaps - const qreal columnInc = int(unusedWidth / (m_columnCount + 1)); + const qreal columnInc = unusedWidth / (m_columnCount + 1); m_columnWidth += columnInc; m_xPosInc += columnInc; } @@ -313,11 +337,9 @@ void KItemListViewLayouter::doLayout() m_itemRects.reserve(itemCount); - qreal y = m_headerHeight; + qreal y = m_headerHeight + itemMargin.height(); int rowIndex = 0; - const bool grouped = createGroupHeaders(); - int index = 0; while (index < itemCount) { qreal x = m_xPosInc; @@ -371,9 +393,9 @@ void KItemListViewLayouter::doLayout() // (in average a character requires the halve width of the font height). // // TODO: Let the group headers provide a minimum width and respect this width here - const qreal minimumGroupHeaderWidth = int(m_groupHeaderHeight * 15 / 2); // See [Comment #1] - if (requiredItemHeight < minimumGroupHeaderWidth) { - requiredItemHeight = minimumGroupHeaderWidth; + const qreal headerWidth = minimumGroupHeaderWidth(); + if (requiredItemHeight < headerWidth) { + requiredItemHeight = headerWidth; } } @@ -389,16 +411,25 @@ void KItemListViewLayouter::doLayout() } } - y += maxItemHeight; + y += maxItemHeight + itemMargin.height(); ++rowIndex; } if (m_itemRects.count() > itemCount) { m_itemRects.erase(m_itemRects.begin() + itemCount, - m_itemRects.end()); + m_itemRects.end()); } if (itemCount > 0) { + // Calculate the maximum y-range of the last row for m_maximumScrollOffset m_maximumScrollOffset = m_itemRects.last().bottom(); + const qreal rowY = m_itemRects.last().y(); + + int index = m_itemRects.count() - 2; + while (index >= 0 && m_itemRects.at(index).bottom() >= rowY) { + m_maximumScrollOffset = qMax(m_maximumScrollOffset, m_itemRects.at(index).bottom()); + --index; + } + m_maximumItemOffset = m_columnCount * m_columnWidth; } else { m_maximumScrollOffset = 0; @@ -431,21 +462,31 @@ void KItemListViewLayouter::updateVisibleIndexes() const int maxIndex = m_model->count() - 1; - // Calculate the first visible index that is (at least partly) visible + // Calculate the first visible index that is fully visible int min = 0; int max = maxIndex; int mid = 0; do { mid = (min + max) / 2; - if (m_itemRects[mid].bottom() < m_scrollOffset) { + if (m_itemRects[mid].top() < m_scrollOffset) { min = mid + 1; } else { max = mid - 1; } } while (min <= max); - while (mid < maxIndex && m_itemRects[mid].bottom() < m_scrollOffset) { - ++mid; + if (mid > 0) { + // Include the row before the first fully visible index, as it might + // be partly visible + if (m_itemRects[mid].top() >= m_scrollOffset) { + --mid; + Q_ASSERT(m_itemRects[mid].top() < m_scrollOffset); + } + + const qreal rowTop = m_itemRects[mid].top(); + while (mid > 0 && m_itemRects[mid - 1].top() == rowTop) { + --mid; + } } m_firstVisibleIndex = mid; @@ -496,4 +537,9 @@ bool KItemListViewLayouter::createGroupHeaders() return true; } +qreal KItemListViewLayouter::minimumGroupHeaderWidth() const +{ + return m_groupHeaderHeight * 15 / 2; +} + #include "kitemlistviewlayouter_p.moc"