From 441be22410db2e8d5072ddc8e5c2f1ae6d81e660 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 11 Jan 2021 11:45:18 +0000 Subject: [PATCH] Override QTreeView::moveCursor to fix scrollbar behaviour. Closes #2144 * This prevents SH_ItemView_ArrowKeysNavigateIntoChildren from causing left-move from an expanded node to jump immediately to its parent instead of collapsing it when the scrollbar is not leftmost --- qrenderdoc/Widgets/Extended/RDTreeView.cpp | 66 ++++++++++++++++++++++ qrenderdoc/Widgets/Extended/RDTreeView.h | 2 + 2 files changed, 68 insertions(+) diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.cpp b/qrenderdoc/Widgets/Extended/RDTreeView.cpp index 334189e70..4f420955f 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeView.cpp @@ -26,11 +26,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -602,3 +604,67 @@ void RDTreeView::drawBranches(QPainter *painter, const QRect &rect, const QModel style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this); } } + +QModelIndex RDTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) +{ + // Qt's handling for MoveLeft is a little broken when scrollbars are in use, so we customise it + // do almost the same thing but with a fix + if(cursorAction == QAbstractItemView::MoveLeft) + { + // The default MoveRight is fine. It does in order: + // 1. if the current item is expandable but not expanded, it expands it. + // 2. if SH_ItemView_ArrowKeysNavigateIntoChildren is enabled it moves to the first child of the + // current item if there is one. + // 3. finally it tries to scroll right, either by selecting the next column or just moving the + // scrollbar. + // + // That's all good, but MoveLeft is not symmetric. Meaning it will do this: + // 1. if the current item is expandable and expanded, collapse it, *but only if the scrollbar is + // all the way to the left*. + // 2. if SH_ItemView_ArrowKeysNavigateIntoChildren is enabled it moves to the current item's + // parent. + // 3. finally it tries to scroll left if it can't do that. + // + // The problem here is that because scrolling left is still the last-resort icon, pressing right + // to expand an item and then perhaps scrolling right is not "undone" by pressing left, since + // we've now scrolled so the collapse doesn't happen and instead we jump to the parent node. + // + // To fix this, we scroll first, then handle the other two cases + + QModelIndex current = currentIndex(); + + if(selectionBehavior() == QAbstractItemView::SelectItems || + selectionBehavior() == QAbstractItemView::SelectColumns) + { + int col = header()->visualIndex(current.column()); + // move left one + col--; + + // keep moving if the column is hiden + while(col >= 0 && isColumnHidden(header()->logicalIndex(col))) + col--; + + // if we landed on a valid column (we may have gone negative if we were already on the first + // column) return it + if(col >= 0) + { + QModelIndex sel = current.sibling(current.row(), header()->logicalIndex(col)); + if(sel.isValid()) + return sel; + } + } + + // if we didn't scroll left above by selecting an index, and the scrollbar is still not + // minimised, scroll it left now. + QScrollBar *scroll = horizontalScrollBar(); + if(scroll->value() > scroll->minimum()) + { + scroll->setValue(scroll->value() - scroll->singleStep()); + return current; + } + + // otherwise we can use the default behaviour + } + + return QTreeView::moveCursor(cursorAction, modifiers); +} diff --git a/qrenderdoc/Widgets/Extended/RDTreeView.h b/qrenderdoc/Widgets/Extended/RDTreeView.h index a30db224d..b3bbbf8f3 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeView.h +++ b/qrenderdoc/Widgets/Extended/RDTreeView.h @@ -148,6 +148,8 @@ protected: const QModelIndex &index) const override; void drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const override; + QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override; + void fillBranchesRect(QPainter *painter, const QRect &rect, const QModelIndex &index) const; void enableBranchRectFill(bool fill) { m_fillBranchRect = fill; } QModelIndex m_currentHoverIndex;