QCodeEdit blockselection patch, ready to use

This commit is contained in:
2020-09-23 22:14:13 +03:00
parent a89fb3d8f2
commit 577f20a110
2 changed files with 95 additions and 39 deletions

View File

@@ -30,18 +30,12 @@ public:
} }
void paintEvent(QPaintEvent * e) override { void paintEvent(QPaintEvent * e) override {
//qDebug() << "paint" << geometry(); if (!isEnabled()) return;
//QPainter p(this);
//p.fillRect(rect(), Qt::red);
//QWidget::paintEvent(e);
ce->drawCursor(); ce->drawCursor();
} }
bool event(QEvent * e) override {
//qDebug() << "event" << e;
return QWidget::event(e);
}
QCodeEdit * ce; QCodeEdit * ce;
}; };
@@ -157,6 +151,7 @@ QCodeEdit::QCodeEdit(QWidget * parent): QWidget(parent) {
connect(ui->textCode, SIGNAL(textChanged()), this, SIGNAL(textChanged())); connect(ui->textCode, SIGNAL(textChanged()), this, SIGNAL(textChanged()));
connect(ui->textCode, SIGNAL(cursorPositionChanged()), this, SLOT(textEdit_cursorPositionChanged())); connect(ui->textCode, SIGNAL(cursorPositionChanged()), this, SLOT(textEdit_cursorPositionChanged()));
connect(ui->textCode, SIGNAL(selectionChanged()), this, SLOT(textEdit_selectionChanged())); connect(ui->textCode, SIGNAL(selectionChanged()), this, SLOT(textEdit_selectionChanged()));
connect(ui->textCode, SIGNAL(redoAvailable(bool)), this, SLOT(textEdit_redoAvailable(bool)));
connect(ui->comboSearch->lineEdit(), SIGNAL(returnPressed()), this, SLOT(searchNext())); connect(ui->comboSearch->lineEdit(), SIGNAL(returnPressed()), this, SLOT(searchNext()));
connect(ui->comboReplace->lineEdit(), SIGNAL(returnPressed()), this, SLOT(on_buttonReplaceSearch_clicked())); connect(ui->comboReplace->lineEdit(), SIGNAL(returnPressed()), this, SLOT(on_buttonReplaceSearch_clicked()));
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
@@ -190,6 +185,7 @@ QTextDocument * QCodeEdit::document() const {
void QCodeEdit::setDocument(QTextDocument * doc) { void QCodeEdit::setDocument(QTextDocument * doc) {
cancelBlockSelection();
if (document()) { if (document()) {
document()->setProperty("_cursor", QVariant::fromValue(textCursor())); document()->setProperty("_cursor", QVariant::fromValue(textCursor()));
document()->setProperty("_vpos", textEdit()->verticalScrollBar()->value()); document()->setProperty("_vpos", textEdit()->verticalScrollBar()->value());
@@ -454,23 +450,36 @@ bool QCodeEdit::eventFilter(QObject * o, QEvent * e) {
} }
if (ui->textCode) { if (ui->textCode) {
if (o == ui->textCode->viewport()) { if (o == ui->textCode->viewport()) {
if (e->type() == QEvent::MouseButtonPress) { switch (e->type()) {
case QEvent::MouseButtonPress: {
cancelBlockSelection(); cancelBlockSelection();
completer->hide(); completer->hide();
hideHelp(); hideHelp();
QMouseEvent * me = (QMouseEvent*)e; QMouseEvent * me = (QMouseEvent*)e;
if (me->modifiers().testFlag(Qt::ControlModifier) && (me->button() == Qt::LeftButton)) { if (me->modifiers().testFlag(Qt::ControlModifier) && (me->button() == Qt::LeftButton))
gotoLink(); gotoLink();
} } break;
} case QEvent::MouseMove: {
if (e->type() == QEvent::MouseMove && completer->isHidden()) { if (!completer->isHidden()) break;
QMouseEvent * me = (QMouseEvent*)e; QMouseEvent * me = (QMouseEvent*)e;
switchBlockSelection(); switchBlockSelection();
if (me->modifiers().testFlag(Qt::ControlModifier)) if (me->modifiers().testFlag(Qt::ControlModifier))
showLink(); showLink();
} } break;
if (e->type() == QEvent::Paint) { case QEvent::Paint:
resizeOverlay(); resizeOverlay();
break;
case QEvent::DragMove:
if (!isEnabled()) break;
drag_cursor = ui->textCode->cursorForPosition(((QDragMoveEvent*)e)->pos());
repaintCursor();
break;
case QEvent::MouseButtonRelease:
case QEvent::DragLeave:
case QEvent::Drop:
cancelDragCursor();
break;
default: break;
} }
return QWidget::eventFilter(o, e); return QWidget::eventFilter(o, e);
} }
@@ -498,6 +507,9 @@ bool QCodeEdit::eventFilter(QObject * o, QEvent * e) {
_ignore_focus_out = false; _ignore_focus_out = false;
break; break;
} }
case QEvent::FocusIn:
createBlockSelection();
break;
case QEvent::Hide: case QEvent::Hide:
case QEvent::HideToParent: case QEvent::HideToParent:
hideLink(); hideLink();
@@ -636,7 +648,7 @@ bool QCodeEdit::codeKeyEvent(QKeyEvent * ke) {
case Qt::Key_Return: case Qt::Key_Return:
if (hasBlockSelection()) { if (hasBlockSelection()) {
cancelBlockSelection(); cancelBlockSelection();
break; return true;
} }
if (completer->isVisible()) { if (completer->isVisible()) {
commitCompletition(); commitCompletition();
@@ -745,7 +757,8 @@ void QCodeEdit::highlightBrackets() {
void QCodeEdit::applyExtraSelection() { void QCodeEdit::applyExtraSelection() {
ui->textCode->setExtraSelections(QList<QTextEdit::ExtraSelection>() << es_line << es_selected ui->textCode->setExtraSelections(QList<QTextEdit::ExtraSelection>() << es_line << es_selected
<< es_custom << es_brackets << es_search_list << es_cursor << es_link); << es_custom << es_brackets << es_search_list << es_cursor
<< es_link << es_blockselection);
} }
@@ -774,7 +787,7 @@ int QCodeEdit::searchIndFromCursor() {
} }
QRect QCodeEdit::cursorRect(QRect * line) { QRect QCodeEdit::cursorRect() {
QRect r = ui->textCode->cursorRect(textCursor()), lr = r; QRect r = ui->textCode->cursorRect(textCursor()), lr = r;
if (hasBlockSelection()) { if (hasBlockSelection()) {
r |= ui->textCode->cursorRect(block_start_cursor); r |= ui->textCode->cursorRect(block_start_cursor);
@@ -782,15 +795,14 @@ QRect QCodeEdit::cursorRect(QRect * line) {
lr.setHeight(r.height()); lr.setHeight(r.height());
} }
lr.setWidth(cursor_width); lr.setWidth(cursor_width);
if (line) *line = lr; return lr;
return (r | lr);
} }
QRect QCodeEdit::blockSelectionRect() { QRect QCodeEdit::blockSelectionRect() {
QTextCursor tc = ui->textCode->textCursor(); QTextCursor tc = ui->textCode->textCursor();
QPoint ps(block_start_cursor.columnNumber(), block_start_cursor.blockNumber()), QPoint ps(block_start_cursor.positionInBlock(), block_start_cursor.blockNumber()),
pe(tc.columnNumber(), tc.blockNumber()); pe(tc.positionInBlock(), tc.blockNumber());
QRect bsr(QPoint(qMin(ps.x(), pe.x()), qMin(ps.y(), pe.y())), QRect bsr(QPoint(qMin(ps.x(), pe.x()), qMin(ps.y(), pe.y())),
QSize(qAbs(ps.x() - pe.x()), qAbs(ps.y() - pe.y()) + 1)); QSize(qAbs(ps.x() - pe.x()), qAbs(ps.y() - pe.y()) + 1));
return bsr; return bsr;
@@ -803,20 +815,22 @@ void QCodeEdit::repaintCursor() {
void QCodeEdit::drawCursor() { void QCodeEdit::drawCursor() {
if (!isEnabled() || !ui->textCode->hasFocus()) return;
QPainter p(overlay); QPainter p(overlay);
QTextCursor tc = textCursor(); QTextCursor tc = textCursor();
//qDebug() << block_start_cursor.position() << tc.position(); //qDebug() << block_start_cursor.position() << tc.position();
QRect line, all = cursorRect(&line); QRect line = cursorRect();
if (hasBlockSelection() && (tc.columnNumber() != block_start_cursor.columnNumber())) {
p.setCompositionMode(QPainter::CompositionMode_Difference);
QColor hc = palette().color(QPalette::Highlight);
p.fillRect(all, QColor(255 - hc.red(), 255 - hc.green(), 255 - hc.blue()));
}
if (cursor_state && ui->textCode->hasFocus()) { if (cursor_state && ui->textCode->hasFocus()) {
line.adjust(0, 1, 0, -1); line.adjust(0, 1, 0, -1);
p.setCompositionMode(QPainter::CompositionMode_Difference); p.setCompositionMode(QPainter::CompositionMode_Difference);
p.fillRect(line, Qt::white); p.fillRect(line, Qt::white);
} }
if (!drag_cursor.isNull()) {
line = ui->textCode->cursorRect(drag_cursor);
line.setWidth(cursor_width);
p.setCompositionMode(QPainter::CompositionMode_Difference);
p.fillRect(line, Qt::white);
}
} }
@@ -830,17 +844,20 @@ void QCodeEdit::startBlockSelection() {
QTextCursor tc = textCursor(); QTextCursor tc = textCursor();
block_start_cursor = tc; block_start_cursor = tc;
block_start_cursor.setPosition(tc.selectionStart()); block_start_cursor.setPosition(tc.selectionStart());
}} }
}
void QCodeEdit::cancelBlockSelection() { void QCodeEdit::cancelBlockSelection() {
block_start_cursor = QTextCursor(); block_start_cursor = QTextCursor();
es_blockselection.clear();
applyExtraSelection();
} }
void QCodeEdit::switchBlockSelection(QKeyEvent * ke) { void QCodeEdit::switchBlockSelection(QKeyEvent * ke) {
bool alt = QApplication::keyboardModifiers().testFlag(Qt::AltModifier); bool alt = QApplication::keyboardModifiers().testFlag(Qt::AltModifier);
if (ke) alt = ke->modifiers().testFlag(Qt::AltModifier); if (ke) alt = ke->modifiers().testFlag(Qt::AltModifier) && ke->modifiers().testFlag(Qt::ShiftModifier);
if (alt) { if (alt) {
startBlockSelection(); startBlockSelection();
QTextCursor tc = ui->textCode->textCursor(); QTextCursor tc = ui->textCode->textCursor();
@@ -875,10 +892,10 @@ bool QCodeEdit::removeBlockSelection(bool is_del) {
//qDebug() << bsr; //qDebug() << bsr;
for (int l = bsr.top(); l <= bsr.bottom(); ++l) { for (int l = bsr.top(); l <= bsr.bottom(); ++l) {
QTextCursor ctc(ui->textCode->document()->findBlockByNumber(l)); QTextCursor ctc(ui->textCode->document()->findBlockByNumber(l));
ctc.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, bsr.left()); ctc.setPosition(ctc.block().position() + bsr.left(), QTextCursor::MoveAnchor);
if (l != ctc.blockNumber()) continue; if (l != ctc.blockNumber()) continue;
int pos = ctc.position(); int pos = ctc.position();
ctc.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, bsr.width()); ctc.setPosition(ctc.block().position() + bsr.right() + 1, QTextCursor::KeepAnchor);
if (l != ctc.blockNumber()) { if (l != ctc.blockNumber()) {
ctc.setPosition(pos); ctc.setPosition(pos);
ctc.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); ctc.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
@@ -900,7 +917,7 @@ void QCodeEdit::insertBlockSelection(QString text) {
if (bsr.width() > 0) removeBlockSelection(false); if (bsr.width() > 0) removeBlockSelection(false);
for (int l = bsr.top(); l <= bsr.bottom(); ++l) { for (int l = bsr.top(); l <= bsr.bottom(); ++l) {
QTextCursor ctc(ui->textCode->document()->findBlockByNumber(l)); QTextCursor ctc(ui->textCode->document()->findBlockByNumber(l));
ctc.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, bsr.left()); ctc.setPosition(ctc.block().position() + bsr.left(), QTextCursor::MoveAnchor);
if (l != ctc.blockNumber()) { if (l != ctc.blockNumber()) {
ctc = QTextCursor(ui->textCode->document()->findBlockByNumber(l)); ctc = QTextCursor(ui->textCode->document()->findBlockByNumber(l));
ctc.movePosition(QTextCursor::EndOfLine); ctc.movePosition(QTextCursor::EndOfLine);
@@ -914,6 +931,36 @@ void QCodeEdit::insertBlockSelection(QString text) {
} }
void QCodeEdit::createBlockSelection() {
if (!hasBlockSelection()) return;
es_blockselection.clear();
QTextEdit::ExtraSelection es;
es.format.setForeground(palette().brush(QPalette::HighlightedText));
es.format.setBackground(palette().brush(QPalette::Highlight));
QRect bsr = blockSelectionRect();
for (int l = bsr.top(); l <= bsr.bottom(); ++l) {
QTextCursor ctc(ui->textCode->document()->findBlockByNumber(l));
ctc.setPosition(ctc.block().position() + bsr.left(), QTextCursor::MoveAnchor);
if (l != ctc.blockNumber()) continue;
int pos = ctc.position();
ctc.setPosition(ctc.block().position() + bsr.right() + 1, QTextCursor::KeepAnchor);
if (l != ctc.blockNumber()) {
ctc.setPosition(pos);
ctc.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
}
es.cursor = ctc;
es_blockselection << es;
}
applyExtraSelection();
}
void QCodeEdit::cancelDragCursor() {
drag_cursor = QTextCursor();
overlay->update();
}
void QCodeEdit::searchAll() { void QCodeEdit::searchAll() {
QString st = ui->comboSearch->currentText(); QString st = ui->comboSearch->currentText();
es_search_list.clear(); es_search_list.clear();
@@ -1206,7 +1253,6 @@ void QCodeEdit::autoIndent() {
QTextCursor tc = ui->textCode->textCursor(), stc = tc; QTextCursor tc = ui->textCode->textCursor(), stc = tc;
tc.movePosition(QTextCursor::StartOfLine); tc.movePosition(QTextCursor::StartOfLine);
if (!tc.movePosition(QTextCursor::Up)) return; if (!tc.movePosition(QTextCursor::Up)) return;
tc.beginEditBlock();
tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor); tc.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor);
QString line = tc.selectedText(), tabs; QString line = tc.selectedText(), tabs;
int i = 0; int i = 0;
@@ -1220,9 +1266,10 @@ void QCodeEdit::autoIndent() {
int nt = qMax<int>(0, line.count(QChar('{')) - line.count(QChar('}'))); int nt = qMax<int>(0, line.count(QChar('{')) - line.count(QChar('}')));
tabs.append(QString("\t").repeated(nt)); tabs.append(QString("\t").repeated(nt));
if (tabs.isEmpty()) return; if (tabs.isEmpty()) return;
stc.beginEditBlock();
stc.insertText(tabs); stc.insertText(tabs);
ui->textCode->setTextCursor(stc); ui->textCode->setTextCursor(stc);
tc.endEditBlock(); stc.endEditBlock();
} }
@@ -1641,6 +1688,7 @@ void QCodeEdit::commitCompletition() {
void QCodeEdit::textEdit_cursorPositionChanged() { void QCodeEdit::textEdit_cursorPositionChanged() {
es_line.cursor = ui->textCode->textCursor(); es_line.cursor = ui->textCode->textCursor();
//qDebug() << "cursorPositionChanged" << es_line.cursor.position();
es_line.cursor.select(QTextCursor::LineUnderCursor); es_line.cursor.select(QTextCursor::LineUnderCursor);
es_line.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); es_line.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
highlightBrackets(); highlightBrackets();
@@ -1648,7 +1696,7 @@ void QCodeEdit::textEdit_cursorPositionChanged() {
if (timer_blink) killTimer(timer_blink); if (timer_blink) killTimer(timer_blink);
timer_blink = startTimer(QApplication::cursorFlashTime() / 2); timer_blink = startTimer(QApplication::cursorFlashTime() / 2);
cursor_state = true; cursor_state = true;
repaintCursor(); createBlockSelection();
} }
@@ -1690,6 +1738,11 @@ void QCodeEdit::textEdit_selectionChanged() {
} }
void QCodeEdit::textEdit_redoAvailable(bool available) {
if (available) cancelBlockSelection();
}
void QCodeEdit::setShowSpaces(bool yes) { void QCodeEdit::setShowSpaces(bool yes) {
spaces_ = yes; spaces_ = yes;
QTextOption to = ui->textCode->document()->defaultTextOption(); QTextOption to = ui->textCode->document()->defaultTextOption();

View File

@@ -143,11 +143,11 @@ private:
QFrame * widget_help; QFrame * widget_help;
_QCE_Viewport * overlay; _QCE_Viewport * overlay;
QTextEdit::ExtraSelection es_line, es_cursor, es_bracket, es_range, es_search, es_link; QTextEdit::ExtraSelection es_line, es_cursor, es_bracket, es_range, es_search, es_link;
QList<QTextEdit::ExtraSelection> es_selected, es_custom, es_brackets, es_search_list; QList<QTextEdit::ExtraSelection> es_selected, es_custom, es_brackets, es_search_list, es_blockselection;
QMap<int, ACClass> ac_classes; QMap<int, ACClass> ac_classes;
QStringList cursor_scope; QStringList cursor_scope;
ACEntry link_entry, help_entry; ACEntry link_entry, help_entry;
QTextCursor block_start_cursor; QTextCursor block_start_cursor, drag_cursor;
int prev_lc, auto_comp_pl, timer_parse, timer_blink, cur_search_ind, pos_press, pos_el_press; int prev_lc, auto_comp_pl, timer_parse, timer_blink, cur_search_ind, pos_press, pos_el_press;
int cursor_width; int cursor_width;
bool spaces_, _ignore_focus_out, _first, _destructor, _replacing; bool spaces_, _ignore_focus_out, _first, _destructor, _replacing;
@@ -164,7 +164,7 @@ private:
void clearSearch(); void clearSearch();
void moveToSearch(); void moveToSearch();
int searchIndFromCursor(); int searchIndFromCursor();
QRect cursorRect(QRect * line = 0); QRect cursorRect();
QRect blockSelectionRect(); QRect blockSelectionRect();
void repaintCursor(); void repaintCursor();
void drawCursor(); void drawCursor();
@@ -174,6 +174,8 @@ private:
void switchBlockSelection(QKeyEvent * ke = 0); void switchBlockSelection(QKeyEvent * ke = 0);
bool removeBlockSelection(bool is_del); bool removeBlockSelection(bool is_del);
void insertBlockSelection(QString text); void insertBlockSelection(QString text);
void createBlockSelection();
void cancelDragCursor();
ACEntry findEntryOnCursor(QTextCursor tc, int arg = -1, ACClass * acc = 0, QPair<QStringList, QString> * scope = 0); ACEntry findEntryOnCursor(QTextCursor tc, int arg = -1, ACClass * acc = 0, QPair<QStringList, QString> * scope = 0);
private slots: private slots:
@@ -202,6 +204,7 @@ private slots:
void textEdit_cursorPositionChanged(); void textEdit_cursorPositionChanged();
void textEdit_textChanged(); void textEdit_textChanged();
void textEdit_selectionChanged(); void textEdit_selectionChanged();
void textEdit_redoAvailable(bool available);
void on_comboSearch_currentTextChanged(const QString & t); void on_comboSearch_currentTextChanged(const QString & t);
void on_buttonReplace_clicked(); void on_buttonReplace_clicked();
void on_buttonReplaceSearch_clicked(); void on_buttonReplaceSearch_clicked();