summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-06-15 21:00:04 -0400
committerisanae <14251494+isanae@users.noreply.github.com>2019-07-02 10:10:17 -0400
commitc79cf72d2250631110e8605ced6f34dda0378dc0 (patch)
tree9f7e18acc0d0d24f146bb845ce0590fed35fd84a /src
parentfc8d5c1708aa126bb3301079d15787943a0f47c9 (diff)
line numbers, which required inheriting from QPlainTextEdit instead
Diffstat (limited to 'src')
-rw-r--r--src/modinfodialog.cpp12
-rw-r--r--src/modinfodialog.h1
-rw-r--r--src/modinfodialog.ui14
-rw-r--r--src/texteditor.cpp148
-rw-r--r--src/texteditor.h33
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