1
0
mirror of https://invent.kde.org/system/dolphin synced 2024-07-02 16:31:23 +00:00

Better support for RTL

This MR fixes some issues related to RTL scripts:
- wrong layout in Compact View mode
- broken horizontal scrolling in Icon View and Details View modes
- broken navigation with left and right arrow keys in Details View mode

BUG: 484012  
BUG: 449493
This commit is contained in:
Eugene Popov 2024-03-27 10:28:15 +00:00 committed by Méven Car
parent 7a7cab61b6
commit 240d33ce17
6 changed files with 79 additions and 37 deletions

View File

@ -399,6 +399,11 @@ void KItemListContainer::updateSmoothScrollers(Qt::Orientation orientation)
m_horizontalSmoothScroller->setPropertyName("scrollOffset");
m_verticalSmoothScroller->setPropertyName("itemOffset");
}
const bool isRightToLeft = m_controller->view()->layoutDirection() == Qt::RightToLeft;
QScrollBar *hScrollBar = horizontalScrollBar();
hScrollBar->setInvertedAppearance(isRightToLeft && orientation == Qt::Vertical);
hScrollBar->setInvertedControls(!isRightToLeft || orientation == Qt::Vertical);
}
void KItemListContainer::updateScrollOffsetScrollBarPolicy()

View File

