- 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.
{
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)
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);
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)
m_scrollOrientation = orientation;
if (orientation == Qt::Vertical) {
m_dirtyCache = true;
- } else {
- deleteCache();
}
scrollOrientationChanged(orientation, previous);
}
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)
{
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"
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
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.
private:
void updateCache();
- void deleteCache();
private:
bool m_dirtyCache;
KItemListStyleOption m_styleOption;
Qt::Orientation m_scrollOrientation;
- QPixmap* m_leftBorderCache;
- QPixmap* m_rightBorderCache;
- QColor m_outlineColor;
+ QColor m_roleColor;
+ QRectF m_roleBounds;
};
#endif
m_enabledSelectionToggles(false),
m_grouped(false),
m_activeTransactions(0),
+ m_endTransactionAnimationHint(Animation),
m_itemSize(),
m_controller(0),
m_model(0),
it.next();
it.value()->setScrollOrientation(orientation);
}
+ updateGroupHeaderHeight();
+
}
doLayout(NoAnimation);
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);
}
if (m_activeTransactions == 0) {
onTransactionEnd();
- doLayout(NoAnimation);
+ doLayout(m_endTransactionAnimationHint);
+ m_endTransactionAnimationHint = Animation;
}
}
return m_activeTransactions > 0;
}
-
void KItemListView::setHeaderShown(bool show)
{
// 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;
}
}
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);
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;
}
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
}
} 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);
// 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)
: 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;
*/
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;
/**
*/
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.
bool m_enabledSelectionToggles;
bool m_grouped;
int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
+ LayoutAnimationHint m_endTransactionAnimationHint;
QSizeF m_itemSize;
KItemListController* m_controller;
QRectF KItemListViewLayouter::groupHeaderRect(int index) const
{
+ const_cast<KItemListViewLayouter*>(this)->doLayout();
+
const QRectF firstItemRect = itemRect(index);
QPointF pos = firstItemRect.topLeft();
if (pos.isNull()) {
// 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()