/*
* SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
+ * SPDX-FileCopyrightText: 2022, 2024 Felix Ernst <felixernst@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <QPainter>
#include <QStyleOptionHeader>
+namespace
+{
+/**
+ * @returns a list which has a reversed order of elements compared to @a list.
+ */
+QList<QByteArray> reversed(const QList<QByteArray> list)
+{
+ QList<QByteArray> reversedList;
+ for (auto i = list.rbegin(); i != list.rend(); i++) {
+ reversedList.emplaceBack(*i);
+ }
+ return reversedList;
+};
-KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget* parent) :
- QGraphicsWidget(parent),
- m_automaticColumnResizing(true),
- m_model(nullptr),
- m_offset(0),
- m_columns(),
- m_columnWidths(),
- m_preferredColumnWidths(),
- m_hoveredRoleIndex(-1),
- m_pressedRoleIndex(-1),
- m_roleOperation(NoRoleOperation),
- m_pressedMousePos(),
- m_movingRole()
+/**
+ * @returns the index of the column for the name/text of items. This depends on the layoutDirection() and column count of @a itemListHeaderWidget.
+ */
+int nameColumnIndex(const KItemListHeaderWidget *itemListHeaderWidget)
+{
+ if (itemListHeaderWidget->layoutDirection() == Qt::LeftToRight) {
+ return 0;
+ }
+ return itemListHeaderWidget->columns().count() - 1;
+};
+}
+
+KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget *parent)
+ : QGraphicsWidget(parent)
+ , m_automaticColumnResizing(true)
+ , m_model(nullptr)
+ , m_offset(0)
+ , m_leftPadding(0)
+ , m_rightPadding(0)
+ , m_columns()
+ , m_columnWidths()
+ , m_preferredColumnWidths()
+ , m_hoveredIndex(-1)
+ , m_pressedRoleIndex(-1)
+ , m_pressedMousePos()
+ , m_movingRole()
{
m_movingRole.x = 0;
m_movingRole.xDec = 0;
m_movingRole.index = -1;
setAcceptHoverEvents(true);
+ // TODO update when font changes at runtime
+ setFont(QApplication::font("QHeaderView"));
}
KItemListHeaderWidget::~KItemListHeaderWidget()
{
}
-void KItemListHeaderWidget::setModel(KItemModelBase* model)
+void KItemListHeaderWidget::setModel(KItemModelBase *model)
{
if (m_model == model) {
return;
}
if (m_model) {
- disconnect(m_model, &KItemModelBase::sortRoleChanged,
- this, &KItemListHeaderWidget::slotSortRoleChanged);
- disconnect(m_model, &KItemModelBase::sortOrderChanged,
- this, &KItemListHeaderWidget::slotSortOrderChanged);
+ disconnect(m_model, &KItemModelBase::sortRoleChanged, this, &KItemListHeaderWidget::slotSortRoleChanged);
+ disconnect(m_model, &KItemModelBase::sortOrderChanged, this, &KItemListHeaderWidget::slotSortOrderChanged);
}
m_model = model;
if (m_model) {
- connect(m_model, &KItemModelBase::sortRoleChanged,
- this, &KItemListHeaderWidget::slotSortRoleChanged);
- connect(m_model, &KItemModelBase::sortOrderChanged,
- this, &KItemListHeaderWidget::slotSortOrderChanged);
+ connect(m_model, &KItemModelBase::sortRoleChanged, this, &KItemListHeaderWidget::slotSortRoleChanged);
+ connect(m_model, &KItemModelBase::sortOrderChanged, this, &KItemListHeaderWidget::slotSortOrderChanged);
}
}
-KItemModelBase* KItemListHeaderWidget::model() const
+KItemModelBase *KItemListHeaderWidget::model() const
{
return m_model;
}
return m_automaticColumnResizing;
}
-void KItemListHeaderWidget::setColumns(const QList<QByteArray>& roles)
+void KItemListHeaderWidget::setColumns(const QList<QByteArray> &roles)
{
- foreach (const QByteArray& role, roles) {
+ for (const QByteArray &role : roles) {
if (!m_columnWidths.contains(role)) {
m_preferredColumnWidths.remove(role);
}
}
- m_columns = roles;
+ m_columns = layoutDirection() == Qt::LeftToRight ? roles : reversed(roles);
update();
}
QList<QByteArray> KItemListHeaderWidget::columns() const
{
- return m_columns;
+ return layoutDirection() == Qt::LeftToRight ? m_columns : reversed(m_columns);
}
-void KItemListHeaderWidget::setColumnWidth(const QByteArray& role, qreal width)
+void KItemListHeaderWidget::setColumnWidth(const QByteArray &role, qreal width)
{
const qreal minWidth = minimumColumnWidth();
if (width < minWidth) {
}
}
-qreal KItemListHeaderWidget::columnWidth(const QByteArray& role) const
+qreal KItemListHeaderWidget::columnWidth(const QByteArray &role) const
{
return m_columnWidths.value(role);
}
-void KItemListHeaderWidget::setPreferredColumnWidth(const QByteArray& role, qreal width)
+void KItemListHeaderWidget::setPreferredColumnWidth(const QByteArray &role, qreal width)
{
m_preferredColumnWidths.insert(role, width);
}
-qreal KItemListHeaderWidget::preferredColumnWidth(const QByteArray& role) const
+qreal KItemListHeaderWidget::preferredColumnWidth(const QByteArray &role) const
{
return m_preferredColumnWidths.value(role);
}
return m_offset;
}
+void KItemListHeaderWidget::setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth)
+{
+ bool changed = false;
+ if (m_leftPadding != leftPaddingWidth) {
+ m_leftPadding = leftPaddingWidth;
+ changed = true;
+ }
+
+ if (m_rightPadding != rightPaddingWidth) {
+ m_rightPadding = rightPaddingWidth;
+ changed = true;
+ }
+
+ if (!changed) {
+ return;
+ }
+
+ Q_EMIT sidePaddingChanged(leftPaddingWidth, rightPaddingWidth);
+ update();
+}
+
+qreal KItemListHeaderWidget::leftPadding() const
+{
+ return m_leftPadding;
+}
+
+qreal KItemListHeaderWidget::rightPadding() const
+{
+ return m_rightPadding;
+}
+
qreal KItemListHeaderWidget::minimumColumnWidth() const
{
QFontMetricsF fontMetrics(font());
return fontMetrics.height() * 4;
}
-void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+void KItemListHeaderWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->setFont(font());
painter->setPen(palette().text().color());
- qreal x = -m_offset;
+ qreal x = -m_offset + m_leftPadding + unusedSpace();
int orderIndex = 0;
- foreach (const QByteArray& role, m_columns) {
+ for (const QByteArray &role : std::as_const(m_columns)) {
const qreal roleWidth = m_columnWidths.value(role);
const QRectF rect(x, 0, roleWidth, size().height());
paintRole(painter, role, rect, orderIndex, widget);
}
if (!m_movingRole.pixmap.isNull()) {
- Q_ASSERT(m_roleOperation == MoveRoleOperation);
painter->drawPixmap(m_movingRole.x, 0, m_movingRole.pixmap);
}
}
-void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent* event)
+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;
+ m_pressedGrip = isAboveResizeGrip(m_pressedMousePos);
+ if (!m_pressedGrip) {
+ updatePressedRoleIndex(event->pos());
+ }
event->accept();
} else {
event->ignore();
}
}
-void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
+void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget::mouseReleaseEvent(event);
- if (m_pressedRoleIndex == -1) {
- return;
- }
-
- switch (m_roleOperation) {
- case NoRoleOperation: {
+ if (m_pressedGrip) {
+ // Emitting a column width change removes automatic column resizing, so we do not emit if only the padding is being changed.
+ // Eception: In mouseMoveEvent() we also resize the last column if the right padding is at zero but the user still quickly resizes beyond the screen
+ // boarder. Such a resize "of the right padding" is let through when automatic column resizing was disabled by that resize.
+ if (m_pressedGrip->roleToTheLeft != "leftPadding" && (m_pressedGrip->roleToTheRight != "rightPadding" || !m_automaticColumnResizing)) {
+ const qreal currentWidth = m_columnWidths.value(m_pressedGrip->roleToTheLeft);
+ Q_EMIT columnWidthChangeFinished(m_pressedGrip->roleToTheLeft, currentWidth);
+ }
+ } else if (m_pressedRoleIndex != -1 && m_movingRole.index == -1) {
// Only a click has been done and no moving or resizing has been started
const QByteArray sortRole = m_model->sortRole();
const int sortRoleIndex = m_columns.indexOf(sortRole);
if (m_pressedRoleIndex == sortRoleIndex) {
// Toggle the sort order
const Qt::SortOrder previous = m_model->sortOrder();
- const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ?
- Qt::DescendingOrder : Qt::AscendingOrder;
+ 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;
}
- case ResizeRoleOperation: {
- const QByteArray pressedRole = m_columns[m_pressedRoleIndex];
- const qreal currentWidth = m_columnWidths.value(pressedRole);
- emit columnWidthChangeFinished(pressedRole, currentWidth);
- break;
- }
-
- case MoveRoleOperation:
- m_movingRole.pixmap = QPixmap();
- m_movingRole.x = 0;
- m_movingRole.xDec = 0;
- m_movingRole.index = -1;
- break;
-
- default:
- break;
- }
+ m_movingRole.pixmap = QPixmap();
+ m_movingRole.x = 0;
+ m_movingRole.xDec = 0;
+ m_movingRole.index = -1;
+ m_pressedGrip = std::nullopt;
m_pressedRoleIndex = -1;
- m_roleOperation = NoRoleOperation;
update();
QApplication::restoreOverrideCursor();
}
-void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
+void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsWidget::mouseMoveEvent(event);
- switch (m_roleOperation) {
- 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.
- m_roleOperation = MoveRoleOperation;
- const int roleIndex = roleIndexAt(m_pressedMousePos);
- m_movingRole.index = roleIndex;
- if (roleIndex == 0) {
- // 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
- // changed if KItemViews are used in a more generic way.
- QApplication::setOverrideCursor(QCursor(Qt::ForbiddenCursor));
- } else {
- m_movingRole.pixmap = createRolePixmap(roleIndex);
-
- qreal roleX = -m_offset;
- for (int i = 0; i < roleIndex; ++i) {
- const QByteArray role = m_columns[i];
- roleX += m_columnWidths.value(role);
- }
+ if (m_pressedGrip) {
+ if (m_pressedGrip->roleToTheLeft == "leftPadding") {
+ qreal currentWidth = m_leftPadding;
+ currentWidth += event->pos().x() - event->lastPos().x();
+ m_leftPadding = qMax(0.0, currentWidth);
- m_movingRole.xDec = event->pos().x() - roleX;
- m_movingRole.x = roleX;
- update();
- }
+ update();
+ Q_EMIT sidePaddingChanged(m_leftPadding, m_rightPadding);
+ return;
}
- break;
- case ResizeRoleOperation: {
- const QByteArray pressedRole = m_columns[m_pressedRoleIndex];
+ if (m_pressedGrip->roleToTheRight == "rightPadding") {
+ qreal currentWidth = m_rightPadding;
+ currentWidth -= event->pos().x() - event->lastPos().x();
+ m_rightPadding = qMax(0.0, currentWidth);
- qreal previousWidth = m_columnWidths.value(pressedRole);
+ update();
+ Q_EMIT sidePaddingChanged(m_leftPadding, m_rightPadding);
+ if (m_rightPadding > 0.0) {
+ return;
+ }
+ // Continue so resizing of the last column beyond the view width is possible.
+ if (currentWidth > -10) {
+ return; // Automatic column resizing is valuable, so we don't want to give it up just for a few pixels of extra width for the rightmost column.
+ }
+ m_automaticColumnResizing = false;
+ }
+
+ qreal previousWidth = m_columnWidths.value(m_pressedGrip->roleToTheLeft);
qreal currentWidth = previousWidth;
currentWidth += event->pos().x() - event->lastPos().x();
currentWidth = qMax(minimumColumnWidth(), currentWidth);
- m_columnWidths.insert(pressedRole, currentWidth);
+ m_columnWidths.insert(m_pressedGrip->roleToTheLeft, currentWidth);
update();
- emit columnWidthChanged(pressedRole, currentWidth, previousWidth);
- break;
+ Q_EMIT columnWidthChanged(m_pressedGrip->roleToTheLeft, currentWidth, previousWidth);
+ return;
}
- case MoveRoleOperation: {
+ if (m_movingRole.index != -1) {
// 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
// changed if KItemViews are used in a more generic way.
- if (m_movingRole.index > 0) {
+ if (m_movingRole.index != nameColumnIndex(this)) {
m_movingRole.x = event->pos().x() - m_movingRole.xDec;
update();
const QByteArray role = m_columns[m_movingRole.index];
const int previousIndex = m_movingRole.index;
m_movingRole.index = targetIndex;
- emit columnMoved(role, targetIndex, previousIndex);
+ if (layoutDirection() == Qt::LeftToRight) {
+ Q_EMIT columnMoved(role, targetIndex, previousIndex);
+ } else {
+ Q_EMIT columnMoved(role, m_columns.count() - 1 - targetIndex, m_columns.count() - 1 - previousIndex);
+ }
m_movingRole.xDec = event->pos().x() - roleXPosition(role);
}
}
- break;
+ return;
}
- default:
- break;
+ 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 further mouse-move-event with the mouse-position.
+ const int roleIndex = roleIndexAt(m_pressedMousePos);
+ m_movingRole.index = roleIndex;
+ if (roleIndex == nameColumnIndex(this)) {
+ // 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
+ // changed if KItemViews are used in a more generic way.
+ QApplication::setOverrideCursor(QCursor(Qt::ForbiddenCursor));
+ return;
+ }
+
+ m_movingRole.pixmap = createRolePixmap(roleIndex);
+
+ qreal roleX = -m_offset + m_leftPadding + unusedSpace();
+ for (int i = 0; i < roleIndex; ++i) {
+ const QByteArray role = m_columns[i];
+ roleX += m_columnWidths.value(role);
+ }
+
+ m_movingRole.xDec = event->pos().x() - roleX;
+ m_movingRole.x = roleX;
+ update();
}
}
-void KItemListHeaderWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
+void KItemListHeaderWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsItem::mouseDoubleClickEvent(event);
- const int roleIndex = roleIndexAt(event->pos());
- if (roleIndex >= 0 && isAboveRoleGrip(event->pos(), roleIndex)) {
- const QByteArray role = m_columns.at(roleIndex);
+ const std::optional<Grip> doubleClickedGrip = isAboveResizeGrip(event->pos());
+ if (!doubleClickedGrip || doubleClickedGrip->roleToTheLeft.isEmpty()) {
+ return;
+ }
- qreal previousWidth = columnWidth(role);
- setColumnWidth(role, preferredColumnWidth(role));
- qreal currentWidth = columnWidth(role);
+ qreal previousWidth = columnWidth(doubleClickedGrip->roleToTheLeft);
+ setColumnWidth(doubleClickedGrip->roleToTheLeft, preferredColumnWidth(doubleClickedGrip->roleToTheLeft));
+ qreal currentWidth = columnWidth(doubleClickedGrip->roleToTheLeft);
- emit columnWidthChanged(role, currentWidth, previousWidth);
- emit columnWidthChangeFinished(role, currentWidth);
- }
+ Q_EMIT columnWidthChanged(doubleClickedGrip->roleToTheLeft, currentWidth, previousWidth);
+ Q_EMIT columnWidthChangeFinished(doubleClickedGrip->roleToTheLeft, currentWidth);
}
-void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
+void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
QGraphicsWidget::hoverEnterEvent(event);
- updateHoveredRoleIndex(event->pos());
+ updateHoveredIndex(event->pos());
}
-void KItemListHeaderWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
+void KItemListHeaderWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
QGraphicsWidget::hoverLeaveEvent(event);
- if (m_hoveredRoleIndex != -1) {
- m_hoveredRoleIndex = -1;
+ if (m_hoveredIndex != -1) {
+ Q_EMIT columnUnHovered(m_hoveredIndex);
+ m_hoveredIndex = -1;
update();
}
}
-void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
+void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
QGraphicsWidget::hoverMoveEvent(event);
- const QPointF& pos = event->pos();
- updateHoveredRoleIndex(pos);
- if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) {
+ const QPointF &pos = event->pos();
+ updateHoveredIndex(pos);
+ if (isAboveResizeGrip(pos)) {
setCursor(Qt::SplitHCursor);
} else {
unsetCursor();
}
}
-void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous)
+void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray ¤t, const QByteArray &previous)
{
Q_UNUSED(current)
Q_UNUSED(previous)
update();
}
-void KItemListHeaderWidget::paintRole(QPainter* painter,
- const QByteArray& role,
- const QRectF& rect,
- int orderIndex,
- QWidget* widget) const
+void KItemListHeaderWidget::paintRole(QPainter *painter, const QByteArray &role, const QRectF &rect, int orderIndex, QWidget *widget) const
{
// The following code is based on the code from QHeaderView::paintSection().
// SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies).
if (window() && window()->isActiveWindow()) {
option.state |= QStyle::State_Active;
}
- if (m_hoveredRoleIndex == orderIndex) {
+ if (m_hoveredIndex == orderIndex) {
option.state |= QStyle::State_MouseOver;
}
if (m_pressedRoleIndex == orderIndex) {
option.state |= QStyle::State_Sunken;
}
if (m_model->sortRole() == role) {
- option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ?
- QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
+ option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ? 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.right(), 0.0, size().width() - rect.right(), 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.right(), 0.0, size().width() - rect.right(), rect.height()), QStyleOptionHeader::End);
} else {
option.position = QStyleOptionHeader::End;
}
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)
+void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF &pos)
{
const int pressedIndex = roleIndexAt(pos);
if (m_pressedRoleIndex != pressedIndex) {
}
}
-void KItemListHeaderWidget::updateHoveredRoleIndex(const QPointF& pos)
+void KItemListHeaderWidget::updateHoveredIndex(const QPointF &pos)
{
- const int hoverIndex = roleIndexAt(pos);
- if (m_hoveredRoleIndex != hoverIndex) {
- m_hoveredRoleIndex = hoverIndex;
+ const int hoverIndex = isAboveResizeGrip(pos) ? -1 : roleIndexAt(pos);
+
+ if (m_hoveredIndex != hoverIndex) {
+ if (m_hoveredIndex != -1) {
+ Q_EMIT columnUnHovered(m_hoveredIndex);
+ }
+ m_hoveredIndex = hoverIndex;
+ if (m_hoveredIndex != -1) {
+ Q_EMIT columnHovered(m_hoveredIndex);
+ }
update();
}
}
-int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const
+int KItemListHeaderWidget::roleIndexAt(const QPointF &pos) const
{
- int index = -1;
+ qreal x = -m_offset + m_leftPadding + unusedSpace();
+ if (pos.x() < x) {
+ return -1;
+ }
- qreal x = -m_offset;
- foreach (const QByteArray& role, m_columns) {
+ int index = -1;
+ for (const QByteArray &role : std::as_const(m_columns)) {
++index;
x += m_columnWidths.value(role);
if (pos.x() <= x) {
- break;
+ return index;
}
}
- return index;
+ return -1;
}
-bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) const
+std::optional<const KItemListHeaderWidget::Grip> KItemListHeaderWidget::isAboveResizeGrip(const QPointF &position) const
{
- qreal x = -m_offset;
- for (int i = 0; i <= roleIndex; ++i) {
+ qreal x = -m_offset + m_leftPadding + unusedSpace();
+ const int gripWidthTolerance = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
+
+ if (x - gripWidthTolerance < position.x() && position.x() < x + gripWidthTolerance) {
+ return std::optional{Grip{"leftPadding", m_columns[0]}};
+ }
+
+ for (int i = 0; i < m_columns.count(); ++i) {
const QByteArray role = m_columns[i];
x += m_columnWidths.value(role);
+ if (x - gripWidthTolerance < position.x() && position.x() < x + gripWidthTolerance) {
+ if (i + 1 < m_columns.count()) {
+ return std::optional{Grip{m_columns[i], m_columns[i + 1]}};
+ }
+ return std::optional{Grip{m_columns[i], "rightPadding"}};
+ }
}
-
- const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin);
- return pos.x() >= (x - grip) && pos.x() <= x;
+ return std::nullopt;
}
QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const
const int movingRight = movingLeft + movingWidth - 1;
int targetIndex = 0;
- qreal targetLeft = -m_offset;
+ qreal targetLeft = -m_offset + m_leftPadding + unusedSpace();
while (targetIndex < m_columns.count()) {
const QByteArray role = m_columns[targetIndex];
const qreal targetWidth = m_columnWidths.value(role);
const qreal targetRight = targetLeft + targetWidth - 1;
- const bool isInTarget = (targetWidth >= movingWidth &&
- movingLeft >= targetLeft &&
- movingRight <= targetRight) ||
- (targetWidth < movingWidth &&
- movingLeft <= targetLeft &&
- movingRight >= targetRight);
+ const bool isInTarget = (targetWidth >= movingWidth && movingLeft >= targetLeft && movingRight <= targetRight)
+ || (targetWidth < movingWidth && movingLeft <= targetLeft && movingRight >= targetRight);
if (isInTarget) {
return targetIndex;
return m_movingRole.index;
}
-qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const
+qreal KItemListHeaderWidget::roleXPosition(const QByteArray &role) const
{
- qreal x = -m_offset;
- foreach (const QByteArray& visibleRole, m_columns) {
+ qreal x = -m_offset + m_leftPadding + unusedSpace();
+ for (const QByteArray &visibleRole : std::as_const(m_columns)) {
if (visibleRole == role) {
return x;
}
return -1;
}
+qreal KItemListHeaderWidget::unusedSpace() const
+{
+ if (layoutDirection() == Qt::LeftToRight) {
+ return 0;
+ }
+ int unusedSpace = size().width() - m_leftPadding - m_rightPadding;
+ for (int i = 0; i < m_columns.count(); ++i) {
+ const QByteArray role = m_columns[i];
+ unusedSpace -= m_columnWidths.value(role);
+ }
+ return qMax(unusedSpace, 0);
+}
+
+#include "moc_kitemlistheaderwidget.cpp"