1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "codeeditor.h"
#include "linenumberarea.h"
#include <QPainter>
#include <QTextBlock>
CodeEditor::CodeEditor(QWidget *parent)
: QPlainTextEdit{parent}
, m_lineNumberArea{new LineNumberArea{this}}
{
setupConnections();
updateLineNumberAreaWidth();
highlightCurrentLine();
}
void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
const QRect eventRect = event->rect();
QPainter painter{m_lineNumberArea};
painter.fillRect(eventRect, palette().color(QPalette::AlternateBase));
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
qreal top = blockBoundingGeometry(block).translated(contentOffset()).top();
qreal bottom = top + blockBoundingRect(block).height();
while (block.isVisible() && (top <= eventRect.bottom()) && (blockNumber < blockCount())) {
if (block.isVisible() && (bottom >= eventRect.top())) {
const QString number = QString::number(blockNumber + 1);
painter.setPen(palette().color(QPalette::Text));
painter.drawText(0, qRound(top), m_lineNumberArea->width() - 5, fontMetrics().height(),
Qt::AlignRight, number);
}
block = block.next();
top = bottom;
bottom = top + blockBoundingRect(block).height();
++blockNumber;
}
}
int CodeEditor::lineNumberAreaWidth() const
{
int digits = 1;
int max = qMax(1, blockCount());
while (max >= 10) {
max /= 10;
++digits;
}
const int space = 9 + fontMetrics().horizontalAdvance('9') * digits;
return space;
}
void CodeEditor::setupConnections()
{
connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth);
connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea);
connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine);
}
void CodeEditor::resizeEvent(QResizeEvent *event)
{
QPlainTextEdit::resizeEvent(event);
const QRect rect = contentsRect();
m_lineNumberArea->setGeometry(rect.left(), rect.top(), lineNumberAreaWidth(), rect.height());
}
void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
{
if (dy)
m_lineNumberArea->scroll(0, dy);
else
m_lineNumberArea->update(0, rect.y(), m_lineNumberArea->width(), rect.height());
if (rect.contains(viewport()->rect()))
updateLineNumberAreaWidth();
}
void CodeEditor::updateLineNumberAreaWidth()
{
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
void CodeEditor::highlightCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;
if (!isReadOnly()) {
QTextEdit::ExtraSelection selection;
selection.format.setBackground(palette().color(QPalette::AlternateBase));
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}
setExtraSelections(extraSelections);
}
|