diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-06-15 21:00:04 -0400 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2019-07-02 10:10:17 -0400 |
| commit | c79cf72d2250631110e8605ced6f34dda0378dc0 (patch) | |
| tree | 9f7e18acc0d0d24f146bb845ce0590fed35fd84a /src | |
| parent | fc8d5c1708aa126bb3301079d15787943a0f47c9 (diff) | |
line numbers, which required inheriting from QPlainTextEdit instead
Diffstat (limited to 'src')
| -rw-r--r-- | src/modinfodialog.cpp | 12 | ||||
| -rw-r--r-- | src/modinfodialog.h | 1 | ||||
| -rw-r--r-- | src/modinfodialog.ui | 14 | ||||
| -rw-r--r-- | src/texteditor.cpp | 148 | ||||
| -rw-r--r-- | src/texteditor.h | 33 |
5 files changed, 170 insertions, 38 deletions
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 169623ad..743f76b0 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -359,7 +359,7 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo } } - m_textFileEditor.reset(new TextEditor(ui->textFileView)); + ui->textFileView->setupToolbar(); ui->tabTextSplitter->setSizes({200, 1}); ui->tabTextSplitter->setStretchFactor(0, 0); @@ -1037,10 +1037,10 @@ void ModInfoDialog::thumbnailClicked(const QString &fileName) bool ModInfoDialog::allowNavigateFromTXT() { - if (m_textFileEditor->dirty()) { + if (ui->textFileView->dirty()) { const int res = QMessageBox::question( this, tr("Save changes?"), - tr("Save changes to \"%1\"?").arg(m_textFileEditor->filename()), + tr("Save changes to \"%1\"?").arg(ui->textFileView->filename()), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); if (res == QMessageBox::Cancel) { @@ -1071,7 +1071,7 @@ void ModInfoDialog::on_textFileList_currentItemChanged( { const QString fullPath = m_RootPath + "/" + current->text(); - if (fullPath == m_textFileEditor->filename()) { + if (fullPath == ui->textFileView->filename()) { // the new file is the same as the currently displayed file. May be the // result of a cancellation return; @@ -1086,7 +1086,7 @@ void ModInfoDialog::on_textFileList_currentItemChanged( void ModInfoDialog::openTextFile(const QString &fileName) { - m_textFileEditor->load(fileName); + ui->textFileView->load(fileName); } void ModInfoDialog::openIniFile(const QString &fileName) @@ -1165,7 +1165,7 @@ void ModInfoDialog::on_saveButton_clicked() void ModInfoDialog::saveCurrentTextFile() { - m_textFileEditor->save(); + ui->textFileView->save(); } diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 42ef990d..09924671 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -304,7 +304,6 @@ private: ExpanderWidget m_overwriteExpander, m_overwrittenExpander, m_nonconflictExpander;
FilterWidget m_advancedConflictFilter;
- std::unique_ptr<TextEditor> m_textFileEditor;
void refreshConflictLists(bool refreshGeneral, bool refreshAdvanced);
diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 513506a7..785fdeb4 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -46,14 +46,7 @@ <string>A list of text-files in the mod directory like readmes. </string>
</property>
</widget>
- <widget class="QPlainTextEdit" name="textFileView">
- <property name="toolTip">
- <string/>
- </property>
- <property name="whatsThis">
- <string/>
- </property>
- </widget>
+ <widget class="TextEditor" name="textFileView"/>
</widget>
</item>
</layout>
@@ -1217,6 +1210,11 @@ p, li { white-space: pre-wrap; } <extends>QLineEdit</extends>
<header>modidlineedit.h</header>
</customwidget>
+ <customwidget>
+ <class>TextEditor</class>
+ <extends>QPlainTextEdit</extends>
+ <header>texteditor.h</header>
+ </customwidget>
</customwidgets>
<resources>
<include location="resources.qrc"/>
diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 56ccfd2c..ecb46547 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -2,26 +2,27 @@ #include "utility.h" #include <QSplitter> -TextEditor::TextEditor(QPlainTextEdit* edit) - : m_edit(edit), m_toolbar(*this), m_dirty(false) +TextEditor::TextEditor(QWidget* parent) : + QPlainTextEdit(parent), + m_toolbar(*this), m_lineNumbers(nullptr), m_dirty(false) { - setupToolbar(); - - m_edit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); wordWrap(true); + m_lineNumbers = new TextEditorLineNumbers(*this); + emit modified(false); QObject::connect( - m_edit->document(), &QTextDocument::modificationChanged, + document(), &QTextDocument::modificationChanged, [&](bool b){ onModified(b); }); } bool TextEditor::load(const QString& filename) { m_filename = filename; - m_edit->setPlainText(MOBase::readFileText(filename, &m_encoding)); - m_edit->document()->setModified(false); + setPlainText(MOBase::readFileText(filename, &m_encoding)); + document()->setModified(false); return true; } @@ -37,10 +38,10 @@ bool TextEditor::save() file.resize(0); QTextCodec* codec = QTextCodec::codecForName(m_encoding.toUtf8()); - QString data = m_edit->toPlainText().replace("\n", "\r\n"); + QString data = toPlainText().replace("\n", "\r\n"); file.write(codec->fromUnicode(data)); - m_edit->document()->setModified(false); + document()->setModified(false); return true; } @@ -53,9 +54,9 @@ const QString& TextEditor::filename() const void TextEditor::wordWrap(bool b) { if (b) { - m_edit->setLineWrapMode(QPlainTextEdit::WidgetWidth); + setLineWrapMode(QPlainTextEdit::WidgetWidth); } else { - m_edit->setLineWrapMode(QPlainTextEdit::NoWrap); + setLineWrapMode(QPlainTextEdit::NoWrap); } emit wordWrapChanged(b); @@ -68,7 +69,7 @@ void TextEditor::toggleWordWrap() bool TextEditor::wordWrap() const { - return (m_edit->lineWrapMode() == QPlainTextEdit::WidgetWidth); + return (lineWrapMode() == QPlainTextEdit::WidgetWidth); } void TextEditor::dirty(bool b) @@ -98,7 +99,7 @@ void TextEditor::setupToolbar() // adding toolbar and edit layout->addWidget(m_toolbar.widget()); - layout->addWidget(m_edit); + layout->addWidget(this); // make the edit stretch layout->setStretch(0, 0); @@ -116,23 +117,132 @@ QWidget* TextEditor::wrapEditWidget() // wrapping the QPlainTextEdit into a new widget so the toolbar can be // displayed above it - if (auto* parentLayout=m_edit->parentWidget()->layout()) { + if (auto* parentLayout=parentWidget()->layout()) { // the edit's parent has a regular layout, replace the edit by the new // widget and delete the QLayoutItem that's returned as it's not needed - delete parentLayout->replaceWidget(m_edit, widget.get()); - } else if (auto* splitter=qobject_cast<QSplitter*>(m_edit->parentWidget())) { + delete parentLayout->replaceWidget(this, widget.get()); + + } else if (auto* splitter=qobject_cast<QSplitter*>(parentWidget())) { // the edit's parent is a QSplitter, which doesn't have a layout; replace // the edit by using its index in the splitter - splitter->replaceWidget(splitter->indexOf(m_edit), widget.get()); + auto index = splitter->indexOf(this); + + if (index == -1) { + qCritical( + "TextEditor: cannot wrap edit widget to display a toolbar, " + "parent is a splitter, but widget isn't in it"); + + return nullptr; + } + + splitter->replaceWidget(index, widget.get()); + } else { // unknown parent - qCritical("TextEditor: cannot wrap edit widget to display a toolbar"); + qCritical( + "TextEditor: cannot wrap edit widget to display a toolbar, " + "no parent or parent has no layout"); + return nullptr; } return widget.release(); } +void TextEditor::resizeEvent(QResizeEvent* e) +{ + QPlainTextEdit::resizeEvent(e); + + QRect cr = contentsRect(); + m_lineNumbers->setGeometry(QRect(cr.left(), cr.top(), m_lineNumbers->areaWidth(), cr.height())); +} + +void TextEditor::paintLineNumbers(QPaintEvent* e) +{ + QPainter painter(m_lineNumbers); + painter.fillRect(e->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 <= e->rect().bottom()) { + if (block.isVisible() && bottom >= e->rect().top()) { + QString number = QString::number(blockNumber + 1); + painter.setPen(Qt::black); + + painter.drawText( + 0, top, m_lineNumbers->width(), fontMetrics().height(), + Qt::AlignRight, number); + } + + block = block.next(); + top = bottom; + bottom = top + (int) blockBoundingRect(block).height(); + ++blockNumber; + } +} + + +TextEditorLineNumbers::TextEditorLineNumbers(TextEditor& editor) + : QWidget(&editor), m_editor(editor) +{ + setFont(editor.font()); + + connect(&m_editor, &QPlainTextEdit::blockCountChanged, [&]{ updateAreaWidth(); }); + connect(&m_editor, &QPlainTextEdit::updateRequest, [&](auto&& rect, int dy){ updateArea(rect, dy); }); + //connect(e, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); + + updateAreaWidth(); + //highlightCurrentLine(); +} + +QSize TextEditorLineNumbers::sizeHint() const +{ + return QSize(areaWidth(), 0); +} + +void TextEditorLineNumbers::paintEvent(QPaintEvent* e) +{ + m_editor.paintLineNumbers(e); +} + +int TextEditorLineNumbers::areaWidth() const +{ + int digits = 1; + int max = qMax(1, m_editor.blockCount()); + + while (max >= 10) { + max /= 10; + ++digits; + } + + digits = std::max(3, digits); + + int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits; + + return space; +} + +void TextEditorLineNumbers::updateAreaWidth() +{ + m_editor.setViewportMargins(areaWidth(), 0, 0, 0); +} + +void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) +{ + if (dy) { + scroll(0, dy); + } else { + update(0, rect.y(), width(), rect.height()); + } + + if (rect.contains(m_editor.viewport()->rect())) { + updateAreaWidth(); + } +} + TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : m_editor(editor), diff --git a/src/texteditor.h b/src/texteditor.h index c196b7a4..af542341 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -23,12 +23,33 @@ private: }; -class TextEditor : public QObject +class TextEditorLineNumbers : public QWidget +{ +public: + TextEditorLineNumbers(TextEditor& editor); + QSize sizeHint() const override; + int areaWidth() const; + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + TextEditor& m_editor; + + void updateAreaWidth(); + void updateArea(const QRect &rect, int dy); +}; + + +class TextEditor : public QPlainTextEdit { Q_OBJECT + friend class TextEditorLineNumbers; public: - TextEditor(QPlainTextEdit* edit); + TextEditor(QWidget* parent=nullptr); + + void setupToolbar(); bool load(const QString& filename); bool save(); @@ -45,9 +66,12 @@ signals: void modified(bool b); void wordWrapChanged(bool b); +protected: + void resizeEvent(QResizeEvent* e) override; + private: - QPlainTextEdit* m_edit; TextEditorToolbar m_toolbar; + TextEditorLineNumbers* m_lineNumbers; QString m_filename; QString m_encoding; bool m_dirty; @@ -55,8 +79,9 @@ private: void onModified(bool b); void dirty(bool b); - void setupToolbar(); QWidget* wrapEditWidget(); + + void paintLineNumbers(QPaintEvent* e); }; #endif // MO_TEXTEDITOR_H |
