X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/f7a824b70d3854598e8dece5c2437b4e76c8a862..d3839617193e92463806580699caa595c892b8a6:/src/kitemviews/private/kitemlistheaderwidget.cpp diff --git a/src/kitemviews/private/kitemlistheaderwidget.cpp b/src/kitemviews/private/kitemlistheaderwidget.cpp index a3f3f521f..8b39c25fe 100644 --- a/src/kitemviews/private/kitemlistheaderwidget.cpp +++ b/src/kitemviews/private/kitemlistheaderwidget.cpp @@ -1,21 +1,8 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ +/* + * SPDX-FileCopyrightText: 2011 Peter Penz + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ #include "kitemlistheaderwidget.h" #include "kitemviews/kitemmodelbase.h" @@ -31,6 +18,7 @@ KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget* parent) : m_automaticColumnResizing(true), m_model(nullptr), m_offset(0), + m_leadingPadding(0), m_columns(), m_columnWidths(), m_preferredColumnWidths(), @@ -91,9 +79,8 @@ bool KItemListHeaderWidget::automaticColumnResizing() const void KItemListHeaderWidget::setColumns(const QList& roles) { - foreach (const QByteArray& role, roles) { + for (const QByteArray& role : roles) { if (!m_columnWidths.contains(role)) { - m_columnWidths.remove(role); m_preferredColumnWidths.remove(role); } } @@ -148,6 +135,20 @@ qreal KItemListHeaderWidget::offset() const return m_offset; } +void KItemListHeaderWidget::setLeadingPadding(qreal width) +{ + if (m_leadingPadding != width) { + m_leadingPadding = width; + leadingPaddingChanged(width); + update(); + } +} + +qreal KItemListHeaderWidget::leadingPadding() const +{ + return m_leadingPadding; +} + qreal KItemListHeaderWidget::minimumColumnWidth() const { QFontMetricsF fontMetrics(font()); @@ -156,8 +157,8 @@ qreal KItemListHeaderWidget::minimumColumnWidth() const void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { - Q_UNUSED(option); - Q_UNUSED(widget); + Q_UNUSED(option) + Q_UNUSED(widget) if (!m_model) { return; @@ -167,9 +168,9 @@ void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsI painter->setFont(font()); painter->setPen(palette().text().color()); - qreal x = -m_offset; + qreal x = -m_offset + m_leadingPadding; int orderIndex = 0; - foreach (const QByteArray& role, m_columns) { + for (const QByteArray& role : qAsConst(m_columns)) { const qreal roleWidth = m_columnWidths.value(role); const QRectF rect(x, 0, roleWidth, size().height()); paintRole(painter, role, rect, orderIndex, widget); @@ -186,10 +187,14 @@ void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsI void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (event->button() & Qt::LeftButton) { - updatePressedRoleIndex(event->pos()); m_pressedMousePos = event->pos(); - m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ? - ResizeRoleOperation : NoRoleOperation; + if (isAbovePaddingGrip(m_pressedMousePos, PaddingGrip::Leading)) { + m_roleOperation = ResizeLeadingColumnOperation; + } else { + updatePressedRoleIndex(event->pos()); + m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ? + ResizeRoleOperation : NoRoleOperation; + } event->accept(); } else { event->ignore(); @@ -215,18 +220,18 @@ void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder; m_model->setSortOrder(current); - emit sortOrderChanged(current, previous); + Q_EMIT sortOrderChanged(current, previous); } else { // Change the sort role and reset to the ascending order const QByteArray previous = m_model->sortRole(); const QByteArray current = m_columns[m_pressedRoleIndex]; const bool resetSortOrder = m_model->sortOrder() == Qt::DescendingOrder; m_model->setSortRole(current, !resetSortOrder); - emit sortRoleChanged(current, previous); + Q_EMIT sortRoleChanged(current, previous); if (resetSortOrder) { m_model->setSortOrder(Qt::AscendingOrder); - emit sortOrderChanged(Qt::AscendingOrder, Qt::DescendingOrder); + Q_EMIT sortOrderChanged(Qt::AscendingOrder, Qt::DescendingOrder); } } break; @@ -235,7 +240,7 @@ void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) case ResizeRoleOperation: { const QByteArray pressedRole = m_columns[m_pressedRoleIndex]; const qreal currentWidth = m_columnWidths.value(pressedRole); - emit columnWidthChangeFinished(pressedRole, currentWidth); + Q_EMIT columnWidthChangeFinished(pressedRole, currentWidth); break; } @@ -265,7 +270,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) case NoRoleOperation: if ((event->pos() - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) { // A role gets dragged by the user. Create a pixmap of the role that will get - // synchronized on each furter mouse-move-event with the mouse-position. + // synchronized on each further mouse-move-event with the mouse-position. m_roleOperation = MoveRoleOperation; const int roleIndex = roleIndexAt(m_pressedMousePos); m_movingRole.index = roleIndex; @@ -277,7 +282,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) } else { m_movingRole.pixmap = createRolePixmap(roleIndex); - qreal roleX = -m_offset; + qreal roleX = -m_offset + m_leadingPadding; for (int i = 0; i < roleIndex; ++i) { const QByteArray role = m_columns[i]; roleX += m_columnWidths.value(role); @@ -301,7 +306,21 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) m_columnWidths.insert(pressedRole, currentWidth); update(); - emit columnWidthChanged(pressedRole, currentWidth, previousWidth); + Q_EMIT columnWidthChanged(pressedRole, currentWidth, previousWidth); + break; + } + + case ResizeLeadingColumnOperation: { + qreal currentWidth = m_leadingPadding; + currentWidth += event->pos().x() - event->lastPos().x(); + currentWidth = qMax(0.0, currentWidth); + + m_leadingPadding = currentWidth; + + update(); + + Q_EMIT leadingPaddingChanged(currentWidth); + break; } @@ -318,7 +337,7 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) const QByteArray role = m_columns[m_movingRole.index]; const int previousIndex = m_movingRole.index; m_movingRole.index = targetIndex; - emit columnMoved(role, targetIndex, previousIndex); + Q_EMIT columnMoved(role, targetIndex, previousIndex); m_movingRole.xDec = event->pos().x() - roleXPosition(role); } @@ -343,8 +362,8 @@ void KItemListHeaderWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* even setColumnWidth(role, preferredColumnWidth(role)); qreal currentWidth = columnWidth(role); - emit columnWidthChanged(role, currentWidth, previousWidth); - emit columnWidthChangeFinished(role, currentWidth); + Q_EMIT columnWidthChanged(role, currentWidth, previousWidth); + Q_EMIT columnWidthChangeFinished(role, currentWidth); } } @@ -369,7 +388,9 @@ void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event) const QPointF& pos = event->pos(); updateHoveredRoleIndex(pos); - if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) { + if ((m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) || + isAbovePaddingGrip(pos, PaddingGrip::Leading) || + isAbovePaddingGrip(pos, PaddingGrip::Trailing)) { setCursor(Qt::SplitHCursor); } else { unsetCursor(); @@ -378,15 +399,15 @@ void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event) void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) update(); } void KItemListHeaderWidget::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous) { - Q_UNUSED(current); - Q_UNUSED(previous); + Q_UNUSED(current) + Q_UNUSED(previous) update(); } @@ -397,7 +418,7 @@ void KItemListHeaderWidget::paintRole(QPainter* painter, QWidget* widget) const { // The following code is based on the code from QHeaderView::paintSection(). - // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + // SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies). QStyleOptionHeader option; option.section = orderIndex; option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal; @@ -418,19 +439,39 @@ void KItemListHeaderWidget::paintRole(QPainter* painter, QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp; } option.rect = rect.toRect(); + option.orientation = Qt::Horizontal; + option.selectedPosition = QStyleOptionHeader::NotAdjacent; + option.text = m_model->roleDescription(role); - bool paintBackgroundForEmptyArea = false; + // First we paint any potential empty (padding) space on left and/or right of this role's column. + const auto paintPadding = [&](int section, const QRectF &rect, const QStyleOptionHeader::SectionPosition &pos){ + QStyleOptionHeader padding; + padding.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal; + padding.section = section; + padding.sortIndicator = QStyleOptionHeader::None; + padding.rect = rect.toRect(); + padding.position = pos; + padding.text = QString(); + style()->drawControl(QStyle::CE_Header, &padding, painter, widget); + }; if (m_columns.count() == 1) { - option.position = QStyleOptionHeader::OnlyOneSection; + option.position = QStyleOptionHeader::Middle; + paintPadding(0, QRectF(0.0, 0.0, rect.left(), rect.height()), QStyleOptionHeader::Beginning); + paintPadding(1, QRectF(rect.left(), 0.0, size().width() - rect.left(), rect.height()), QStyleOptionHeader::End); } else if (orderIndex == 0) { - option.position = QStyleOptionHeader::Beginning; + // Paint the header for the first column; check if there is some empty space to the left which needs to be filled. + if (rect.left() > 0) { + option.position = QStyleOptionHeader::Middle; + paintPadding(0,QRectF(0.0, 0.0, rect.left(), rect.height()), QStyleOptionHeader::Beginning); + } else { + option.position = QStyleOptionHeader::Beginning; + } } else if (orderIndex == m_columns.count() - 1) { - // We are just painting the header for the last column. Check if there - // is some empty space to the right which needs to be filled. + // Paint the header for the last column; check if there is some empty space to the right which needs to be filled. if (rect.right() < size().width()) { option.position = QStyleOptionHeader::Middle; - paintBackgroundForEmptyArea = true; + paintPadding(m_columns.count(), QRectF(rect.left(), 0.0, size().width() - rect.left(), rect.height()), QStyleOptionHeader::End); } else { option.position = QStyleOptionHeader::End; } @@ -438,25 +479,7 @@ void KItemListHeaderWidget::paintRole(QPainter* painter, option.position = QStyleOptionHeader::Middle; } - option.orientation = Qt::Horizontal; - option.selectedPosition = QStyleOptionHeader::NotAdjacent; - option.text = m_model->roleDescription(role); - style()->drawControl(QStyle::CE_Header, &option, painter, widget); - - if (paintBackgroundForEmptyArea) { - option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal; - option.section = m_columns.count(); - option.sortIndicator = QStyleOptionHeader::None; - - qreal backgroundRectX = rect.x() + rect.width(); - QRectF backgroundRect(backgroundRectX, 0.0, size().width() - backgroundRectX, rect.height()); - option.rect = backgroundRect.toRect(); - option.position = QStyleOptionHeader::End; - option.text = QString(); - - style()->drawControl(QStyle::CE_Header, &option, painter, widget); - } } void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF& pos) @@ -481,8 +504,8 @@ int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const { int index = -1; - qreal x = -m_offset; - foreach (const QByteArray& role, m_columns) { + qreal x = -m_offset + m_leadingPadding; + for (const QByteArray& role : qAsConst(m_columns)) { ++index; x += m_columnWidths.value(role); if (pos.x() <= x) { @@ -495,7 +518,7 @@ int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) const { - qreal x = -m_offset; + qreal x = -m_offset + m_leadingPadding; for (int i = 0; i <= roleIndex; ++i) { const QByteArray role = m_columns[i]; x += m_columnWidths.value(role); @@ -505,6 +528,27 @@ bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) c return pos.x() >= (x - grip) && pos.x() <= x; } +bool KItemListHeaderWidget::isAbovePaddingGrip(const QPointF& pos, PaddingGrip paddingGrip) const +{ + const qreal lx = -m_offset + m_leadingPadding; + const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin); + + switch (paddingGrip) { + case Leading: + return pos.x() >= (lx - grip) && pos.x() <= lx; + case Trailing: + { + qreal rx = lx; + for (const QByteArray& role : qAsConst(m_columns)) { + rx += m_columnWidths.value(role); + } + return pos.x() >= (rx - grip) && pos.x() <= rx; + } + default: + return false; + } +} + QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const { const QByteArray role = m_columns[roleIndex]; @@ -536,7 +580,7 @@ int KItemListHeaderWidget::targetOfMovingRole() const const int movingRight = movingLeft + movingWidth - 1; int targetIndex = 0; - qreal targetLeft = -m_offset; + qreal targetLeft = -m_offset + m_leadingPadding; while (targetIndex < m_columns.count()) { const QByteArray role = m_columns[targetIndex]; const qreal targetWidth = m_columnWidths.value(role); @@ -562,8 +606,8 @@ int KItemListHeaderWidget::targetOfMovingRole() const qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const { - qreal x = -m_offset; - foreach (const QByteArray& visibleRole, m_columns) { + qreal x = -m_offset + m_leadingPadding; + for (const QByteArray& visibleRole : qAsConst(m_columns)) { if (visibleRole == role) { return x; }