diff options
| author | Tom Lin <[email protected]> | 2022-01-16 14:01:32 +0000 |
|---|---|---|
| committer | Felix Ernst <[email protected]> | 2022-01-16 14:01:32 +0000 |
| commit | d3839617193e92463806580699caa595c892b8a6 (patch) | |
| tree | 9819ace996bc994dd047206669eaa2869471a79b /src/kitemviews/private | |
| parent | a286506405550fe299e1f4a5fd73543e642655a0 (diff) | |
Full row highlight implementation
This commit implements full-row selection and hover highlights for the
details view mode.
This commit also contains fixes for 444680, 444753, both uncovered
during this change.
BUG: 181438
BUG: 444680
BUG: 444753
FIXED-IN: 22.04
Diffstat (limited to 'src/kitemviews/private')
| -rw-r--r-- | src/kitemviews/private/kitemlistheaderwidget.cpp | 126 | ||||
| -rw-r--r-- | src/kitemviews/private/kitemlistheaderwidget.h | 15 |
2 files changed, 107 insertions, 34 deletions
diff --git a/src/kitemviews/private/kitemlistheaderwidget.cpp b/src/kitemviews/private/kitemlistheaderwidget.cpp index 9a7e850a9..8b39c25fe 100644 --- a/src/kitemviews/private/kitemlistheaderwidget.cpp +++ b/src/kitemviews/private/kitemlistheaderwidget.cpp @@ -18,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(), @@ -134,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()); @@ -153,7 +168,7 @@ 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; for (const QByteArray& role : qAsConst(m_columns)) { const qreal roleWidth = m_columnWidths.value(role); @@ -172,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(); @@ -263,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); @@ -291,6 +310,20 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) 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; + } + case MoveRoleOperation: { // TODO: It should be configurable whether moving the first role is allowed. // In the context of Dolphin this is not required, however this should be @@ -355,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(); @@ -404,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; } @@ -424,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) @@ -467,7 +504,7 @@ int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const { int index = -1; - qreal x = -m_offset; + qreal x = -m_offset + m_leadingPadding; for (const QByteArray& role : qAsConst(m_columns)) { ++index; x += m_columnWidths.value(role); @@ -481,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); @@ -491,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]; @@ -522,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); @@ -548,7 +606,7 @@ int KItemListHeaderWidget::targetOfMovingRole() const qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const { - qreal x = -m_offset; + qreal x = -m_offset + m_leadingPadding; for (const QByteArray& visibleRole : qAsConst(m_columns)) { if (visibleRole == role) { return x; diff --git a/src/kitemviews/private/kitemlistheaderwidget.h b/src/kitemviews/private/kitemlistheaderwidget.h index 44adc23c5..58f0dc98e 100644 --- a/src/kitemviews/private/kitemlistheaderwidget.h +++ b/src/kitemviews/private/kitemlistheaderwidget.h @@ -50,6 +50,9 @@ public: void setOffset(qreal offset); qreal offset() const; + void setLeadingPadding(qreal width); + qreal leadingPadding() const; + qreal minimumColumnWidth() const; void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override; @@ -63,6 +66,8 @@ Q_SIGNALS: qreal currentWidth, qreal previousWidth); + void leadingPaddingChanged(qreal width); + /** * Is emitted if the user has released the mouse button after adjusting the * width of a visible role. @@ -105,6 +110,13 @@ private Q_SLOTS: void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); private: + + enum PaddingGrip + { + Leading, + Trailing, + }; + void paintRole(QPainter* painter, const QByteArray& role, const QRectF& rect, @@ -115,6 +127,7 @@ private: void updateHoveredRoleIndex(const QPointF& pos); int roleIndexAt(const QPointF& pos) const; bool isAboveRoleGrip(const QPointF& pos, int roleIndex) const; + bool isAbovePaddingGrip(const QPointF& pos, PaddingGrip paddingGrip) const; /** * Creates a pixmap of the role with the index \a roleIndex that is shown @@ -138,12 +151,14 @@ private: { NoRoleOperation, ResizeRoleOperation, + ResizeLeadingColumnOperation, MoveRoleOperation }; bool m_automaticColumnResizing; KItemModelBase* m_model; qreal m_offset; + qreal m_leadingPadding; QList<QByteArray> m_columns; QHash<QByteArray, qreal> m_columnWidths; QHash<QByteArray, qreal> m_preferredColumnWidths; |
