--- /dev/null
+#include <QPainter>
+#include <QPaintEvent>
+#include <QTextBlock>
+#include "CodeWidget.hxx"
+
+// --- CodeWidget: constructors and deconstructors ---
+
+CodeWidget::CodeWidget(QWidget *parent)
+: QPlainTextEdit(parent), _area(new Area(this))
+{
+ setupActions();
+ updateAreaWidth(0);
+ highlightLine();
+}
+
+CodeWidget::CodeWidget(const QString& text, QWidget *parent)
+: QPlainTextEdit(text, parent), _area(new Area(this))
+{
+ setupActions();
+ updateAreaWidth(0);
+ highlightLine();
+}
+
+CodeWidget::~CodeWidget()
+{
+ delete _area;
+}
+
+// --- CodeWidget: public methods ---
+
+void CodeWidget::areaPaintEvent(QPaintEvent *event)
+{
+ QPainter painter(_area);
+ QTextBlock block = firstVisibleBlock();
+ qint32 block_num = block.blockNumber();
+ qint32 top = blockBoundingGeometry(block).translated(contentOffset()).top();
+ qint32 bottom = top + blockBoundingRect(block).height();
+
+ painter.fillRect(event->rect(), Qt::lightGray);
+
+ while (block.isValid() && top <= event->rect().bottom())
+ {
+ if (block.isVisible() && bottom >= event->rect().top())
+ {
+ QString number = QString::number(block_num + 1);
+ painter.setPen(Qt::black);
+ painter.drawText(0, top, _area->width(), fontMetrics().height(), Qt::AlignRight, number);
+ }
+
+ block = block.next();
+ top = bottom;
+ bottom = top + blockBoundingRect(block).height();
+ ++block_num;
+ }
+}
+
+qint32 CodeWidget::areaWidth() const
+{
+ qint32 digits = 1;
+ qint32 max = qMax(1, blockCount());
+ qint32 space = 3;
+
+ while (max >= 10)
+ {
+ max /= 10;
+ ++digits;
+ }
+
+ space += fontMetrics().width(QLatin1Char('9')) * digits;
+
+ return space;
+}
+
+// --- CodeWidget: protected methods ---
+
+void CodeWidget::resizeEvent(QResizeEvent *event)
+{
+ QPlainTextEdit::resizeEvent(event);
+ _area->setGeometry(QRect(contentsRect().left(), contentsRect().top(), areaWidth(), contentsRect().height()));
+}
+
+void CodeWidget::setupActions()
+{
+ connect(this, SIGNAL(blockCountChanged(qint32)),
+ this, SLOT(updateAreaWidth(qint32)));
+ connect(this, SIGNAL(updateRequest(QRect, qint32)),
+ this, SLOT(updateArea(QRect, qint32)));
+ connect(this, SIGNAL(cursorPositionChanged()),
+ this, SLOT(highlightLine()));
+}
+
+// --- CodeWidget: protected slots ---
+
+void CodeWidget::updateAreaWidth(qint32 /*block_count*/)
+{
+ setViewportMargins(areaWidth(), 0, 0, 0);
+}
+
+void CodeWidget::highlightLine()
+{
+ QList<QTextEdit::ExtraSelection> selections;
+
+ if (!isReadOnly())
+ {
+ QTextEdit::ExtraSelection sel;
+ QColor color = QColor(Qt::yellow).lighter(160);
+
+ sel.format.setBackground(color);
+ sel.format.setProperty(QTextFormat::FullWidthSelection, true);
+ sel.cursor = textCursor();
+ sel.cursor.clearSelection();
+ selections.append(sel);
+ }
+
+ setExtraSelections(selections);
+}
+
+void CodeWidget::updateArea(const QRect& rect, qint32 dy)
+{
+ if (dy)
+ _area->scroll(0, dy);
+ else
+ _area->update(0, rect.y(), _area->width(), rect.height());
+
+ if (rect.contains(viewport()->rect()))
+ updateAreaWidth(0);
+}
+
+// --- Area: constructors and deconstructors ---
+
+Area::Area(CodeWidget *parent)
+: QWidget(parent), _parent(parent)
+{
+}
+
+Area::~Area()
+{
+ _parent = 0;
+}
+
+// --- Area: public methods ---
+
+QSize Area::sizeHint() const
+{
+ return QSize(_parent->areaWidth(), 0);
+}
+
+// --- Area: protected methods ---
+
+void Area::paintEvent(QPaintEvent *event)
+{
+ _parent->areaPaintEvent(event);
+}
--- /dev/null
+#pragma once
+
+#include <QPlainTextEdit>
+
+class CodeWidget : public QPlainTextEdit {
+ Q_OBJECT
+public:
+ explicit CodeWidget(QWidget *parent = 0);
+ explicit CodeWidget(const QString& text, QWidget *parent = 0);
+ virtual ~CodeWidget();
+
+ void areaPaintEvent(QPaintEvent *event);
+ qint32 areaWidth() const;
+
+protected:
+ virtual void resizeEvent(QResizeEvent *event) override;
+
+ void setupActions();
+
+protected slots:
+ void updateAreaWidth(qint32 block_count);
+ void highlightLine();
+ void updateArea(const QRect& rect, qint32 dy);
+
+private:
+ QWidget *_area;
+};
+
+class Area : public QWidget {
+ Q_OBJECT
+public:
+ explicit Area(CodeWidget *parent);
+ virtual ~Area();
+
+ QSize sizeHint() const;
+
+protected:
+ virtual void paintEvent(QPaintEvent *event) override;
+
+private:
+ CodeWidget *_parent;
+};
<x>0</x>
<y>0</y>
<width>782</width>
- <height>530</height>
+ <height>531</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<number>0</number>
</property>
<item>
- <widget class="QTextEdit" name="ed_text">
+ <widget class="CodeWidget" name="ed_text">
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
- <property name="documentTitle">
- <string notr="true"/>
- </property>
- <property name="html">
- <string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
- </property>
</widget>
</item>
</layout>
<x>0</x>
<y>0</y>
<width>800</width>
- <height>22</height>
+ <height>21</height>
</rect>
</property>
<widget class="QMenu" name="mm_text">
</property>
</action>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>CodeWidget</class>
+ <extends>QPlainTextEdit</extends>
+ <header>common/CodeWidget.hxx</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>