]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Group header improvements
authorPeter Penz <peter.penz19@gmail.com>
Mon, 6 Feb 2012 22:26:20 +0000 (23:26 +0100)
committerPeter Penz <peter.penz19@gmail.com>
Mon, 6 Feb 2012 22:31:49 +0000 (23:31 +0100)
- Use a simpler background and colors as suggested by Martin Zilz.
  This is just an early draft, I need to post some comparison screenshots to
  Martin for review.
- Fixes of some layout issues that have been revealed because of adjusting
  the group header heights.
- More clever animation/no-animation detection when doing listview-property
  changes in parallel.

src/kitemviews/kfileitemlistgroupheader.cpp
src/kitemviews/kitemlistgroupheader.cpp
src/kitemviews/kitemlistgroupheader.h
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/kitemlistviewlayouter.cpp
src/views/dolphinitemlistcontainer.cpp

index 06d410f28566827bcc3f68a0cfe927401261cb9b..237a974c2a2761de8ae843e8ecadffd8b3d8b4ad 100644 (file)
@@ -41,10 +41,9 @@ void KFileItemListGroupHeader::paint(QPainter* painter, const QStyleOptionGraphi
 {
     KItemListGroupHeader::paint(painter, option, widget);
 
-    painter->setPen(styleOption().palette.text().color());
+    painter->setPen(roleColor());
     painter->setFont(m_font);
-    const int margin = styleOption().margin;
-    painter->drawStaticText(margin * 2, margin, m_text);
+    painter->drawStaticText(roleBounds().topLeft(), m_text);
 }
 
 void KFileItemListGroupHeader::dataChanged(const QVariant& current, const QVariant& previous)
@@ -63,8 +62,7 @@ void KFileItemListGroupHeader::resizeEvent(QGraphicsSceneResizeEvent* event)
 void KFileItemListGroupHeader::updateText()
 {
     const qreal width = size().width() - 4 * styleOption().margin;
-    m_font = font();
-    m_font.setBold(true);
+    m_font = font(); // TODO: Most probably the font size will be slightly shrinked in future
 
     QFontMetricsF fontMetrics(m_font);
     const QString text = fontMetrics.elidedText(data().toString(), Qt::ElideRight, width);
index a63ad8d0913c79025a19dc206485020e5265fc3c..8eff399011ff37a19b00be012ee701b0952c85f5 100644 (file)
@@ -36,15 +36,13 @@ KItemListGroupHeader::KItemListGroupHeader(QGraphicsWidget* parent) :
     m_data(),
     m_styleOption(),
     m_scrollOrientation(Qt::Vertical),
-    m_leftBorderCache(0),
-    m_rightBorderCache(0),
-    m_outlineColor()
+    m_roleColor(),
+    m_roleBounds()
 {
 }
 
 KItemListGroupHeader::~KItemListGroupHeader()
 {
-    deleteCache();
 }
 
 void KItemListGroupHeader::setRole(const QByteArray& role)
@@ -97,8 +95,6 @@ void KItemListGroupHeader::setScrollOrientation(Qt::Orientation orientation)
         m_scrollOrientation = orientation;
         if (orientation == Qt::Vertical) {
             m_dirtyCache = true;
-        } else {
-            deleteCache();
         }
         scrollOrientationChanged(orientation, previous);
     }
@@ -114,24 +110,25 @@ void KItemListGroupHeader::paint(QPainter* painter, const QStyleOptionGraphicsIt
     Q_UNUSED(option);
     Q_UNUSED(widget);
 
-    if (m_scrollOrientation == Qt::Horizontal) {
-        Q_ASSERT(!m_leftBorderCache);
-        Q_ASSERT(!m_rightBorderCache);
-        return;
-    }
-
     if (m_dirtyCache) {
         updateCache();
     }
 
-    const int leftBorderX = m_leftBorderCache->width() + 1;
-    const int rightBorderX = size().width() - m_rightBorderCache->width() - 2;
+    if (m_scrollOrientation != Qt::Horizontal) {
+        painter->setPen(m_roleColor);
+        const qreal y = m_roleBounds.y() - m_styleOption.margin;
+        painter->drawLine(0, y, size().width() - 1, y);
+    }
+}
 
-    painter->setPen(m_outlineColor);
-    painter->drawLine(leftBorderX, 1, rightBorderX, 1);
+QRectF KItemListGroupHeader::roleBounds() const
+{
+    return m_roleBounds;
+}
 
-    painter->drawPixmap(1, 1, *m_leftBorderCache);
-    painter->drawPixmap(rightBorderX, 1, *m_rightBorderCache);
+QColor KItemListGroupHeader::roleColor() const
+{
+    return m_roleColor;
 }
 
 void KItemListGroupHeader::roleChanged(const QByteArray& current, const QByteArray& previous)
@@ -170,82 +167,26 @@ void KItemListGroupHeader::updateCache()
 {
     Q_ASSERT(m_dirtyCache);
 
-    deleteCache();
-
-    const int length = qMax(int(size().height() - 1), 1);
-    m_leftBorderCache = new QPixmap(length, length);
-    m_leftBorderCache->fill(Qt::transparent);
-
-    m_rightBorderCache = new QPixmap(length, length);
-    m_rightBorderCache->fill(Qt::transparent);
-
     // Calculate the outline 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_outlineColor = QColor((c1.red()   * p1 + c2.red()   * p2) / 100,
-                            (c1.green() * p1 + c2.green() * p2) / 100,
-                            (c1.blue()  * p1 + c2.blue()  * p2) / 100);
-
-    // The drawing code is based on the code of DolphinCategoryDrawer from Dolphin 1.7
-    // Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
-    {
-        // Cache the left border as pixmap
-        QPainter painter(m_leftBorderCache);
-        painter.setPen(m_outlineColor);
-
-        // 1. Draw top horizontal line
-        painter.drawLine(3, 0, length, 0);
-
-        // 2. Draw vertical line with gradient
-        const QPoint start(0, 3);
-        QLinearGradient gradient(start, QPoint(0, length));
-        gradient.setColorAt(0, m_outlineColor);
-        gradient.setColorAt(1, Qt::transparent);
-        painter.fillRect(QRect(start, QSize(1, length - start.y())), gradient);
-
-        // 3. Draw arc
-        painter.setRenderHint(QPainter::Antialiasing);
-        QRectF arc(QPointF(0, 0), QSizeF(4, 4));
-        arc.translate(0.5, 0.5);
-        painter.drawArc(arc, 1440, 1440);
-    }
-
-    {
-        // Cache the right border as pixmap
-        QPainter painter(m_rightBorderCache);
-        painter.setPen(m_outlineColor);
-
-        // 1. Draw top horizontal line
-        painter.drawLine(0, 0, length - 3, 0);
-
-        // 2. Draw vertical line with gradient
-        const int right = length - 1;
-        const QPoint start(right, 3);
-        QLinearGradient gradient(start, QPoint(right, length));
-        gradient.setColorAt(0, m_outlineColor);
-        gradient.setColorAt(1, Qt::transparent);
-        painter.fillRect(QRect(start, QSize(1, length - start.y())), gradient);
-
-        // 3. Draw arc
-        painter.setRenderHint(QPainter::Antialiasing);
-        QRectF arc(QPointF(length - 5, 0), QSizeF(4, 4));
-        arc.translate(0.5, 0.5);
-        painter.drawArc(arc, 0, 1440);
-    }
+    m_roleColor = QColor((c1.red()   * p1 + c2.red()   * p2) / 100,
+                         (c1.green() * p1 + c2.green() * p2) / 100,
+                         (c1.blue()  * p1 + c2.blue()  * p2) / 100);
 
-    m_dirtyCache = false;
-}
+    const int margin = m_styleOption.margin;
+    const QFontMetrics fontMetrics(m_styleOption.font);
+    const qreal roleHeight = fontMetrics.height();
 
