|
@@ -0,0 +1,112 @@
|
|
|
|
|
+#include "wgtcodeeditor.h"
|
|
|
|
|
+
|
|
|
|
|
+#include <QPainter>
|
|
|
|
|
+#include <QTextBlock>
|
|
|
|
|
+#include "wgtlinenumberarea.h"
|
|
|
|
|
+#include "syntaxhighlighter.h"
|
|
|
|
|
+
|
|
|
|
|
+WgtCodeEditor::WgtCodeEditor(QWidget *parent)
|
|
|
|
|
+ : QPlainTextEdit(parent)
|
|
|
|
|
+{
|
|
|
|
|
+ QFont font;
|
|
|
|
|
+ font.setFamily("Courier");
|
|
|
|
|
+ font.setStyleHint(QFont::Monospace);
|
|
|
|
|
+ font.setFixedPitch(true);
|
|
|
|
|
+ font.setPointSize(10);
|
|
|
|
|
+ setFont(font);
|
|
|
|
|
+
|
|
|
|
|
+ const int tabStop = 4; // 4 characters
|
|
|
|
|
+ QFontMetrics metrics(font);
|
|
|
|
|
+ setTabStopWidth(tabStop * metrics.width(' '));
|
|
|
|
|
+
|
|
|
|
|
+ lineNumberArea = new WgtLineNumberArea(this);
|
|
|
|
|
+
|
|
|
|
|
+ new SyntaxHighlighter(document());
|
|
|
|
|
+
|
|
|
|
|
+ connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
|
|
|
|
|
+ connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
|
|
|
|
|
+ connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
|
|
|
|
|
+
|
|
|
|
|
+ updateLineNumberAreaWidth(0);
|
|
|
|
|
+ highlightCurrentLine();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int WgtCodeEditor::lineNumberAreaWidth()
|
|
|
|
|
+{
|
|
|
|
|
+ int digits = 1;
|
|
|
|
|
+ int max = qMax(1, blockCount());
|
|
|
|
|
+ while (max >= 10) {
|
|
|
|
|
+ max /= 10;
|
|
|
|
|
+ ++digits;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
|
|
|
|
|
+
|
|
|
|
|
+ return space;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void WgtCodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
|
|
|
|
|
+{
|
|
|
|
|
+ setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void WgtCodeEditor::updateLineNumberArea(const QRect &rect, int dy)
|
|
|
|
|
+{
|
|
|
|
|
+ if (dy)
|
|
|
|
|
+ lineNumberArea->scroll(0, dy);
|
|
|
|
|
+ else
|
|
|
|
|
+ lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
|
|
|
|
|
+
|
|
|
|
|
+ if (rect.contains(viewport()->rect()))
|
|
|
|
|
+ updateLineNumberAreaWidth(0);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void WgtCodeEditor::resizeEvent(QResizeEvent *e)
|
|
|
|
|
+{
|
|
|
|
|
+ QPlainTextEdit::resizeEvent(e);
|
|
|
|
|
+
|
|
|
|
|
+ QRect cr = contentsRect();
|
|
|
|
|
+ lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void WgtCodeEditor::highlightCurrentLine()
|
|
|
|
|
+{
|
|
|
|
|
+ QList<QTextEdit::ExtraSelection> extraSelections;
|
|
|
|
|
+
|
|
|
|
|
+ if (!isReadOnly()) {
|
|
|
|
|
+ QTextEdit::ExtraSelection selection;
|
|
|
|
|
+
|
|
|
|
|
+ QColor lineColor = QColor(Qt::yellow).lighter(160);
|
|
|
|
|
+
|
|
|
|
|
+ selection.format.setBackground(lineColor);
|
|
|
|
|
+ selection.format.setProperty(QTextFormat::FullWidthSelection, true);
|
|
|
|
|
+ selection.cursor = textCursor();
|
|
|
|
|
+ selection.cursor.clearSelection();
|
|
|
|
|
+ extraSelections.append(selection);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ setExtraSelections(extraSelections);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void WgtCodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
|
|
|
|
|
+{
|
|
|
|
|
+ QPainter painter(lineNumberArea);
|
|
|
|
|
+ painter.fillRect(event->rect(), Qt::lightGray);
|
|
|
|
|
+ QTextBlock block = firstVisibleBlock();
|
|
|
|
|
+ int blockNumber = block.blockNumber();
|
|
|
|
|
+ int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
|
|
|
|
|
+ int bottom = top + (int) blockBoundingRect(block).height();
|
|
|
|
|
+ while (block.isValid() && top <= event->rect().bottom()) {
|
|
|
|
|
+ if (block.isVisible() && bottom >= event->rect().top()) {
|
|
|
|
|
+ QString number = QString::number(blockNumber + 1);
|
|
|
|
|
+ painter.setPen(Qt::black);
|
|
|
|
|
+ painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(),
|
|
|
|
|
+ Qt::AlignRight, number);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ block = block.next();
|
|
|
|
|
+ top = bottom;
|
|
|
|
|
+ bottom = top + (int) blockBoundingRect(block).height();
|
|
|
|
|
+ ++blockNumber;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|