]> git.sven.stormbind.net Git - sven/vym.git/blob - src/codeeditor.cpp
Replace Pierre as the maintainer
[sven/vym.git] / src / codeeditor.cpp
1 #include <QtWidgets>
2
3 #include "codeeditor.h"
4
5 extern bool usingDarkTheme;
6
7 CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
8 {
9     lineNumberArea = new LineNumberArea(this);
10
11     connect(this, SIGNAL(blockCountChanged(int)), this,
12             SLOT(updateLineNumberAreaWidth(int)));
13     connect(this, SIGNAL(updateRequest(QRect, int)), this,
14             SLOT(updateLineNumberArea(QRect, int)));
15     connect(this, SIGNAL(cursorPositionChanged()), this,
16             SLOT(highlightCurrentLine()));
17
18     updateLineNumberAreaWidth(0);
19     highlightCurrentLine();
20 }
21
22 int CodeEditor::lineNumberAreaWidth()
23 {
24     int digits = 1;
25     int max = qMax(1, blockCount());
26     while (max >= 10) {
27         max /= 10;
28         ++digits;
29     }
30
31     int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
32
33     return space;
34 }
35
36 void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
37 {
38     setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
39 }
40
41 void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
42 {
43     if (dy)
44         lineNumberArea->scroll(0, dy);
45     else
46         lineNumberArea->update(0, rect.y(), lineNumberArea->width(),
47                                rect.height());
48
49     if (rect.contains(viewport()->rect()))
50         updateLineNumberAreaWidth(0);
51 }
52
53 void CodeEditor::resizeEvent(QResizeEvent *e)
54 {
55     QPlainTextEdit::resizeEvent(e);
56
57     QRect cr = contentsRect();
58     lineNumberArea->setGeometry(
59         QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
60 }
61
62 void CodeEditor::highlightCurrentLine()
63 {
64     QList<QTextEdit::ExtraSelection> extraSelections;
65
66     if (!isReadOnly()) {
67         QTextEdit::ExtraSelection selection;
68
69         QColor lineColor;
70         if (usingDarkTheme)
71             lineColor = QColor(Qt::darkGray).darker(150);
72         else
73             lineColor = QColor(Qt::yellow).lighter(160);
74
75         selection.format.setBackground(lineColor);
76         selection.format.setProperty(QTextFormat::FullWidthSelection, true);
77         selection.cursor = textCursor();
78         selection.cursor.clearSelection();
79         extraSelections.append(selection);
80     }
81
82     setExtraSelections(extraSelections);
83 }
84
85 void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
86 {
87     QPainter painter(lineNumberArea);
88     if (usingDarkTheme)
89         painter.fillRect(event->rect(), QColor(Qt::darkGray).darker(150));
90     else
91         painter.fillRect(event->rect(), Qt::lightGray);
92
93     QTextBlock block = firstVisibleBlock();
94     int blockNumber = block.blockNumber();
95     int top =
96         (int)blockBoundingGeometry(block).translated(contentOffset()).top();
97     int bottom = top + (int)blockBoundingRect(block).height();
98
99     QColor penColor;
100     if (usingDarkTheme)
101         penColor = Qt::lightGray;
102     else
103         penColor = Qt::black;
104
105     while (block.isValid() && top <= event->rect().bottom()) {
106         if (block.isVisible() && bottom >= event->rect().top()) {
107             QString number = QString::number(blockNumber + 1);
108             painter.setPen(penColor);
109             painter.drawText(0, top, lineNumberArea->width(),
110                              fontMetrics().height(), Qt::AlignRight, number);
111         }
112
113         block = block.next();
114         top = bottom;
115         bottom = top + (int)blockBoundingRect(block).height();
116         ++blockNumber;
117     }
118 }