From 6a675bb7e90418de544abaaf0d2a7e06cc2bff51 Mon Sep 17 00:00:00 2001 From: The11Doctor Date: Tue, 16 Nov 2021 12:54:59 +0100 Subject: [PATCH] First implementation of CodeEditor cell with line numbers and highligting current line --- Algorithm-visualizer/GUI/codeeditor.cpp | 105 ++++++++++++++++++++ Algorithm-visualizer/GUI/codeeditor.h | 33 ++++++ Algorithm-visualizer/GUI/linenumberarea.cpp | 1 + Algorithm-visualizer/GUI/linenumberarea.h | 31 ++++++ 4 files changed, 170 insertions(+) create mode 100644 Algorithm-visualizer/GUI/codeeditor.cpp create mode 100644 Algorithm-visualizer/GUI/codeeditor.h create mode 100644 Algorithm-visualizer/GUI/linenumberarea.cpp create mode 100644 Algorithm-visualizer/GUI/linenumberarea.h diff --git a/Algorithm-visualizer/GUI/codeeditor.cpp b/Algorithm-visualizer/GUI/codeeditor.cpp new file mode 100644 index 0000000..4e4f574 --- /dev/null +++ b/Algorithm-visualizer/GUI/codeeditor.cpp @@ -0,0 +1,105 @@ +#include "codeeditor.h" +#include "linenumberarea.h" + +CodeEditor::CodeEditor(QWidget *parent) +{ + lineNumberArea = new LineNumberArea(this); + + connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth); + connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea); + connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine); + + updateLineNumberAreaWidth(0); + highlightCurrentLine(); + +} + +int CodeEditor::lineNumberAreaWidth() +{ + int digits = 1; + int max = qMax(1, blockCount()); + while (max >= 10){ + max /=10; + digits++; + } + + int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits; + + return space; +} + +void CodeEditor::updateLineNumberAreaWidth(int /*newBlockCount*/) +{ + setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); +} + +void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) +{ + //dy holds the number of pixels, if it is non-zero we call scrol method between 0 and dy. + //else, + if (dy) { + lineNumberArea->scroll(0, dy); + } + else { + lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); + } + + if (rect.contains(viewport()->rect())) { + updateLineNumberAreaWidth(0); + } +} + +void CodeEditor::resizeEvent(QResizeEvent *event) +{ + QPlainTextEdit::resizeEvent(event); + + QRect cr = contentsRect(); + lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); +} + +void CodeEditor::highlightCurrentLine() +{ + QList 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 CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) +{ + //We start by creating the painter to paint the background of the widget. + QPainter painter(lineNumberArea); + painter.fillRect(event->rect(), Qt::lightGray); + + //Getting information on the blocks (i.e. the text lines) + QTextBlock block = firstVisibleBlock(); + int blockNumber = block.blockNumber(); + int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); //Need doc on this line + int bottom = top + qRound(blockBoundingRect(block).height()); //Need doc on this line as well (qRound??) + + 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); + } + + //We go to the next block + block = block.next(); + top = bottom; + bottom = top + qRound(blockBoundingRect(block).height()); + blockNumber++; + } +} diff --git a/Algorithm-visualizer/GUI/codeeditor.h b/Algorithm-visualizer/GUI/codeeditor.h new file mode 100644 index 0000000..0412a6e --- /dev/null +++ b/Algorithm-visualizer/GUI/codeeditor.h @@ -0,0 +1,33 @@ +#ifndef CODEEDITOR_H +#define CODEEDITOR_H + +#include +#include +#include +#include + +class CodeEditor : public QPlainTextEdit +{ + Q_OBJECT +public: + CodeEditor(QWidget *parent = nullptr); + + //Methos to paint the line numbers and to have acess to it's width + void lineNumberAreaPaintEvent(QPaintEvent *event); + int lineNumberAreaWidth(); + +protected: + //We need to be able to resize in case the viewer scrolls or the number of lines changes (adding a line at the bottom) + void resizeEvent(QResizeEvent *event) override; + +private slots: + //Methods to modify the elements of the line number are + void updateLineNumberAreaWidth(int newBlockCount); + void highlightCurrentLine(); + void updateLineNumberArea(const QRect &rect, int dy); + +private: + QWidget *lineNumberArea; +}; + +#endif // CODEEDITOR_H diff --git a/Algorithm-visualizer/GUI/linenumberarea.cpp b/Algorithm-visualizer/GUI/linenumberarea.cpp new file mode 100644 index 0000000..1feeb4d --- /dev/null +++ b/Algorithm-visualizer/GUI/linenumberarea.cpp @@ -0,0 +1 @@ +#include "linenumberarea.h" diff --git a/Algorithm-visualizer/GUI/linenumberarea.h b/Algorithm-visualizer/GUI/linenumberarea.h new file mode 100644 index 0000000..4a13153 --- /dev/null +++ b/Algorithm-visualizer/GUI/linenumberarea.h @@ -0,0 +1,31 @@ +#ifndef LINENUMBERAREA_H +#define LINENUMBERAREA_H + +#include + +#include "codeeditor.h" + +class LineNumberArea : public QWidget +{ + //Q_OBJECT +public: + //Constructor, we initialize the code editor attribute as a QWidget + LineNumberArea(CodeEditor *editor) : QWidget(editor), codeEditor(editor) + {} + + QSize sizeHint() const override + { + return QSize(codeEditor->lineNumberAreaWidth(), 0); + } + +protected: + void paintEvent(QPaintEvent *event) override + { + codeEditor->lineNumberAreaPaintEvent(event); + } + +private: + CodeEditor *codeEditor; +}; + +#endif // LINENUMBERAREA_H