m_data(),
m_styleOption(),
m_scrollOrientation(Qt::Vertical),
+ m_itemIndex(-1),
+ m_lineColor(),
m_roleColor(),
m_roleBounds()
{
}
}
+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;
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);
}
Q_UNUSED(previous);
}
+void KItemListGroupHeader::itemIndexChanged(int current, int previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
void KItemListGroupHeader::resizeEvent(QGraphicsSceneResizeEvent* event)
{
QGraphicsWidget::resizeEvent(event);
{
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"
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:
*/
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;
};
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) {
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);
groupHeader->setRole(model()->sortRole());
groupHeader->setStyleOption(m_styleOption);
groupHeader->setScrollOrientation(scrollOrientation());
+ groupHeader->setItemIndex(index);
groupHeader->show();
}
// 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)
header->setParentItem(0);
m_groupHeaderCreator->recycle(header);
m_visibleGroups.remove(widget);
+ disconnect(widget, SIGNAL(geometryChanged()), this, SLOT(slotGeometryOfGroupHeaderParentChanged()));
}
}
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();
}
*/
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
{
m_columnCount(0),
m_groupItemIndexes(),
m_groupHeaderHeight(0),
+ m_groupHeaderMargin(0),
m_itemRects()
{
}
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) {
// 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;
}
}
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;
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;
}
}
--index;
}
+ m_maximumScrollOffset += itemMargin.height();
+
m_maximumItemOffset = m_columnCount * m_columnWidth;
} else {
m_maximumScrollOffset = 0;
*/
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;
// Assures fast access for KItemListViewLayouter::isFirstGroupItem().
QSet<int> m_groupItemIndexes;
qreal m_groupHeaderHeight;
+ qreal m_groupHeaderMargin;
QList<QRectF> m_itemRects;
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);
}
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;
int itemHeight;
switch (itemLayout()) {
case KFileItemListView::IconsLayout: {
- const int minItemWidth = 64;
+ const int minItemWidth = 48;
itemWidth = minItemWidth + IconsModeSettings::textWidthIndex() * 64;
if (previewsShown()) {
}
itemHeight = padding * 3 + iconSize + styleOption.fontMetrics.height();
- horizontalMargin = padding * 2;
- verticalMargin = horizontalMargin;
+ horizontalMargin = 4;
+ verticalMargin = 8;
break;
}
case KFileItemListView::CompactLayout: {
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: