forked from qt-creator/qt-creator
Editor: Allow creating block selections with alt+shift again
These block selections are a convenience for people used to the block selection allowing to also unselect parts again (at least as long as alt+shift is pressed). Fixes: QTCREATORBUG-26535 Fixes: QTCREATORBUG-26529 Change-Id: I19558dc1d823c268cc1cfda0ea8151bac483701f Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -294,7 +294,7 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
|
||||
return layout->lineForTextPosition(relativePos);
|
||||
}
|
||||
|
||||
bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey)
|
||||
bool MultiTextCursor::multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey)
|
||||
{
|
||||
uint searchkey = (e->modifiers() | e->key())
|
||||
& ~(Qt::KeypadModifier
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "utils_global.h"
|
||||
|
||||
#include <QKeySequence>
|
||||
#include <QTextCursor>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@@ -99,6 +100,8 @@ public:
|
||||
const_iterator constBegin() const { return m_cursors.constBegin(); }
|
||||
const_iterator constEnd() const { return m_cursors.constEnd(); }
|
||||
|
||||
static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey);
|
||||
|
||||
private:
|
||||
QList<QTextCursor> m_cursors;
|
||||
};
|
||||
|
@@ -204,6 +204,11 @@ int TabSettings::columnAt(const QString &text, int position) const
|
||||
return column;
|
||||
}
|
||||
|
||||
int TabSettings::columnAtCursorPosition(const QTextCursor &cursor) const
|
||||
{
|
||||
return columnAt(cursor.block().text(), cursor.positionInBlock());
|
||||
}
|
||||
|
||||
int TabSettings::positionAtColumn(const QString &text, int column, int *offset, bool allowOverstep) const
|
||||
{
|
||||
int col = 0;
|
||||
|
@@ -66,6 +66,7 @@ public:
|
||||
|
||||
int lineIndentPosition(const QString &text) const;
|
||||
int columnAt(const QString &text, int position) const;
|
||||
int columnAtCursorPosition(const QTextCursor &cursor) const;
|
||||
int positionAtColumn(const QString &text, int column, int *offset = nullptr, bool allowOverstep = false) const;
|
||||
int columnCountForText(const QString &text, int startColumn = 0) const;
|
||||
int indentedColumn(int column, bool doIndent = true) const;
|
||||
|
@@ -782,6 +782,18 @@ public:
|
||||
bool m_scrollBarUpdateScheduled = false;
|
||||
|
||||
const MultiTextCursor m_cursors;
|
||||
struct BlockSelection
|
||||
{
|
||||
int blockNumber = -1;
|
||||
int column = -1;
|
||||
int anchorBlockNumber = -1;
|
||||
int anchorColumn = -1;
|
||||
};
|
||||
QList<BlockSelection> m_blockSelections;
|
||||
QList<QTextCursor> generateCursorsForBlockSelection(const BlockSelection &blockSelection);
|
||||
void initBlockSelection();
|
||||
void clearBlockSelection();
|
||||
void handleMoveBlockSelection(QTextCursor::MoveOperation op);
|
||||
|
||||
class UndoCursor
|
||||
{
|
||||
@@ -1348,6 +1360,81 @@ void TextEditorWidgetPrivate::updateAutoCompleteHighlight()
|
||||
q->setExtraSelections(TextEditorWidget::AutoCompleteSelection, extraSelections);
|
||||
}
|
||||
|
||||
QList<QTextCursor> TextEditorWidgetPrivate::generateCursorsForBlockSelection(
|
||||
const BlockSelection &blockSelection)
|
||||
{
|
||||
const TabSettings tabSettings = m_document->tabSettings();
|
||||
|
||||
QList<QTextCursor> result;
|
||||
QTextBlock block = m_document->document()->findBlockByNumber(blockSelection.anchorBlockNumber);
|
||||
QTextCursor cursor(block);
|
||||
cursor.setPosition(block.position()
|
||||
+ tabSettings.positionAtColumn(block.text(), blockSelection.anchorColumn));
|
||||
|
||||
const bool forward = blockSelection.blockNumber > blockSelection.anchorBlockNumber
|
||||
|| (blockSelection.blockNumber == blockSelection.anchorBlockNumber
|
||||
&& blockSelection.column == blockSelection.anchorColumn);
|
||||
|
||||
while (block.isValid()) {
|
||||
const QString &blockText = block.text();
|
||||
cursor.setPosition(block.position()
|
||||
+ tabSettings.positionAtColumn(blockText, blockSelection.anchorColumn));
|
||||
cursor.setPosition(block.position()
|
||||
+ tabSettings.positionAtColumn(blockText, blockSelection.column),
|
||||
QTextCursor::KeepAnchor);
|
||||
result.append(cursor);
|
||||
if (block.blockNumber() == blockSelection.blockNumber)
|
||||
break;
|
||||
block = forward ? block.next() : block.previous();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::initBlockSelection()
|
||||
{
|
||||
const TabSettings tabSettings = m_document->tabSettings();
|
||||
for (const QTextCursor &cursor : m_cursors) {
|
||||
const int column = tabSettings.columnAtCursorPosition(cursor);
|
||||
QTextCursor anchor = cursor;
|
||||
anchor.setPosition(anchor.anchor());
|
||||
const int anchorColumn = tabSettings.columnAtCursorPosition(anchor);
|
||||
m_blockSelections.append({cursor.blockNumber(), column, anchor.blockNumber(), anchorColumn});
|
||||
}
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::clearBlockSelection()
|
||||
{
|
||||
m_blockSelections.clear();
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::handleMoveBlockSelection(QTextCursor::MoveOperation op)
|
||||
{
|
||||
if (m_blockSelections.isEmpty())
|
||||
initBlockSelection();
|
||||
QList<QTextCursor> cursors;
|
||||
for (BlockSelection &blockSelection : m_blockSelections) {
|
||||
switch (op) {
|
||||
case QTextCursor::Up:
|
||||
blockSelection.blockNumber = qMax(0, blockSelection.blockNumber - 1);
|
||||
break;
|
||||
case QTextCursor::Down:
|
||||
blockSelection.blockNumber = qMin(m_document->document()->blockCount() - 1,
|
||||
blockSelection.blockNumber + 1);
|
||||
break;
|
||||
case QTextCursor::NextCharacter:
|
||||
++blockSelection.column;
|
||||
break;
|
||||
case QTextCursor::PreviousCharacter:
|
||||
blockSelection.column = qMax(0, blockSelection.column - 1);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
cursors.append(generateCursorsForBlockSelection(blockSelection));
|
||||
}
|
||||
q->setMultiTextCursor(MultiTextCursor(cursors));
|
||||
}
|
||||
|
||||
void TextEditorWidget::selectEncoding()
|
||||
{
|
||||
TextDocument *doc = d->m_document.data();
|
||||
@@ -2181,6 +2268,8 @@ static inline bool isPrintableText(const QString &text)
|
||||
|
||||
void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
ExecuteOnDestruction eod([&]() { d->clearBlockSelection(); });
|
||||
|
||||
if (!isModifier(e) && mouseHidingEnabled())
|
||||
viewport()->setCursor(Qt::BlankCursor);
|
||||
ToolTip::hide();
|
||||
@@ -2420,7 +2509,23 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
||||
}
|
||||
|
||||
if (ro || !isPrintableText(eventText)) {
|
||||
if (!d->cursorMoveKeyEvent(e)) {
|
||||
QTextCursor::MoveOperation blockSelectionOperation = QTextCursor::NoMove;
|
||||
if (e->modifiers() & Qt::AltModifier && !Utils::HostOsInfo::isMacHost()) {
|
||||
if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextLine))
|
||||
blockSelectionOperation = QTextCursor::Down;
|
||||
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousLine))
|
||||
blockSelectionOperation = QTextCursor::Up;
|
||||
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextChar))
|
||||
blockSelectionOperation = QTextCursor::NextCharacter;
|
||||
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousChar))
|
||||
blockSelectionOperation = QTextCursor::PreviousCharacter;
|
||||
}
|
||||
|
||||
if (blockSelectionOperation != QTextCursor::NoMove) {
|
||||
auto doNothing = [](){};
|
||||
eod.reset(doNothing);
|
||||
d->handleMoveBlockSelection(blockSelectionOperation);
|
||||
} else if (!d->cursorMoveKeyEvent(e)) {
|
||||
QTextCursor cursor = textCursor();
|
||||
bool cursorWithinSnippet = false;
|
||||
if (d->m_snippetOverlay->isVisible()
|
||||
@@ -5134,7 +5239,7 @@ void TextEditorWidget::mouseMoveEvent(QMouseEvent *e)
|
||||
cursor.addCursor(c);
|
||||
}
|
||||
cursor.mergeCursors();
|
||||
if (!cursor.isNull() && cursor != multiTextCursor())
|
||||
if (!cursor.isNull())
|
||||
setMultiTextCursor(cursor);
|
||||
} else {
|
||||
if (startMouseMoveCursor.has_value())
|
||||
|
Reference in New Issue
Block a user