From 95542a389112491abf3a31c338e7d78f7785f48e Mon Sep 17 00:00:00 2001 From: Felix Ernst Date: Sun, 29 Dec 2024 11:42:22 +0000 Subject: [PATCH] Mirror details view mode for right-to-left languages This commit implements mirroring of the details view mode for right-to- left languages. This is the last of the Dolphin view modes which did not adapt to right-to-left languages correctly. Implementation-wise this is mostly about adapting the math so all the information is placed correctly no matter the view mode or layout direction. While most of the view actually changes the painting code for right-to-left languages, for the column header I decided to keep the logic left-to-right and instead reverse the order of the role columns. To implement this mirroring I needed to rework quite a bit of logic, so I used the opportunity to fix some bugs/behaviur quirks: - Left and right padding is now saved and restored separately instead of only saving the left padding - Changing the right padding no longer disables "automatic column resizing". - The grip handles for column resizing can now be grabbed when near the grip handle instead of only allowing grabbing when slightly to the left of the grip. - Role column headers now only show a hover highlight effect when the mouse cursor is actually above that role and not above the grip handle or the padding. - There is now a soft-boarder when shrinking the right padding so shrinking the padding "below zero width" will no longer immediately clear automatic resize behaviour. So now it is possible to simply remove the right padding by resizing it to zero width. BUG: 449211 BUG: 495942 # Acknowledgement This work is part of a my project funded through the NGI0 Entrust Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology. --- src/kitemviews/kitemlistcontroller.cpp | 42 +-- src/kitemviews/kitemlistheader.cpp | 15 +- src/kitemviews/kitemlistheader.h | 9 +- src/kitemviews/kitemlistview.cpp | 12 +- src/kitemviews/kitemlistwidget.cpp | 41 ++- src/kitemviews/kitemlistwidget.h | 10 +- src/kitemviews/kstandarditemlistwidget.cpp | 73 ++-- src/kitemviews/kstandarditemlistwidget.h | 3 +- .../private/kitemlistheaderwidget.cpp | 326 ++++++++++-------- .../private/kitemlistheaderwidget.h | 37 +- src/settings/dolphin_detailsmodesettings.kcfg | 8 +- src/settings/dolphin_detailsmodesettings.upd | 8 +- src/settings/viewmodes/viewsettingstab.cpp | 13 +- src/views/dolphinview.cpp | 15 +- src/views/dolphinview.h | 2 +- 15 files changed, 361 insertions(+), 253 deletions(-) diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 2ae4a1f25..5a396de61 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -243,6 +243,20 @@ bool KItemListController::keyPressEvent(QKeyEvent *event) const bool horizontalScrolling = m_view->scrollOrientation() == Qt::Horizontal; + if (m_view->layoutDirection() == Qt::RightToLeft) { + // swap left and right arrow keys + switch (key) { + case Qt::Key_Left: + key = Qt::Key_Right; + break; + case Qt::Key_Right: + key = Qt::Key_Left; + break; + default: + break; + } + } + // Handle the expanding/collapsing of items // expand / collapse all selected directories if (m_view->supportsItemExpanding() && m_model->isExpandable(index) && (key == Qt::Key_Right || key == Qt::Key_Left)) { @@ -299,34 +313,6 @@ bool KItemListController::keyPressEvent(QKeyEvent *event) } } - if (m_view->layoutDirection() == Qt::RightToLeft) { - if (horizontalScrolling) { - // swap up and down arrow keys - switch (key) { - case Qt::Key_Up: - key = Qt::Key_Down; - break; - case Qt::Key_Down: - key = Qt::Key_Up; - break; - default: - break; - } - } else if (!m_view->supportsItemExpanding()) { - // swap left and right arrow keys - switch (key) { - case Qt::Key_Left: - key = Qt::Key_Right; - break; - case Qt::Key_Right: - key = Qt::Key_Left; - break; - default: - break; - } - } - } - const bool selectSingleItem = m_selectionBehavior != NoSelection && itemCount == 1 && navigationPressed; if (selectSingleItem) { diff --git a/src/kitemviews/kitemlistheader.cpp b/src/kitemviews/kitemlistheader.cpp index bb3153794..97d0cdfbf 100644 --- a/src/kitemviews/kitemlistheader.cpp +++ b/src/kitemviews/kitemlistheader.cpp @@ -61,10 +61,10 @@ qreal KItemListHeader::preferredColumnWidth(const QByteArray &role) const return m_headerWidget->preferredColumnWidth(role); } -void KItemListHeader::setSidePadding(qreal width) +void KItemListHeader::setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth) { - if (m_headerWidget->sidePadding() != width) { - m_headerWidget->setSidePadding(width); + if (m_headerWidget->leftPadding() != leftPaddingWidth || m_headerWidget->rightPadding() != rightPaddingWidth) { + m_headerWidget->setSidePadding(leftPaddingWidth, rightPaddingWidth); if (m_headerWidget->automaticColumnResizing()) { m_view->applyAutomaticColumnWidths(); } @@ -72,9 +72,14 @@ void KItemListHeader::setSidePadding(qreal width) } } -qreal KItemListHeader::sidePadding() const +qreal KItemListHeader::leftPadding() const { - return m_headerWidget->sidePadding(); + return m_headerWidget->leftPadding(); +} + +qreal KItemListHeader::rightPadding() const +{ + return m_headerWidget->rightPadding(); } KItemListHeader::KItemListHeader(KItemListView *listView) diff --git a/src/kitemviews/kitemlistheader.h b/src/kitemviews/kitemlistheader.h index 04519f12c..d84832dab 100644 --- a/src/kitemviews/kitemlistheader.h +++ b/src/kitemviews/kitemlistheader.h @@ -59,14 +59,15 @@ public: qreal preferredColumnWidth(const QByteArray &role) const; /** - * Sets the width of the column *before* the first column. + * Sets the widths of the columns *before* the first column and *after* the last column. * This is intended to facilitate an empty region for deselection in the main viewport. */ - void setSidePadding(qreal width); - qreal sidePadding() const; + void setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth); + qreal leftPadding() const; + qreal rightPadding() const; Q_SIGNALS: - void sidePaddingChanged(qreal width); + void sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth); /** * Is emitted if the width of a column has been adjusted by the user with the mouse diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 42c5e25c2..369415f1b 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -385,7 +385,7 @@ void KItemListView::setGeometry(const QRectF &rect) if (m_headerWidget->automaticColumnResizing()) { applyAutomaticColumnWidths(); } else { - const qreal requiredWidth = columnWidthsSum() + 2 * m_headerWidget->sidePadding(); + const qreal requiredWidth = m_headerWidget->leftPadding() + columnWidthsSum() + m_headerWidget->rightPadding(); const QSizeF dynamicItemSize(qMax(newSize.width(), requiredWidth), m_itemSize.height()); m_layouter->setItemSize(dynamicItemSize); } @@ -2389,7 +2389,7 @@ QHash KItemListView::preferredColumnWidths(const KItemRangeLi void KItemListView::applyColumnWidthsFromHeader() { // Apply the new size to the layouter - const qreal requiredWidth = columnWidthsSum() + 2 * m_headerWidget->sidePadding(); + const qreal requiredWidth = m_headerWidget->leftPadding() + columnWidthsSum() + m_headerWidget->rightPadding(); const QSizeF dynamicItemSize(qMax(size().width(), requiredWidth), m_itemSize.height()); m_layouter->setItemSize(dynamicItemSize); @@ -2406,7 +2406,7 @@ void KItemListView::updateWidgetColumnWidths(KItemListWidget *widget) for (const QByteArray &role : std::as_const(m_visibleRoles)) { widget->setColumnWidth(role, m_headerWidget->columnWidth(role)); } - widget->setSidePadding(m_headerWidget->sidePadding()); + widget->setSidePadding(m_headerWidget->leftPadding(), m_headerWidget->rightPadding()); } void KItemListView::updatePreferredColumnWidths(const KItemRangeList &itemRanges) @@ -2484,9 +2484,9 @@ void KItemListView::applyAutomaticColumnWidths() qreal firstColumnWidth = m_headerWidget->columnWidth(firstRole); QSizeF dynamicItemSize = m_itemSize; - qreal requiredWidth = columnWidthsSum() + 2 * m_headerWidget->sidePadding(); // Adding the padding a second time so we have the same padding - // symmetrically on both sides of the view. This improves UX, looks better and increases the chances of users figuring out that the padding - // area can be used for deselecting and dropping files. + qreal requiredWidth = m_headerWidget->leftPadding() + columnWidthsSum() + m_headerWidget->rightPadding(); + // By default we want the same padding symmetrically on both sides of the view. This improves UX, looks better and increases the chances of users figuring + // out that the padding area can be used for deselecting and dropping files. const qreal availableWidth = size().width(); if (requiredWidth < availableWidth) { // Stretch the first column to use the whole remaining width diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index 4c9f25986..dac5ac296 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -40,7 +40,8 @@ KItemListWidget::KItemListWidget(KItemListWidgetInformant *informant, QGraphicsI , m_data() , m_visibleRoles() , m_columnWidths() - , m_sidePadding(0) + , m_leftPadding(0) + , m_rightPadding(0) , m_styleOption() , m_siblingsInfo() , m_hoverOpacity(0) @@ -183,18 +184,35 @@ qreal KItemListWidget::columnWidth(const QByteArray &role) const return m_columnWidths.value(role); } -qreal KItemListWidget::sidePadding() const +void KItemListWidget::setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth) { - return m_sidePadding; + bool changed = false; + if (m_leftPadding != leftPaddingWidth) { + m_leftPadding = leftPaddingWidth; + changed = true; + } + + if (m_rightPadding != rightPaddingWidth) { + m_rightPadding = rightPaddingWidth; + changed = true; + } + + if (!changed) { + return; + } + + sidePaddingChanged(leftPaddingWidth, rightPaddingWidth); + update(); } -void KItemListWidget::setSidePadding(qreal width) +qreal KItemListWidget::leftPadding() const { - if (m_sidePadding != width) { - m_sidePadding = width; - sidePaddingChanged(width); - update(); - } + return m_leftPadding; +} + +qreal KItemListWidget::rightPadding() const +{ + return m_rightPadding; } void KItemListWidget::setStyleOption(const KItemListStyleOption &option) @@ -462,9 +480,10 @@ void KItemListWidget::columnWidthChanged(const QByteArray &role, qreal current, Q_UNUSED(previous) } -void KItemListWidget::sidePaddingChanged(qreal width) +void KItemListWidget::sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth) { - Q_UNUSED(width) + Q_UNUSED(leftPaddingWidth) + Q_UNUSED(rightPaddingWidth) } void KItemListWidget::styleOptionChanged(const KItemListStyleOption ¤t, const KItemListStyleOption &previous) diff --git a/src/kitemviews/kitemlistwidget.h b/src/kitemviews/kitemlistwidget.h index fdfe5e78a..e254292c0 100644 --- a/src/kitemviews/kitemlistwidget.h +++ b/src/kitemviews/kitemlistwidget.h @@ -81,8 +81,9 @@ public: void setColumnWidth(const QByteArray &role, qreal width); qreal columnWidth(const QByteArray &role) const; - void setSidePadding(qreal width); - qreal sidePadding() const; + void setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth); + qreal leftPadding() const; + qreal rightPadding() const; void setStyleOption(const KItemListStyleOption &option); const KItemListStyleOption &styleOption() const; @@ -202,7 +203,7 @@ protected: virtual void dataChanged(const QHash ¤t, const QSet &roles = QSet()); virtual void visibleRolesChanged(const QList ¤t, const QList &previous); virtual void columnWidthChanged(const QByteArray &role, qreal current, qreal previous); - virtual void sidePaddingChanged(qreal width); + virtual void sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth); virtual void styleOptionChanged(const KItemListStyleOption ¤t, const KItemListStyleOption &previous); virtual void currentChanged(bool current); virtual void selectedChanged(bool selected); @@ -263,7 +264,8 @@ private: QHash m_data; QList m_visibleRoles; QHash m_columnWidths; - qreal m_sidePadding; + qreal m_leftPadding; + qreal m_rightPadding; KItemListStyleOption m_styleOption; QBitArray m_siblingsInfo; diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index bc7023e12..05628d391 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -409,15 +409,26 @@ void KStandardItemListWidget::paint(QPainter *painter, const QStyleOptionGraphic painter->drawStaticText(textInfo->pos, textInfo->staticText); bool clipAdditionalInfoBounds = false; - if (m_supportsItemExpanding) { - // Prevent a possible overlapping of the additional-information texts - // with the icon. This can happen if the user has minimized the width - // of the name-column to a very small value. - const qreal minX = m_pixmapPos.x() + m_pixmap.width() + 4 * itemListStyleOption.padding; - if (textInfo->pos.x() + columnWidth("text") > minX) { - clipAdditionalInfoBounds = true; - painter->save(); - painter->setClipRect(minX, 0, size().width() - minX, size().height(), Qt::IntersectClip); + if (m_supportsItemExpanding && m_sortedVisibleRoles.count() > 1) { + // Prevent a possible overlapping of the additional-information-texts with the icon. + // This will happen if the user has resized the width of the name-column to be very narrow while having folders expanded. + // We only want to draw additional info text outside the area of the icon or expansion area, so we set a clip rect that does not contain the icon area. + // This needs to work both for left-to-right as well as right-to-left layout directions. + const TextInfo *potentiallyOverlappingRoleText = m_textInfo.value(m_sortedVisibleRoles[1]); // Only the first column after the name column can overlap. + if (layoutDirection() == Qt::LeftToRight) { // In left-to-right languages the left end of text would overlap. This is mirrored for right-to-left. + const qreal minX = m_iconRect.right() + 2 * itemListStyleOption.padding; + if (potentiallyOverlappingRoleText->pos.x() < minX) { + clipAdditionalInfoBounds = true; + painter->save(); + painter->setClipRect(minX, 0, size().width() - minX, size().height(), Qt::IntersectClip); + } + } else { + const qreal maxX = m_iconRect.left() - 2 * itemListStyleOption.padding; + if (potentiallyOverlappingRoleText->pos.x() + m_customizedFontMetrics.horizontalAdvance(potentiallyOverlappingRoleText->staticText.text()) > maxX) { + clipAdditionalInfoBounds = true; + painter->save(); + painter->setClipRect(0, 0, maxX, size().height(), Qt::IntersectClip); + } } } @@ -524,7 +535,11 @@ QRectF KStandardItemListWidget::selectionRect() const QRectF adjustedIconRect = iconRect().adjusted(-padding, -padding, padding, padding); QRectF result = adjustedIconRect | m_textRect; if (m_highlightEntireRow) { - result.setRight(m_columnWidthSum + sidePadding()); + if (layoutDirection() == Qt::LeftToRight) { + result.setRight(leftPadding() + m_columnWidthSum); + } else { + result.setLeft(size().width() - m_columnWidthSum - rightPadding()); + } } return result; } @@ -786,9 +801,10 @@ void KStandardItemListWidget::columnWidthChanged(const QByteArray &role, qreal c m_dirtyLayout = true; } -void KStandardItemListWidget::sidePaddingChanged(qreal padding) +void KStandardItemListWidget::sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth) { - Q_UNUSED(padding) + Q_UNUSED(leftPaddingWidth) + Q_UNUSED(rightPaddingWidth) m_dirtyLayout = true; } @@ -1012,8 +1028,13 @@ void KStandardItemListWidget::updateExpansionArea() const qreal inc = (widgetHeight - widgetIconSize) / 2; const qreal x = expandedParentsCount * widgetHeight + inc; const qreal y = inc; - const qreal xPadding = m_highlightEntireRow ? sidePadding() : 0; - m_expansionArea = QRectF(xPadding + x, y, widgetIconSize, widgetIconSize); + if (layoutDirection() == Qt::LeftToRight) { + const qreal leftPaddingWidth = m_highlightEntireRow ? leftPadding() : 0; + m_expansionArea = QRectF(leftPaddingWidth + x, y, widgetIconSize, widgetIconSize); + return; + } + const qreal rightPaddingWidth = m_highlightEntireRow ? rightPadding() : 0; + m_expansionArea = QRectF(size().width() - rightPaddingWidth - x - widgetIconSize, y, widgetIconSize, widgetIconSize); return; } } @@ -1155,8 +1176,8 @@ void KStandardItemListWidget::updatePixmapCache() } else { // Center horizontally and vertically within the icon-area const TextInfo *textInfo = m_textInfo.value("text"); - if (QApplication::isRightToLeft() && m_layout == CompactLayout) { - m_pixmapPos.setX(size().width() - padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0); + if (QApplication::isRightToLeft()) { + m_pixmapPos.setX(m_textRect.right() + 2.0 * padding); } else { m_pixmapPos.setX(textInfo->pos.x() - 2.0 * padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0); } @@ -1464,6 +1485,8 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache() // +------+ // | Icon | Name role Additional role 1 Additional role 2 // +------+ + // Mirror the above for right-to-left languages. + const bool isLeftToRight = QApplication::layoutDirection() == Qt::LeftToRight; m_textRect = QRectF(); const KItemListStyleOption &option = styleOption(); @@ -1475,9 +1498,10 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache() const qreal columnWidthInc = columnPadding(option); qreal firstColumnInc = iconSize(); if (m_supportsItemExpanding) { - firstColumnInc += (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2; + firstColumnInc += isLeftToRight ? (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2 + : ((size().width() - m_expansionArea.left()) + (size().width() - m_expansionArea.right()) + widgetHeight) / 2; } else { - firstColumnInc += option.padding + sidePadding(); + firstColumnInc += option.padding + (isLeftToRight ? leftPadding() : rightPadding()); } qreal x = firstColumnInc; @@ -1494,7 +1518,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache() const bool isTextRole = (role == "text"); if (isTextRole) { text = escapeString(text); - availableTextWidth -= firstColumnInc - sidePadding(); + availableTextWidth -= firstColumnInc - (isLeftToRight ? leftPadding() : rightPadding()); } if (requiredWidth > availableTextWidth) { @@ -1504,17 +1528,16 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache() TextInfo *textInfo = m_textInfo.value(role); textInfo->staticText.setText(text); - textInfo->pos = QPointF(x + columnWidthInc / 2, y); + textInfo->pos = QPointF(isLeftToRight ? (x + columnWidthInc / 2) : (size().width() - (x + columnWidthInc / 2) - requiredWidth), y); x += roleWidth; if (isTextRole) { - const qreal textWidth = option.extendedSelectionRegion ? size().width() - textInfo->pos.x() : requiredWidth + 2 * option.padding; - m_textRect = QRectF(textInfo->pos.x() - option.padding, 0, textWidth, size().height()); + m_textRect = QRectF(textInfo->pos.x() - option.padding, 0, requiredWidth + 2 * option.padding, size().height()); // The column after the name should always be aligned on the same x-position independent // from the expansion-level shown in the name column - x -= firstColumnInc - sidePadding(); - } else if (isRoleRightAligned(role)) { + x -= firstColumnInc - (isLeftToRight ? leftPadding() : rightPadding()); + } else if (isRoleRightAligned(role) && isLeftToRight) { textInfo->pos.rx() += roleWidth - requiredWidth - columnWidthInc; } } @@ -1594,7 +1617,7 @@ void KStandardItemListWidget::drawSiblingsInformation(QPainter *painter) style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter); - siblingRect.translate(-siblingRect.width(), 0); + siblingRect.translate(layoutDirection() == Qt::LeftToRight ? -siblingRect.width() : siblingRect.width(), 0); } } diff --git a/src/kitemviews/kstandarditemlistwidget.h b/src/kitemviews/kstandarditemlistwidget.h index 588ec3548..7ff97a126 100644 --- a/src/kitemviews/kstandarditemlistwidget.h +++ b/src/kitemviews/kstandarditemlistwidget.h @@ -176,7 +176,7 @@ protected: void dataChanged(const QHash ¤t, const QSet &roles = QSet()) override; void visibleRolesChanged(const QList ¤t, const QList &previous) override; void columnWidthChanged(const QByteArray &role, qreal current, qreal previous) override; - void sidePaddingChanged(qreal width) override; + void sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth) override; void styleOptionChanged(const KItemListStyleOption ¤t, const KItemListStyleOption &previous) override; void hoveredChanged(bool hovered) override; void selectedChanged(bool selected) override; @@ -213,6 +213,7 @@ private: void updateDetailsLayoutTextCache(); void drawPixmap(QPainter *painter, const QPixmap &pixmap); + /** Draw the lines and arrows that visualize the expanded state and level of this row. */ void drawSiblingsInformation(QPainter *painter); QRectF roleEditingRect(const QByteArray &role) const; diff --git a/src/kitemviews/private/kitemlistheaderwidget.cpp b/src/kitemviews/private/kitemlistheaderwidget.cpp index 02a4f939d..3dc82ad6b 100644 --- a/src/kitemviews/private/kitemlistheaderwidget.cpp +++ b/src/kitemviews/private/kitemlistheaderwidget.cpp @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2011 Peter Penz + * SPDX-FileCopyrightText: 2022, 2024 Felix Ernst * * SPDX-License-Identifier: GPL-2.0-or-later */ @@ -12,18 +13,44 @@ #include #include +namespace +{ +/** + * @returns a list which has a reversed order of elements compared to @a list. + */ +QList reversed(const QList list) +{ + QList reversedList; + for (auto i = list.rbegin(); i != list.rend(); i++) { + reversedList.emplaceBack(*i); + } + return reversedList; +}; + +/** + * @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_sidePadding(0) + , m_leftPadding(0) + , m_rightPadding(0) , m_columns() , m_columnWidths() , m_preferredColumnWidths() , m_hoveredIndex(-1) , m_pressedRoleIndex(-1) - , m_roleOperation(NoRoleOperation) , m_pressedMousePos() , m_movingRole() { @@ -82,13 +109,13 @@ void KItemListHeaderWidget::setColumns(const QList &roles) } } - m_columns = roles; + m_columns = layoutDirection() == Qt::LeftToRight ? roles : reversed(roles); update(); } QList KItemListHeaderWidget::columns() const { - return m_columns; + return layoutDirection() == Qt::LeftToRight ? m_columns : reversed(m_columns); } void KItemListHeaderWidget::setColumnWidth(const QByteArray &role, qreal width) @@ -132,18 +159,35 @@ qreal KItemListHeaderWidget::offset() const return m_offset; } -void KItemListHeaderWidget::setSidePadding(qreal width) +void KItemListHeaderWidget::setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth) { - if (m_sidePadding != width) { - m_sidePadding = width; - Q_EMIT sidePaddingChanged(width); - update(); + 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::sidePadding() const +qreal KItemListHeaderWidget::rightPadding() const { - return m_sidePadding; + return m_rightPadding; } qreal KItemListHeaderWidget::minimumColumnWidth() const @@ -165,7 +209,7 @@ void KItemListHeaderWidget::paint(QPainter *painter, const QStyleOptionGraphicsI painter->setFont(font()); painter->setPen(palette().text().color()); - qreal x = -m_offset + m_sidePadding; + qreal x = -m_offset + m_leftPadding + unusedSpace(); int orderIndex = 0; for (const QByteArray &role : std::as_const(m_columns)) { const qreal roleWidth = m_columnWidths.value(role); @@ -176,7 +220,6 @@ void KItemListHeaderWidget::paint(QPainter *painter, const QStyleOptionGraphicsI } if (!m_movingRole.pixmap.isNull()) { - Q_ASSERT(m_roleOperation == MoveRoleOperation); painter->drawPixmap(m_movingRole.x, 0, m_movingRole.pixmap); } } @@ -185,11 +228,9 @@ void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() & Qt::LeftButton) { m_pressedMousePos = event->pos(); - if (isAbovePaddingGrip(m_pressedMousePos, PaddingGrip::Leading)) { - m_roleOperation = ResizePaddingColumnOperation; - } else { + m_pressedGrip = isAboveResizeGrip(m_pressedMousePos); + if (!m_pressedGrip) { updatePressedRoleIndex(event->pos()); - m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ? ResizeRoleOperation : NoRoleOperation; } event->accept(); } else { @@ -201,12 +242,15 @@ 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); @@ -229,29 +273,15 @@ void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) Q_EMIT sortOrderChanged(Qt::AscendingOrder, Qt::DescendingOrder); } } - break; } - case ResizeRoleOperation: { - const QByteArray pressedRole = m_columns[m_pressedRoleIndex]; - const qreal currentWidth = m_columnWidths.value(pressedRole); - Q_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(); @@ -261,69 +291,51 @@ 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 further 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 + m_sidePadding; - 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); + + 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(pressedRole); + 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); - update(); - - Q_EMIT columnWidthChanged(pressedRole, currentWidth, previousWidth); - break; - } - - case ResizePaddingColumnOperation: { - qreal currentWidth = m_sidePadding; - currentWidth += event->pos().x() - event->lastPos().x(); - currentWidth = qMax(0.0, currentWidth); - - m_sidePadding = currentWidth; - + m_columnWidths.insert(m_pressedGrip->roleToTheLeft, currentWidth); update(); - Q_EMIT sidePaddingChanged(currentWidth); - - 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(); @@ -332,16 +344,42 @@ void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event) const QByteArray role = m_columns[m_movingRole.index]; const int previousIndex = m_movingRole.index; m_movingRole.index = targetIndex; - Q_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(); } } @@ -349,17 +387,17 @@ void KItemListHeaderWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even { 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 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); - Q_EMIT columnWidthChanged(role, currentWidth, previousWidth); - Q_EMIT columnWidthChangeFinished(role, currentWidth); - } + Q_EMIT columnWidthChanged(doubleClickedGrip->roleToTheLeft, currentWidth, previousWidth); + Q_EMIT columnWidthChangeFinished(doubleClickedGrip->roleToTheLeft, currentWidth); } void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) @@ -384,8 +422,7 @@ void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event) const QPointF &pos = event->pos(); updateHoveredIndex(pos); - if ((m_hoveredIndex >= 0 && isAboveRoleGrip(pos, m_hoveredIndex)) || isAbovePaddingGrip(pos, PaddingGrip::Leading) - || isAbovePaddingGrip(pos, PaddingGrip::Trailing)) { + if (isAboveResizeGrip(pos)) { setCursor(Qt::SplitHCursor); } else { unsetCursor(); @@ -408,14 +445,9 @@ void KItemListHeaderWidget::slotSortOrderChanged(Qt::SortOrder current, Qt::Sort void KItemListHeaderWidget::paintRole(QPainter *painter, const QByteArray &role, const QRectF &rect, int orderIndex, QWidget *widget) const { - const auto direction = widget ? widget->layoutDirection() : qApp->layoutDirection(); - // The following code is based on the code from QHeaderView::paintSection(). // SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies). QStyleOptionHeader option; - option.direction = direction; - option.textAlignment = direction == Qt::LeftToRight ? Qt::AlignLeft : Qt::AlignRight; - option.section = orderIndex; option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal; if (isEnabled()) { @@ -453,7 +485,7 @@ void KItemListHeaderWidget::paintRole(QPainter *painter, const QByteArray &role, if (m_columns.count() == 1) { 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); + paintPadding(1, QRectF(rect.right(), 0.0, size().width() - rect.right(), rect.height()), QStyleOptionHeader::End); } else if (orderIndex == 0) { // 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) { @@ -466,7 +498,7 @@ void KItemListHeaderWidget::paintRole(QPainter *painter, const QByteArray &role, // 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; - paintPadding(m_columns.count(), QRectF(rect.left(), 0.0, size().width() - rect.left(), rect.height()), QStyleOptionHeader::End); + paintPadding(m_columns.count(), QRectF(rect.right(), 0.0, size().width() - rect.right(), rect.height()), QStyleOptionHeader::End); } else { option.position = QStyleOptionHeader::End; } @@ -488,7 +520,7 @@ void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF &pos) void KItemListHeaderWidget::updateHoveredIndex(const QPointF &pos) { - const int hoverIndex = roleIndexAt(pos); + const int hoverIndex = isAboveResizeGrip(pos) ? -1 : roleIndexAt(pos); if (m_hoveredIndex != hoverIndex) { if (m_hoveredIndex != -1) { @@ -504,50 +536,43 @@ void KItemListHeaderWidget::updateHoveredIndex(const QPointF &pos) 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 + m_sidePadding; + 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 KItemListHeaderWidget::isAboveResizeGrip(const QPointF &position) const { - qreal x = -m_offset + m_sidePadding; - for (int i = 0; i <= roleIndex; ++i) { - const QByteArray role = m_columns[i]; - x += m_columnWidths.value(role); - } - - const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin); - return pos.x() >= (x - grip) && pos.x() <= x; -} + qreal x = -m_offset + m_leftPadding + unusedSpace(); + const int gripWidthTolerance = style()->pixelMetric(QStyle::PM_HeaderGripMargin); -bool KItemListHeaderWidget::isAbovePaddingGrip(const QPointF &pos, PaddingGrip paddingGrip) const -{ - const qreal lx = -m_offset + m_sidePadding; - const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin); + if (x - gripWidthTolerance < position.x() && position.x() < x + gripWidthTolerance) { + return std::optional{Grip{"leftPadding", m_columns[0]}}; + } - switch (paddingGrip) { - case Leading: - return pos.x() >= (lx - grip) && pos.x() <= lx; - case Trailing: { - qreal rx = lx; - for (const QByteArray &role : std::as_const(m_columns)) { - rx += m_columnWidths.value(role); + 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"}}; } - return pos.x() >= (rx - grip) && pos.x() <= rx; - } - default: - return false; } + return std::nullopt; } QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const @@ -581,7 +606,7 @@ int KItemListHeaderWidget::targetOfMovingRole() const const int movingRight = movingLeft + movingWidth - 1; int targetIndex = 0; - qreal targetLeft = -m_offset + m_sidePadding; + 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); @@ -603,7 +628,7 @@ int KItemListHeaderWidget::targetOfMovingRole() const qreal KItemListHeaderWidget::roleXPosition(const QByteArray &role) const { - qreal x = -m_offset + m_sidePadding; + qreal x = -m_offset + m_leftPadding + unusedSpace(); for (const QByteArray &visibleRole : std::as_const(m_columns)) { if (visibleRole == role) { return x; @@ -615,4 +640,17 @@ qreal KItemListHeaderWidget::roleXPosition(const QByteArray &role) const 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" diff --git a/src/kitemviews/private/kitemlistheaderwidget.h b/src/kitemviews/private/kitemlistheaderwidget.h index a522fa3a2..42dfda503 100644 --- a/src/kitemviews/private/kitemlistheaderwidget.h +++ b/src/kitemviews/private/kitemlistheaderwidget.h @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2011 Peter Penz + * SPDX-FileCopyrightText: 2022, 2024 Felix Ernst * * SPDX-License-Identifier: GPL-2.0-or-later */ @@ -50,8 +51,9 @@ public: void setOffset(qreal offset); qreal offset() const; - void setSidePadding(qreal width); - qreal sidePadding() const; + void setSidePadding(qreal leftPaddingWidth, qreal rightPaddingWidth); + qreal leftPadding() const; + qreal rightPadding() const; qreal minimumColumnWidth() const; @@ -64,7 +66,7 @@ Q_SIGNALS: */ void columnWidthChanged(const QByteArray &role, qreal currentWidth, qreal previousWidth); - void sidePaddingChanged(qreal width); + void sidePaddingChanged(qreal leftPaddingWidth, qreal rightPaddingWidth); /** * Is emitted if the user has released the mouse button after adjusting the @@ -110,9 +112,9 @@ private Q_SLOTS: void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); private: - enum PaddingGrip { - Leading, - Trailing, + struct Grip { + QByteArray roleToTheLeft; + QByteArray roleToTheRight; }; void paintRole(QPainter *painter, const QByteArray &role, const QRectF &rect, int orderIndex, QWidget *widget = nullptr) const; @@ -120,8 +122,13 @@ private: void updatePressedRoleIndex(const QPointF &pos); void updateHoveredIndex(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; + + /** + * @returns std::nullopt if none of the resize grips is below @p position. + * Otherwise returns a Grip defined by the two roles on each side of @p position. + * @note If the Grip is between a padding and a role, a class-specific "leftPadding" or "rightPadding" role is used. + */ + std::optional isAboveResizeGrip(const QPointF &position) const; /** * Creates a pixmap of the role with the index \a roleIndex that is shown @@ -140,20 +147,26 @@ private: */ qreal roleXPosition(const QByteArray &role) const; -private: - enum RoleOperation { NoRoleOperation, ResizeRoleOperation, ResizePaddingColumnOperation, MoveRoleOperation }; + /** + * @returns 0 for left-to-right layoutDirection(). + * Otherwise returns the space that is left over when space is distributed between padding and role columns. + * Used to make the column headers stay above their information columns for right-to-left layout directions. + */ + qreal unusedSpace() const; +private: bool m_automaticColumnResizing; KItemModelBase *m_model; qreal m_offset; - qreal m_sidePadding; + qreal m_leftPadding; + qreal m_rightPadding; QList m_columns; QHash m_columnWidths; QHash m_preferredColumnWidths; int m_hoveredIndex; + std::optional m_pressedGrip; int m_pressedRoleIndex; - RoleOperation m_roleOperation; QPointF m_pressedMousePos; struct MovingRole { diff --git a/src/settings/dolphin_detailsmodesettings.kcfg b/src/settings/dolphin_detailsmodesettings.kcfg index 98fe0efff..52d85fa12 100644 --- a/src/settings/dolphin_detailsmodesettings.kcfg +++ b/src/settings/dolphin_detailsmodesettings.kcfg @@ -27,8 +27,12 @@ 0,1,2,3,4,5,6,7,8 - - + + + 20 + + + 20 diff --git a/src/settings/dolphin_detailsmodesettings.upd b/src/settings/dolphin_detailsmodesettings.upd index da8f4b9cd..f9def96b6 100644 --- a/src/settings/dolphin_detailsmodesettings.upd +++ b/src/settings/dolphin_detailsmodesettings.upd @@ -1,5 +1,5 @@ #Configuration update for Dolphin -Version=5 +Version=6 #Rename LeadingPadding to SidePadding Id=rename-leading-padding @@ -7,6 +7,12 @@ File=dolphinrc Group=DetailsMode Key=LeadingPadding,SidePadding +#Rename SidePadding to LeftPadding +Id=rename-side-padding +File=dolphinrc +Group=DetailsMode +Key=SidePadding,LeftPadding + #Rename Move content-display from detailsMode Id=move-content-display File=dolphinrc diff --git a/src/settings/viewmodes/viewsettingstab.cpp b/src/settings/viewmodes/viewsettingstab.cpp index 5aca58ba1..fc9e94131 100644 --- a/src/settings/viewmodes/viewsettingstab.cpp +++ b/src/settings/viewmodes/viewsettingstab.cpp @@ -154,15 +154,20 @@ void ViewSettingsTab::applySettings() // So here the default padding is enabled when the full row highlight is enabled. if (m_entireRow->isChecked() && !detailsModeSettings->highlightEntireRow()) { const bool usedDefaults = detailsModeSettings->useDefaults(true); - const uint defaultSidePadding = detailsModeSettings->sidePadding(); + const uint defaultLeftPadding = detailsModeSettings->leftPadding(); + const uint defaultRightPadding = detailsModeSettings->rightPadding(); detailsModeSettings->useDefaults(usedDefaults); - if (detailsModeSettings->sidePadding() < defaultSidePadding) { - detailsModeSettings->setSidePadding(defaultSidePadding); + if (detailsModeSettings->leftPadding() < defaultLeftPadding) { + detailsModeSettings->setLeftPadding(defaultLeftPadding); + } + if (detailsModeSettings->rightPadding() < defaultRightPadding) { + detailsModeSettings->setRightPadding(defaultRightPadding); } } else if (!m_entireRow->isChecked() && detailsModeSettings->highlightEntireRow()) { // The full row click target is disabled so now most of the view area can be used to interact // with the view background. Having an extra side padding has no usability benefit in this case. - detailsModeSettings->setSidePadding(0); + detailsModeSettings->setLeftPadding(0); + detailsModeSettings->setRightPadding(0); } detailsModeSettings->setHighlightEntireRow(m_entireRow->isChecked()); detailsModeSettings->setExpandableFolders(m_expandableFolders->isChecked()); diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 8302620e4..a18f53769 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -1239,7 +1239,7 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF &pos) QAction *toggleSidePaddingAction = menu->addAction(i18nc("@action:inmenu", "Side Padding")); toggleSidePaddingAction->setCheckable(true); - toggleSidePaddingAction->setChecked(view->header()->sidePadding() > 0); + toggleSidePaddingAction->setChecked(layoutDirection() == Qt::LeftToRight ? view->header()->leftPadding() > 0 : view->header()->rightPadding() > 0); QAction *autoAdjustWidthsAction = menu->addAction(i18nc("@action:inmenu", "Automatic Column Widths")); autoAdjustWidthsAction->setCheckable(true); @@ -1272,7 +1272,11 @@ void DolphinView::slotHeaderContextMenuRequested(const QPointF &pos) props.setHeaderColumnWidths(columnWidths); header->setAutomaticColumnResizing(false); } else if (action == toggleSidePaddingAction) { - header->setSidePadding(toggleSidePaddingAction->isChecked() ? 20 : 0); + if (toggleSidePaddingAction->isChecked()) { + header->setSidePadding(20, 20); + } else { + header->setSidePadding(0, 0); + } } else { // Show or hide the selected role const QByteArray selectedRole = action->data().toByteArray(); @@ -1325,10 +1329,11 @@ void DolphinView::slotHeaderColumnWidthChangeFinished(const QByteArray &role, qr props.setHeaderColumnWidths(columnWidths); } -void DolphinView::slotSidePaddingWidthChanged(qreal width) +void DolphinView::slotSidePaddingWidthChanged(qreal leftPaddingWidth, qreal rightPaddingWidth) { ViewProperties props(viewPropertiesUrl()); - DetailsModeSettings::setSidePadding(int(width)); + DetailsModeSettings::setLeftPadding(int(leftPaddingWidth)); + DetailsModeSettings::setRightPadding(int(rightPaddingWidth)); m_view->writeSettings(); } @@ -2184,7 +2189,7 @@ void DolphinView::applyViewProperties(const ViewProperties &props) } else { header->setAutomaticColumnResizing(true); } - header->setSidePadding(DetailsModeSettings::sidePadding()); + header->setSidePadding(DetailsModeSettings::leftPadding(), DetailsModeSettings::rightPadding()); } m_view->endTransaction(); diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index e78a9ca9d..d1667334e 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -692,7 +692,7 @@ private Q_SLOTS: void slotViewContextMenuRequested(const QPointF &pos); void slotHeaderContextMenuRequested(const QPointF &pos); void slotHeaderColumnWidthChangeFinished(const QByteArray &role, qreal current); - void slotSidePaddingWidthChanged(qreal width); + void slotSidePaddingWidthChanged(qreal leftPaddingWidth, qreal rightPaddingWidth); void slotItemHovered(int index); void slotItemUnhovered(int index); void slotItemDropEvent(int index, QGraphicsSceneDragDropEvent *event); -- 2.47.3