]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Group header layout fixes
authorPeter Penz <peter.penz19@gmail.com>
Sat, 11 Feb 2012 17:02:38 +0000 (18:02 +0100)
committerPeter Penz <peter.penz19@gmail.com>
Sat, 11 Feb 2012 17:04:53 +0000 (18:04 +0100)
- 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

src/kitemviews/kitemlistgroupheader.cpp
src/kitemviews/kitemlistgroupheader.h
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/kitemlistviewlayouter.cpp
src/kitemviews/kitemlistviewlayouter_p.h
src/kitemviews/kitemlistwidget.cpp
src/views/dolphinitemlistcontainer.cpp

index 03964e2b5c864e9e29ab3c7141b5543f55e141fb..ffc81eb120483be421f0052b19f7b059d3693141 100644 (file)
@@ -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"
index 5ddf20896f8a000600270023318a13a535b7dace..c996a48708065b198bec5f01c81d61fd03b2f1b6 100644 (file)
@@ -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;
 };
index 451e5183369c460cae44352f4358c7263768a781..323e6745296e276392b17c81d143781b5e381f11 100644 (file)
@@ -1224,6 +1224,15 @@ void KItemListView::triggerAutoScrolling()
    m_autoScrollTimer->start(RepeatingAutoScrollDelay);
 }
 
+void KItemListView::slotGeometryOfGroupHeaderParentChanged()
+{
+    KItemListWidget* widget = qobject_cast<KItemListWidget*>(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();
 }
index 808ff5b3ec115137b3307c224480f6cd073d2584..6ed714b2050f4059a061e9f2c63e0defb53d7a1d 100644 (file)
@@ -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
     {
index 2d02b6725102d04b5dc2ddf5dc9c58480eadf0a3..a9b59051dcf3f987d628dc264ee99cb3bfcb7c4c 100644 (file)
@@ -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;
index af8a6dacb047f45e63e46200354b7d9a59b8c2f1..ebed39a41a9633d38fa87a267993864636e1ce7f 100644 (file)
@@ -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<int> m_groupItemIndexes;
     qreal m_groupHeaderHeight;
+    qreal m_groupHeaderMargin;
 
     QList<QRectF> m_itemRects;
 
index 67df036c837764bac862d3f7a62996223a37698f..3d593f76f54715dc71c267c2a5ec9a5105e87f3a 100644 (file)
@@ -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);
 }
 
index 544892674f3a5111cf54a60ddf2b75eb1c9a88a6..299f32fabb9faca9dbe11c5e79d17ff0bf6da17f 100644 (file)
@@ -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: