From: Peter Penz Date: Sat, 11 Feb 2012 17:02:38 +0000 (+0100) Subject: Group header layout fixes X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/056d12d60f93a052e19f6e2cff9b826e500eef16?ds=inline Group header layout fixes - Don't use a margin for the first group header - Provide margins between the groups - Use a more subtle coloring - Prevent animation glitches when resizing a window --- diff --git a/src/kitemviews/kitemlistgroupheader.cpp b/src/kitemviews/kitemlistgroupheader.cpp index 03964e2b5..ffc81eb12 100644 --- a/src/kitemviews/kitemlistgroupheader.cpp +++ b/src/kitemviews/kitemlistgroupheader.cpp @@ -36,6 +36,8 @@ KItemListGroupHeader::KItemListGroupHeader(QGraphicsWidget* parent) : m_data(), m_styleOption(), m_scrollOrientation(Qt::Vertical), + m_itemIndex(-1), + m_lineColor(), m_roleColor(), m_roleBounds() { @@ -100,6 +102,21 @@ void KItemListGroupHeader::setScrollOrientation(Qt::Orientation orientation) } } +void KItemListGroupHeader::setItemIndex(int index) +{ + if (m_itemIndex != index) { + const int previous = m_itemIndex; + m_itemIndex = index; + m_dirtyCache = true; + itemIndexChanged(m_itemIndex, previous); + } +} + +int KItemListGroupHeader::itemIndex() const +{ + return m_itemIndex; +} + Qt::Orientation KItemListGroupHeader::scrollOrientation() const { return m_scrollOrientation; @@ -114,8 +131,13 @@ void KItemListGroupHeader::paint(QPainter* painter, const QStyleOptionGraphicsIt updateCache(); } - if (m_scrollOrientation != Qt::Horizontal) { - painter->setPen(m_roleColor); + if (m_scrollOrientation == Qt::Horizontal) { + painter->setPen(m_lineColor); + const qreal x = m_roleBounds.x() - m_styleOption.padding; + painter->drawLine(x, 0, x, size().height() - 1); + + } else if (m_itemIndex > 0) { + painter->setPen(m_lineColor); const qreal y = m_roleBounds.y() - m_styleOption.padding; painter->drawLine(0, y, size().width() - 1, y); } @@ -155,6 +177,12 @@ void KItemListGroupHeader::scrollOrientationChanged(Qt::Orientation current, Qt: Q_UNUSED(previous); } +void KItemListGroupHeader::itemIndexChanged(int current, int previous) +{ + Q_UNUSED(current); + Q_UNUSED(previous); +} + void KItemListGroupHeader::resizeEvent(QGraphicsSceneResizeEvent* event) { QGraphicsWidget::resizeEvent(event); @@ -167,26 +195,40 @@ void KItemListGroupHeader::updateCache() { Q_ASSERT(m_dirtyCache); - // Calculate the outline color. No alphablending is used for + // Calculate the role- and line-color. No alphablending is used for // performance reasons. const QColor c1 = m_styleOption.palette.text().color(); - const QColor c2 = m_styleOption.palette.background().color(); - const int p1 = 35; - const int p2 = 100 - p1; - m_roleColor = QColor((c1.red() * p1 + c2.red() * p2) / 100, - (c1.green() * p1 + c2.green() * p2) / 100, - (c1.blue() * p1 + c2.blue() * p2) / 100); - - const int padding = m_styleOption.padding; + const QColor c2 = m_styleOption.palette.base().color(); + m_lineColor = mixedColor(c1, c2, 10); + m_roleColor = mixedColor(c1, c2, 50); + + int horizontalMargin = 0; + if (m_scrollOrientation == Qt::Vertical) { + // The x-position of the group-header-widget will always be 0, + // Add a minimum margin. + horizontalMargin = qMax(2, m_styleOption.horizontalMargin); + } + + const int padding = qMax(2, m_styleOption.padding); const QFontMetrics fontMetrics(m_styleOption.font); const qreal roleHeight = fontMetrics.height(); - m_roleBounds = QRectF(padding, + m_roleBounds = QRectF(horizontalMargin + padding, size().height() - roleHeight - padding, - size().width() - 2 * padding, + size().width() - 2 * (horizontalMargin + padding), roleHeight); m_dirtyCache = false; } +QColor KItemListGroupHeader::mixedColor(const QColor& c1, const QColor& c2, int c1Percent) +{ + Q_ASSERT(c1Percent >= 0 && c1Percent <= 100); + + const int c2Percent = 100 - c1Percent; + return QColor((c1.red() * c1Percent + c2.red() * c2Percent) / 100, + (c1.green() * c1Percent + c2.green() * c2Percent) / 100, + (c1.blue() * c1Percent + c2.blue() * c2Percent) / 100); +} + #include "kitemlistgroupheader.moc" diff --git a/src/kitemviews/kitemlistgroupheader.h b/src/kitemviews/kitemlistgroupheader.h index 5ddf20896..c996a4870 100644 --- a/src/kitemviews/kitemlistgroupheader.h +++ b/src/kitemviews/kitemlistgroupheader.h @@ -62,6 +62,9 @@ public: void setScrollOrientation(Qt::Orientation orientation); Qt::Orientation scrollOrientation() const; + void setItemIndex(int index); + int itemIndex() const; + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); protected: @@ -95,19 +98,29 @@ protected: */ virtual void scrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous); + /** + * Is called after the item index has been changed and allows the derived class to react on + * this change. + */ + virtual void itemIndexChanged(int current, int previous); + /** @reimp */ virtual void resizeEvent(QGraphicsSceneResizeEvent* event); private: void updateCache(); + static QColor mixedColor(const QColor& c1, const QColor& c2, int c1Percent = 50); + private: bool m_dirtyCache; QByteArray m_role; QVariant m_data; KItemListStyleOption m_styleOption; Qt::Orientation m_scrollOrientation; + int m_itemIndex; + QColor m_lineColor; QColor m_roleColor; QRectF m_roleBounds; }; diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 451e51833..323e67452 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -1224,6 +1224,15 @@ void KItemListView::triggerAutoScrolling() m_autoScrollTimer->start(RepeatingAutoScrollDelay); } +void KItemListView::slotGeometryOfGroupHeaderParentChanged() +{ + KItemListWidget* widget = qobject_cast(sender()); + Q_ASSERT(widget); + KItemListGroupHeader* groupHeader = m_visibleGroups.value(widget); + Q_ASSERT(groupHeader); + updateGroupHeaderLayout(widget); +} + void KItemListView::setController(KItemListController* controller) { if (m_controller != controller) { @@ -1642,6 +1651,7 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget) groupHeader = m_groupHeaderCreator->create(this); groupHeader->setParentItem(widget); m_visibleGroups.insert(widget, groupHeader); + connect(widget, SIGNAL(geometryChanged()), this, SLOT(slotGeometryOfGroupHeaderParentChanged())); } Q_ASSERT(groupHeader->parentItem() == widget); @@ -1663,6 +1673,7 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget) groupHeader->setRole(model()->sortRole()); groupHeader->setStyleOption(m_styleOption); groupHeader->setScrollOrientation(scrollOrientation()); + groupHeader->setItemIndex(index); groupHeader->show(); } @@ -1678,10 +1689,16 @@ void KItemListView::updateGroupHeaderLayout(KItemListWidget* widget) // The group-header is a child of the itemlist widget. Translate the // group header position to the relative position. - const QPointF groupHeaderPos(groupHeaderRect.x() - itemRect.x(), - - groupHeaderRect.height()); - groupHeader->setPos(groupHeaderPos); - groupHeader->resize(groupHeaderRect.size()); + if (scrollOrientation() == Qt::Vertical) { + // In the vertical scroll orientation the group header should always span + // the whole width no matter which temporary position the parent widget + // has. In this case the x-position and width will be adjusted manually. + groupHeader->setPos(-widget->x(), -groupHeaderRect.height()); + groupHeader->resize(size().width(), groupHeaderRect.size().height()); + } else { + groupHeader->setPos(groupHeaderRect.x() - itemRect.x(), -groupHeaderRect.height()); + groupHeader->resize(groupHeaderRect.size()); + } } void KItemListView::recycleGroupHeaderForWidget(KItemListWidget* widget) @@ -1691,6 +1708,7 @@ void KItemListView::recycleGroupHeaderForWidget(KItemListWidget* widget) header->setParentItem(0); m_groupHeaderCreator->recycle(header); m_visibleGroups.remove(widget); + disconnect(widget, SIGNAL(geometryChanged()), this, SLOT(slotGeometryOfGroupHeaderParentChanged())); } } @@ -1934,10 +1952,18 @@ bool KItemListView::scrollBarRequired(const QSizeF& size) const void KItemListView::updateGroupHeaderHeight() { - qreal groupHeaderHeight = m_styleOption.fontMetrics.height(); - groupHeaderHeight += (scrollOrientation() == Qt::Vertical) - ? m_styleOption.padding * 4 : m_styleOption.padding * 2; + const qreal groupHeaderHeight = m_styleOption.fontMetrics.height() + m_styleOption.padding * 2; + + qreal groupHeaderMargin = 0; + if (scrollOrientation() == Qt::Horizontal) { + groupHeaderMargin = m_styleOption.horizontalMargin; + } else if (m_itemSize.isEmpty()){ + groupHeaderMargin = groupHeaderHeight / 2; + } else { + groupHeaderMargin = m_styleOption.verticalMargin * 2; + } m_layouter->setGroupHeaderHeight(groupHeaderHeight); + m_layouter->setGroupHeaderMargin(groupHeaderMargin); updateVisibleGroupHeaders(); } diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 808ff5b3e..6ed714b20 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -336,6 +336,14 @@ private slots: */ void triggerAutoScrolling(); + /** + * Is invoked if the geometry of the parent-widget from a group-header has been + * changed. The x-position and width of the group-header gets adjusted to assure + * that it always spans the whole width even during temporary transitions of the + * parent widget. + */ + void slotGeometryOfGroupHeaderParentChanged(); + private: enum LayoutAnimationHint { diff --git a/src/kitemviews/kitemlistviewlayouter.cpp b/src/kitemviews/kitemlistviewlayouter.cpp index 2d02b6725..a9b59051d 100644 --- a/src/kitemviews/kitemlistviewlayouter.cpp +++ b/src/kitemviews/kitemlistviewlayouter.cpp @@ -48,6 +48,7 @@ KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : m_columnCount(0), m_groupItemIndexes(), m_groupHeaderHeight(0), + m_groupHeaderMargin(0), m_itemRects() { } @@ -134,6 +135,19 @@ qreal KItemListViewLayouter::groupHeaderHeight() const return m_groupHeaderHeight; } +void KItemListViewLayouter::setGroupHeaderMargin(qreal margin) +{ + if (m_groupHeaderMargin != margin) { + m_groupHeaderMargin = margin; + m_dirty = true; + } +} + +qreal KItemListViewLayouter::groupHeaderMargin() const +{ + return m_groupHeaderMargin; +} + void KItemListViewLayouter::setScrollOffset(qreal offset) { if (m_scrollOffset != offset) { @@ -310,7 +324,7 @@ void KItemListViewLayouter::doLayout() // 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; + size.rwidth() -= m_groupHeaderMargin + m_groupHeaderHeight; } } @@ -322,7 +336,7 @@ void KItemListViewLayouter::doLayout() const int itemCount = m_model->count(); if (itemCount > m_columnCount && m_columnWidth >= 32) { // Apply the unused width equally to each column - const qreal unusedWidth = size.width() - m_columnCount * m_columnWidth; + const qreal unusedWidth = widthForColumns - m_columnCount * m_columnWidth; if (unusedWidth > 0) { const qreal columnInc = unusedWidth / (m_columnCount + 1); m_columnWidth += columnInc; @@ -349,16 +363,22 @@ void KItemListViewLayouter::doLayout() if (horizontalScrolling) { // All group headers will always be aligned on the top and not // flipped like the other properties - x += m_groupHeaderHeight; + x += m_groupHeaderMargin + m_groupHeaderHeight; } - if (m_groupItemIndexes.contains(index)) { - if (!horizontalScrolling) { - // The item is the first item of a group. - // Increase the y-position to provide space - // for the group header. - y += m_groupHeaderHeight; + if (m_groupItemIndexes.contains(index) && !horizontalScrolling) { + // The item is the first item of a group. + // Increase the y-position to provide space + // for the group header. + if (index == 0) { + // The first group header should be aligned on top + y -= itemMargin.height(); + } else { + // Only add a margin if there has been added another + // group already before + y += m_groupHeaderMargin; } + y += m_groupHeaderHeight; } } @@ -430,6 +450,8 @@ void KItemListViewLayouter::doLayout() --index; } + m_maximumScrollOffset += itemMargin.height(); + m_maximumItemOffset = m_columnCount * m_columnWidth; } else { m_maximumScrollOffset = 0; diff --git a/src/kitemviews/kitemlistviewlayouter_p.h b/src/kitemviews/kitemlistviewlayouter_p.h index af8a6dacb..ebed39a41 100644 --- a/src/kitemviews/kitemlistviewlayouter_p.h +++ b/src/kitemviews/kitemlistviewlayouter_p.h @@ -67,6 +67,13 @@ public: */ void setGroupHeaderHeight(qreal height); qreal groupHeaderHeight() const; + + /** + * Sets the margin between the last items of the group n and + * the group header for the group n + 1. + */ + void setGroupHeaderMargin(qreal margin); + qreal groupHeaderMargin() const; void setScrollOffset(qreal scrollOffset); qreal scrollOffset() const; @@ -165,6 +172,7 @@ private: // Assures fast access for KItemListViewLayouter::isFirstGroupItem(). QSet m_groupItemIndexes; qreal m_groupHeaderHeight; + qreal m_groupHeaderMargin; QList m_itemRects; diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index 67df036c8..3d593f76f 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -439,7 +439,7 @@ void KItemListWidget::drawItemStyleOption(QPainter* painter, QWidget* widget, QS viewItemOption.state = styleState; viewItemOption.viewItemPosition = QStyleOptionViewItemV4::OnlyOne; viewItemOption.showDecorationSelected = true; - viewItemOption.rect = textBounds; + viewItemOption.rect = textBounds.adjusted(1, 0, -1, 0); widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, painter, widget); } diff --git a/src/views/dolphinitemlistcontainer.cpp b/src/views/dolphinitemlistcontainer.cpp index 544892674..299f32fab 100644 --- a/src/views/dolphinitemlistcontainer.cpp +++ b/src/views/dolphinitemlistcontainer.cpp @@ -206,7 +206,7 @@ void DolphinItemListContainer::updateGridSize() m_zoomLevel = ZoomLevelInfo::zoomLevelForIconSize(QSize(iconSize, iconSize)); KItemListStyleOption styleOption = m_fileItemListView->styleOption(); - const int padding = (iconSize >= KIconLoader::SizeSmallMedium) ? 4 : 2; + int padding = 2; int horizontalMargin = 0; int verticalMargin = 0; @@ -215,7 +215,7 @@ void DolphinItemListContainer::updateGridSize() int itemHeight; switch (itemLayout()) { case KFileItemListView::IconsLayout: { - const int minItemWidth = 64; + const int minItemWidth = 48; itemWidth = minItemWidth + IconsModeSettings::textWidthIndex() * 64; if (previewsShown()) { @@ -231,8 +231,8 @@ void DolphinItemListContainer::updateGridSize() } itemHeight = padding * 3 + iconSize + styleOption.fontMetrics.height(); - horizontalMargin = padding * 2; - verticalMargin = horizontalMargin; + horizontalMargin = 4; + verticalMargin = 8; break; } case KFileItemListView::CompactLayout: { @@ -240,12 +240,13 @@ void DolphinItemListContainer::updateGridSize() const int textLinesCount = m_fileItemListView->visibleRoles().count(); itemHeight = padding * 2 + qMax(iconSize, textLinesCount * styleOption.fontMetrics.height()); - horizontalMargin = padding * 2; + horizontalMargin = 8; break; } case KFileItemListView::DetailsLayout: { itemWidth = -1; itemHeight = padding * 2 + qMax(iconSize, styleOption.fontMetrics.height()); + padding = 3; break; } default: