Editor: Improve multi text cursor selection

Allow to select text with ctrl+shift+(move operation in a line)

Fixes: QTCREATORBUG-31166
Change-Id: I2ffd02ca4a25e9074cf073d1d7e6639931fe7dc7
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2024-07-01 10:51:55 +02:00
parent 057a54364d
commit bb08762123
3 changed files with 48 additions and 42 deletions

View File

@@ -330,13 +330,10 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
return layout->lineForTextPosition(relativePos); return layout->lineForTextPosition(relativePos);
} }
bool MultiTextCursor::multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey) bool MultiTextCursor::multiCursorEvent(
QKeyEvent *e, QKeySequence::StandardKey matchKey, Qt::KeyboardModifiers filterModifiers)
{ {
uint searchkey = (e->modifiers() | e->key()) uint searchkey = (e->modifiers() | e->key()) & ~(filterModifiers | Qt::AltModifier);
& ~(Qt::KeypadModifier
| Qt::GroupSwitchModifier
| Qt::AltModifier
| Qt::ShiftModifier);
const QList<QKeySequence> bindings = QKeySequence::keyBindings(matchKey); const QList<QKeySequence> bindings = QKeySequence::keyBindings(matchKey);
return bindings.contains(QKeySequence(searchkey)); return bindings.contains(QKeySequence(searchkey));
@@ -348,42 +345,42 @@ bool MultiTextCursor::handleMoveKeyEvent(QKeyEvent *e,
{ {
if (e->modifiers() & Qt::AltModifier && !Utils::HostOsInfo::isMacHost()) { if (e->modifiers() & Qt::AltModifier && !Utils::HostOsInfo::isMacHost()) {
QTextCursor::MoveOperation op = QTextCursor::NoMove; QTextCursor::MoveOperation op = QTextCursor::NoMove;
if (multiCursorAddEvent(e, QKeySequence::MoveToNextWord)) { if (multiCursorEvent(e, QKeySequence::MoveToNextWord)) {
op = QTextCursor::WordRight; op = QTextCursor::WordRight;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToPreviousWord)) { } else if (multiCursorEvent(e, QKeySequence::MoveToPreviousWord)) {
op = QTextCursor::WordLeft; op = QTextCursor::WordLeft;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToEndOfBlock)) { } else if (multiCursorEvent(e, QKeySequence::MoveToEndOfBlock)) {
op = QTextCursor::EndOfBlock; op = QTextCursor::EndOfBlock;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToStartOfBlock)) { } else if (multiCursorEvent(e, QKeySequence::MoveToStartOfBlock)) {
op = QTextCursor::StartOfBlock; op = QTextCursor::StartOfBlock;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToNextLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToNextLine, Qt::ShiftModifier)) {
op = QTextCursor::Down; op = QTextCursor::Down;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToPreviousLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToPreviousLine, Qt::ShiftModifier)) {
op = QTextCursor::Up; op = QTextCursor::Up;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToStartOfLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToStartOfLine)) {
op = QTextCursor::StartOfLine; op = QTextCursor::StartOfLine;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToEndOfLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToEndOfLine)) {
op = QTextCursor::EndOfLine; op = QTextCursor::EndOfLine;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToStartOfDocument)) { } else if (multiCursorEvent(e, QKeySequence::MoveToStartOfDocument)) {
op = QTextCursor::Start; op = QTextCursor::Start;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToEndOfDocument)) { } else if (multiCursorEvent(e, QKeySequence::MoveToEndOfDocument)) {
op = QTextCursor::End; op = QTextCursor::End;
} else {
return false;
} }
const std::list<QTextCursor> cursors = m_cursorList; if (op != QTextCursor::NoMove) {
for (QTextCursor cursor : cursors) { const std::list<QTextCursor> cursors = m_cursorList;
if (camelCaseNavigationEnabled && op == QTextCursor::WordRight) for (QTextCursor cursor : cursors) {
CamelCaseCursor::right(&cursor, edit, QTextCursor::MoveAnchor); if (camelCaseNavigationEnabled && op == QTextCursor::WordRight)
else if (camelCaseNavigationEnabled && op == QTextCursor::WordLeft) CamelCaseCursor::right(&cursor, edit, QTextCursor::MoveAnchor);
CamelCaseCursor::left(&cursor, edit, QTextCursor::MoveAnchor); else if (camelCaseNavigationEnabled && op == QTextCursor::WordLeft)
else CamelCaseCursor::left(&cursor, edit, QTextCursor::MoveAnchor);
cursor.movePosition(op, QTextCursor::MoveAnchor); else
cursor.movePosition(op, QTextCursor::MoveAnchor);
addCursor(cursor); addCursor(cursor);
}
return true;
} }
return true;
} }
for (auto it = m_cursorList.begin(); it != m_cursorList.end(); ++it) { for (auto it = m_cursorList.begin(); it != m_cursorList.end(); ++it) {
@@ -395,28 +392,28 @@ bool MultiTextCursor::handleMoveKeyEvent(QKeyEvent *e,
op = QTextCursor::Right; op = QTextCursor::Right;
} else if (e == QKeySequence::MoveToPreviousChar) { } else if (e == QKeySequence::MoveToPreviousChar) {
op = QTextCursor::Left; op = QTextCursor::Left;
} else if (e == QKeySequence::SelectNextChar) { } else if (multiCursorEvent(e, QKeySequence::SelectNextChar)) {
op = QTextCursor::Right; op = QTextCursor::Right;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectPreviousChar) { } else if (multiCursorEvent(e, QKeySequence::SelectPreviousChar)) {
op = QTextCursor::Left; op = QTextCursor::Left;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectNextWord) { } else if (multiCursorEvent(e, QKeySequence::SelectNextWord)) {
op = QTextCursor::WordRight; op = QTextCursor::WordRight;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectPreviousWord) { } else if (multiCursorEvent(e, QKeySequence::SelectPreviousWord)) {
op = QTextCursor::WordLeft; op = QTextCursor::WordLeft;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectStartOfLine) { } else if (multiCursorEvent(e, QKeySequence::SelectStartOfLine)) {
op = QTextCursor::StartOfLine; op = QTextCursor::StartOfLine;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectEndOfLine) { } else if (multiCursorEvent(e, QKeySequence::SelectEndOfLine)) {
op = QTextCursor::EndOfLine; op = QTextCursor::EndOfLine;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectStartOfBlock) { } else if (multiCursorEvent(e, QKeySequence::SelectStartOfBlock)) {
op = QTextCursor::StartOfBlock; op = QTextCursor::StartOfBlock;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectEndOfBlock) { } else if (multiCursorEvent(e, QKeySequence::SelectEndOfBlock)) {
op = QTextCursor::EndOfBlock; op = QTextCursor::EndOfBlock;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectStartOfDocument) { } else if (e == QKeySequence::SelectStartOfDocument) {

View File

@@ -108,7 +108,10 @@ public:
const_iterator constBegin() const { return m_cursorMap.cbegin(); } const_iterator constBegin() const { return m_cursorMap.cbegin(); }
const_iterator constEnd() const { return m_cursorMap.cend(); } const_iterator constEnd() const { return m_cursorMap.cend(); }
static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey); static bool multiCursorEvent(
QKeyEvent *e,
QKeySequence::StandardKey matchKey,
Qt::KeyboardModifiers additionalFilterModifier = {});
private: private:
std::list<QTextCursor> m_cursorList; std::list<QTextCursor> m_cursorList;

View File

@@ -3089,15 +3089,21 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
if (ro || !isPrintableText(eventText)) { if (ro || !isPrintableText(eventText)) {
QTextCursor::MoveOperation blockSelectionOperation = QTextCursor::NoMove; QTextCursor::MoveOperation blockSelectionOperation = QTextCursor::NoMove;
if (e->modifiers() == (Qt::AltModifier | Qt::ShiftModifier) && !Utils::HostOsInfo::isMacHost()) { if (e->modifiers() == (Qt::AltModifier | Qt::ShiftModifier)
if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextLine)) && !Utils::HostOsInfo::isMacHost()) {
if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToNextLine, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::Down; blockSelectionOperation = QTextCursor::Down;
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousLine)) } else if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToPreviousLine, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::Up; blockSelectionOperation = QTextCursor::Up;
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextChar)) } else if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToNextChar, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::NextCharacter; blockSelectionOperation = QTextCursor::NextCharacter;
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousChar)) } else if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToPreviousChar, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::PreviousCharacter; blockSelectionOperation = QTextCursor::PreviousCharacter;
}
} }
if (blockSelectionOperation != QTextCursor::NoMove) { if (blockSelectionOperation != QTextCursor::NoMove) {