@ -241,6 +241,8 @@ bool KItemListController::keyPressEvent(QKeyEvent *event)
int key = event->key();
const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
const bool horizontalScrolling = m_view->scrollOrientation() == Qt::Horizontal;
// 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)) {
@ -276,7 +278,7 @@ bool KItemListController::keyPressEvent(QKeyEvent *event)
// For horizontal scroll orientation, transform
// the arrow keys to simplify the event handling.
if (m_view->scrollOrientation() == Qt::Horizontal) {
if (horizontalScrolling) {
switch (key) {
case Qt::Key_Up:
key = Qt::Key_Left;
@ -295,17 +297,31 @@ bool KItemListController::keyPressEvent(QKeyEvent *event)
}
}
// For right to left languages, exchange right and left arrow keys.
if (m_view->layoutDirection() == Qt::RightToLeft) {
switch (key) {
case Qt::Key_Left:
key = Qt::Key_Right;
break;
case Qt::Key_Right:
key = Qt::Key_Left;
break;
default:
break;
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;
}
}
}
@ -371,7 +387,7 @@ bool KItemListController::keyPressEvent(QKeyEvent *event)
break;
case Qt::Key_PageUp:
if (m_view->scrollOrientation() == Qt::Horizontal) {
if (horizontalScrolling) {
// The new current index should correspond to the first item in the current column.
int newIndex = qMax(index - 1, 0);
while (newIndex != index && m_view->itemRect(newIndex).topLeft().y() < m_view->itemRect(index).topLeft().y()) {
@ -399,7 +415,7 @@ bool KItemListController::keyPressEvent(QKeyEvent *event)
break;
case Qt::Key_PageDown:
if (m_view->scrollOrientation() == Qt::Horizontal) {
if (horizontalScrolling) {
// The new current index should correspond to the last item in the current column.
int newIndex = qMin(index + 1, m_model->count() - 1);
while (newIndex != index && m_view->itemRect(newIndex).topLeft().y() > m_view->itemRect(index).topLeft().y()) {
@ -1486,12 +1502,12 @@ int KItemListController::nextRowIndex(int index) const
return index;
}
const bool leftToRight = m_view->layoutDirection() != Qt::RightToLeft;
const bool reversed = m_view->layoutDirection() == Qt::RightToLeft && m_view->scrollOrientation() == Qt::Vertical;
// Calculate the index of the last column inside the row of the current index
int lastColumnIndex = index;
while ((leftToRight && keyboardAnchorPos(lastColumnIndex + 1) > keyboardAnchorPos(lastColumnIndex))
|| (!leftToRight && keyboardAnchorPos(lastColumnIndex + 1) < keyboardAnchorPos(lastColumnIndex))) {
while ((!reversed && keyboardAnchorPos(lastColumnIndex + 1) > keyboardAnchorPos(lastColumnIndex))
|| (reversed && keyboardAnchorPos(lastColumnIndex + 1) < keyboardAnchorPos(lastColumnIndex))) {
++lastColumnIndex;
if (lastColumnIndex >= maxIndex) {
return index;
@ -1504,8 +1520,8 @@ int KItemListController::nextRowIndex(int index) const
int searchIndex = nextRowIndex;
qreal minDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(nextRowIndex));
while (searchIndex < maxIndex
&& ((leftToRight && keyboardAnchorPos(searchIndex + 1) > keyboardAnchorPos(searchIndex))
|| (!leftToRight && keyboardAnchorPos(searchIndex + 1) < keyboardAnchorPos(searchIndex)))) {
&& ((!reversed && keyboardAnchorPos(searchIndex + 1) > keyboardAnchorPos(searchIndex))
|| (reversed && keyboardAnchorPos(searchIndex + 1) < keyboardAnchorPos(searchIndex)))) {
++searchIndex;
const qreal searchDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(searchIndex));
if (searchDiff < minDiff) {
@ -1523,12 +1539,12 @@ int KItemListController::previousRowIndex(int index) const
return index;
}
const bool leftToRight = m_view->layoutDirection() != Qt::RightToLeft;
const bool reversed = m_view->layoutDirection() == Qt::RightToLeft && m_view->scrollOrientation() == Qt::Vertical;
// Calculate the index of the first column inside the row of the current index
int firstColumnIndex = index;
while ((leftToRight && keyboardAnchorPos(firstColumnIndex - 1) < keyboardAnchorPos(firstColumnIndex))
|| (!leftToRight && keyboardAnchorPos(firstColumnIndex - 1) > keyboardAnchorPos(firstColumnIndex))) {
while ((!reversed && keyboardAnchorPos(firstColumnIndex - 1) < keyboardAnchorPos(firstColumnIndex))
|| (reversed && keyboardAnchorPos(firstColumnIndex - 1) > keyboardAnchorPos(firstColumnIndex))) {
--firstColumnIndex;
if (firstColumnIndex <= 0) {
return index;
@ -1541,8 +1557,8 @@ int KItemListController::previousRowIndex(int index) const
int searchIndex = previousRowIndex;
qreal minDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(previousRowIndex));
while (searchIndex > 0
&& ((leftToRight && keyboardAnchorPos(searchIndex - 1) < keyboardAnchorPos(searchIndex))
|| (!leftToRight && keyboardAnchorPos(searchIndex - 1) > keyboardAnchorPos(searchIndex)))) {
&& ((!reversed && keyboardAnchorPos(searchIndex - 1) < keyboardAnchorPos(searchIndex))
|| (reversed && keyboardAnchorPos(searchIndex - 1) > keyboardAnchorPos(searchIndex)))) {
--searchIndex;
const qreal searchDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(searchIndex));
if (searchDiff < minDiff) {

View File

@ -550,6 +550,10 @@ void KItemListView::scrollToItem(int index, ViewItemPosition viewItemPosition)
}
QRectF currentRect = itemRect(index);
if (layoutDirection() == Qt::RightToLeft && scrollOrientation() == Qt::Horizontal) {
currentRect.moveTo(m_layouter->size().width() - currentRect.right(), 0);
}
// Fix for Bug 311099 - View the underscore when using Ctrl + PageDown
currentRect.adjust(-m_styleOption.horizontalMargin, -m_styleOption.verticalMargin, m_styleOption.horizontalMargin, m_styleOption.verticalMargin);

View File

@ -1132,7 +1132,11 @@ void KStandardItemListWidget::updatePixmapCache()
} else {
// Center horizontally and vertically within the icon-area
const TextInfo *textInfo = m_textInfo.value("text");
m_pixmapPos.setX(textInfo->pos.x() - 2.0 * padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0);
if (QApplication::isRightToLeft() && m_layout == CompactLayout) {
m_pixmapPos.setX(size().width() - padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0);
} else {
m_pixmapPos.setX(textInfo->pos.x() - 2.0 * padding - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0);
}
// Derive icon's vertical center from the center of the text frame, including
// any necessary adjustment if the font's midline is offset from the frame center
@ -1175,6 +1179,9 @@ void KStandardItemListWidget::updateTextsCache()
textOption.setAlignment(Qt::AlignHCenter);
break;
case CompactLayout:
textOption.setAlignment(QApplication::isRightToLeft() ? Qt::AlignRight : Qt::AlignLeft);
textOption.setWrapMode(QTextOption::NoWrap);
break;
case DetailsLayout:
textOption.setAlignment(Qt::AlignLeft);
textOption.setWrapMode(QTextOption::NoWrap);
@ -1404,9 +1411,9 @@ void KStandardItemListWidget::updateCompactLayoutTextCache()
const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * lineSpacing;
qreal maximumRequiredTextWidth = 0;
const qreal x = option.padding * 3 + iconSize();
const qreal x = QApplication::isRightToLeft() ? option.padding : option.padding * 3 + iconSize();
qreal y = qRound((widgetHeight - textLinesHeight) / 2);
const qreal maxWidth = size().width() - x - option.padding;
const qreal maxWidth = size().width() - iconSize() - 4 * option.padding;
for (const QByteArray &role : std::as_const(m_sortedVisibleRoles)) {
const QString text = escapeString(roleText(role, values));
TextInfo *textInfo = m_textInfo.value(role);

View File

@ -226,8 +226,12 @@ QRectF KItemListViewLayouter::itemRect(int index) const
// Rotate the logical direction which is always vertical by 90°
// to get the physical horizontal direction
QPointF pos(y, x);
pos.rx() -= m_scrollOffset;
sizeHint.transpose();
if (QGuiApplication::isRightToLeft()) {
pos.rx() = m_size.width() + m_scrollOffset - pos.x() - sizeHint.width();
} else {
pos.rx() -= m_scrollOffset;
}
return QRectF(pos, sizeHint);
}
@ -361,7 +365,7 @@ void KItemListViewLayouter::doLayout()
const bool grouped = createGroupHeaders();
const bool horizontalScrolling = (m_scrollOrientation == Qt::Horizontal);
const bool horizontalScrolling = m_scrollOrientation == Qt::Horizontal;
if (horizontalScrolling) {
// Flip everything so that the layout logically can work like having
// a vertical scrolling
@ -377,8 +381,9 @@ void KItemListViewLayouter::doLayout()
}
}
const bool isRightToLeft = QGuiApplication::isRightToLeft();
m_columnWidth = itemSize.width() + itemMargin.width();
const qreal widthForColumns = size.width() - itemMargin.width();
const qreal widthForColumns = std::max(size.width() - itemMargin.width(), m_columnWidth);
m_columnCount = qMax(1, int(widthForColumns / m_columnWidth));
m_xPosInc = itemMargin.width();
@ -397,7 +402,7 @@ void KItemListViewLayouter::doLayout()
// Calculate the offset of each column, i.e., the x-coordinate where the column starts.
m_columnOffsets.resize(m_columnCount);
qreal currentOffset = QGuiApplication::isRightToLeft() ? widthForColumns : m_xPosInc;
qreal currentOffset = isRightToLeft ? widthForColumns : m_xPosInc;
if (grouped && horizontalScrolling) {
// All group headers will always be aligned on the top and not
@ -405,16 +410,21 @@ void KItemListViewLayouter::doLayout()
currentOffset += m_groupHeaderHeight;
}
if (QGuiApplication::isLeftToRight())
if (isRightToLeft) {
for (int column = 0; column < m_columnCount; ++column) {
if (horizontalScrolling) {
m_columnOffsets[column] = column * m_columnWidth;
} else {
currentOffset -= m_columnWidth;
m_columnOffsets[column] = currentOffset;
}
}
} else {
for (int column = 0; column < m_columnCount; ++column) {
m_columnOffsets[column] = currentOffset;
currentOffset += m_columnWidth;
}
else
for (int column = 0; column < m_columnCount; ++column) {
m_columnOffsets[column] = currentOffset - m_columnWidth;
currentOffset -= m_columnWidth;
}
}
// Prepare the QVector which stores the y-coordinate for each new row.
int numberOfRows = (itemCount + m_columnCount - 1) / m_columnCount;

View File

@ -309,7 +309,7 @@ void KItemListControllerTest::testKeyboardNavigation_data()
std::swap(nextItemKey, previousItemKey);
break;
case KFileItemListView::CompactLayout:
std::swap(nextItemKey, previousItemKey);
std::swap(nextRowKey, previousRowKey);
break;
default:
break;