-void KItemListGroupHeader::deleteCache()
-{
-    delete m_leftBorderCache;
-    m_leftBorderCache = 0;
+    m_roleBounds = QRectF(margin,
+                          size().height() - roleHeight - margin,
+                          size().width() - 2 * margin,
+                          roleHeight);
 
-    delete m_rightBorderCache;
-    m_rightBorderCache = 0;
+    m_dirtyCache = false;
 }
 
 #include "kitemlistgroupheader.moc"
index 8f556afc50a78dadb7984b81d0aa5ff0770a12f7..5ddf20896f8a000600270023318a13a535b7dace 100644 (file)
 
 class KItemListView;
 
+/**
+ * @brief Base class for group headers.
+ *
+ * Draws a default header background. Derived classes must reimplement
+ * the method paint() and draw the role within the given roleBounds() with
+ * the color roleColor().
+ */
 class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeader : public QGraphicsWidget
 {
     Q_OBJECT
@@ -58,6 +65,12 @@ public:
     virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
 
 protected:
+    /** @return Bounding rectangle where the role should be drawn into. */
+    QRectF roleBounds() const;
+
+    /** @return Primary color that should be used for drawing the role. */
+    QColor roleColor() const;
+
     /**
      * Is called after the role has been changed and allows the derived class
      * to react on this change.
@@ -87,7 +100,6 @@ protected:
 
 private:
     void updateCache();
-    void deleteCache();
 
 private:
     bool m_dirtyCache;
@@ -96,9 +108,8 @@ private:
     KItemListStyleOption m_styleOption;
     Qt::Orientation m_scrollOrientation;
 
-    QPixmap* m_leftBorderCache;
-    QPixmap* m_rightBorderCache;
-    QColor m_outlineColor;
+    QColor m_roleColor;
+    QRectF m_roleBounds;
 };
 #endif
 
index 52d85770549c0be87f6ac07dc1bdb445e40b4821..a2252b918e986fca48ebc45d0009bc07f01c5d3c 100644 (file)
@@ -55,6 +55,7 @@ KItemListView::KItemListView(QGraphicsWidget* parent) :
     m_enabledSelectionToggles(false),
     m_grouped(false),
     m_activeTransactions(0),
+    m_endTransactionAnimationHint(Animation),
     m_itemSize(),
     m_controller(0),
     m_model(0),
@@ -125,6 +126,8 @@ void KItemListView::setScrollOrientation(Qt::Orientation orientation)
             it.next();
             it.value()->setScrollOrientation(orientation);
         }
+        updateGroupHeaderHeight();
+
     }
 
     doLayout(NoAnimation);
@@ -331,14 +334,19 @@ void KItemListView::setStyleOption(const KItemListStyleOption& option)
     const KItemListStyleOption previousOption = m_styleOption;
     m_styleOption = option;
 
+    if (m_grouped) {
+        updateGroupHeaderHeight();
+    }
+
     QHashIterator<int, KItemListWidget*> it(m_visibleItems);
     while (it.hasNext()) {
         it.next();
         it.value()->setStyleOption(option);
     }
 
-    m_sizeHintResolver->clearCache();
+    m_sizeHintResolver->clearCache();   
     doLayout(Animation);
+
     onStyleOptionChanged(option, previousOption);
 }
 
@@ -548,7 +556,8 @@ void KItemListView::endTransaction()
 
     if (m_activeTransactions == 0) {
         onTransactionEnd();
-        doLayout(NoAnimation);
+        doLayout(m_endTransactionAnimationHint);
+        m_endTransactionAnimationHint = Animation;
     }
 }
 
@@ -557,7 +566,6 @@ bool KItemListView::isTransactionActive() const
     return m_activeTransactions > 0;
 }
 
-
 void KItemListView::setHeaderShown(bool show)
 {
 
@@ -893,7 +901,7 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
             // geometry update if necessary.
             const int activeTransactions = m_activeTransactions;
             m_activeTransactions = 0;
-            doLayout(animateChangedItemCount(count) ? Animation : NoAnimation, index, -count);            
+            doLayout(animateChangedItemCount(count) ? Animation : NoAnimation, index, -count);
             m_activeTransactions = activeTransactions;
         }
     }
@@ -978,12 +986,7 @@ void KItemListView::slotGroupedSortingChanged(bool current)
     m_layouter->markAsDirty();
 
     if (m_grouped) {
-        // Apply the height of the header to the layouter
-        const qreal groupHeaderHeight = m_styleOption.fontMetrics.height() +
-                                        m_styleOption.margin * 2;
-        m_layouter->setGroupHeaderHeight(groupHeaderHeight);
-
-        updateVisibleGroupHeaders();
+        updateGroupHeaderHeight();
     } else {
         // Clear all visible headers
         QMutableHashIterator<KItemListWidget*, KItemListGroupHeader*> it (m_visibleGroups);
@@ -1287,7 +1290,16 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha
         m_layoutTimer->stop();
     }
 
-    if (!m_model || m_model->count() < 0 || m_activeTransactions > 0) {
+    if (m_activeTransactions > 0) {
+        if (hint == NoAnimation) {
+            // As soon as at least one property change should be done without animation,
+            // the whole transaction will be marked as not animated.
+            m_endTransactionAnimationHint = NoAnimation;
+        }
+        return;
+    }
+
+    if (!m_model || m_model->count() < 0) {
         return;
     }
 
@@ -1608,13 +1620,13 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget)
         return;
     }
 
-    KItemListGroupHeader* header = m_visibleGroups.value(widget);
-    if (!header) {
-        header = m_groupHeaderCreator->create(this);
-        header->setParentItem(widget);
-        m_visibleGroups.insert(widget, header);
+    KItemListGroupHeader* groupHeader = m_visibleGroups.value(widget);
+    if (!groupHeader) {
+        groupHeader = m_groupHeaderCreator->create(this);
+        groupHeader->setParentItem(widget);
+        m_visibleGroups.insert(widget, groupHeader);
     }
-    Q_ASSERT(header->parentItem() == widget);
+    Q_ASSERT(groupHeader->parentItem() == widget);
 
     // Determine the shown data for the header by doing a binary
     // search in the groups-list
@@ -1630,18 +1642,18 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget* widget)
         }
     } while (groups.at(mid).first != index && min <= max);
 
-    header->setData(groups.at(mid).second);
-    header->setRole(model()->sortRole());
-    header->setStyleOption(m_styleOption);
-    header->setScrollOrientation(scrollOrientation());
+    groupHeader->setData(groups.at(mid).second);
+    groupHeader->setRole(model()->sortRole());
+    groupHeader->setStyleOption(m_styleOption);
+    groupHeader->setScrollOrientation(scrollOrientation());
 
-    header->show();
+    groupHeader->show();
 }
 
 void KItemListView::updateGroupHeaderLayout(KItemListWidget* widget)
 {
-    KItemListGroupHeader* header = m_visibleGroups.value(widget);
-    Q_ASSERT(header);
+    KItemListGroupHeader* groupHeader = m_visibleGroups.value(widget);
+    Q_ASSERT(groupHeader);
 
     const int index = widget->index();
     const QRectF groupHeaderRect = m_layouter->groupHeaderRect(index);
@@ -1651,8 +1663,8 @@ void KItemListView::updateGroupHeaderLayout(KItemListWidget* widget)
     // group header position to the relative position.
     const QPointF groupHeaderPos(groupHeaderRect.x() - itemRect.x(),
                                  - groupHeaderRect.height());
-    header->setPos(groupHeaderPos);
-    header->resize(groupHeaderRect.size());
+    groupHeader->setPos(groupHeaderPos);
+    groupHeader->resize(groupHeaderRect.size());
 }
 
 void KItemListView::recycleGroupHeaderForWidget(KItemListWidget* widget)
@@ -1893,6 +1905,16 @@ bool KItemListView::scrollBarRequired(const QSizeF& size) const
                                                            : maxOffset > size.width();
 }
 
+void KItemListView::updateGroupHeaderHeight()
+{
+    qreal groupHeaderHeight = m_styleOption.fontMetrics.height();
+    groupHeaderHeight += (scrollOrientation() == Qt::Vertical)
+                         ? m_styleOption.margin * 4 : m_styleOption.margin * 2;
+    m_layouter->setGroupHeaderHeight(groupHeaderHeight);
+
+    updateVisibleGroupHeaders();
+}
+
 int KItemListView::calculateAutoScrollingIncrement(int pos, int range, int oldInc)
 {
     int inc = 0;
index e675df2211e946a2223c127de142282bd716c2f0..50d8908e5884864cd6b03a05878be1d510f7d4d9 100644 (file)
@@ -202,8 +202,20 @@ public:
      */
     void scrollToItem(int index);
 
+    /**
+     * If several properties of KItemListView are changed synchronously, it is
+     * recommended to encapsulate the calls between beginTransaction() and endTransaction().
+     * This prevents unnecessary and expensive layout-calculations.
+     */
     void beginTransaction();
+
+    /**
+     * Counterpart to beginTransaction(). The layout changes will only be animated if
+     * all property changes between beginTransaction() and endTransaction() support
+     * animations.
+     */
     void endTransaction();
+
     bool isTransactionActive() const;
 
     /**
@@ -468,6 +480,12 @@ private:
      */
     bool scrollBarRequired(const QSizeF& size) const;
 
+    /**
+     * Applies the height of the group header to the layouter. The height
+     * depends on the used scroll orientation.
+     */
+    void updateGroupHeaderHeight();
+
     /**
      * Helper function for triggerAutoScrolling().
      * @param pos    Logical position of the mouse relative to the range.
@@ -484,6 +502,7 @@ private:
     bool m_enabledSelectionToggles;
     bool m_grouped;
     int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
+    LayoutAnimationHint m_endTransactionAnimationHint;
 
     QSizeF m_itemSize;
     KItemListController* m_controller;
index 60822adc7f1ad96301fe89206ece8ee6ced1997c..4e7a910873430185b8f69fd43168a006e3da1aff 100644 (file)
@@ -221,6 +221,8 @@ QRectF KItemListViewLayouter::itemRect(int index) const
 
 QRectF KItemListViewLayouter::groupHeaderRect(int index) const
 {
+    const_cast<KItemListViewLayouter*>(this)->doLayout();
+
     const QRectF firstItemRect = itemRect(index);
     QPointF pos = firstItemRect.topLeft();
     if (pos.isNull()) {
index 4f7a0e06b16ac89d378643b69e203cc188c656b1..65f69d963219592116949fb3a573a27b0bcdb43d 100644 (file)
@@ -242,8 +242,10 @@ void DolphinItemListContainer::updateGridSize()
     // Apply the calculated values
     styleOption.margin = innerMargin;
     styleOption.iconSize = iconSize;
+    m_fileItemListView->beginTransaction();
     m_fileItemListView->setStyleOption(styleOption);
     m_fileItemListView->setItemSize(QSizeF(itemWidth, itemHeight));
+    m_fileItemListView->endTransaction();
 }
 
 void DolphinItemListContainer::updateFont()